Skip to content

tests: assign proxy ports dynamically#1524

Open
supervacuus wants to merge 5 commits intomasterfrom
tests/dynamic_proxy_port_assignment
Open

tests: assign proxy ports dynamically#1524
supervacuus wants to merge 5 commits intomasterfrom
tests/dynamic_proxy_port_assignment

Conversation

@supervacuus
Copy link
Collaborator

I often encounter issues when running proxy integration tests because required ports are already in use, which leads to various errors.

This PR

  • instructs mitmdump to acquire the test port from the OS
  • parses the output of mitmdump (unbuffered!)
  • and uses the assigned port number throughout the test
  • example constructs the full URL from a port number we pass in via env SENTRY_TEST_PROXY_PORT

#skip-changelog

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

buf = b""
while time.monotonic() < deadline:
ch = proxy_process.stdout.read(1)
if not ch:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proxy startup timeout can block indefinitely

Medium Severity

_parse_listening_port uses blocking proxy_process.stdout.read(1) inside a deadline loop. If mitmdump stays alive but does not emit a byte on stdout, the read blocks and the timeout is never enforced, so tests can hang instead of failing fast.

Fix in Cursor Fix in Web

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I enabled PYTHONUNBUFFERED=1 exactly for this reason, and mitdump always prints at the start. I think this is a fair assumption. If this turns out to be pathological, we can start with IO-multiplexing or a thread with a timer. Until then i prefer the simple solution.

deadline = time.monotonic() + timeout
buf = b""
while time.monotonic() < deadline:
ch = proxy_process.stdout.read(1)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: A deadlock can occur because the code performs a blocking read on the subprocess's stdout while never reading from stderr, potentially causing the stderr buffer to fill and block the process.
Severity: CRITICAL

Suggested Fix

To prevent a deadlock, use non-blocking I/O to read from both the stdout and stderr streams of the subprocess concurrently. This ensures that the stderr buffer does not fill up and block the subprocess from writing to stdout. Consider using select.select or threads to handle both streams.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: tests/proxy.py#L39

Potential issue: The function `_parse_listening_port` initiates a subprocess with both
`stdout` and `stderr` pipes. It then performs a blocking read on `stdout` via
`proxy_process.stdout.read(1)` but never reads from `stderr`. If the subprocess writes
enough data to fill the `stderr` pipe's buffer, it will block. This, in turn, prevents
it from writing to `stdout`, causing the parent process to wait indefinitely on the
`read(1)` call. This creates a deadlock, and the timeout check `while time.monotonic() <
deadline` becomes ineffective because the loop is stuck on the blocking I/O call,
causing the test to hang.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant