// Fork can hang if preempted with signals frequently enough (see issue 5517). // Ensure that we do not do this. func TestCPUProfileWithFork(t *testing.T) { testenv.MustHaveExec(t) heap := 1 << 30 if runtime.GOOS == "android" { // Use smaller size for Android to avoid crash. heap = 100 << 20 } if testing.Short() { heap = 100 << 20 } // This makes fork slower. garbage := make([]byte, heap) // Need to touch the slice, otherwise it won't be paged in. done := make(chan bool) go func() { for i := range garbage { garbage[i] = 42 } done <- true }() <-done var prof bytes.Buffer if err := StartCPUProfile(&prof); err != nil { t.Fatal(err) } defer StopCPUProfile() for i := 0; i < 10; i++ { exec.Command(os.Args[0], "-h").CombinedOutput() } }
func TestStackBarrierProfiling(t *testing.T) { if !strings.Contains(os.Getenv("GODEBUG"), "gcstackbarrierall=1") { // Re-execute this test with constant GC and stack // barriers at every frame. testenv.MustHaveExec(t) if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" { t.Skip("gcstackbarrierall doesn't work on ppc64") } cmd := exec.Command(os.Args[0], "-test.run=TestStackBarrierProfiling") cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1"}, os.Environ()...) if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("subprocess failed with %v:\n%s", err, out) } return } testCPUProfile(t, nil, func() { // This is long enough that we're likely to get one or // two samples in stackBarrier. duration := 5 * time.Second if testing.Short() { duration = 1 * time.Second } t := time.After(duration) for { deepStack(1000) select { case <-t: return default: } } }) }
func TestCommandRelativeName(t *testing.T) { testenv.MustHaveExec(t) // Run our own binary as a relative path // (e.g. "_test/exec.test") our parent directory. base := filepath.Base(os.Args[0]) // "exec.test" dir := filepath.Dir(os.Args[0]) // "/tmp/go-buildNNNN/os/exec/_test" if dir == "." { t.Skip("skipping; running test at root somehow") } parentDir := filepath.Dir(dir) // "/tmp/go-buildNNNN/os/exec" dirBase := filepath.Base(dir) // "_test" if dirBase == "." { t.Skipf("skipping; unexpected shallow dir of %q", dir) } cmd := exec.Command(filepath.Join(dirBase, base), "-test.run=TestHelperProcess", "--", "echo", "foo") cmd.Dir = parentDir cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} out, err := cmd.Output() if err != nil { t.Errorf("echo: %v", err) } if g, e := string(out), "foo\n"; g != e { t.Errorf("echo: want %q, got %q", e, g) } }
func TestHostname(t *testing.T) { // There is no other way to fetch hostname on windows, but via winapi. // On Plan 9 it can be taken from #c/sysname as Hostname() does. switch runtime.GOOS { case "android", "plan9": t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS) case "windows": testWindowsHostname(t) return } testenv.MustHaveExec(t) // Check internal Hostname() against the output of /bin/hostname. // Allow that the internal Hostname returns a Fully Qualified Domain Name // and the /bin/hostname only returns the first component hostname, err := Hostname() if err != nil { t.Fatalf("%v", err) } want := runBinHostname(t) if hostname != want { i := strings.Index(hostname, ".") if i < 0 || hostname[0:i] != want { t.Errorf("Hostname() = %q, want %q", hostname, want) } } }
func TestStatStdin(t *testing.T) { switch runtime.GOOS { case "android", "plan9": t.Skipf("%s doesn't have /bin/sh", runtime.GOOS) } testenv.MustHaveExec(t) if Getenv("GO_WANT_HELPER_PROCESS") == "1" { st, err := Stdin.Stat() if err != nil { t.Fatalf("Stat failed: %v", err) } fmt.Println(st.Mode() & ModeNamedPipe) Exit(0) } var cmd *osexec.Cmd if runtime.GOOS == "windows" { cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin") } else { cmd = osexec.Command("/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin") } cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") output, err := cmd.CombinedOutput() if err != nil { t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) } // result will be like "prw-rw-rw" if len(output) < 1 || output[0] != 'p' { t.Fatalf("Child process reports stdin is not pipe '%v'", string(output)) } }
func TestGetppid(t *testing.T) { if runtime.GOOS == "plan9" { // TODO: golang.org/issue/8206 t.Skipf("skipping test on plan9; see issue 8206") } testenv.MustHaveExec(t) if Getenv("GO_WANT_HELPER_PROCESS") == "1" { fmt.Print(Getppid()) Exit(0) } cmd := osexec.Command(Args[0], "-test.run=TestGetppid") cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1") // verify that Getppid() from the forked process reports our process id output, err := cmd.CombinedOutput() if err != nil { t.Fatalf("Failed to spawn child process: %v %q", err, string(output)) } childPpid := string(output) ourPid := fmt.Sprintf("%d", Getpid()) if childPpid != ourPid { t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid) } }
func TestMutexMisuse(t *testing.T) { testenv.MustHaveExec(t) for _, test := range misuseTests { out, err := exec.Command(os.Args[0], "TESTMISUSE", test.name).CombinedOutput() if err == nil || !strings.Contains(string(out), "unlocked") { t.Errorf("%s: did not find failure with message about unlocked lock: %s\n%s\n", test.name, err, out) } } }
func TestStackBarrierProfiling(t *testing.T) { if (runtime.GOOS == "linux" && runtime.GOARCH == "arm") || runtime.GOOS == "openbsd" || runtime.GOOS == "solaris" || runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" { // This test currently triggers a large number of // usleep(100)s. These kernels/arches have poor // resolution timers, so this gives up a whole // scheduling quantum. On Linux and the BSDs (and // probably Solaris), profiling signals are only // generated when a process completes a whole // scheduling quantum, so this test often gets zero // profiling signals and fails. t.Skipf("low resolution timers inhibit profiling signals (golang.org/issue/13405)") return } if runtime.GOOS == "linux" && strings.HasPrefix(runtime.GOARCH, "mips") { if !haveLinuxHiresTimers() { t.Skipf("low resolution timers inhibit profiling signals (golang.org/issue/13405, golang.org/issue/17936)") } } if !strings.Contains(os.Getenv("GODEBUG"), "gcstackbarrierall=1") { // Re-execute this test with constant GC and stack // barriers at every frame. testenv.MustHaveExec(t) if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" { t.Skip("gcstackbarrierall doesn't work on ppc64") } args := []string{"-test.run=TestStackBarrierProfiling"} if testing.Short() { args = append(args, "-test.short") } cmd := exec.Command(os.Args[0], args...) cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1", "GOTRACEBACK=system"}, os.Environ()...) if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("subprocess failed with %v:\n%s", err, out) } return } testCPUProfile(t, nil, func(duration time.Duration) { // In long mode, we're likely to get one or two // samples in stackBarrier. t := time.After(duration) for { deepStack(1000) select { case <-t: return default: } } }) }
func helperCommand(t *testing.T, s ...string) *exec.Cmd { testenv.MustHaveExec(t) cs := []string{"-test.run=TestHelperProcess", "--"} cs = append(cs, s...) cmd := exec.Command(os.Args[0], cs...) cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} return cmd }
// Check that permuting child process fds doesn't interfere with // reporting of fork/exec status. See Issue 14979. func TestExecErrPermutedFds(t *testing.T) { testenv.MustHaveExec(t) attr := &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stderr, os.Stdout}} _, err := os.StartProcess("/", []string{"/"}, attr) if err == nil { t.Fatalf("StartProcess of invalid program returned err = nil") } }
func create(t *testing.T) *command { testenv.MustHaveExec(t) proc := exec.Command("cat") stdin, err := proc.StdinPipe() if err != nil { t.Fatal(err) } return &command{stdin, proc, t} }
func helperCommandContext(t *testing.T, ctx context.Context, s ...string) (cmd *exec.Cmd) { testenv.MustHaveExec(t) cs := []string{"-test.run=TestHelperProcess", "--"} cs = append(cs, s...) if ctx != nil { cmd = exec.CommandContext(ctx, os.Args[0], cs...) } else { cmd = exec.Command(os.Args[0], cs...) } cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} return cmd }
func helperCommand(t *testing.T, s ...string) *exec.Cmd { testenv.MustHaveExec(t) cs := []string{"-test.run=TestHelperProcess", "--"} cs = append(cs, s...) cmd := exec.Command(os.Args[0], cs...) cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} path := os.Getenv("LD_LIBRARY_PATH") if path != "" { cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+path) } return cmd }
func TestOutputStderrCapture(t *testing.T) { testenv.MustHaveExec(t) cmd := helperCommand(t, "stderrfail") _, err := cmd.Output() ee, ok := err.(*exec.ExitError) if !ok { t.Fatalf("Output error type = %T; want ExitError", err) } got := string(ee.Stderr) want := "some stderr text\n" if got != want { t.Errorf("ExitError.Stderr = %q; want %q", got, want) } }
// Test that a child handler writing only headers works. // golang.org/issue/7196 func TestChildOnlyHeaders(t *testing.T) { testenv.MustHaveExec(t) h := &Handler{ Path: os.Args[0], Root: "/test.go", Args: []string{"-test.run=TestBeChildCGIProcess"}, } expectedMap := map[string]string{ "_body": "", } replay := runCgiTest(t, h, "GET /test.go?no-body=1 HTTP/1.0\nHost: example.com\n\n", expectedMap) if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected { t.Errorf("got a X-Test-Header of %q; expected %q", got, expected) } }
func testKillProcess(t *testing.T, processKiller func(p *Process)) { testenv.MustHaveExec(t) // Re-exec the test binary itself to emulate "sleep 1". cmd := osexec.Command(Args[0], "-test.run", "TestSleep") err := cmd.Start() if err != nil { t.Fatalf("Failed to start test process: %v", err) } go func() { time.Sleep(100 * time.Millisecond) processKiller(cmd.Process) }() err = cmd.Wait() if err == nil { t.Errorf("Test process succeeded, but expected to fail") } }
func TestStdPipe(t *testing.T) { testenv.MustHaveExec(t) r, w, err := os.Pipe() if err != nil { t.Fatal(err) } if err := r.Close(); err != nil { t.Fatal(err) } // Invoke the test program to run the test and write to a closed pipe. // If sig is false: // writing to stdout or stderr should cause an immediate SIGPIPE; // writing to descriptor 3 should fail with EPIPE and then exit 0. // If sig is true: // all writes should fail with EPIPE and then exit 0. for _, sig := range []bool{false, true} { for dest := 1; dest < 4; dest++ { cmd := osexec.Command(os.Args[0], "-test.run", "TestStdPipeHelper") cmd.Stdout = w cmd.Stderr = w cmd.ExtraFiles = []*os.File{w} cmd.Env = append(os.Environ(), fmt.Sprintf("GO_TEST_STD_PIPE_HELPER=%d", dest)) if sig { cmd.Env = append(cmd.Env, "GO_TEST_STD_PIPE_HELPER_SIGNAL=1") } if err := cmd.Run(); err == nil { if !sig && dest < 3 { t.Errorf("unexpected success of write to closed pipe %d sig %t in child", dest, sig) } } else if ee, ok := err.(*osexec.ExitError); !ok { t.Errorf("unexpected exec error type %T: %v", err, err) } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok { t.Errorf("unexpected wait status type %T: %v", ee.Sys(), ee.Sys()) } else if ws.Signaled() && ws.Signal() == syscall.SIGPIPE { if sig || dest > 2 { t.Errorf("unexpected SIGPIPE signal for descriptor %d sig %t", dest, sig) } } else { t.Errorf("unexpected exit status %v for descriptor %ds sig %t", err, dest, sig) } } } }
// Issue 9173: ignore stdin pipe writes if the program completes successfully. func TestIgnorePipeErrorOnSuccess(t *testing.T) { testenv.MustHaveExec(t) // We really only care about testing this on Unixy things. if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { t.Skipf("skipping test on %q", runtime.GOOS) } cmd := helperCommand(t, "echo", "foo") var out bytes.Buffer cmd.Stdin = strings.NewReader(strings.Repeat("x", 10<<20)) cmd.Stdout = &out if err := cmd.Run(); err != nil { t.Fatal(err) } if got, want := out.String(), "foo\n"; got != want { t.Errorf("output = %q; want %q", got, want) } }
// If there's an error copying the child's output to the parent, test // that we kill the child. func TestKillChildAfterCopyError(t *testing.T) { testenv.MustHaveExec(t) defer func() { testHookStartProcess = nil }() proc := make(chan *os.Process, 1) testHookStartProcess = func(p *os.Process) { proc <- p } h := &Handler{ Path: os.Args[0], Root: "/test.go", Args: []string{"-test.run=TestBeChildCGIProcess"}, } req, _ := http.NewRequest("GET", "http://example.com/test.cgi?write-forever=1", nil) rec := httptest.NewRecorder() var out bytes.Buffer const writeLen = 50 << 10 rw := &customWriterRecorder{&limitWriter{&out, writeLen}, rec} donec := make(chan bool, 1) go func() { h.ServeHTTP(rw, req) donec <- true }() select { case <-donec: if out.Len() != writeLen || out.Bytes()[0] != 'a' { t.Errorf("unexpected output: %q", out.Bytes()) } case <-time.After(5 * time.Second): t.Errorf("timeout. ServeHTTP hung and didn't kill the child process?") select { case p := <-proc: p.Kill() t.Logf("killed process") default: t.Logf("didn't kill process") } } }
func TestClosePipeOnCopyError(t *testing.T) { testenv.MustHaveExec(t) if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { t.Skipf("skipping test on %s - no yes command", runtime.GOOS) } cmd := exec.Command("yes") cmd.Stdout = new(badWriter) c := make(chan int, 1) go func() { err := cmd.Run() if err == nil { t.Errorf("yes completed successfully") } c <- 1 }() select { case <-c: // ok case <-time.After(5 * time.Second): t.Fatalf("yes got stuck writing to bad writer") } }
func TestStartProcess(t *testing.T) { testenv.MustHaveExec(t) var dir, cmd string var args []string switch runtime.GOOS { case "android": t.Skip("android doesn't have /bin/pwd") case "windows": cmd = Getenv("COMSPEC") dir = Getenv("SystemRoot") args = []string{"/c", "cd"} default: cmd = "/bin/pwd" dir = "/" args = []string{} } cmddir, cmdbase := filepath.Split(cmd) args = append([]string{cmdbase}, args...) // Test absolute executable path. exec(t, dir, cmd, args, dir) // Test relative executable path. exec(t, cmddir, cmdbase, args, cmddir) }
func TestExecutable(t *testing.T) { testenv.MustHaveExec(t) // will also execlude nacl, which doesn't support Executable anyway ep, err := os.Executable() if err != nil { switch goos := runtime.GOOS; goos { case "openbsd": // procfs is not mounted by default t.Skipf("Executable failed on %s: %v, expected", goos, err) } t.Fatalf("Executable failed: %v", err) } // we want fn to be of the form "dir/prog" dir := filepath.Dir(filepath.Dir(ep)) fn, err := filepath.Rel(dir, ep) if err != nil { t.Fatalf("filepath.Rel: %v", err) } cmd := &osexec.Cmd{} // make child start with a relative program path cmd.Dir = dir cmd.Path = fn // forge argv[0] for child, so that we can verify we could correctly // get real path of the executable without influenced by argv[0]. cmd.Args = []string{"-", "-test.run=XXXX"} cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", executable_EnvVar)) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("exec(self) failed: %v", err) } outs := string(out) if !filepath.IsAbs(outs) { t.Fatalf("Child returned %q, want an absolute path", out) } if !sameFile(outs, ep) { t.Fatalf("Child returned %q, not the same file as %q", out, ep) } }
// This test is a CGI host (testing host.go) that runs its own binary // as a child process testing the other half of CGI (child.go). func TestHostingOurselves(t *testing.T) { testenv.MustHaveExec(t) h := &Handler{ Path: os.Args[0], Root: "/test.go", Args: []string{"-test.run=TestBeChildCGIProcess"}, } expectedMap := map[string]string{ "test": "Hello CGI-in-CGI", "param-a": "b", "param-foo": "bar", "env-GATEWAY_INTERFACE": "CGI/1.1", "env-HTTP_HOST": "example.com", "env-PATH_INFO": "", "env-QUERY_STRING": "foo=bar&a=b", "env-REMOTE_ADDR": "1.2.3.4", "env-REMOTE_HOST": "1.2.3.4", "env-REMOTE_PORT": "1234", "env-REQUEST_METHOD": "GET", "env-REQUEST_URI": "/test.go?foo=bar&a=b", "env-SCRIPT_FILENAME": os.Args[0], "env-SCRIPT_NAME": "/test.go", "env-SERVER_NAME": "example.com", "env-SERVER_PORT": "80", "env-SERVER_SOFTWARE": "go", } replay := runCgiTest(t, h, "GET /test.go?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap) if expected, got := "text/html; charset=utf-8", replay.Header().Get("Content-Type"); got != expected { t.Errorf("got a Content-Type of %q; expected %q", got, expected) } if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected { t.Errorf("got a X-Test-Header of %q; expected %q", got, expected) } }
func TestExtraFiles(t *testing.T) { testenv.MustHaveExec(t) if runtime.GOOS == "windows" { t.Skipf("skipping test on %q", runtime.GOOS) } // Ensure that file descriptors have not already been leaked into // our environment. if !testedAlreadyLeaked { testedAlreadyLeaked = true closeUnexpectedFds(t, "TestExtraFiles") } // Force network usage, to verify the epoll (or whatever) fd // doesn't leak to the child, ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer ln.Close() // Make sure duplicated fds don't leak to the child. f, err := ln.(*net.TCPListener).File() if err != nil { t.Fatal(err) } defer f.Close() ln2, err := net.FileListener(f) if err != nil { t.Fatal(err) } defer ln2.Close() // Force TLS root certs to be loaded (which might involve // cgo), to make sure none of that potential C code leaks fds. ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) // quiet expected TLS handshake error "remote error: bad certificate" ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) ts.StartTLS() defer ts.Close() _, err = http.Get(ts.URL) if err == nil { t.Errorf("success trying to fetch %s; want an error", ts.URL) } tf, err := ioutil.TempFile("", "") if err != nil { t.Fatalf("TempFile: %v", err) } defer os.Remove(tf.Name()) defer tf.Close() const text = "Hello, fd 3!" _, err = tf.Write([]byte(text)) if err != nil { t.Fatalf("Write: %v", err) } _, err = tf.Seek(0, os.SEEK_SET) if err != nil { t.Fatalf("Seek: %v", err) } c := helperCommand(t, "read3") var stdout, stderr bytes.Buffer c.Stdout = &stdout c.Stderr = &stderr c.ExtraFiles = []*os.File{tf} err = c.Run() if err != nil { t.Fatalf("Run: %v; stdout %q, stderr %q", err, stdout.Bytes(), stderr.Bytes()) } if stdout.String() != text { t.Errorf("got stdout %q, stderr %q; want %q on stdout", stdout.String(), stderr.String(), text) } }
// TestTraceSymbolize tests symbolization and that events has proper stacks. // In particular that we strip bottom uninteresting frames like goexit, // top uninteresting frames (runtime guts). func TestTraceSymbolize(t *testing.T) { testenv.MustHaveExec(t) buf := new(bytes.Buffer) if err := Start(buf); err != nil { t.Fatalf("failed to start tracing: %v", err) } defer Stop() // in case of early return // Now we will do a bunch of things for which we verify stacks later. // It is impossible to ensure that a goroutine has actually blocked // on a channel, in a select or otherwise. So we kick off goroutines // that need to block first in the hope that while we are executing // the rest of the test, they will block. go func() { select {} }() go func() { var c chan int c <- 0 }() go func() { var c chan int <-c }() done1 := make(chan bool) go func() { <-done1 }() done2 := make(chan bool) go func() { done2 <- true }() c1 := make(chan int) c2 := make(chan int) go func() { select { case <-c1: case <-c2: } }() var mu sync.Mutex mu.Lock() go func() { mu.Lock() mu.Unlock() }() var wg sync.WaitGroup wg.Add(1) go func() { wg.Wait() }() cv := sync.NewCond(&sync.Mutex{}) go func() { cv.L.Lock() cv.Wait() cv.L.Unlock() }() ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("failed to listen: %v", err) } go func() { c, err := ln.Accept() if err != nil { t.Fatalf("failed to accept: %v", err) } c.Close() }() rp, wp, err := os.Pipe() if err != nil { t.Fatalf("failed to create a pipe: %v", err) } defer rp.Close() defer wp.Close() pipeReadDone := make(chan bool) go func() { var data [1]byte rp.Read(data[:]) pipeReadDone <- true }() time.Sleep(time.Millisecond) runtime.GC() runtime.Gosched() time.Sleep(time.Millisecond) // the last chance for the goroutines above to block done1 <- true <-done2 select { case c1 <- 0: case c2 <- 0: } mu.Unlock() wg.Done() cv.Signal() c, err := net.Dial("tcp", ln.Addr().String()) if err != nil { t.Fatalf("failed to dial: %v", err) } c.Close() var data [1]byte wp.Write(data[:]) <-pipeReadDone Stop() events, _, err := parseTrace(t, buf) if err != nil { t.Fatalf("failed to parse trace: %v", err) } err = trace.Symbolize(events, os.Args[0]) if err != nil { t.Fatalf("failed to symbolize trace: %v", err) } // Now check that the stacks are correct. type frame struct { Fn string Line int } type eventDesc struct { Type byte Stk []frame } want := []eventDesc{ eventDesc{trace.EvGCStart, []frame{ frame{"runtime.GC", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 106}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoSched, []frame{ frame{"runtime/trace_test.TestTraceSymbolize", 107}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoCreate, []frame{ frame{"runtime/trace_test.TestTraceSymbolize", 39}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoStop, []frame{ frame{"runtime.block", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func1", 38}, }}, eventDesc{trace.EvGoStop, []frame{ frame{"runtime.chansend1", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func2", 42}, }}, eventDesc{trace.EvGoStop, []frame{ frame{"runtime.chanrecv1", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func3", 46}, }}, eventDesc{trace.EvGoBlockRecv, []frame{ frame{"runtime.chanrecv1", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func4", 50}, }}, eventDesc{trace.EvGoUnblock, []frame{ frame{"runtime.chansend1", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 109}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoBlockSend, []frame{ frame{"runtime.chansend1", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func5", 54}, }}, eventDesc{trace.EvGoUnblock, []frame{ frame{"runtime.chanrecv1", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 110}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoBlockSelect, []frame{ frame{"runtime.selectgo", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func6", 59}, }}, eventDesc{trace.EvGoUnblock, []frame{ frame{"runtime.selectgo", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 111}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoBlockSync, []frame{ frame{"sync.(*Mutex).Lock", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func7", 67}, }}, eventDesc{trace.EvGoUnblock, []frame{ frame{"sync.(*Mutex).Unlock", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 115}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoBlockSync, []frame{ frame{"sync.(*WaitGroup).Wait", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func8", 73}, }}, eventDesc{trace.EvGoUnblock, []frame{ frame{"sync.(*WaitGroup).Add", 0}, frame{"sync.(*WaitGroup).Done", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 116}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoBlockCond, []frame{ frame{"sync.(*Cond).Wait", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func9", 78}, }}, eventDesc{trace.EvGoUnblock, []frame{ frame{"sync.(*Cond).Signal", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 117}, frame{"testing.tRunner", 0}, }}, eventDesc{trace.EvGoSleep, []frame{ frame{"time.Sleep", 0}, frame{"runtime/trace_test.TestTraceSymbolize", 108}, frame{"testing.tRunner", 0}, }}, } // Stacks for the following events are OS-dependent due to OS-specific code in net package. if runtime.GOOS != "windows" && runtime.GOOS != "plan9" { want = append(want, []eventDesc{ eventDesc{trace.EvGoBlockNet, []frame{ frame{"net.(*netFD).accept", 0}, frame{"net.(*TCPListener).AcceptTCP", 0}, frame{"net.(*TCPListener).Accept", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func10", 86}, }}, eventDesc{trace.EvGoSysCall, []frame{ frame{"syscall.read", 0}, frame{"syscall.Read", 0}, frame{"os.(*File).read", 0}, frame{"os.(*File).Read", 0}, frame{"runtime/trace_test.TestTraceSymbolize.func11", 101}, }}, }...) } matched := make([]bool, len(want)) for _, ev := range events { wantLoop: for i, w := range want { if matched[i] || w.Type != ev.Type || len(w.Stk) != len(ev.Stk) { continue } for fi, f := range ev.Stk { wf := w.Stk[fi] if wf.Fn != f.Fn || wf.Line != 0 && wf.Line != f.Line { continue wantLoop } } matched[i] = true } } for i, m := range matched { if m { continue } w := want[i] t.Errorf("did not match event %v at %v:%v", trace.EventDescriptions[w.Type].Name, w.Stk[0].Fn, w.Stk[0].Line) t.Errorf("seen the following events of this type:") for _, ev := range events { if ev.Type != w.Type { continue } for _, f := range ev.Stk { t.Logf(" %v:%v", f.Fn, f.Line) } t.Logf("---") } } }
func TestBSSHasZeros(t *testing.T) { testenv.MustHaveExec(t) if runtime.GOOS != "windows" { t.Skip("skipping windows only test") } gccpath, err := exec.LookPath("gcc") if err != nil { t.Skip("skipping test: gcc is missing") } tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) srcpath := filepath.Join(tmpdir, "a.c") src := ` #include <stdio.h> int zero = 0; int main(void) { printf("%d\n", zero); return 0; } ` err = ioutil.WriteFile(srcpath, []byte(src), 0644) if err != nil { t.Fatal(err) } objpath := filepath.Join(tmpdir, "a.obj") cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("failed to build object file: %v - %v", err, string(out)) } f, err := Open(objpath) if err != nil { t.Fatal(err) } defer f.Close() var bss *Section for _, sect := range f.Sections { if sect.Name == ".bss" { bss = sect break } } if bss == nil { t.Fatal("could not find .bss section") } data, err := bss.Data() if err != nil { t.Fatal(err) } if len(data) == 0 { t.Fatalf("%s file .bss section cannot be empty", objpath) } for _, b := range data { if b != 0 { t.Fatalf(".bss section has non zero bytes: %v", data) } } }
// TestPassFD tests passing a file descriptor over a Unix socket. // // This test involved both a parent and child process. The parent // process is invoked as a normal test, with "go test", which then // runs the child process by running the current test binary with args // "-test.run=^TestPassFD$" and an environment variable used to signal // that the test should become the child process instead. func TestPassFD(t *testing.T) { switch runtime.GOOS { case "dragonfly": // TODO(jsing): Figure out why sendmsg is returning EINVAL. t.Skip("skipping test on dragonfly") case "solaris": // TODO(aram): Figure out why ReadMsgUnix is returning empty message. t.Skip("skipping test on solaris, see issue 7402") } testenv.MustHaveExec(t) if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { passFDChild() return } tempDir, err := ioutil.TempDir("", "TestPassFD") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0) if err != nil { t.Fatalf("Socketpair: %v", err) } defer syscall.Close(fds[0]) defer syscall.Close(fds[1]) writeFile := os.NewFile(uintptr(fds[0]), "child-writes") readFile := os.NewFile(uintptr(fds[1]), "parent-reads") defer writeFile.Close() defer readFile.Close() cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") cmd.ExtraFiles = []*os.File{writeFile} out, err := cmd.CombinedOutput() if len(out) > 0 || err != nil { t.Fatalf("child process: %q, %v", out, err) } c, err := net.FileConn(readFile) if err != nil { t.Fatalf("FileConn: %v", err) } defer c.Close() uc, ok := c.(*net.UnixConn) if !ok { t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) } buf := make([]byte, 32) // expect 1 byte oob := make([]byte, 32) // expect 24 bytes closeUnix := time.AfterFunc(5*time.Second, func() { t.Logf("timeout reading from unix socket") uc.Close() }) _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) closeUnix.Stop() scms, err := syscall.ParseSocketControlMessage(oob[:oobn]) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } if len(scms) != 1 { t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) } scm := scms[0] gotFds, err := syscall.ParseUnixRights(&scm) if err != nil { t.Fatalf("syscall.ParseUnixRights: %v", err) } if len(gotFds) != 1 { t.Fatalf("wanted 1 fd; got %#v", gotFds) } f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") defer f.Close() got, err := ioutil.ReadAll(f) want := "Hello from child process!\n" if string(got) != want { t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) } }