Skip to content

Commit 7e455b6

Browse files
meirfianlancetaylor
authored andcommitted
testing: ensure profiles are written upon -timeout panic
This addresses the case of a -timeout panic, but not the more general case of a signal arriving. See CL 48370 and CL 44352 for recent difficulties in that area. "-timeout" here means flag usage to distinguish from the default timeout termination which uses signals. Fixes #19394 Change-Id: I5452d5422c0c080e940cbcc8c6606049975268c6 Reviewed-on: https://go-review.googlesource.com/48491 Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 85deaf6 commit 7e455b6

File tree

2 files changed

+48
-10
lines changed

2 files changed

+48
-10
lines changed

src/cmd/go/go_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,19 @@ func (tg *testgoData) mustNotExist(path string) {
599599
}
600600
}
601601

602+
// mustHaveContent succeeds if filePath is a path to a file,
603+
// and that file is readable and not empty.
604+
func (tg *testgoData) mustHaveContent(filePath string) {
605+
tg.mustExist(filePath)
606+
f, err := os.Stat(filePath)
607+
if err != nil {
608+
tg.t.Fatal(err)
609+
}
610+
if f.Size() == 0 {
611+
tg.t.Fatalf("expected %s to have data, but is empty", filePath)
612+
}
613+
}
614+
602615
// wantExecutable fails with msg if path is not executable.
603616
func (tg *testgoData) wantExecutable(path, msg string) {
604617
tg.t.Helper()
@@ -3909,6 +3922,24 @@ func TestBenchTimeout(t *testing.T) {
39093922
tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
39103923
}
39113924

3925+
// Issue 19394
3926+
func TestWriteProfilesOnTimeout(t *testing.T) {
3927+
tg := testgo(t)
3928+
defer tg.cleanup()
3929+
tg.tempDir("profiling")
3930+
tg.tempFile("profiling/timeouttest_test.go", `package timeouttest_test
3931+
import "testing"
3932+
import "time"
3933+
func TestSleep(t *testing.T) { time.Sleep(time.Second) }`)
3934+
tg.cd(tg.path("profiling"))
3935+
tg.runFail(
3936+
"test",
3937+
"-cpuprofile", tg.path("profiling/cpu.pprof"), "-memprofile", tg.path("profiling/mem.pprof"),
3938+
"-timeout", "1ms")
3939+
tg.mustHaveContent(tg.path("profiling/cpu.pprof"))
3940+
tg.mustHaveContent(tg.path("profiling/mem.pprof"))
3941+
}
3942+
39123943
func TestLinkXImportPathEscape(t *testing.T) {
39133944
// golang.org/issue/16710
39143945
tg := testgo(t)

src/testing/testing.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,9 @@ type M struct {
876876
tests []InternalTest
877877
benchmarks []InternalBenchmark
878878
examples []InternalExample
879+
880+
timer *time.Timer
881+
afterOnce sync.Once
879882
}
880883

881884
// testDeps is an internal interface of functionality that is
@@ -918,22 +921,21 @@ func (m *M) Run() int {
918921
parseCpuList()
919922

920923
m.before()
921-
startAlarm()
924+
defer m.after()
925+
m.startAlarm()
922926
haveExamples = len(m.examples) > 0
923927
testRan, testOk := runTests(m.deps.MatchString, m.tests)
924928
exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
925-
stopAlarm()
929+
m.stopAlarm()
926930
if !testRan && !exampleRan && *matchBenchmarks == "" {
927931
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
928932
}
929933
if !testOk || !exampleOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
930934
fmt.Println("FAIL")
931-
m.after()
932935
return 1
933936
}
934937

935938
fmt.Println("PASS")
936-
m.after()
937939
return 0
938940
}
939941

@@ -1063,6 +1065,12 @@ func (m *M) before() {
10631065

10641066
// after runs after all testing.
10651067
func (m *M) after() {
1068+
m.afterOnce.Do(func() {
1069+
m.writeProfiles()
1070+
})
1071+
}
1072+
1073+
func (m *M) writeProfiles() {
10661074
if *cpuProfile != "" {
10671075
m.deps.StopCPUProfile() // flushes profile to disk
10681076
}
@@ -1139,22 +1147,21 @@ func toOutputDir(path string) string {
11391147
return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
11401148
}
11411149

1142-
var timer *time.Timer
1143-
11441150
// startAlarm starts an alarm if requested.
1145-
func startAlarm() {
1151+
func (m *M) startAlarm() {
11461152
if *timeout > 0 {
1147-
timer = time.AfterFunc(*timeout, func() {
1153+
m.timer = time.AfterFunc(*timeout, func() {
1154+
m.after()
11481155
debug.SetTraceback("all")
11491156
panic(fmt.Sprintf("test timed out after %v", *timeout))
11501157
})
11511158
}
11521159
}
11531160

11541161
// stopAlarm turns off the alarm.
1155-
func stopAlarm() {
1162+
func (m *M) stopAlarm() {
11561163
if *timeout > 0 {
1157-
timer.Stop()
1164+
m.timer.Stop()
11581165
}
11591166
}
11601167

0 commit comments

Comments
 (0)