// When a test is skipped or fails, runtime.Goexit() is called which destroys the callstack.
// This means the name of the test case is lost, so we need to grab a copy of pc before.
func Report(t testing.TB) {
	// If the goroutine panics, Fatal()s, or Skip()s, the function name is at the 3rd callstack
	// layer.  On success, its at 1st.  Since it's hard to check which happened, just try both.
	pcs := make([]uintptr, 10)
	total := runtime.Callers(1, pcs)
	var name string
	for _, pc := range pcs[:total] {
		fn := runtime.FuncForPC(pc)
		fullName := fn.Name()
		if strings.HasPrefix(path.Ext(fullName), ".Test") {
			// Skip the leading .
			name = string([]byte(path.Ext(fullName))[1:])
			break
		}
	}
	if name == "" {
		return
	}

	allCaseInfos.lock.Lock()
	defer allCaseInfos.lock.Unlock()
	allCaseInfos.Cases = append(allCaseInfos.Cases, &caseInfo{
		Name:    name,
		Passed:  !t.Failed() && !t.Skipped(),
		Skipped: t.Skipped(),
		Fatal:   t.Failed() && !strings.HasPrefix(name, "TestSoon"),
	})
}
Example #2
0
// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := interestingGoroutines()
	return func() {
		if t.Failed() {
			return
		}
		if r := recover(); r != nil {
			panic(r)
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for id, stack := range interestingGoroutines() {
				if _, ok := orig[id]; !ok {
					leaked = append(leaked, stack)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			sort.Strings(leaked)
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
Example #3
0
// WithTestServer creates a new TestServer, runs the passed function, and then
// verifies that no resources were leaked.
func WithTestServer(t testing.TB, chanOpts *ChannelOpts, f func(*TestServer)) {
	chanOpts = chanOpts.Copy()
	runCount := chanOpts.RunCount
	if runCount < 1 {
		runCount = 1
	}

	for i := 0; i < runCount; i++ {
		if t.Failed() {
			return
		}

		// Run without the relay, unless OnlyRelay was set.
		if !chanOpts.OnlyRelay {
			noRelayOpts := chanOpts.Copy()
			noRelayOpts.DisableRelay = true
			withServer(t, noRelayOpts, f)
		}

		// Run with the relay, unless the user has disabled it.
		if !chanOpts.DisableRelay {
			withServer(t, chanOpts.Copy(), f)
		}
	}
}
Example #4
0
// AfterTest snapshots the currently-running goroutines and returns a
// function to be run at the end of tests to see whether any
// goroutines leaked.
func AfterTest(t testing.TB) func() {
	orig := map[string]bool{}
	for _, g := range interestingGoroutines() {
		orig[g] = true
	}
	return func() {
		if t.Failed() {
			return
		}
		// Loop, waiting for goroutines to shut down.
		// Wait up to 5 seconds, but finish as quickly as possible.
		deadline := timeutil.Now().Add(5 * time.Second)
		for {
			var leaked []string
			for _, g := range interestingGoroutines() {
				if !orig[g] {
					leaked = append(leaked, g)
				}
			}
			if len(leaked) == 0 {
				return
			}
			if timeutil.Now().Before(deadline) {
				time.Sleep(50 * time.Millisecond)
				continue
			}
			for _, g := range leaked {
				t.Errorf("Leaked goroutine: %v", g)
			}
			return
		}
	}
}
Example #5
0
// AfterTest should be called (generally with "defer leaktest.AfterTest(t)")
// from each test which uses goroutines. This waits for all goroutines
// on a blacklist to terminate and provides more precise error reporting
// than TestMainWithLeakCheck alone.
// If a previous test's check has already failed, this is a noop (to avoid
// failing unrelated tests).
func AfterTest(t testing.TB) {
	if atomic.LoadInt32(&hasFailed) > 0 {
		t.Log("prior leak detected, leaktest disabled")
		return
	}
	if r := recover(); r != nil {
		// Don't bother with leaktest if we're recovering from a panic.
		panic(r)
	}
	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
	if testing.Short() || t.Failed() {
		// If a test has failed, chances are it hasn't shut down cleanly, so
		// stop checking for leaks in this run altogether.
		atomic.StoreInt32(&hasFailed, 1)
		return
	}
	if r := recover(); r != nil {
		panic(r)
	}
	var bad string
	badSubstring := map[string]string{
		").readLoop(":                                  "a Transport",
		").writeLoop(":                                 "a Transport",
		"created by net/http/httptest.(*Server).Start": "an httptest.Server",
		"timeoutHandler":                               "a TimeoutHandler",
		"net.(*netFD).connect(":                        "a timing out dial",
		").noteClientGone(":                            "a closenotifier sender",
		"created by net/rpc.NewClientWithCodec":        "an rpc client",
		"created by net/rpc.(*Server.ServeCodec)":      "an rpc server connection",
		"(*Store).Start":                               "a store",
		"(*Range).Send":                                "a range command",
	}
	var stacks string
	for i := 0; i < 8; i++ {
		bad = ""
		stacks = strings.Join(interestingGoroutines(), "\n\n")
		for substr, what := range badSubstring {
			if strings.Contains(stacks, substr) {
				bad = what
			}
		}
		if bad == "" {
			return
		}
		// Bad stuff found, but goroutines might just still be
		// shutting down, so give it some time.
		time.Sleep(10 * time.Millisecond)
	}
	atomic.StoreInt32(&hasFailed, 1)
	t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
}
Example #6
0
// AfterTest should be called (generally with "defer leaktest.AfterTest(t)")
// from each test which uses goroutines. This waits for all goroutines
// on a blacklist to terminate and provides more precise error reporting
// than TestMainWithLeakCheck alone.
func AfterTest(t testing.TB) {
	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
	if testing.Short() || t.Failed() {
		return
	}
	if r := recover(); r != nil {
		panic(r)
	}
	var bad string
	badSubstring := map[string]string{
		").readLoop(":                                  "a Transport",
		").writeLoop(":                                 "a Transport",
		"created by net/http/httptest.(*Server).Start": "an httptest.Server",
		"timeoutHandler":                               "a TimeoutHandler",
		"net.(*netFD).connect(":                        "a timing out dial",
		").noteClientGone(":                            "a closenotifier sender",
		"created by net/rpc.NewClientWithCodec":        "an rpc client",
		"created by net/rpc.(*Server.ServeCodec)":      "an rpc server connection",
		"(*Store).Start":                               "a store",
		"(*Range).AddCmd":                              "a range command",
	}
	var stacks string
	for i := 0; i < 8; i++ {
		bad = ""
		stacks = strings.Join(interestingGoroutines(), "\n\n")
		for substr, what := range badSubstring {
			if strings.Contains(stacks, substr) {
				bad = what
			}
		}
		if bad == "" {
			return
		}
		// Bad stuff found, but goroutines might just still be
		// shutting down, so give it some time.
		time.Sleep(10 * time.Millisecond)
	}
	t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
}
Example #7
0
func (m *MockStats) assertCallEqual(t testing.TB, expected *MockCallStats, actual *MockCallStats) {
	// Revisit these assertions if we ever need to assert zero or many calls to
	// End.
	require.Equal(t, 1, expected.ended, "Expected call must assert exactly one call to End.")
	require.False(
		t,
		expected.succeeded <= 0 && len(expected.failedMsgs) == 0,
		"Expectation must indicate whether RPC should succeed or fail.",
	)

	assert.Equal(t, expected.succeeded, actual.succeeded, "Unexpected number of successes.")
	assert.Equal(t, expected.failedMsgs, actual.failedMsgs, "Unexpected reasons for RPC failure.")
	assert.Equal(t, expected.ended, actual.ended, "Unexpected number of calls to End.")

	if expected.verifyPeer {
		assert.Equal(t, expected.peer, actual.peer, "Unexpected peer used for the call")
	}

	if t.Failed() {
		// The default testify output is often insufficient.
		t.Logf("\nExpected relayed stats were:\n\t%+v\nActual relayed stats were:\n\t%+v\n", expected, actual)
	}
}
Example #8
0
// Destroy collects the logs and tears down the cluster.
func (f *Farmer) Destroy(t testing.TB) error {
	f.CollectLogs()
	if f.LogDir != "" {
		defer f.logf("logs copied to %s\n", f.AbsLogDir())
	}

	wd, err := os.Getwd()
	if err != nil {
		wd = "acceptance"
	}
	baseDir := filepath.Join(wd, f.Cwd)
	if (t.Failed() && f.KeepCluster == KeepClusterFailed) ||
		f.KeepCluster == KeepClusterAlways {

		t.Logf("not destroying; run:\n(cd %s && terraform destroy -force -state %s && rm %s)",
			baseDir, f.StateFile, f.StateFile)
		return nil
	}

	if err := f.Resize(0); err != nil {
		return err
	}
	return os.Remove(filepath.Join(baseDir, f.StateFile))
}