internal/gocore: add sanity checking to TestVersions This strengthens the guarantees about what viewcore(1) supports. Specifically, we have binaries built with PIE which appear to load properly (`Core(...)` doesn't return an error, but return (e.g.) zero goroutines. Tests should fail if this happens, there's always at least one goroutine. The sanity checking functions are defined separately so we can re-use them in a test extension patch where we supply several types of binaries built with non-standard flags (and without the `go build` tool). Change-Id: I492724a7a9d371ce694829368c7dfb73066bb821 Reviewed-on: https://go-review.googlesource.com/c/debug/+/618976 Reviewed-by: Nicolas Hillegeer <aktau@google.com> Auto-Submit: Nicolas Hillegeer <aktau@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com> Run-TryBot: Nicolas Hillegeer <aktau@google.com>
diff --git a/internal/gocore/dominator_test.go b/internal/gocore/dominator_test.go index 79404f3..699169e 100644 --- a/internal/gocore/dominator_test.go +++ b/internal/gocore/dominator_test.go
@@ -15,7 +15,7 @@ func TestLT(t *testing.T) { p := loadExample(t) lt := runLT(p) - sanityCheck(t, lt) + checkDominator(t, lt) if false { lt.dot(os.Stdout) } @@ -29,7 +29,7 @@ } } -func sanityCheck(t *testing.T, d ltDom) bool { +func checkDominator(t *testing.T, d ltDom) bool { t.Helper() // Build pointer-y graph. pRoot := sanityVertex{}
diff --git a/internal/gocore/gocore_test.go b/internal/gocore/gocore_test.go index 90889ef..91f69c1 100644 --- a/internal/gocore/gocore_test.go +++ b/internal/gocore/gocore_test.go
@@ -390,6 +390,33 @@ } } +// getStat returns the first (depth first) stat in the hierarchy which matches +// name, nil otherwise. +func getStat(stat *Stats, name string) *Stats { + if stat.Name == name { + return stat + } + for _, child := range stat.Children { + if found := getStat(child, name); found != nil { + return found + } + } + return nil +} + +func checkProcess(t *testing.T, p *Process) { + t.Helper() + if gs := p.Goroutines(); len(gs) == 0 { + t.Error("len(p.Goroutines()) == 0, want >0") + } + + const heapName = "heap" + heapStat := getStat(p.Stats(), heapName) + if heapStat == nil || heapStat.Size == 0 { + t.Errorf("stat[%q].Size == 0, want >0", heapName) + } +} + func TestVersions(t *testing.T) { versions := []string{ "1.10", @@ -405,12 +432,27 @@ } for _, ver := range versions { t.Run(ver, func(t *testing.T) { - loadExampleVersion(t, ver) + p := loadExampleVersion(t, ver) + checkProcess(t, p) + + lt := runLT(p) + if !checkDominator(t, lt) { + t.Errorf("sanityCheckDominator(...) = false, want true") + } }) } t.Run("goroot", func(t *testing.T) { - loadExampleGenerated(t) + p := loadExampleGenerated(t) + checkProcess(t, p) + + // TODO(aktau): Move sanityCheckDominator into sanityCheckProcess once this + // passes for loadExampleGenerated. + t.Skip(`skipping dominator check due to "panic: can't find type runtime.itab"`) + lt := runLT(p) + if !checkDominator(t, lt) { + t.Errorf("sanityCheckDominator(...) = false, want true") + } }) }