1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
23 func helperCommand(s ...string) *Cmd {
24 cs := []string{"-test.run=TestHelperProcess", "--"}
26 cmd := Command(os.Args[0], cs...)
27 cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
31 func TestEcho(t *testing.T) {
32 bs, err := helperCommand("echo", "foo bar", "baz").Output()
34 t.Errorf("echo: %v", err)
36 if g, e := string(bs), "foo bar baz\n"; g != e {
37 t.Errorf("echo: want %q, got %q", e, g)
41 func TestCatStdin(t *testing.T) {
42 // Cat, testing stdin and stdout.
43 input := "Input string\nLine 2"
44 p := helperCommand("cat")
45 p.Stdin = strings.NewReader(input)
48 t.Errorf("cat: %v", err)
52 t.Errorf("cat: want %q, got %q", input, s)
56 func TestCatGoodAndBadFile(t *testing.T) {
57 // Testing combined output and error values.
58 bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
59 if _, ok := err.(*ExitError); !ok {
60 t.Errorf("expected *ExitError from cat combined; got %T: %v", err, err)
63 sp := strings.SplitN(s, "\n", 2)
65 t.Fatalf("expected two lines from cat; got %q", s)
67 errLine, body := sp[0], sp[1]
68 if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") {
69 t.Errorf("expected stderr to complain about file; got %q", errLine)
71 if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") {
72 t.Errorf("expected test code; got %q (len %d)", body, len(body))
76 func TestNoExistBinary(t *testing.T) {
77 // Can't run a non-existent binary
78 err := Command("/no-exist-binary").Run()
80 t.Error("expected error from /no-exist-binary")
84 func TestExitStatus(t *testing.T) {
85 // Test that exit values are returned correctly
86 err := helperCommand("exit", "42").Run()
87 if werr, ok := err.(*ExitError); ok {
88 if s, e := werr.Error(), "exit status 42"; s != e {
89 t.Errorf("from exit 42 got exit %q, want %q", s, e)
92 t.Fatalf("expected *ExitError from exit 42; got %T: %v", err, err)
96 func TestPipes(t *testing.T) {
97 check := func(what string, err error) {
99 t.Fatalf("%s: %v", what, err)
102 // Cat, testing stdin and stdout.
103 c := helperCommand("pipetest")
104 stdin, err := c.StdinPipe()
105 check("StdinPipe", err)
106 stdout, err := c.StdoutPipe()
107 check("StdoutPipe", err)
108 stderr, err := c.StderrPipe()
109 check("StderrPipe", err)
111 outbr := bufio.NewReader(stdout)
112 errbr := bufio.NewReader(stderr)
113 line := func(what string, br *bufio.Reader) string {
114 line, _, err := br.ReadLine()
116 t.Fatalf("%s: %v", what, err)
124 _, err = stdin.Write([]byte("O:I am output\n"))
125 check("first stdin Write", err)
126 if g, e := line("first output line", outbr), "O:I am output"; g != e {
127 t.Errorf("got %q, want %q", g, e)
130 _, err = stdin.Write([]byte("E:I am error\n"))
131 check("second stdin Write", err)
132 if g, e := line("first error line", errbr), "E:I am error"; g != e {
133 t.Errorf("got %q, want %q", g, e)
136 _, err = stdin.Write([]byte("O:I am output2\n"))
137 check("third stdin Write 3", err)
138 if g, e := line("second output line", outbr), "O:I am output2"; g != e {
139 t.Errorf("got %q, want %q", g, e)
147 func TestExtraFiles(t *testing.T) {
148 if runtime.GOOS == "windows" {
149 t.Logf("no operating system support; skipping")
153 // Ensure that file descriptors have not already been leaked into
155 for fd := os.Stderr.Fd() + 1; fd <= 101; fd++ {
156 err := os.NewFile(fd, "").Close()
158 t.Logf("Something already leaked - closed fd %d", fd)
162 // Force network usage, to verify the epoll (or whatever) fd
163 // doesn't leak to the child,
164 ln, err := net.Listen("tcp", "127.0.0.1:0")
170 // Make sure duplicated fds don't leak to the child.
171 f, err := ln.(*net.TCPListener).File()
176 ln2, err := net.FileListener(f)
182 // Force TLS root certs to be loaded (which might involve
183 // cgo), to make sure none of that potential C code leaks fds.
184 ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
185 w.Write([]byte("Hello"))
188 http.Get(ts.URL) // ignore result; just calling to force root cert loading
190 tf, err := ioutil.TempFile("", "")
192 t.Fatalf("TempFile: %v", err)
194 defer os.Remove(tf.Name())
197 const text = "Hello, fd 3!"
198 _, err = tf.Write([]byte(text))
200 t.Fatalf("Write: %v", err)
202 _, err = tf.Seek(0, os.SEEK_SET)
204 t.Fatalf("Seek: %v", err)
207 c := helperCommand("read3")
208 c.ExtraFiles = []*os.File{tf}
209 bs, err := c.CombinedOutput()
211 t.Fatalf("CombinedOutput: %v; output %q", err, bs)
213 if string(bs) != text {
214 t.Errorf("got %q; want %q", string(bs), text)
218 func TestExtraFilesRace(t *testing.T) {
219 if runtime.GOOS == "windows" {
220 t.Logf("no operating system support; skipping")
223 listen := func() net.Listener {
224 ln, err := net.Listen("tcp", "127.0.0.1:0")
230 listenerFile := func(ln net.Listener) *os.File {
231 f, err := ln.(*net.TCPListener).File()
237 runCommand := func(c *Cmd, out chan<- string) {
238 bout, err := c.CombinedOutput()
240 out <- "ERROR:" + err.Error()
246 for i := 0; i < 10; i++ {
248 ca := helperCommand("describefiles")
249 ca.ExtraFiles = []*os.File{listenerFile(la)}
251 cb := helperCommand("describefiles")
252 cb.ExtraFiles = []*os.File{listenerFile(lb)}
253 ares := make(chan string)
254 bres := make(chan string)
255 go runCommand(ca, ares)
256 go runCommand(cb, bres)
257 if got, want := <-ares, fmt.Sprintf("fd3: listener %s\n", la.Addr()); got != want {
258 t.Errorf("iteration %d, process A got:\n%s\nwant:\n%s\n", i, got, want)
260 if got, want := <-bres, fmt.Sprintf("fd3: listener %s\n", lb.Addr()); got != want {
261 t.Errorf("iteration %d, process B got:\n%s\nwant:\n%s\n", i, got, want)
268 // TestHelperProcess isn't a real test. It's used as a helper process
269 // for TestParameterRun.
270 func TestHelperProcess(*testing.T) {
271 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
276 // Determine which command to use to display open files.
278 switch runtime.GOOS {
279 case "freebsd", "netbsd", "openbsd":
292 fmt.Fprintf(os.Stderr, "No command\n")
296 cmd, args := args[0], args[1:]
299 iargs := []interface{}{}
300 for _, s := range args {
301 iargs = append(iargs, s)
303 fmt.Println(iargs...)
306 io.Copy(os.Stdout, os.Stdin)
310 for _, fn := range args {
311 f, err := os.Open(fn)
313 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
317 io.Copy(os.Stdout, f)
322 bufr := bufio.NewReader(os.Stdin)
324 line, _, err := bufr.ReadLine()
327 } else if err != nil {
330 if bytes.HasPrefix(line, []byte("O:")) {
331 os.Stdout.Write(line)
332 os.Stdout.Write([]byte{'\n'})
333 } else if bytes.HasPrefix(line, []byte("E:")) {
334 os.Stderr.Write(line)
335 os.Stderr.Write([]byte{'\n'})
340 case "read3": // read fd 3
341 fd3 := os.NewFile(3, "fd3")
342 bs, err := ioutil.ReadAll(fd3)
344 fmt.Printf("ReadAll from fd 3: %v", err)
347 switch runtime.GOOS {
349 // TODO(bradfitz): broken? Sometimes.
350 // http://golang.org/issue/2603
351 // Skip this additional part of the test for now.
353 // Now verify that there are no other open fds.
355 for wantfd := os.Stderr.Fd() + 2; wantfd <= 100; wantfd++ {
356 f, err := os.Open(os.Args[0])
358 fmt.Printf("error opening file with expected fd %d: %v", wantfd, err)
361 if got := f.Fd(); got != wantfd {
362 fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
363 out, _ := Command(ofcmd, "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
364 fmt.Print(string(out))
367 files = append(files, f)
369 for _, f := range files {
373 // Referring to fd3 here ensures that it is not
374 // garbage collected, and therefore closed, while
375 // executing the wantfd loop above. It doesn't matter
376 // what we do with fd3 as long as we refer to it;
377 // closing it is the easy choice.
381 n, _ := strconv.Atoi(args[0])
383 case "describefiles":
384 for fd := uintptr(3); fd < 25; fd++ {
385 f := os.NewFile(fd, fmt.Sprintf("fd-%d", fd))
386 ln, err := net.FileListener(f)
388 fmt.Printf("fd%d: listener %s\n", fd, ln.Addr())
394 fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)