test(pty): synchronize darwin resize assertion
- commit
- 3f44aacc7e0dd80352e4d9a6a418cc2028f465c0
- author
- brice · · 2026-07-16 17:57 UTC
- parent
- 68625c9
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +36 -1
M internal/adapters/pty/pty_darwin_test.go +36 -1
| @@ -74,19 +74,54 @@ func TestOpen_DarwinEchoAndOutputEOF(t *testing.T) { | |||
| 74 | 74 | require.Contains(t, output, "roundtrip") | |
| 75 | 75 | } | |
| 76 | 76 | ||
| 77 | + | func readUntilDarwin(t *testing.T, p ports.PTY, marker string, deadline time.Duration) string { | |
| 78 | + | t.Helper() | |
| 79 | + | type result struct { | |
| 80 | + | output string | |
| 81 | + | err error | |
| 82 | + | } | |
| 83 | + | resultCh := make(chan result, 1) | |
| 84 | + | go func() { | |
| 85 | + | var output strings.Builder | |
| 86 | + | buf := make([]byte, 256) | |
| 87 | + | for !strings.Contains(output.String(), marker) { | |
| 88 | + | n, err := p.Read(buf) | |
| 89 | + | output.Write(buf[:n]) | |
| 90 | + | if err != nil { | |
| 91 | + | resultCh <- result{output: output.String(), err: err} | |
| 92 | + | return | |
| 93 | + | } | |
| 94 | + | } | |
| 95 | + | resultCh <- result{output: output.String()} | |
| 96 | + | }() | |
| 97 | + | ||
| 98 | + | select { | |
| 99 | + | case result := <-resultCh: | |
| 100 | + | require.NoError(t, result.err) | |
| 101 | + | return result.output | |
| 102 | + | case <-time.After(deadline): | |
| 103 | + | t.Fatal("timed out waiting for pty readiness") | |
| 104 | + | return "" | |
| 105 | + | } | |
| 106 | + | } | |
| 107 | + | ||
| 77 | 108 | func TestOpen_DarwinResizeAndForegroundPgid(t *testing.T) { | |
| 78 | 109 | if testing.Short() { | |
| 79 | 110 | t.Skip("skipping pty integration test in -short mode") | |
| 80 | 111 | } | |
| 81 | 112 | ||
| 82 | - | p, err := pty.NewFactory().Open(context.Background(), "sh", []string{"-c", "sleep 0.2; stty size"}, os.Environ(), "", domain.Size{Cols: 80, Rows: 24}) | |
| 113 | + | const ready = "__vev_ready__" | |
| 114 | + | p, err := pty.NewFactory().Open(context.Background(), "sh", []string{"-c", "stty -echo; printf '__vev_ready__\\n'; IFS= read -r release; stty size"}, os.Environ(), "", domain.Size{Cols: 80, Rows: 24}) | |
| 83 | 115 | require.NoError(t, err) | |
| 84 | 116 | t.Cleanup(func() { _ = p.Close() }) | |
| 85 | 117 | ||
| 118 | + | require.Contains(t, readUntilDarwin(t, p, ready, 5*time.Second), ready) | |
| 86 | 119 | pgid, err := p.ForegroundPgid() | |
| 87 | 120 | require.NoError(t, err) | |
| 88 | 121 | require.Greater(t, pgid, 0) | |
| 89 | 122 | require.NoError(t, p.Resize(domain.Size{Cols: 120, Rows: 40})) | |
| 123 | + | _, err = io.WriteString(p, "release\n") | |
| 124 | + | require.NoError(t, err) | |
| 90 | 125 | require.Equal(t, "40 120", strings.TrimSpace(string(readAllDarwin(t, p, 5*time.Second)))) | |
| 91 | 126 | } | |
| 92 | 127 | ||
| @@ -74,19 +74,54 @@ func TestOpen_DarwinEchoAndOutputEOF(t *testing.T) { | |||||
| 74 | require.Contains(t, output, "roundtrip") | 74 | require.Contains(t, output, "roundtrip") | ||
| 75 | } | 75 | } | ||
| 76 | 76 | ||||
| 77 | + | func readUntilDarwin(t *testing.T, p ports.PTY, marker string, deadline time.Duration) string { | |||
| 78 | + | t.Helper() | |||
| 79 | + | type result struct { | |||
| 80 | + | output string | |||
| 81 | + | err error | |||
| 82 | + | } | |||
| 83 | + | resultCh := make(chan result, 1) | |||
| 84 | + | go func() { | |||
| 85 | + | var output strings.Builder | |||
| 86 | + | buf := make([]byte, 256) | |||
| 87 | + | for !strings.Contains(output.String(), marker) { | |||
| 88 | + | n, err := p.Read(buf) | |||
| 89 | + | output.Write(buf[:n]) | |||
| 90 | + | if err != nil { | |||
| 91 | + | resultCh <- result{output: output.String(), err: err} | |||
| 92 | + | return | |||
| 93 | + | } | |||
| 94 | + | } | |||
| 95 | + | resultCh <- result{output: output.String()} | |||
| 96 | + | }() | |||
| 97 | + | ||||
| 98 | + | select { | |||
| 99 | + | case result := <-resultCh: | |||
| 100 | + | require.NoError(t, result.err) | |||
| 101 | + | return result.output | |||
| 102 | + | case <-time.After(deadline): | |||
| 103 | + | t.Fatal("timed out waiting for pty readiness") | |||
| 104 | + | return "" | |||
| 105 | + | } | |||
| 106 | + | } | |||
| 107 | + | ||||
| 77 | func TestOpen_DarwinResizeAndForegroundPgid(t *testing.T) { | 108 | func TestOpen_DarwinResizeAndForegroundPgid(t *testing.T) { | ||
| 78 | if testing.Short() { | 109 | if testing.Short() { | ||
| 79 | t.Skip("skipping pty integration test in -short mode") | 110 | t.Skip("skipping pty integration test in -short mode") | ||
| 80 | } | 111 | } | ||
| 81 | 112 | ||||
| 82 | - | p, err := pty.NewFactory().Open(context.Background(), "sh", []string{"-c", "sleep 0.2; stty size"}, os.Environ(), "", domain.Size{Cols: 80, Rows: 24}) | 113 | + | const ready = "__vev_ready__" |
| 114 | + | p, err := pty.NewFactory().Open(context.Background(), "sh", []string{"-c", "stty -echo; printf '__vev_ready__\\n'; IFS= read -r release; stty size"}, os.Environ(), "", domain.Size{Cols: 80, Rows: 24}) | |||
| 83 | require.NoError(t, err) | 115 | require.NoError(t, err) | ||
| 84 | t.Cleanup(func() { _ = p.Close() }) | 116 | t.Cleanup(func() { _ = p.Close() }) | ||
| 85 | 117 | ||||
| 118 | + | require.Contains(t, readUntilDarwin(t, p, ready, 5*time.Second), ready) | |||
| 86 | pgid, err := p.ForegroundPgid() | 119 | pgid, err := p.ForegroundPgid() | ||
| 87 | require.NoError(t, err) | 120 | require.NoError(t, err) | ||
| 88 | require.Greater(t, pgid, 0) | 121 | require.Greater(t, pgid, 0) | ||
| 89 | require.NoError(t, p.Resize(domain.Size{Cols: 120, Rows: 40})) | 122 | require.NoError(t, p.Resize(domain.Size{Cols: 120, Rows: 40})) | ||
| 123 | + | _, err = io.WriteString(p, "release\n") | |||
| 124 | + | require.NoError(t, err) | |||
| 90 | require.Equal(t, "40 120", strings.TrimSpace(string(readAllDarwin(t, p, 5*time.Second)))) | 125 | require.Equal(t, "40 120", strings.TrimSpace(string(readAllDarwin(t, p, 5*time.Second)))) | ||
| 91 | } | 126 | } | ||
| 92 | 127 | ||||