test(darwin): stabilize macos CI paths and prewarm
- commit
- f569d8b7f056a5834a43ec454aef47ea9046c0bb
- author
- brice · · 2026-07-16 18:58 UTC
- parent
- 27e6e25
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +52 -10
M internal/adapters/ipc/dial_test.go +2 -3
| @@ -3,7 +3,6 @@ package ipc | |||
| 3 | 3 | import ( | |
| 4 | 4 | "context" | |
| 5 | 5 | "errors" | |
| 6 | - | "path/filepath" | |
| 7 | 6 | "testing" | |
| 8 | 7 | "time" | |
| 9 | 8 | ||
| @@ -43,7 +42,7 @@ func TestDialContextCanceledOrExpired(t *testing.T) { | |||
| 43 | 42 | ctx, cancel := tt.ctx() | |
| 44 | 43 | defer cancel() | |
| 45 | 44 | ||
| 46 | - | transport, err := DialContext(ctx, t.TempDir()) | |
| 45 | + | transport, err := DialContext(ctx, shortSocketDir(t)) | |
| 47 | 46 | if transport != nil { | |
| 48 | 47 | t.Fatal("DialContext returned a transport for a completed context") | |
| 49 | 48 | } | |
| @@ -55,7 +54,7 @@ func TestDialContextCanceledOrExpired(t *testing.T) { | |||
| 55 | 54 | } | |
| 56 | 55 | ||
| 57 | 56 | func TestDialContextPreservesOptions(t *testing.T) { | |
| 58 | - | dir := filepath.Join(t.TempDir(), "vev") | |
| 57 | + | dir := shortSocketDir(t, "vev") | |
| 59 | 58 | listener, err := Listen(dir) | |
| 60 | 59 | if err != nil { | |
| 61 | 60 | t.Fatalf("Listen: %v", err) | |
| @@ -3,7 +3,6 @@ package ipc | |||||
| 3 | import ( | 3 | import ( | ||
| 4 | "context" | 4 | "context" | ||
| 5 | "errors" | 5 | "errors" | ||
| 6 | - | "path/filepath" | |||
| 7 | "testing" | 6 | "testing" | ||
| 8 | "time" | 7 | "time" | ||
| 9 | 8 | ||||
| @@ -43,7 +42,7 @@ func TestDialContextCanceledOrExpired(t *testing.T) { | |||||
| 43 | ctx, cancel := tt.ctx() | 42 | ctx, cancel := tt.ctx() | ||
| 44 | defer cancel() | 43 | defer cancel() | ||
| 45 | 44 | ||||
| 46 | - | transport, err := DialContext(ctx, t.TempDir()) | 45 | + | transport, err := DialContext(ctx, shortSocketDir(t)) |
| 47 | if transport != nil { | 46 | if transport != nil { | ||
| 48 | t.Fatal("DialContext returned a transport for a completed context") | 47 | t.Fatal("DialContext returned a transport for a completed context") | ||
| 49 | } | 48 | } | ||
| @@ -55,7 +54,7 @@ func TestDialContextCanceledOrExpired(t *testing.T) { | |||||
| 55 | } | 54 | } | ||
| 56 | 55 | ||||
| 57 | func TestDialContextPreservesOptions(t *testing.T) { | 56 | func TestDialContextPreservesOptions(t *testing.T) { | ||
| 58 | - | dir := filepath.Join(t.TempDir(), "vev") | 57 | + | dir := shortSocketDir(t, "vev") |
| 59 | listener, err := Listen(dir) | 58 | listener, err := Listen(dir) | ||
| 60 | if err != nil { | 59 | if err != nil { | ||
| 61 | t.Fatalf("Listen: %v", err) | 60 | t.Fatalf("Listen: %v", err) | ||
M internal/adapters/ipc/listener_test.go +5 -6
| @@ -13,7 +13,7 @@ import ( | |||
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | func TestListenAcceptRoundTrip(t *testing.T) { | |
| 16 | - | dir := filepath.Join(t.TempDir(), "vev") | |
| 16 | + | dir := shortSocketDir(t, "vev") | |
| 17 | 17 | ||
| 18 | 18 | ln, err := Listen(dir) | |
| 19 | 19 | if err != nil { | |
| @@ -65,8 +65,7 @@ func TestListenAcceptRoundTrip(t *testing.T) { | |||
| 65 | 65 | } | |
| 66 | 66 | ||
| 67 | 67 | func TestListenMkdirsSocketDir(t *testing.T) { | |
| 68 | - | base := t.TempDir() | |
| 69 | - | dir := filepath.Join(base, "nested", "socketdir") | |
| 68 | + | dir := shortSocketDir(t, "nested", "socketdir") | |
| 70 | 69 | ||
| 71 | 70 | ln, err := Listen(dir) | |
| 72 | 71 | if err != nil { | |
| @@ -87,7 +86,7 @@ func TestListenMkdirsSocketDir(t *testing.T) { | |||
| 87 | 86 | } | |
| 88 | 87 | ||
| 89 | 88 | func TestListenRejectsHostileSocketDir(t *testing.T) { | |
| 90 | - | dir := filepath.Join(t.TempDir(), "socketdir") | |
| 89 | + | dir := shortSocketDir(t, "socketdir") | |
| 91 | 90 | if err := os.MkdirAll(dir, 0o777); err != nil { | |
| 92 | 91 | t.Fatalf("mkdir hostile socket dir: %v", err) | |
| 93 | 92 | } | |
| @@ -106,7 +105,7 @@ func TestListenRejectsHostileSocketDir(t *testing.T) { | |||
| 106 | 105 | } | |
| 107 | 106 | ||
| 108 | 107 | func TestListenStaleSocketCleanedUp(t *testing.T) { | |
| 109 | - | dir := filepath.Join(t.TempDir(), "vev") | |
| 108 | + | dir := shortSocketDir(t, "vev") | |
| 110 | 109 | if err := os.Mkdir(dir, 0o700); err != nil { | |
| 111 | 110 | t.Fatalf("mkdir safe socket dir: %v", err) | |
| 112 | 111 | } | |
| @@ -140,7 +139,7 @@ func TestListenStaleSocketCleanedUp(t *testing.T) { | |||
| 140 | 139 | } | |
| 141 | 140 | ||
| 142 | 141 | func TestListenLiveDaemonRejected(t *testing.T) { | |
| 143 | - | dir := filepath.Join(t.TempDir(), "vev") | |
| 142 | + | dir := shortSocketDir(t, "vev") | |
| 144 | 143 | ||
| 145 | 144 | first, err := Listen(dir) | |
| 146 | 145 | if err != nil { | |
| @@ -13,7 +13,7 @@ import ( | |||||
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | func TestListenAcceptRoundTrip(t *testing.T) { | 15 | func TestListenAcceptRoundTrip(t *testing.T) { | ||
| 16 | - | dir := filepath.Join(t.TempDir(), "vev") | 16 | + | dir := shortSocketDir(t, "vev") |
| 17 | 17 | ||||
| 18 | ln, err := Listen(dir) | 18 | ln, err := Listen(dir) | ||
| 19 | if err != nil { | 19 | if err != nil { | ||
| @@ -65,8 +65,7 @@ func TestListenAcceptRoundTrip(t *testing.T) { | |||||
| 65 | } | 65 | } | ||
| 66 | 66 | ||||
| 67 | func TestListenMkdirsSocketDir(t *testing.T) { | 67 | func TestListenMkdirsSocketDir(t *testing.T) { | ||
| 68 | - | base := t.TempDir() | 68 | + | dir := shortSocketDir(t, "nested", "socketdir") |
| 69 | - | dir := filepath.Join(base, "nested", "socketdir") | |||
| 70 | 69 | ||||
| 71 | ln, err := Listen(dir) | 70 | ln, err := Listen(dir) | ||
| 72 | if err != nil { | 71 | if err != nil { | ||
| @@ -87,7 +86,7 @@ func TestListenMkdirsSocketDir(t *testing.T) { | |||||
| 87 | } | 86 | } | ||
| 88 | 87 | ||||
| 89 | func TestListenRejectsHostileSocketDir(t *testing.T) { | 88 | func TestListenRejectsHostileSocketDir(t *testing.T) { | ||
| 90 | - | dir := filepath.Join(t.TempDir(), "socketdir") | 89 | + | dir := shortSocketDir(t, "socketdir") |
| 91 | if err := os.MkdirAll(dir, 0o777); err != nil { | 90 | if err := os.MkdirAll(dir, 0o777); err != nil { | ||
| 92 | t.Fatalf("mkdir hostile socket dir: %v", err) | 91 | t.Fatalf("mkdir hostile socket dir: %v", err) | ||
| 93 | } | 92 | } | ||
| @@ -106,7 +105,7 @@ func TestListenRejectsHostileSocketDir(t *testing.T) { | |||||
| 106 | } | 105 | } | ||
| 107 | 106 | ||||
| 108 | func TestListenStaleSocketCleanedUp(t *testing.T) { | 107 | func TestListenStaleSocketCleanedUp(t *testing.T) { | ||
| 109 | - | dir := filepath.Join(t.TempDir(), "vev") | 108 | + | dir := shortSocketDir(t, "vev") |
| 110 | if err := os.Mkdir(dir, 0o700); err != nil { | 109 | if err := os.Mkdir(dir, 0o700); err != nil { | ||
| 111 | t.Fatalf("mkdir safe socket dir: %v", err) | 110 | t.Fatalf("mkdir safe socket dir: %v", err) | ||
| 112 | } | 111 | } | ||
| @@ -140,7 +139,7 @@ func TestListenStaleSocketCleanedUp(t *testing.T) { | |||||
| 140 | } | 139 | } | ||
| 141 | 140 | ||||
| 142 | func TestListenLiveDaemonRejected(t *testing.T) { | 141 | func TestListenLiveDaemonRejected(t *testing.T) { | ||
| 143 | - | dir := filepath.Join(t.TempDir(), "vev") | 142 | + | dir := shortSocketDir(t, "vev") |
| 144 | 143 | ||||
| 145 | first, err := Listen(dir) | 144 | first, err := Listen(dir) | ||
| 146 | if err != nil { | 145 | if err != nil { | ||
A internal/adapters/ipc/test_helpers_test.go +35 -0
| @@ -0,0 +1,35 @@ | |||
| 1 | + | package ipc | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "os" | |
| 5 | + | "path/filepath" | |
| 6 | + | "testing" | |
| 7 | + | ) | |
| 8 | + | ||
| 9 | + | const darwinUnixSocketPathMax = 103 | |
| 10 | + | ||
| 11 | + | func shortSocketDir(t *testing.T, nested ...string) string { | |
| 12 | + | t.Helper() | |
| 13 | + | ||
| 14 | + | root, err := os.MkdirTemp("/tmp", "v") | |
| 15 | + | if err != nil { | |
| 16 | + | t.Fatalf("create short socket test root: %v", err) | |
| 17 | + | } | |
| 18 | + | t.Cleanup(func() { | |
| 19 | + | if err := os.RemoveAll(root); err != nil { | |
| 20 | + | t.Errorf("remove short socket test root %q: %v", root, err) | |
| 21 | + | } | |
| 22 | + | }) | |
| 23 | + | ||
| 24 | + | dir := filepath.Join(append([]string{root}, nested...)...) | |
| 25 | + | assertDarwinSafeSocketPath(t, filepath.Join(dir, "daemon.sock")) | |
| 26 | + | return dir | |
| 27 | + | } | |
| 28 | + | ||
| 29 | + | func assertDarwinSafeSocketPath(t *testing.T, path string) { | |
| 30 | + | t.Helper() | |
| 31 | + | ||
| 32 | + | if len(path) >= darwinUnixSocketPathMax { | |
| 33 | + | t.Fatalf("test socket path %q is %d bytes; must be shorter than Darwin's %d-byte AF_UNIX pathname maximum", path, len(path), darwinUnixSocketPathMax) | |
| 34 | + | } | |
| 35 | + | } | |
| @@ -0,0 +1,35 @@ | |||||
| 1 | + | package ipc | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "os" | |||
| 5 | + | "path/filepath" | |||
| 6 | + | "testing" | |||
| 7 | + | ) | |||
| 8 | + | ||||
| 9 | + | const darwinUnixSocketPathMax = 103 | |||
| 10 | + | ||||
| 11 | + | func shortSocketDir(t *testing.T, nested ...string) string { | |||
| 12 | + | t.Helper() | |||
| 13 | + | ||||
| 14 | + | root, err := os.MkdirTemp("/tmp", "v") | |||
| 15 | + | if err != nil { | |||
| 16 | + | t.Fatalf("create short socket test root: %v", err) | |||
| 17 | + | } | |||
| 18 | + | t.Cleanup(func() { | |||
| 19 | + | if err := os.RemoveAll(root); err != nil { | |||
| 20 | + | t.Errorf("remove short socket test root %q: %v", root, err) | |||
| 21 | + | } | |||
| 22 | + | }) | |||
| 23 | + | ||||
| 24 | + | dir := filepath.Join(append([]string{root}, nested...)...) | |||
| 25 | + | assertDarwinSafeSocketPath(t, filepath.Join(dir, "daemon.sock")) | |||
| 26 | + | return dir | |||
| 27 | + | } | |||
| 28 | + | ||||
| 29 | + | func assertDarwinSafeSocketPath(t *testing.T, path string) { | |||
| 30 | + | t.Helper() | |||
| 31 | + | ||||
| 32 | + | if len(path) >= darwinUnixSocketPathMax { | |||
| 33 | + | t.Fatalf("test socket path %q is %d bytes; must be shorter than Darwin's %d-byte AF_UNIX pathname maximum", path, len(path), darwinUnixSocketPathMax) | |||
| 34 | + | } | |||
| 35 | + | } | |||
M internal/usecase/daemon/picker_test.go +10 -1
| @@ -857,9 +857,13 @@ func TestResumeStoppedAndSwitchInheritsTerminalEnv(t *testing.T) { | |||
| 857 | 857 | }, | |
| 858 | 858 | ).Twice() | |
| 859 | 859 | floating := newQuietPTY() | |
| 860 | + | floatingOpened := make(chan struct{}) | |
| 860 | 861 | f.EXPECT().Open(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.MatchedBy(func(got domain.Size) bool { | |
| 861 | 862 | return got != normalSize && got.Valid() | |
| 862 | - | })).Return(floating, nil).Once() | |
| 863 | + | })).RunAndReturn(func(context.Context, string, []string, []string, string, domain.Size) (ports.PTY, error) { | |
| 864 | + | close(floatingOpened) | |
| 865 | + | return floating, nil | |
| 866 | + | }).Once() | |
| 863 | 867 | d := newTestDaemon(t, f, stubClock{}) | |
| 864 | 868 | d.stopped["old"] = stoppedSession{name: "old", cwd: t.TempDir(), createdAt: 1} | |
| 865 | 869 | tr := portsmocks.NewMockTransport(t) | |
| @@ -877,6 +881,11 @@ func TestResumeStoppedAndSwitchInheritsTerminalEnv(t *testing.T) { | |||
| 877 | 881 | require.Contains(t, opens[1], "TERM=xterm-direct") | |
| 878 | 882 | require.Contains(t, opens[1], "COLORTERM=truecolor") | |
| 879 | 883 | require.Contains(t, opens[1], "TERM_PROGRAM=vev") | |
| 884 | + | select { | |
| 885 | + | case <-floatingOpened: | |
| 886 | + | case <-time.After(time.Second): | |
| 887 | + | t.Fatal("floating prewarm PTY was not opened") | |
| 888 | + | } | |
| 880 | 889 | _ = d.killSession(got, ports.ReasonSessionKilled, false) | |
| 881 | 890 | release1() | |
| 882 | 891 | release2() | |
| @@ -857,9 +857,13 @@ func TestResumeStoppedAndSwitchInheritsTerminalEnv(t *testing.T) { | |||||
| 857 | }, | 857 | }, | ||
| 858 | ).Twice() | 858 | ).Twice() | ||
| 859 | floating := newQuietPTY() | 859 | floating := newQuietPTY() | ||
| 860 | + | floatingOpened := make(chan struct{}) | |||
| 860 | f.EXPECT().Open(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.MatchedBy(func(got domain.Size) bool { | 861 | f.EXPECT().Open(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.MatchedBy(func(got domain.Size) bool { | ||
| 861 | return got != normalSize && got.Valid() | 862 | return got != normalSize && got.Valid() | ||
| 862 | - | })).Return(floating, nil).Once() | 863 | + | })).RunAndReturn(func(context.Context, string, []string, []string, string, domain.Size) (ports.PTY, error) { |
| 864 | + | close(floatingOpened) | |||
| 865 | + | return floating, nil | |||
| 866 | + | }).Once() | |||
| 863 | d := newTestDaemon(t, f, stubClock{}) | 867 | d := newTestDaemon(t, f, stubClock{}) | ||
| 864 | d.stopped["old"] = stoppedSession{name: "old", cwd: t.TempDir(), createdAt: 1} | 868 | d.stopped["old"] = stoppedSession{name: "old", cwd: t.TempDir(), createdAt: 1} | ||
| 865 | tr := portsmocks.NewMockTransport(t) | 869 | tr := portsmocks.NewMockTransport(t) | ||
| @@ -877,6 +881,11 @@ func TestResumeStoppedAndSwitchInheritsTerminalEnv(t *testing.T) { | |||||
| 877 | require.Contains(t, opens[1], "TERM=xterm-direct") | 881 | require.Contains(t, opens[1], "TERM=xterm-direct") | ||
| 878 | require.Contains(t, opens[1], "COLORTERM=truecolor") | 882 | require.Contains(t, opens[1], "COLORTERM=truecolor") | ||
| 879 | require.Contains(t, opens[1], "TERM_PROGRAM=vev") | 883 | require.Contains(t, opens[1], "TERM_PROGRAM=vev") | ||
| 884 | + | select { | |||
| 885 | + | case <-floatingOpened: | |||
| 886 | + | case <-time.After(time.Second): | |||
| 887 | + | t.Fatal("floating prewarm PTY was not opened") | |||
| 888 | + | } | |||
| 880 | _ = d.killSession(got, ports.ReasonSessionKilled, false) | 889 | _ = d.killSession(got, ports.ReasonSessionKilled, false) | ||
| 881 | release1() | 890 | release1() | ||
| 882 | release2() | 891 | release2() | ||