LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package exec | 5 // Use an external test to avoid os/exec -> net/http -> crypto/x509 -> os/exec |
| 6 // circular dependency on non-cgo darwin. |
| 7 |
| 8 package exec_test |
6 | 9 |
7 import ( | 10 import ( |
8 "bufio" | 11 "bufio" |
9 "bytes" | 12 "bytes" |
10 "fmt" | 13 "fmt" |
11 "io" | 14 "io" |
12 "io/ioutil" | 15 "io/ioutil" |
13 "net" | 16 "net" |
14 "net/http" | 17 "net/http" |
15 "net/http/httptest" | 18 "net/http/httptest" |
16 "os" | 19 "os" |
| 20 "os/exec" |
17 "path/filepath" | 21 "path/filepath" |
18 "runtime" | 22 "runtime" |
19 "strconv" | 23 "strconv" |
20 "strings" | 24 "strings" |
21 "testing" | 25 "testing" |
22 "time" | 26 "time" |
23 ) | 27 ) |
24 | 28 |
25 func helperCommand(s ...string) *Cmd { | 29 func helperCommand(s ...string) *exec.Cmd { |
26 cs := []string{"-test.run=TestHelperProcess", "--"} | 30 cs := []string{"-test.run=TestHelperProcess", "--"} |
27 cs = append(cs, s...) | 31 cs = append(cs, s...) |
28 » cmd := Command(os.Args[0], cs...) | 32 » cmd := exec.Command(os.Args[0], cs...) |
29 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} | 33 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} |
30 return cmd | 34 return cmd |
31 } | 35 } |
32 | 36 |
33 func TestEcho(t *testing.T) { | 37 func TestEcho(t *testing.T) { |
34 bs, err := helperCommand("echo", "foo bar", "baz").Output() | 38 bs, err := helperCommand("echo", "foo bar", "baz").Output() |
35 if err != nil { | 39 if err != nil { |
36 t.Errorf("echo: %v", err) | 40 t.Errorf("echo: %v", err) |
37 } | 41 } |
38 if g, e := string(bs), "foo bar baz\n"; g != e { | 42 if g, e := string(bs), "foo bar baz\n"; g != e { |
(...skipping 12 matching lines...) Expand all Loading... |
51 } | 55 } |
52 s := string(bs) | 56 s := string(bs) |
53 if s != input { | 57 if s != input { |
54 t.Errorf("cat: want %q, got %q", input, s) | 58 t.Errorf("cat: want %q, got %q", input, s) |
55 } | 59 } |
56 } | 60 } |
57 | 61 |
58 func TestCatGoodAndBadFile(t *testing.T) { | 62 func TestCatGoodAndBadFile(t *testing.T) { |
59 // Testing combined output and error values. | 63 // Testing combined output and error values. |
60 bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").Combi
nedOutput() | 64 bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").Combi
nedOutput() |
61 » if _, ok := err.(*ExitError); !ok { | 65 » if _, ok := err.(*exec.ExitError); !ok { |
62 » » t.Errorf("expected *ExitError from cat combined; got %T: %v", er
r, err) | 66 » » t.Errorf("expected *exec.ExitError from cat combined; got %T: %v
", err, err) |
63 } | 67 } |
64 s := string(bs) | 68 s := string(bs) |
65 sp := strings.SplitN(s, "\n", 2) | 69 sp := strings.SplitN(s, "\n", 2) |
66 if len(sp) != 2 { | 70 if len(sp) != 2 { |
67 t.Fatalf("expected two lines from cat; got %q", s) | 71 t.Fatalf("expected two lines from cat; got %q", s) |
68 } | 72 } |
69 errLine, body := sp[0], sp[1] | 73 errLine, body := sp[0], sp[1] |
70 if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") { | 74 if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") { |
71 t.Errorf("expected stderr to complain about file; got %q", errLi
ne) | 75 t.Errorf("expected stderr to complain about file; got %q", errLi
ne) |
72 } | 76 } |
73 if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") { | 77 if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") { |
74 t.Errorf("expected test code; got %q (len %d)", body, len(body)) | 78 t.Errorf("expected test code; got %q (len %d)", body, len(body)) |
75 } | 79 } |
76 } | 80 } |
77 | 81 |
78 func TestNoExistBinary(t *testing.T) { | 82 func TestNoExistBinary(t *testing.T) { |
79 // Can't run a non-existent binary | 83 // Can't run a non-existent binary |
80 » err := Command("/no-exist-binary").Run() | 84 » err := exec.Command("/no-exist-binary").Run() |
81 if err == nil { | 85 if err == nil { |
82 t.Error("expected error from /no-exist-binary") | 86 t.Error("expected error from /no-exist-binary") |
83 } | 87 } |
84 } | 88 } |
85 | 89 |
86 func TestExitStatus(t *testing.T) { | 90 func TestExitStatus(t *testing.T) { |
87 // Test that exit values are returned correctly | 91 // Test that exit values are returned correctly |
88 cmd := helperCommand("exit", "42") | 92 cmd := helperCommand("exit", "42") |
89 err := cmd.Run() | 93 err := cmd.Run() |
90 want := "exit status 42" | 94 want := "exit status 42" |
91 switch runtime.GOOS { | 95 switch runtime.GOOS { |
92 case "plan9": | 96 case "plan9": |
93 want = fmt.Sprintf("exit status: '%s %d: 42'", filepath.Base(cmd
.Path), cmd.ProcessState.Pid()) | 97 want = fmt.Sprintf("exit status: '%s %d: 42'", filepath.Base(cmd
.Path), cmd.ProcessState.Pid()) |
94 } | 98 } |
95 » if werr, ok := err.(*ExitError); ok { | 99 » if werr, ok := err.(*exec.ExitError); ok { |
96 if s := werr.Error(); s != want { | 100 if s := werr.Error(); s != want { |
97 t.Errorf("from exit 42 got exit %q, want %q", s, want) | 101 t.Errorf("from exit 42 got exit %q, want %q", s, want) |
98 } | 102 } |
99 } else { | 103 } else { |
100 » » t.Fatalf("expected *ExitError from exit 42; got %T: %v", err, er
r) | 104 » » t.Fatalf("expected *exec.ExitError from exit 42; got %T: %v", er
r, err) |
101 } | 105 } |
102 } | 106 } |
103 | 107 |
104 func TestPipes(t *testing.T) { | 108 func TestPipes(t *testing.T) { |
105 check := func(what string, err error) { | 109 check := func(what string, err error) { |
106 if err != nil { | 110 if err != nil { |
107 t.Fatalf("%s: %v", what, err) | 111 t.Fatalf("%s: %v", what, err) |
108 } | 112 } |
109 } | 113 } |
110 // Cat, testing stdin and stdout. | 114 // Cat, testing stdin and stdout. |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 // Before the fix, this next line would race with cmd.Wait. | 181 // Before the fix, this next line would race with cmd.Wait. |
178 check("Close", stdin.Close()) | 182 check("Close", stdin.Close()) |
179 }() | 183 }() |
180 check("Wait", cmd.Wait()) | 184 check("Wait", cmd.Wait()) |
181 } | 185 } |
182 | 186 |
183 // Issue 5071 | 187 // Issue 5071 |
184 func TestPipeLookPathLeak(t *testing.T) { | 188 func TestPipeLookPathLeak(t *testing.T) { |
185 fd0 := numOpenFDS(t) | 189 fd0 := numOpenFDS(t) |
186 for i := 0; i < 4; i++ { | 190 for i := 0; i < 4; i++ { |
187 » » cmd := Command("something-that-does-not-exist-binary") | 191 » » cmd := exec.Command("something-that-does-not-exist-binary") |
188 cmd.StdoutPipe() | 192 cmd.StdoutPipe() |
189 cmd.StderrPipe() | 193 cmd.StderrPipe() |
190 cmd.StdinPipe() | 194 cmd.StdinPipe() |
191 if err := cmd.Run(); err == nil { | 195 if err := cmd.Run(); err == nil { |
192 t.Fatal("unexpected success") | 196 t.Fatal("unexpected success") |
193 } | 197 } |
194 } | 198 } |
195 fdGrowth := numOpenFDS(t) - fd0 | 199 fdGrowth := numOpenFDS(t) - fd0 |
196 if fdGrowth > 2 { | 200 if fdGrowth > 2 { |
197 t.Errorf("leaked %d fds; want ~0", fdGrowth) | 201 t.Errorf("leaked %d fds; want ~0", fdGrowth) |
198 } | 202 } |
199 } | 203 } |
200 | 204 |
201 func numOpenFDS(t *testing.T) int { | 205 func numOpenFDS(t *testing.T) int { |
202 » lsof, err := Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Outp
ut() | 206 » lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid()))
.Output() |
203 if err != nil { | 207 if err != nil { |
204 t.Skip("skipping test; error finding or running lsof") | 208 t.Skip("skipping test; error finding or running lsof") |
205 return 0 | 209 return 0 |
206 } | 210 } |
207 return bytes.Count(lsof, []byte("\n")) | 211 return bytes.Count(lsof, []byte("\n")) |
208 } | 212 } |
209 | 213 |
210 var testedAlreadyLeaked = false | 214 var testedAlreadyLeaked = false |
211 | 215 |
212 // basefds returns the number of expected file descriptors | 216 // basefds returns the number of expected file descriptors |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
418 } | 422 } |
419 return ln | 423 return ln |
420 } | 424 } |
421 listenerFile := func(ln net.Listener) *os.File { | 425 listenerFile := func(ln net.Listener) *os.File { |
422 f, err := ln.(*net.TCPListener).File() | 426 f, err := ln.(*net.TCPListener).File() |
423 if err != nil { | 427 if err != nil { |
424 t.Fatal(err) | 428 t.Fatal(err) |
425 } | 429 } |
426 return f | 430 return f |
427 } | 431 } |
428 » runCommand := func(c *Cmd, out chan<- string) { | 432 » runCommand := func(c *exec.Cmd, out chan<- string) { |
429 bout, err := c.CombinedOutput() | 433 bout, err := c.CombinedOutput() |
430 if err != nil { | 434 if err != nil { |
431 out <- "ERROR:" + err.Error() | 435 out <- "ERROR:" + err.Error() |
432 } else { | 436 } else { |
433 out <- string(bout) | 437 out <- string(bout) |
434 } | 438 } |
435 } | 439 } |
436 | 440 |
437 for i := 0; i < 10; i++ { | 441 for i := 0; i < 10; i++ { |
438 la := listen() | 442 la := listen() |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 // Now verify that there are no other open fds. | 578 // Now verify that there are no other open fds. |
575 var files []*os.File | 579 var files []*os.File |
576 for wantfd := basefds() + 1; wantfd <= 100; wantfd++ { | 580 for wantfd := basefds() + 1; wantfd <= 100; wantfd++ { |
577 f, err := os.Open(os.Args[0]) | 581 f, err := os.Open(os.Args[0]) |
578 if err != nil { | 582 if err != nil { |
579 fmt.Printf("error opening file with expe
cted fd %d: %v", wantfd, err) | 583 fmt.Printf("error opening file with expe
cted fd %d: %v", wantfd, err) |
580 os.Exit(1) | 584 os.Exit(1) |
581 } | 585 } |
582 if got := f.Fd(); got != wantfd { | 586 if got := f.Fd(); got != wantfd { |
583 fmt.Printf("leaked parent file. fd = %d;
want %d\n", got, wantfd) | 587 fmt.Printf("leaked parent file. fd = %d;
want %d\n", got, wantfd) |
584 » » » » » out, _ := Command(ofcmd, "-p", fmt.Sprin
t(os.Getpid())).CombinedOutput() | 588 » » » » » out, _ := exec.Command(ofcmd, "-p", fmt.
Sprint(os.Getpid())).CombinedOutput() |
585 fmt.Print(string(out)) | 589 fmt.Print(string(out)) |
586 os.Exit(1) | 590 os.Exit(1) |
587 } | 591 } |
588 files = append(files, f) | 592 files = append(files, f) |
589 } | 593 } |
590 for _, f := range files { | 594 for _, f := range files { |
591 f.Close() | 595 f.Close() |
592 } | 596 } |
593 } | 597 } |
594 // Referring to fd3 here ensures that it is not | 598 // Referring to fd3 here ensures that it is not |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 os.Exit(1) | 640 os.Exit(1) |
637 } | 641 } |
638 } | 642 } |
639 fmt.Fprintf(os.Stderr, "child: %s", response) | 643 fmt.Fprintf(os.Stderr, "child: %s", response) |
640 os.Exit(0) | 644 os.Exit(0) |
641 default: | 645 default: |
642 fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) | 646 fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) |
643 os.Exit(2) | 647 os.Exit(2) |
644 } | 648 } |
645 } | 649 } |
LEFT | RIGHT |