github.com/c12o16h1/go/src@v0.0.0-20200114212001-5a151c0f00ed/os/exec/exec_test.go (about) 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 // 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 9 10 import ( 11 "bufio" 12 "bytes" 13 "context" 14 "fmt" 15 "github.com/c12o16h1/go/src/internal/poll" 16 "github.com/c12o16h1/go/src/internal/testenv" 17 "io" 18 "io/ioutil" 19 "log" 20 "net" 21 "net/http" 22 "net/http/httptest" 23 "os" 24 "os/exec" 25 "path/filepath" 26 "runtime" 27 "strconv" 28 "strings" 29 "testing" 30 "time" 31 ) 32 33 // haveUnexpectedFDs is set at init time to report whether any 34 // file descriptors were open at program start. 35 var haveUnexpectedFDs bool 36 37 // unfinalizedFiles holds files that should not be finalized, 38 // because that would close the associated file descriptor, 39 // which we don't want to do. 40 var unfinalizedFiles []*os.File 41 42 func init() { 43 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 44 return 45 } 46 if runtime.GOOS == "windows" { 47 return 48 } 49 for fd := uintptr(3); fd <= 100; fd++ { 50 if poll.IsPollDescriptor(fd) { 51 continue 52 } 53 // We have no good portable way to check whether an FD is open. 54 // We use NewFile to create a *os.File, which lets us 55 // know whether it is open, but then we have to cope with 56 // the finalizer on the *os.File. 57 f := os.NewFile(fd, "") 58 if _, err := f.Stat(); err != nil { 59 // Close the file to clear the finalizer. 60 // We expect the Close to fail. 61 f.Close() 62 } else { 63 fmt.Printf("fd %d open at test start\n", fd) 64 haveUnexpectedFDs = true 65 // Use a global variable to avoid running 66 // the finalizer, which would close the FD. 67 unfinalizedFiles = append(unfinalizedFiles, f) 68 } 69 } 70 } 71 72 func helperCommandContext(t *testing.T, ctx context.Context, s ...string) (cmd *exec.Cmd) { 73 testenv.MustHaveExec(t) 74 75 cs := []string{"-test.run=TestHelperProcess", "--"} 76 cs = append(cs, s...) 77 if ctx != nil { 78 cmd = exec.CommandContext(ctx, os.Args[0], cs...) 79 } else { 80 cmd = exec.Command(os.Args[0], cs...) 81 } 82 cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") 83 return cmd 84 } 85 86 func helperCommand(t *testing.T, s ...string) *exec.Cmd { 87 return helperCommandContext(t, nil, s...) 88 } 89 90 func TestEcho(t *testing.T) { 91 bs, err := helperCommand(t, "echo", "foo bar", "baz").Output() 92 if err != nil { 93 t.Errorf("echo: %v", err) 94 } 95 if g, e := string(bs), "foo bar baz\n"; g != e { 96 t.Errorf("echo: want %q, got %q", e, g) 97 } 98 } 99 100 func TestCommandRelativeName(t *testing.T) { 101 testenv.MustHaveExec(t) 102 103 // Run our own binary as a relative path 104 // (e.g. "_test/exec.test") our parent directory. 105 base := filepath.Base(os.Args[0]) // "exec.test" 106 dir := filepath.Dir(os.Args[0]) // "/tmp/go-buildNNNN/os/exec/_test" 107 if dir == "." { 108 t.Skip("skipping; running test at root somehow") 109 } 110 parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec" 111 dirBase := filepath.Base(dir) // "_test" 112 if dirBase == "." { 113 t.Skipf("skipping; unexpected shallow dir of %q", dir) 114 } 115 116 cmd := exec.Command(filepath.Join(dirBase, base), "-test.run=TestHelperProcess", "--", "echo", "foo") 117 cmd.Dir = parentDir 118 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 119 120 out, err := cmd.Output() 121 if err != nil { 122 t.Errorf("echo: %v", err) 123 } 124 if g, e := string(out), "foo\n"; g != e { 125 t.Errorf("echo: want %q, got %q", e, g) 126 } 127 } 128 129 func TestCatStdin(t *testing.T) { 130 // Cat, testing stdin and stdout. 131 input := "Input string\nLine 2" 132 p := helperCommand(t, "cat") 133 p.Stdin = strings.NewReader(input) 134 bs, err := p.Output() 135 if err != nil { 136 t.Errorf("cat: %v", err) 137 } 138 s := string(bs) 139 if s != input { 140 t.Errorf("cat: want %q, got %q", input, s) 141 } 142 } 143 144 func TestEchoFileRace(t *testing.T) { 145 cmd := helperCommand(t, "echo") 146 stdin, err := cmd.StdinPipe() 147 if err != nil { 148 t.Fatalf("StdinPipe: %v", err) 149 } 150 if err := cmd.Start(); err != nil { 151 t.Fatalf("Start: %v", err) 152 } 153 wrote := make(chan bool) 154 go func() { 155 defer close(wrote) 156 fmt.Fprint(stdin, "echo\n") 157 }() 158 if err := cmd.Wait(); err != nil { 159 t.Fatalf("Wait: %v", err) 160 } 161 <-wrote 162 } 163 164 func TestCatGoodAndBadFile(t *testing.T) { 165 // Testing combined output and error values. 166 bs, err := helperCommand(t, "cat", "/bogus/file.foo", "exec_test.go").CombinedOutput() 167 if _, ok := err.(*exec.ExitError); !ok { 168 t.Errorf("expected *exec.ExitError from cat combined; got %T: %v", err, err) 169 } 170 s := string(bs) 171 sp := strings.SplitN(s, "\n", 2) 172 if len(sp) != 2 { 173 t.Fatalf("expected two lines from cat; got %q", s) 174 } 175 errLine, body := sp[0], sp[1] 176 if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") { 177 t.Errorf("expected stderr to complain about file; got %q", errLine) 178 } 179 if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") { 180 t.Errorf("expected test code; got %q (len %d)", body, len(body)) 181 } 182 } 183 184 func TestNoExistExecutable(t *testing.T) { 185 // Can't run a non-existent executable 186 err := exec.Command("/no-exist-executable").Run() 187 if err == nil { 188 t.Error("expected error from /no-exist-executable") 189 } 190 } 191 192 func TestExitStatus(t *testing.T) { 193 // Test that exit values are returned correctly 194 cmd := helperCommand(t, "exit", "42") 195 err := cmd.Run() 196 want := "exit status 42" 197 switch runtime.GOOS { 198 case "plan9": 199 want = fmt.Sprintf("exit status: '%s %d: 42'", filepath.Base(cmd.Path), cmd.ProcessState.Pid()) 200 } 201 if werr, ok := err.(*exec.ExitError); ok { 202 if s := werr.Error(); s != want { 203 t.Errorf("from exit 42 got exit %q, want %q", s, want) 204 } 205 } else { 206 t.Fatalf("expected *exec.ExitError from exit 42; got %T: %v", err, err) 207 } 208 } 209 210 func TestExitCode(t *testing.T) { 211 // Test that exit code are returned correctly 212 cmd := helperCommand(t, "exit", "42") 213 cmd.Run() 214 want := 42 215 if runtime.GOOS == "plan9" { 216 want = 1 217 } 218 got := cmd.ProcessState.ExitCode() 219 if want != got { 220 t.Errorf("ExitCode got %d, want %d", got, want) 221 } 222 223 cmd = helperCommand(t, "/no-exist-executable") 224 cmd.Run() 225 want = 2 226 if runtime.GOOS == "plan9" { 227 want = 1 228 } 229 got = cmd.ProcessState.ExitCode() 230 if want != got { 231 t.Errorf("ExitCode got %d, want %d", got, want) 232 } 233 234 cmd = helperCommand(t, "exit", "255") 235 cmd.Run() 236 want = 255 237 if runtime.GOOS == "plan9" { 238 want = 1 239 } 240 got = cmd.ProcessState.ExitCode() 241 if want != got { 242 t.Errorf("ExitCode got %d, want %d", got, want) 243 } 244 245 cmd = helperCommand(t, "cat") 246 cmd.Run() 247 want = 0 248 got = cmd.ProcessState.ExitCode() 249 if want != got { 250 t.Errorf("ExitCode got %d, want %d", got, want) 251 } 252 253 // Test when command does not call Run(). 254 cmd = helperCommand(t, "cat") 255 want = -1 256 got = cmd.ProcessState.ExitCode() 257 if want != got { 258 t.Errorf("ExitCode got %d, want %d", got, want) 259 } 260 } 261 262 func TestPipes(t *testing.T) { 263 check := func(what string, err error) { 264 if err != nil { 265 t.Fatalf("%s: %v", what, err) 266 } 267 } 268 // Cat, testing stdin and stdout. 269 c := helperCommand(t, "pipetest") 270 stdin, err := c.StdinPipe() 271 check("StdinPipe", err) 272 stdout, err := c.StdoutPipe() 273 check("StdoutPipe", err) 274 stderr, err := c.StderrPipe() 275 check("StderrPipe", err) 276 277 outbr := bufio.NewReader(stdout) 278 errbr := bufio.NewReader(stderr) 279 line := func(what string, br *bufio.Reader) string { 280 line, _, err := br.ReadLine() 281 if err != nil { 282 t.Fatalf("%s: %v", what, err) 283 } 284 return string(line) 285 } 286 287 err = c.Start() 288 check("Start", err) 289 290 _, err = stdin.Write([]byte("O:I am output\n")) 291 check("first stdin Write", err) 292 if g, e := line("first output line", outbr), "O:I am output"; g != e { 293 t.Errorf("got %q, want %q", g, e) 294 } 295 296 _, err = stdin.Write([]byte("E:I am error\n")) 297 check("second stdin Write", err) 298 if g, e := line("first error line", errbr), "E:I am error"; g != e { 299 t.Errorf("got %q, want %q", g, e) 300 } 301 302 _, err = stdin.Write([]byte("O:I am output2\n")) 303 check("third stdin Write 3", err) 304 if g, e := line("second output line", outbr), "O:I am output2"; g != e { 305 t.Errorf("got %q, want %q", g, e) 306 } 307 308 stdin.Close() 309 err = c.Wait() 310 check("Wait", err) 311 } 312 313 const stdinCloseTestString = "Some test string." 314 315 // Issue 6270. 316 func TestStdinClose(t *testing.T) { 317 check := func(what string, err error) { 318 if err != nil { 319 t.Fatalf("%s: %v", what, err) 320 } 321 } 322 cmd := helperCommand(t, "stdinClose") 323 stdin, err := cmd.StdinPipe() 324 check("StdinPipe", err) 325 // Check that we can access methods of the underlying os.File.` 326 if _, ok := stdin.(interface { 327 Fd() uintptr 328 }); !ok { 329 t.Error("can't access methods of underlying *os.File") 330 } 331 check("Start", cmd.Start()) 332 go func() { 333 _, err := io.Copy(stdin, strings.NewReader(stdinCloseTestString)) 334 check("Copy", err) 335 // Before the fix, this next line would race with cmd.Wait. 336 check("Close", stdin.Close()) 337 }() 338 check("Wait", cmd.Wait()) 339 } 340 341 // Issue 17647. 342 // It used to be the case that TestStdinClose, above, would fail when 343 // run under the race detector. This test is a variant of TestStdinClose 344 // that also used to fail when run under the race detector. 345 // This test is run by cmd/dist under the race detector to verify that 346 // the race detector no longer reports any problems. 347 func TestStdinCloseRace(t *testing.T) { 348 cmd := helperCommand(t, "stdinClose") 349 stdin, err := cmd.StdinPipe() 350 if err != nil { 351 t.Fatalf("StdinPipe: %v", err) 352 } 353 if err := cmd.Start(); err != nil { 354 t.Fatalf("Start: %v", err) 355 } 356 go func() { 357 // We don't check the error return of Kill. It is 358 // possible that the process has already exited, in 359 // which case Kill will return an error "process 360 // already finished". The purpose of this test is to 361 // see whether the race detector reports an error; it 362 // doesn't matter whether this Kill succeeds or not. 363 cmd.Process.Kill() 364 }() 365 go func() { 366 // Send the wrong string, so that the child fails even 367 // if the other goroutine doesn't manage to kill it first. 368 // This test is to check that the race detector does not 369 // falsely report an error, so it doesn't matter how the 370 // child process fails. 371 io.Copy(stdin, strings.NewReader("unexpected string")) 372 if err := stdin.Close(); err != nil { 373 t.Errorf("stdin.Close: %v", err) 374 } 375 }() 376 if err := cmd.Wait(); err == nil { 377 t.Fatalf("Wait: succeeded unexpectedly") 378 } 379 } 380 381 // Issue 5071 382 func TestPipeLookPathLeak(t *testing.T) { 383 // If we are reading from /proc/self/fd we (should) get an exact result. 384 tolerance := 0 385 386 // Reading /proc/self/fd is more reliable than calling lsof, so try that 387 // first. 388 numOpenFDs := func() (int, []byte, error) { 389 fds, err := ioutil.ReadDir("/proc/self/fd") 390 if err != nil { 391 return 0, nil, err 392 } 393 return len(fds), nil, nil 394 } 395 want, before, err := numOpenFDs() 396 if err != nil { 397 // We encountered a problem reading /proc/self/fd (we might be on 398 // a platform that doesn't have it). Fall back onto lsof. 399 t.Logf("using lsof because: %v", err) 400 numOpenFDs = func() (int, []byte, error) { 401 // Android's stock lsof does not obey the -p option, 402 // so extra filtering is needed. 403 // https://golang.org/issue/10206 404 if runtime.GOOS == "android" { 405 // numOpenFDsAndroid handles errors itself and 406 // might skip or fail the test. 407 n, lsof := numOpenFDsAndroid(t) 408 return n, lsof, nil 409 } 410 lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output() 411 return bytes.Count(lsof, []byte("\n")), lsof, err 412 } 413 414 // lsof may see file descriptors associated with the fork itself, 415 // so we allow some extra margin if we have to use it. 416 // https://golang.org/issue/19243 417 tolerance = 5 418 419 // Retry reading the number of open file descriptors. 420 want, before, err = numOpenFDs() 421 if err != nil { 422 t.Log(err) 423 t.Skipf("skipping test; error finding or running lsof") 424 } 425 } 426 427 for i := 0; i < 6; i++ { 428 cmd := exec.Command("something-that-does-not-exist-executable") 429 cmd.StdoutPipe() 430 cmd.StderrPipe() 431 cmd.StdinPipe() 432 if err := cmd.Run(); err == nil { 433 t.Fatal("unexpected success") 434 } 435 } 436 got, after, err := numOpenFDs() 437 if err != nil { 438 // numOpenFDs has already succeeded once, it should work here. 439 t.Errorf("unexpected failure: %v", err) 440 } 441 if got-want > tolerance { 442 t.Errorf("number of open file descriptors changed: got %v, want %v", got, want) 443 if before != nil { 444 t.Errorf("before:\n%v\n", before) 445 } 446 if after != nil { 447 t.Errorf("after:\n%v\n", after) 448 } 449 } 450 } 451 452 func numOpenFDsAndroid(t *testing.T) (n int, lsof []byte) { 453 raw, err := exec.Command("lsof").Output() 454 if err != nil { 455 t.Skip("skipping test; error finding or running lsof") 456 } 457 458 // First find the PID column index by parsing the first line, and 459 // select lines containing pid in the column. 460 pid := []byte(strconv.Itoa(os.Getpid())) 461 pidCol := -1 462 463 s := bufio.NewScanner(bytes.NewReader(raw)) 464 for s.Scan() { 465 line := s.Bytes() 466 fields := bytes.Fields(line) 467 if pidCol < 0 { 468 for i, v := range fields { 469 if bytes.Equal(v, []byte("PID")) { 470 pidCol = i 471 break 472 } 473 } 474 lsof = append(lsof, line...) 475 continue 476 } 477 if bytes.Equal(fields[pidCol], pid) { 478 lsof = append(lsof, '\n') 479 lsof = append(lsof, line...) 480 } 481 } 482 if pidCol < 0 { 483 t.Fatal("error processing lsof output: unexpected header format") 484 } 485 if err := s.Err(); err != nil { 486 t.Fatalf("error processing lsof output: %v", err) 487 } 488 return bytes.Count(lsof, []byte("\n")), lsof 489 } 490 491 // basefds returns the number of expected file descriptors 492 // to be present in a process at start. 493 // stdin, stdout, stderr, epoll/kqueue, epoll/kqueue pipe, maybe testlog 494 func basefds() uintptr { 495 n := os.Stderr.Fd() + 1 496 // The poll (epoll/kqueue) descriptor can be numerically 497 // either between stderr and the testlog-fd, or after 498 // testlog-fd. 499 for poll.IsPollDescriptor(n) { 500 n++ 501 } 502 for _, arg := range os.Args { 503 if strings.HasPrefix(arg, "-test.testlogfile=") { 504 n++ 505 } 506 } 507 return n 508 } 509 510 func TestExtraFilesFDShuffle(t *testing.T) { 511 t.Skip("flaky test; see https://golang.org/issue/5780") 512 switch runtime.GOOS { 513 case "windows": 514 t.Skip("no operating system support; skipping") 515 } 516 517 // syscall.StartProcess maps all the FDs passed to it in 518 // ProcAttr.Files (the concatenation of stdin,stdout,stderr and 519 // ExtraFiles) into consecutive FDs in the child, that is: 520 // Files{11, 12, 6, 7, 9, 3} should result in the file 521 // represented by FD 11 in the parent being made available as 0 522 // in the child, 12 as 1, etc. 523 // 524 // We want to test that FDs in the child do not get overwritten 525 // by one another as this shuffle occurs. The original implementation 526 // was buggy in that in some data dependent cases it would overwrite 527 // stderr in the child with one of the ExtraFile members. 528 // Testing for this case is difficult because it relies on using 529 // the same FD values as that case. In particular, an FD of 3 530 // must be at an index of 4 or higher in ProcAttr.Files and 531 // the FD of the write end of the Stderr pipe (as obtained by 532 // StderrPipe()) must be the same as the size of ProcAttr.Files; 533 // therefore we test that the read end of this pipe (which is what 534 // is returned to the parent by StderrPipe() being one less than 535 // the size of ProcAttr.Files, i.e. 3+len(cmd.ExtraFiles). 536 // 537 // Moving this test case around within the overall tests may 538 // affect the FDs obtained and hence the checks to catch these cases. 539 npipes := 2 540 c := helperCommand(t, "extraFilesAndPipes", strconv.Itoa(npipes+1)) 541 rd, wr, _ := os.Pipe() 542 defer rd.Close() 543 if rd.Fd() != 3 { 544 t.Errorf("bad test value for test pipe: fd %d", rd.Fd()) 545 } 546 stderr, _ := c.StderrPipe() 547 wr.WriteString("_LAST") 548 wr.Close() 549 550 pipes := make([]struct { 551 r, w *os.File 552 }, npipes) 553 data := []string{"a", "b"} 554 555 for i := 0; i < npipes; i++ { 556 r, w, err := os.Pipe() 557 if err != nil { 558 t.Fatalf("unexpected error creating pipe: %s", err) 559 } 560 pipes[i].r = r 561 pipes[i].w = w 562 w.WriteString(data[i]) 563 c.ExtraFiles = append(c.ExtraFiles, pipes[i].r) 564 defer func() { 565 r.Close() 566 w.Close() 567 }() 568 } 569 // Put fd 3 at the end. 570 c.ExtraFiles = append(c.ExtraFiles, rd) 571 572 stderrFd := int(stderr.(*os.File).Fd()) 573 if stderrFd != ((len(c.ExtraFiles) + 3) - 1) { 574 t.Errorf("bad test value for stderr pipe") 575 } 576 577 expected := "child: " + strings.Join(data, "") + "_LAST" 578 579 err := c.Start() 580 if err != nil { 581 t.Fatalf("Run: %v", err) 582 } 583 ch := make(chan string, 1) 584 go func(ch chan string) { 585 buf := make([]byte, 512) 586 n, err := stderr.Read(buf) 587 if err != nil { 588 t.Errorf("Read: %s", err) 589 ch <- err.Error() 590 } else { 591 ch <- string(buf[:n]) 592 } 593 close(ch) 594 }(ch) 595 select { 596 case m := <-ch: 597 if m != expected { 598 t.Errorf("Read: '%s' not '%s'", m, expected) 599 } 600 case <-time.After(5 * time.Second): 601 t.Errorf("Read timedout") 602 } 603 c.Wait() 604 } 605 606 func TestExtraFiles(t *testing.T) { 607 if haveUnexpectedFDs { 608 // The point of this test is to make sure that any 609 // descriptors we open are marked close-on-exec. 610 // If haveUnexpectedFDs is true then there were other 611 // descriptors open when we started the test, 612 // so those descriptors are clearly not close-on-exec, 613 // and they will confuse the test. We could modify 614 // the test to expect those descriptors to remain open, 615 // but since we don't know where they came from or what 616 // they are doing, that seems fragile. For example, 617 // perhaps they are from the startup code on this 618 // system for some reason. Also, this test is not 619 // system-specific; as long as most systems do not skip 620 // the test, we will still be testing what we care about. 621 t.Skip("skipping test because test was run with FDs open") 622 } 623 624 testenv.MustHaveExec(t) 625 626 if runtime.GOOS == "windows" { 627 t.Skipf("skipping test on %q", runtime.GOOS) 628 } 629 630 // Force network usage, to verify the epoll (or whatever) fd 631 // doesn't leak to the child, 632 ln, err := net.Listen("tcp", "127.0.0.1:0") 633 if err != nil { 634 t.Fatal(err) 635 } 636 defer ln.Close() 637 638 // Make sure duplicated fds don't leak to the child. 639 f, err := ln.(*net.TCPListener).File() 640 if err != nil { 641 t.Fatal(err) 642 } 643 defer f.Close() 644 ln2, err := net.FileListener(f) 645 if err != nil { 646 t.Fatal(err) 647 } 648 defer ln2.Close() 649 650 // Force TLS root certs to be loaded (which might involve 651 // cgo), to make sure none of that potential C code leaks fds. 652 ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) 653 // quiet expected TLS handshake error "remote error: bad certificate" 654 ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) 655 ts.StartTLS() 656 defer ts.Close() 657 _, err = http.Get(ts.URL) 658 if err == nil { 659 t.Errorf("success trying to fetch %s; want an error", ts.URL) 660 } 661 662 tf, err := ioutil.TempFile("", "") 663 if err != nil { 664 t.Fatalf("TempFile: %v", err) 665 } 666 defer os.Remove(tf.Name()) 667 defer tf.Close() 668 669 const text = "Hello, fd 3!" 670 _, err = tf.Write([]byte(text)) 671 if err != nil { 672 t.Fatalf("Write: %v", err) 673 } 674 _, err = tf.Seek(0, io.SeekStart) 675 if err != nil { 676 t.Fatalf("Seek: %v", err) 677 } 678 679 c := helperCommand(t, "read3") 680 var stdout, stderr bytes.Buffer 681 c.Stdout = &stdout 682 c.Stderr = &stderr 683 c.ExtraFiles = []*os.File{tf} 684 err = c.Run() 685 if err != nil { 686 t.Fatalf("Run: %v\n--- stdout:\n%s--- stderr:\n%s", err, stdout.Bytes(), stderr.Bytes()) 687 } 688 if stdout.String() != text { 689 t.Errorf("got stdout %q, stderr %q; want %q on stdout", stdout.String(), stderr.String(), text) 690 } 691 } 692 693 func TestExtraFilesRace(t *testing.T) { 694 if runtime.GOOS == "windows" { 695 t.Skip("no operating system support; skipping") 696 } 697 listen := func() net.Listener { 698 ln, err := net.Listen("tcp", "127.0.0.1:0") 699 if err != nil { 700 t.Fatal(err) 701 } 702 return ln 703 } 704 listenerFile := func(ln net.Listener) *os.File { 705 f, err := ln.(*net.TCPListener).File() 706 if err != nil { 707 t.Fatal(err) 708 } 709 return f 710 } 711 runCommand := func(c *exec.Cmd, out chan<- string) { 712 bout, err := c.CombinedOutput() 713 if err != nil { 714 out <- "ERROR:" + err.Error() 715 } else { 716 out <- string(bout) 717 } 718 } 719 720 for i := 0; i < 10; i++ { 721 if testing.Short() && i >= 3 { 722 break 723 } 724 la := listen() 725 ca := helperCommand(t, "describefiles") 726 ca.ExtraFiles = []*os.File{listenerFile(la)} 727 lb := listen() 728 cb := helperCommand(t, "describefiles") 729 cb.ExtraFiles = []*os.File{listenerFile(lb)} 730 ares := make(chan string) 731 bres := make(chan string) 732 go runCommand(ca, ares) 733 go runCommand(cb, bres) 734 if got, want := <-ares, fmt.Sprintf("fd3: listener %s\n", la.Addr()); got != want { 735 t.Errorf("iteration %d, process A got:\n%s\nwant:\n%s\n", i, got, want) 736 } 737 if got, want := <-bres, fmt.Sprintf("fd3: listener %s\n", lb.Addr()); got != want { 738 t.Errorf("iteration %d, process B got:\n%s\nwant:\n%s\n", i, got, want) 739 } 740 la.Close() 741 lb.Close() 742 for _, f := range ca.ExtraFiles { 743 f.Close() 744 } 745 for _, f := range cb.ExtraFiles { 746 f.Close() 747 } 748 749 } 750 } 751 752 // TestHelperProcess isn't a real test. It's used as a helper process 753 // for TestParameterRun. 754 func TestHelperProcess(*testing.T) { 755 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { 756 return 757 } 758 defer os.Exit(0) 759 760 // Determine which command to use to display open files. 761 ofcmd := "lsof" 762 switch runtime.GOOS { 763 case "dragonfly", "freebsd", "netbsd", "openbsd": 764 ofcmd = "fstat" 765 case "plan9": 766 ofcmd = "/bin/cat" 767 case "aix": 768 ofcmd = "procfiles" 769 } 770 771 args := os.Args 772 for len(args) > 0 { 773 if args[0] == "--" { 774 args = args[1:] 775 break 776 } 777 args = args[1:] 778 } 779 if len(args) == 0 { 780 fmt.Fprintf(os.Stderr, "No command\n") 781 os.Exit(2) 782 } 783 784 cmd, args := args[0], args[1:] 785 switch cmd { 786 case "echo": 787 iargs := []interface{}{} 788 for _, s := range args { 789 iargs = append(iargs, s) 790 } 791 fmt.Println(iargs...) 792 case "echoenv": 793 for _, s := range args { 794 fmt.Println(os.Getenv(s)) 795 } 796 os.Exit(0) 797 case "cat": 798 if len(args) == 0 { 799 io.Copy(os.Stdout, os.Stdin) 800 return 801 } 802 exit := 0 803 for _, fn := range args { 804 f, err := os.Open(fn) 805 if err != nil { 806 fmt.Fprintf(os.Stderr, "Error: %v\n", err) 807 exit = 2 808 } else { 809 defer f.Close() 810 io.Copy(os.Stdout, f) 811 } 812 } 813 os.Exit(exit) 814 case "pipetest": 815 bufr := bufio.NewReader(os.Stdin) 816 for { 817 line, _, err := bufr.ReadLine() 818 if err == io.EOF { 819 break 820 } else if err != nil { 821 os.Exit(1) 822 } 823 if bytes.HasPrefix(line, []byte("O:")) { 824 os.Stdout.Write(line) 825 os.Stdout.Write([]byte{'\n'}) 826 } else if bytes.HasPrefix(line, []byte("E:")) { 827 os.Stderr.Write(line) 828 os.Stderr.Write([]byte{'\n'}) 829 } else { 830 os.Exit(1) 831 } 832 } 833 case "stdinClose": 834 b, err := ioutil.ReadAll(os.Stdin) 835 if err != nil { 836 fmt.Fprintf(os.Stderr, "Error: %v\n", err) 837 os.Exit(1) 838 } 839 if s := string(b); s != stdinCloseTestString { 840 fmt.Fprintf(os.Stderr, "Error: Read %q, want %q", s, stdinCloseTestString) 841 os.Exit(1) 842 } 843 os.Exit(0) 844 case "read3": // read fd 3 845 fd3 := os.NewFile(3, "fd3") 846 bs, err := ioutil.ReadAll(fd3) 847 if err != nil { 848 fmt.Printf("ReadAll from fd 3: %v", err) 849 os.Exit(1) 850 } 851 // Now verify that there are no other open fds. 852 var files []*os.File 853 for wantfd := basefds() + 1; wantfd <= 100; wantfd++ { 854 if poll.IsPollDescriptor(wantfd) { 855 continue 856 } 857 f, err := os.Open(os.Args[0]) 858 if err != nil { 859 fmt.Printf("error opening file with expected fd %d: %v", wantfd, err) 860 os.Exit(1) 861 } 862 if got := f.Fd(); got != wantfd { 863 fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd) 864 var args []string 865 switch runtime.GOOS { 866 case "plan9": 867 args = []string{fmt.Sprintf("/proc/%d/fd", os.Getpid())} 868 case "aix": 869 args = []string{fmt.Sprint(os.Getpid())} 870 default: 871 args = []string{"-p", fmt.Sprint(os.Getpid())} 872 } 873 cmd := exec.Command(ofcmd, args...) 874 out, err := cmd.CombinedOutput() 875 if err != nil { 876 fmt.Fprintf(os.Stderr, "%s failed: %v\n", strings.Join(cmd.Args, " "), err) 877 } 878 fmt.Printf("%s", out) 879 os.Exit(1) 880 } 881 files = append(files, f) 882 } 883 for _, f := range files { 884 f.Close() 885 } 886 // Referring to fd3 here ensures that it is not 887 // garbage collected, and therefore closed, while 888 // executing the wantfd loop above. It doesn't matter 889 // what we do with fd3 as long as we refer to it; 890 // closing it is the easy choice. 891 fd3.Close() 892 os.Stdout.Write(bs) 893 case "exit": 894 n, _ := strconv.Atoi(args[0]) 895 os.Exit(n) 896 case "describefiles": 897 f := os.NewFile(3, fmt.Sprintf("fd3")) 898 ln, err := net.FileListener(f) 899 if err == nil { 900 fmt.Printf("fd3: listener %s\n", ln.Addr()) 901 ln.Close() 902 } 903 os.Exit(0) 904 case "extraFilesAndPipes": 905 n, _ := strconv.Atoi(args[0]) 906 pipes := make([]*os.File, n) 907 for i := 0; i < n; i++ { 908 pipes[i] = os.NewFile(uintptr(3+i), strconv.Itoa(i)) 909 } 910 response := "" 911 for i, r := range pipes { 912 ch := make(chan string, 1) 913 go func(c chan string) { 914 buf := make([]byte, 10) 915 n, err := r.Read(buf) 916 if err != nil { 917 fmt.Fprintf(os.Stderr, "Child: read error: %v on pipe %d\n", err, i) 918 os.Exit(1) 919 } 920 c <- string(buf[:n]) 921 close(c) 922 }(ch) 923 select { 924 case m := <-ch: 925 response = response + m 926 case <-time.After(5 * time.Second): 927 fmt.Fprintf(os.Stderr, "Child: Timeout reading from pipe: %d\n", i) 928 os.Exit(1) 929 } 930 } 931 fmt.Fprintf(os.Stderr, "child: %s", response) 932 os.Exit(0) 933 case "exec": 934 cmd := exec.Command(args[1]) 935 cmd.Dir = args[0] 936 output, err := cmd.CombinedOutput() 937 if err != nil { 938 fmt.Fprintf(os.Stderr, "Child: %s %s", err, string(output)) 939 os.Exit(1) 940 } 941 fmt.Printf("%s", string(output)) 942 os.Exit(0) 943 case "lookpath": 944 p, err := exec.LookPath(args[0]) 945 if err != nil { 946 fmt.Fprintf(os.Stderr, "LookPath failed: %v\n", err) 947 os.Exit(1) 948 } 949 fmt.Print(p) 950 os.Exit(0) 951 case "stderrfail": 952 fmt.Fprintf(os.Stderr, "some stderr text\n") 953 os.Exit(1) 954 case "sleep": 955 time.Sleep(3 * time.Second) 956 os.Exit(0) 957 default: 958 fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) 959 os.Exit(2) 960 } 961 } 962 963 type delayedInfiniteReader struct{} 964 965 func (delayedInfiniteReader) Read(b []byte) (int, error) { 966 time.Sleep(100 * time.Millisecond) 967 for i := range b { 968 b[i] = 'x' 969 } 970 return len(b), nil 971 } 972 973 // Issue 9173: ignore stdin pipe writes if the program completes successfully. 974 func TestIgnorePipeErrorOnSuccess(t *testing.T) { 975 testenv.MustHaveExec(t) 976 977 testWith := func(r io.Reader) func(*testing.T) { 978 return func(t *testing.T) { 979 cmd := helperCommand(t, "echo", "foo") 980 var out bytes.Buffer 981 cmd.Stdin = r 982 cmd.Stdout = &out 983 if err := cmd.Run(); err != nil { 984 t.Fatal(err) 985 } 986 if got, want := out.String(), "foo\n"; got != want { 987 t.Errorf("output = %q; want %q", got, want) 988 } 989 } 990 } 991 t.Run("10MB", testWith(strings.NewReader(strings.Repeat("x", 10<<20)))) 992 t.Run("Infinite", testWith(delayedInfiniteReader{})) 993 } 994 995 type badWriter struct{} 996 997 func (w *badWriter) Write(data []byte) (int, error) { 998 return 0, io.ErrUnexpectedEOF 999 } 1000 1001 func TestClosePipeOnCopyError(t *testing.T) { 1002 testenv.MustHaveExec(t) 1003 1004 if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { 1005 t.Skipf("skipping test on %s - no yes command", runtime.GOOS) 1006 } 1007 cmd := exec.Command("yes") 1008 cmd.Stdout = new(badWriter) 1009 c := make(chan int, 1) 1010 go func() { 1011 err := cmd.Run() 1012 if err == nil { 1013 t.Errorf("yes completed successfully") 1014 } 1015 c <- 1 1016 }() 1017 select { 1018 case <-c: 1019 // ok 1020 case <-time.After(5 * time.Second): 1021 t.Fatalf("yes got stuck writing to bad writer") 1022 } 1023 } 1024 1025 func TestOutputStderrCapture(t *testing.T) { 1026 testenv.MustHaveExec(t) 1027 1028 cmd := helperCommand(t, "stderrfail") 1029 _, err := cmd.Output() 1030 ee, ok := err.(*exec.ExitError) 1031 if !ok { 1032 t.Fatalf("Output error type = %T; want ExitError", err) 1033 } 1034 got := string(ee.Stderr) 1035 want := "some stderr text\n" 1036 if got != want { 1037 t.Errorf("ExitError.Stderr = %q; want %q", got, want) 1038 } 1039 } 1040 1041 func TestContext(t *testing.T) { 1042 ctx, cancel := context.WithCancel(context.Background()) 1043 c := helperCommandContext(t, ctx, "pipetest") 1044 stdin, err := c.StdinPipe() 1045 if err != nil { 1046 t.Fatal(err) 1047 } 1048 stdout, err := c.StdoutPipe() 1049 if err != nil { 1050 t.Fatal(err) 1051 } 1052 if err := c.Start(); err != nil { 1053 t.Fatal(err) 1054 } 1055 1056 if _, err := stdin.Write([]byte("O:hi\n")); err != nil { 1057 t.Fatal(err) 1058 } 1059 buf := make([]byte, 5) 1060 n, err := io.ReadFull(stdout, buf) 1061 if n != len(buf) || err != nil || string(buf) != "O:hi\n" { 1062 t.Fatalf("ReadFull = %d, %v, %q", n, err, buf[:n]) 1063 } 1064 waitErr := make(chan error, 1) 1065 go func() { 1066 waitErr <- c.Wait() 1067 }() 1068 cancel() 1069 select { 1070 case err := <-waitErr: 1071 if err == nil { 1072 t.Fatal("expected Wait failure") 1073 } 1074 case <-time.After(3 * time.Second): 1075 t.Fatal("timeout waiting for child process death") 1076 } 1077 } 1078 1079 func TestContextCancel(t *testing.T) { 1080 ctx, cancel := context.WithCancel(context.Background()) 1081 defer cancel() 1082 c := helperCommandContext(t, ctx, "cat") 1083 1084 r, w, err := os.Pipe() 1085 if err != nil { 1086 t.Fatal(err) 1087 } 1088 c.Stdin = r 1089 1090 stdout, err := c.StdoutPipe() 1091 if err != nil { 1092 t.Fatal(err) 1093 } 1094 readDone := make(chan struct{}) 1095 go func() { 1096 defer close(readDone) 1097 var a [1024]byte 1098 for { 1099 n, err := stdout.Read(a[:]) 1100 if err != nil { 1101 if err != io.EOF { 1102 t.Errorf("unexpected read error: %v", err) 1103 } 1104 return 1105 } 1106 t.Logf("%s", a[:n]) 1107 } 1108 }() 1109 1110 if err := c.Start(); err != nil { 1111 t.Fatal(err) 1112 } 1113 1114 if err := r.Close(); err != nil { 1115 t.Fatal(err) 1116 } 1117 1118 if _, err := io.WriteString(w, "echo"); err != nil { 1119 t.Fatal(err) 1120 } 1121 1122 cancel() 1123 1124 // Calling cancel should have killed the process, so writes 1125 // should now fail. Give the process a little while to die. 1126 start := time.Now() 1127 for { 1128 if _, err := io.WriteString(w, "echo"); err != nil { 1129 break 1130 } 1131 if time.Since(start) > time.Second { 1132 t.Fatal("canceling context did not stop program") 1133 } 1134 time.Sleep(time.Millisecond) 1135 } 1136 1137 if err := w.Close(); err != nil { 1138 t.Errorf("error closing write end of pipe: %v", err) 1139 } 1140 <-readDone 1141 1142 if err := c.Wait(); err == nil { 1143 t.Error("program unexpectedly exited successfully") 1144 } else { 1145 t.Logf("exit status: %v", err) 1146 } 1147 } 1148 1149 // test that environment variables are de-duped. 1150 func TestDedupEnvEcho(t *testing.T) { 1151 testenv.MustHaveExec(t) 1152 1153 cmd := helperCommand(t, "echoenv", "FOO") 1154 cmd.Env = append(cmd.Env, "FOO=bad", "FOO=good") 1155 out, err := cmd.CombinedOutput() 1156 if err != nil { 1157 t.Fatal(err) 1158 } 1159 if got, want := strings.TrimSpace(string(out)), "good"; got != want { 1160 t.Errorf("output = %q; want %q", got, want) 1161 } 1162 } 1163 1164 func TestString(t *testing.T) { 1165 echoPath, err := exec.LookPath("echo") 1166 if err != nil { 1167 t.Skip(err) 1168 } 1169 tests := [...]struct { 1170 path string 1171 args []string 1172 want string 1173 }{ 1174 {"echo", nil, echoPath}, 1175 {"echo", []string{"a"}, echoPath + " a"}, 1176 {"echo", []string{"a", "b"}, echoPath + " a b"}, 1177 } 1178 for _, test := range tests { 1179 cmd := exec.Command(test.path, test.args...) 1180 if got := cmd.String(); got != test.want { 1181 t.Errorf("String(%q, %q) = %q, want %q", test.path, test.args, got, test.want) 1182 } 1183 } 1184 } 1185 1186 func TestStringPathNotResolved(t *testing.T) { 1187 _, err := exec.LookPath("makemeasandwich") 1188 if err == nil { 1189 t.Skip("wow, thanks") 1190 } 1191 cmd := exec.Command("makemeasandwich", "-lettuce") 1192 want := "makemeasandwich -lettuce" 1193 if got := cmd.String(); got != want { 1194 t.Errorf("String(%q, %q) = %q, want %q", "makemeasandwich", "-lettuce", got, want) 1195 } 1196 } 1197 1198 // start a child process without the user code explicitly starting 1199 // with a copy of the parent's. (The Windows SYSTEMROOT issue: Issue 1200 // 25210) 1201 func TestChildCriticalEnv(t *testing.T) { 1202 testenv.MustHaveExec(t) 1203 if runtime.GOOS != "windows" { 1204 t.Skip("only testing on Windows") 1205 } 1206 cmd := helperCommand(t, "echoenv", "SYSTEMROOT") 1207 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 1208 out, err := cmd.CombinedOutput() 1209 if err != nil { 1210 t.Fatal(err) 1211 } 1212 if strings.TrimSpace(string(out)) == "" { 1213 t.Error("no SYSTEMROOT found") 1214 } 1215 }