1
2
3 package exec
4
5 import (
6 "context"
7 "io"
8 "os"
9 "path/filepath"
10 "testing"
11 "time"
12
13 "github.com/Microsoft/hcsshim/internal/conpty"
14 "github.com/Microsoft/hcsshim/internal/jobobject"
15 )
16
17 func TestExec(t *testing.T) {
18
19 e, err := New(
20 `C:\Windows\System32\ping.exe`,
21 "ping 127.0.0.1",
22 WithEnv(os.Environ()),
23 )
24 if err != nil {
25 t.Fatal(err)
26 }
27
28 err = e.Start()
29 if err != nil {
30 t.Fatalf("failed to start process: %v", err)
31 }
32
33 err = e.Wait()
34 if err != nil {
35 t.Fatalf("error waiting for process: %v", err)
36 }
37 t.Logf("exit code was: %d", e.ExitCode())
38 }
39
40 func TestExecWithDir(t *testing.T) {
41
42 dir := t.TempDir()
43
44 e, err := New(
45 `C:\Windows\System32\cmd.exe`,
46 "cmd /c echo 'test' > test.txt",
47 WithDir(dir),
48 WithEnv(os.Environ()),
49 )
50 if err != nil {
51 t.Fatal(err)
52 }
53
54 err = e.Start()
55 if err != nil {
56 t.Fatalf("failed to start process: %v", err)
57 }
58
59 err = e.Wait()
60 if err != nil {
61 t.Fatalf("error waiting for process: %v", err)
62 }
63
64 if _, err := os.Stat(filepath.Join(dir, "test.txt")); err != nil {
65 t.Fatal(err)
66 }
67
68 t.Logf("exit code was: %d", e.ExitCode())
69 }
70
71 func TestExecStdinPowershell(t *testing.T) {
72
73 e, err := New(
74 `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`,
75 "powershell",
76 WithStdio(true, false, true),
77 WithEnv(os.Environ()),
78 )
79 if err != nil {
80 t.Fatal(err)
81 }
82
83 err = e.Start()
84 if err != nil {
85 t.Fatalf("failed to start process: %v", err)
86 }
87
88 errChan := make(chan error)
89 go func() {
90 _, _ = io.Copy(os.Stdout, e.Stdout())
91 }()
92
93 go func() {
94 cmd := "ping 127.0.0.1\r\n"
95 if _, err := e.Stdin().Write([]byte(cmd)); err != nil {
96 errChan <- err
97 }
98
99 exit := "exit\r\n"
100 if _, err := e.Stdin().Write([]byte(exit)); err != nil {
101 errChan <- err
102 }
103 close(errChan)
104 }()
105
106 err = <-errChan
107 if err != nil {
108 t.Fatal(err)
109 }
110
111 waitChan := make(chan error)
112 go func() {
113 waitChan <- e.Wait()
114 }()
115
116 select {
117 case err := <-waitChan:
118 if err != nil {
119 t.Fatalf("error waiting for process: %v", err)
120 }
121 case <-time.After(time.Second * 10):
122 _ = e.Kill()
123 t.Fatal("timed out waiting for process to complete")
124 }
125
126 t.Logf("exit code was: %d", e.ExitCode())
127 }
128
129 func TestExecsWithJob(t *testing.T) {
130
131 job, err := jobobject.Create(context.Background(), nil)
132 if err != nil {
133 t.Fatal(err)
134 }
135 defer job.Close()
136
137 e, err := New(
138 `C:\Windows\System32\ping.exe`,
139 "ping -t 127.0.0.1",
140 WithJobObject(job),
141 WithStdio(false, false, false),
142 WithEnv(os.Environ()),
143 )
144 if err != nil {
145 t.Fatal(err)
146 }
147
148 err = e.Start()
149 if err != nil {
150 t.Fatalf("failed to start process: %v", err)
151 }
152
153
154 e2, err := New(
155 `C:\Windows\System32\ping.exe`,
156 "ping -t 127.0.0.1",
157 WithJobObject(job),
158 WithStdio(false, false, false),
159 WithEnv(os.Environ()),
160 )
161 if err != nil {
162 t.Fatal(err)
163 }
164
165 err = e2.Start()
166 if err != nil {
167 t.Fatalf("failed to start process: %v", err)
168 }
169
170 pidMap := map[int]struct{}{
171 e.Pid(): {},
172 e2.Pid(): {},
173 }
174
175 pids, err := job.Pids()
176 if err != nil {
177 t.Fatal(err)
178 }
179
180 if len(pids) != 2 {
181 t.Fatalf("should be two pids in job object, got: %d. Pids: %+v", len(pids), pids)
182 }
183
184 for _, pid := range pids {
185 if _, ok := pidMap[int(pid)]; !ok {
186 t.Fatalf("failed to find pid %d in job object", pid)
187 }
188 }
189
190 err = e.Kill()
191 if err != nil {
192 t.Fatalf("error killing process: %v", err)
193 }
194
195 err = e2.Kill()
196 if err != nil {
197 t.Fatalf("error killing process: %v", err)
198 }
199
200 _ = e.Wait()
201 _ = e2.Wait()
202
203 if !e.Exited() {
204 t.Fatalf("Process %d should have exited after kill", e.Pid())
205 }
206 if !e2.Exited() {
207 t.Fatalf("Process %d should have exited after kill", e2.Pid())
208 }
209 }
210
211 func TestPseudoConsolePowershell(t *testing.T) {
212
213
214
215
216 t.Skip("Skipping flaky test")
217 cpty, err := conpty.Create(80, 20, 0)
218 if err != nil {
219 t.Fatal(err)
220 }
221 defer cpty.Close()
222
223
224
225 e, err := New(
226 `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe`,
227 "powershell",
228 WithEnv(os.Environ()),
229 WithConPty(cpty),
230 )
231 if err != nil {
232 t.Fatal(err)
233 }
234
235 err = e.Start()
236 if err != nil {
237 t.Fatalf("failed to start process: %v", err)
238 }
239
240 errChan := make(chan error)
241 go func() {
242 _, _ = io.Copy(os.Stdout, cpty.OutPipe())
243 }()
244
245 go func() {
246 cmd := "ping 127.0.0.1\r\n"
247 if _, err := cpty.Write([]byte(cmd)); err != nil {
248 errChan <- err
249 }
250
251 exit := "exit\r\n"
252 if _, err := cpty.Write([]byte(exit)); err != nil {
253 errChan <- err
254 }
255 close(errChan)
256 }()
257
258 err = <-errChan
259 if err != nil {
260 t.Fatal(err)
261 }
262
263 waitChan := make(chan error)
264 go func() {
265 waitChan <- e.Wait()
266 }()
267
268 select {
269 case err := <-waitChan:
270 if err != nil {
271 t.Fatalf("error waiting for process: %v", err)
272 }
273 case <-time.After(time.Second * 10):
274 _ = e.Kill()
275 t.Fatal("timed out waiting for process to complete")
276 }
277
278 t.Logf("exit code was: %d", e.ExitCode())
279 }
280
View as plain text