返回 DeepSeek-Reasonix
terminal_process_windows_test.go
根目录 / desktop / terminal_process_windows_test.go
1 //go:build windows
2
3 package main
4
5 import (
6 "bytes"
7 "fmt"
8 "os"
9 "os/exec"
10 "testing"
11 "time"
12 )
13
14 // A loaded Windows runner can take far longer than the shell's own work to echo
15 // a marker or reap a ConPTY child. Keep the outer responsiveness bound generous;
16 // the test still fails if the process never responds.
17 const conptySmokeWait = 30 * time.Second
18
19 func TestWindowsTerminalProcessConPTYSmoke(t *testing.T) {
20 available, reason := terminalPlatformAvailable()
21 if !available {
22 t.Skip(reason)
23 }
24 commandPath, err := exec.LookPath("cmd.exe")
25 if err != nil {
26 t.Fatal(err)
27 }
28 proc, err := startTerminalProcess(terminalStartSpec{
29 command: commandForShellPath(commandPath, "Command Prompt"),
30 dir: t.TempDir(),
31 env: os.Environ(),
32 cols: defaultTerminalColumns,
33 rows: defaultTerminalRows,
34 })
35 if err != nil {
36 t.Fatal(err)
37 }
38 defer proc.Close()
39
40 if err := proc.Resize(100, 30); err != nil {
41 t.Fatalf("resize ConPTY: %v", err)
42 }
43
44 const marker = "reasonix-conpty-smoke"
45 readResult := make(chan error, 1)
46 markerSeen := make(chan struct{})
47 go func() {
48 var output bytes.Buffer
49 buf := make([]byte, 4096)
50 seen := false
51 for {
52 n, readErr := proc.Read(buf)
53 if n > 0 {
54 output.Write(buf[:n])
55 if !seen && bytes.Contains(output.Bytes(), []byte(marker)) {
56 seen = true
57 close(markerSeen)
58 }
59 }
60 if readErr != nil {
61 if !seen {
62 readResult <- fmt.Errorf("read ConPTY output: %w", readErr)
63 } else {
64 readResult <- nil
65 }
66 return
67 }
68 }
69 }()
70
71 // Queue exit with the marker command so seeing terminal input echo cannot
72 // race a second write. Continue draining output until the process is closed.
73 if _, err := proc.Write([]byte("echo " + marker + "\r\nexit\r\n")); err != nil {
74 t.Fatalf("write ConPTY command: %v", err)
75 }
76 select {
77 case <-markerSeen:
78 case <-time.After(conptySmokeWait):
79 t.Fatal("timed out waiting for ConPTY output")
80 }
81
82 waitResult := make(chan error, 1)
83 go func() {
84 _, waitErr := proc.Wait()
85 waitResult <- waitErr
86 }()
87 select {
88 case err := <-waitResult:
89 if err != nil {
90 t.Fatalf("wait for ConPTY exit: %v", err)
91 }
92 case <-time.After(conptySmokeWait):
93 t.Fatal("timed out waiting for ConPTY process exit")
94 }
95 if err := proc.Close(); err != nil {
96 t.Fatalf("close ConPTY process: %v", err)
97 }
98 select {
99 case err := <-readResult:
100 if err != nil {
101 t.Fatal(err)
102 }
103 case <-time.After(conptySmokeWait):
104 t.Fatal("timed out waiting for ConPTY reader to finish")
105 }
106 }
107
107 lines GO