Skip to content

Conversation

@michaeldwan
Copy link
Member

Summary

Fixes the flaky TestLoginGenericRegistryPTY/prompts_for_username_and_password test that was failing in CI.

Problem

The test had a race condition in the PTY reader logic:

  • Each call to waitForPattern() created a new goroutine reading from the PTY with its own buffer
  • These goroutines were never stopped
  • When the second waitForPattern() was called (for the password prompt), its fresh buffer missed data that the first goroutine had already read
  • This caused intermittent failures where the password prompt appeared to be missing

CI failure example:

login_test.go:133: Output after username: ""
login_test.go:136: expected password prompt, got: ""

Solution

Refactored to use a single shared reader pattern (matching the passing rejects_empty_username subtest):

  • One mutex-protected buffer shared across all reads
  • Single reader goroutine that writes to the shared buffer
  • waitForPattern() now polls the shared buffer instead of spawning its own reader
  • Proper cleanup with a done channel

Testing

All login tests pass locally:

=== RUN   TestLoginGenericRegistryPTY/prompts_for_username_and_password
    login_test.go:123: Output after start: "Logging in to fake-registry.example.com\r\n\r\nUsername: "
    login_test.go:140: Output after username: "Logging in to fake-registry.example.com\r\n\r\nUsername: testuser\r\nPassword: "
    login_test.go:155: Final output: "Logging in to fake-registry.example.com\r\n\r\nUsername: testuser\r\nPassword: \r\nLogin succeeded for fake-registry.example.com\r\n"
--- PASS: TestLoginGenericRegistryPTY (2.51s)

The prompts_for_username_and_password subtest was flaky because each
call to waitForPattern() created a new goroutine reading from the PTY
with its own buffer. These goroutines were never stopped, so when the
second waitForPattern() was called, its fresh buffer missed data that
the first goroutine had already read.

Fixed by using a single shared reader pattern:
- One mutex-protected buffer shared across all reads
- Single reader goroutine that writes to the shared buffer
- waitForPattern() now polls the shared buffer
- Proper cleanup with a done channel
@michaeldwan michaeldwan requested a review from a team as a code owner February 4, 2026 00:00
@michaeldwan michaeldwan merged commit 2261c96 into main Feb 4, 2026
27 checks passed
@michaeldwan michaeldwan deleted the md/fix-pty-test branch February 4, 2026 15:54
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.

2 participants