Imported Upstream version 4.7.3
[platform/upstream/gcc48.git] / libgo / go / os / exec / exec_test.go
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.
4
5 package exec
6
7 import (
8         "bufio"
9         "bytes"
10         "fmt"
11         "io"
12         "io/ioutil"
13         "net"
14         "net/http"
15         "net/http/httptest"
16         "os"
17         "runtime"
18         "strconv"
19         "strings"
20         "testing"
21 )
22
23 func helperCommand(s ...string) *Cmd {
24         cs := []string{"-test.run=TestHelperProcess", "--"}
25         cs = append(cs, s...)
26         cmd := Command(os.Args[0], cs...)
27         cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
28         return cmd
29 }
30
31 func TestEcho(t *testing.T) {
32         bs, err := helperCommand("echo", "foo bar", "baz").Output()
33         if err != nil {
34                 t.Errorf("echo: %v", err)
35         }
36         if g, e := string(bs), "foo bar baz\n"; g != e {
37                 t.Errorf("echo: want %q, got %q", e, g)
38         }
39 }
40
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)
46         bs, err := p.Output()
47         if err != nil {
48                 t.Errorf("cat: %v", err)
49         }
50         s := string(bs)
51         if s != input {
52                 t.Errorf("cat: want %q, got %q", input, s)
53         }
54 }
55
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)
61         }
62         s := string(bs)
63         sp := strings.SplitN(s, "\n", 2)
64         if len(sp) != 2 {
65                 t.Fatalf("expected two lines from cat; got %q", s)
66         }
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)
70         }
71         if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") {
72                 t.Errorf("expected test code; got %q (len %d)", body, len(body))
73         }
74 }
75
76 func TestNoExistBinary(t *testing.T) {
77         // Can't run a non-existent binary
78         err := Command("/no-exist-binary").Run()
79         if err == nil {
80                 t.Error("expected error from /no-exist-binary")
81         }
82 }
83
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)
90                 }
91         } else {
92                 t.Fatalf("expected *ExitError from exit 42; got %T: %v", err, err)
93         }
94 }
95
96 func TestPipes(t *testing.T) {
97         check := func(what string, err error) {
98                 if err != nil {
99                         t.Fatalf("%s: %v", what, err)
100                 }
101         }
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)
110
111         outbr := bufio.NewReader(stdout)
112         errbr := bufio.NewReader(stderr)
113         line := func(what string, br *bufio.Reader) string {
114                 line, _, err := br.ReadLine()
115                 if err != nil {
116                         t.Fatalf("%s: %v", what, err)
117                 }
118                 return string(line)
119         }
120
121         err = c.Start()
122         check("Start", err)
123
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)
128         }
129
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)
134         }
135
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)
140         }
141
142         stdin.Close()
143         err = c.Wait()
144         check("Wait", err)
145 }
146
147 func TestExtraFiles(t *testing.T) {
148         if runtime.GOOS == "windows" {
149                 t.Logf("no operating system support; skipping")
150                 return
151         }
152
153         // Ensure that file descriptors have not already been leaked into
154         // our environment.
155         for fd := os.Stderr.Fd() + 1; fd <= 101; fd++ {
156                 err := os.NewFile(fd, "").Close()
157                 if err == nil {
158                         t.Logf("Something already leaked - closed fd %d", fd)
159                 }
160         }
161
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")
165         if err != nil {
166                 t.Fatal(err)
167         }
168         defer ln.Close()
169
170         // Make sure duplicated fds don't leak to the child.
171         f, err := ln.(*net.TCPListener).File()
172         if err != nil {
173                 t.Fatal(err)
174         }
175         defer f.Close()
176         ln2, err := net.FileListener(f)
177         if err != nil {
178                 t.Fatal(err)
179         }
180         defer ln2.Close()
181
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"))
186         }))
187         defer ts.Close()
188         http.Get(ts.URL) // ignore result; just calling to force root cert loading
189
190         tf, err := ioutil.TempFile("", "")
191         if err != nil {
192                 t.Fatalf("TempFile: %v", err)
193         }
194         defer os.Remove(tf.Name())
195         defer tf.Close()
196
197         const text = "Hello, fd 3!"
198         _, err = tf.Write([]byte(text))
199         if err != nil {
200                 t.Fatalf("Write: %v", err)
201         }
202         _, err = tf.Seek(0, os.SEEK_SET)
203         if err != nil {
204                 t.Fatalf("Seek: %v", err)
205         }
206
207         c := helperCommand("read3")
208         c.ExtraFiles = []*os.File{tf}
209         bs, err := c.CombinedOutput()
210         if err != nil {
211                 t.Fatalf("CombinedOutput: %v; output %q", err, bs)
212         }
213         if string(bs) != text {
214                 t.Errorf("got %q; want %q", string(bs), text)
215         }
216 }
217
218 func TestExtraFilesRace(t *testing.T) {
219         if runtime.GOOS == "windows" {
220                 t.Logf("no operating system support; skipping")
221                 return
222         }
223         listen := func() net.Listener {
224                 ln, err := net.Listen("tcp", "127.0.0.1:0")
225                 if err != nil {
226                         t.Fatal(err)
227                 }
228                 return ln
229         }
230         listenerFile := func(ln net.Listener) *os.File {
231                 f, err := ln.(*net.TCPListener).File()
232                 if err != nil {
233                         t.Fatal(err)
234                 }
235                 return f
236         }
237         runCommand := func(c *Cmd, out chan<- string) {
238                 bout, err := c.CombinedOutput()
239                 if err != nil {
240                         out <- "ERROR:" + err.Error()
241                 } else {
242                         out <- string(bout)
243                 }
244         }
245
246         for i := 0; i < 10; i++ {
247                 la := listen()
248                 ca := helperCommand("describefiles")
249                 ca.ExtraFiles = []*os.File{listenerFile(la)}
250                 lb := listen()
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)
259                 }
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)
262                 }
263                 la.Close()
264                 lb.Close()
265         }
266 }
267
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" {
272                 return
273         }
274         defer os.Exit(0)
275
276         // Determine which command to use to display open files.
277         ofcmd := "lsof"
278         switch runtime.GOOS {
279         case "freebsd", "netbsd", "openbsd":
280                 ofcmd = "fstat"
281         }
282
283         args := os.Args
284         for len(args) > 0 {
285                 if args[0] == "--" {
286                         args = args[1:]
287                         break
288                 }
289                 args = args[1:]
290         }
291         if len(args) == 0 {
292                 fmt.Fprintf(os.Stderr, "No command\n")
293                 os.Exit(2)
294         }
295
296         cmd, args := args[0], args[1:]
297         switch cmd {
298         case "echo":
299                 iargs := []interface{}{}
300                 for _, s := range args {
301                         iargs = append(iargs, s)
302                 }
303                 fmt.Println(iargs...)
304         case "cat":
305                 if len(args) == 0 {
306                         io.Copy(os.Stdout, os.Stdin)
307                         return
308                 }
309                 exit := 0
310                 for _, fn := range args {
311                         f, err := os.Open(fn)
312                         if err != nil {
313                                 fmt.Fprintf(os.Stderr, "Error: %v\n", err)
314                                 exit = 2
315                         } else {
316                                 defer f.Close()
317                                 io.Copy(os.Stdout, f)
318                         }
319                 }
320                 os.Exit(exit)
321         case "pipetest":
322                 bufr := bufio.NewReader(os.Stdin)
323                 for {
324                         line, _, err := bufr.ReadLine()
325                         if err == io.EOF {
326                                 break
327                         } else if err != nil {
328                                 os.Exit(1)
329                         }
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'})
336                         } else {
337                                 os.Exit(1)
338                         }
339                 }
340         case "read3": // read fd 3
341                 fd3 := os.NewFile(3, "fd3")
342                 bs, err := ioutil.ReadAll(fd3)
343                 if err != nil {
344                         fmt.Printf("ReadAll from fd 3: %v", err)
345                         os.Exit(1)
346                 }
347                 switch runtime.GOOS {
348                 case "darwin":
349                         // TODO(bradfitz): broken? Sometimes.
350                         // http://golang.org/issue/2603
351                         // Skip this additional part of the test for now.
352                 default:
353                         // Now verify that there are no other open fds.
354                         var files []*os.File
355                         for wantfd := os.Stderr.Fd() + 2; wantfd <= 100; wantfd++ {
356                                 f, err := os.Open(os.Args[0])
357                                 if err != nil {
358                                         fmt.Printf("error opening file with expected fd %d: %v", wantfd, err)
359                                         os.Exit(1)
360                                 }
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))
365                                         os.Exit(1)
366                                 }
367                                 files = append(files, f)
368                         }
369                         for _, f := range files {
370                                 f.Close()
371                         }
372                 }
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.
378                 fd3.Close()
379                 os.Stderr.Write(bs)
380         case "exit":
381                 n, _ := strconv.Atoi(args[0])
382                 os.Exit(n)
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)
387                         if err == nil {
388                                 fmt.Printf("fd%d: listener %s\n", fd, ln.Addr())
389                                 ln.Close()
390                         }
391                 }
392                 os.Exit(0)
393         default:
394                 fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
395                 os.Exit(2)
396         }
397 }