mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
We currently dump traces for internal/trace tests on validation failure, but not for the runtime/trace package. This change moves some of the machinery to do this into the testtrace package and then uses it from the runtime/trace package. For #75665. Change-Id: Ibe2d4f3945c1fd21dcbccf56820865f8d2ea41f9 Reviewed-on: https://go-review.googlesource.com/c/go/+/710755 Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
200 lines
5.2 KiB
Go
200 lines
5.2 KiB
Go
// Copyright 2023 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package trace_test
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"io"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"internal/trace"
|
|
"internal/trace/testtrace"
|
|
)
|
|
|
|
var (
|
|
logEvents = flag.Bool("log-events", false, "whether to log high-level events; significantly slows down tests")
|
|
dumpTraces = flag.Bool("dump-traces", false, "dump traces even on success")
|
|
)
|
|
|
|
func TestReaderGolden(t *testing.T) {
|
|
matches, err := filepath.Glob("./testdata/tests/*.test")
|
|
if err != nil {
|
|
t.Fatalf("failed to glob for tests: %v", err)
|
|
}
|
|
for _, testPath := range matches {
|
|
testName, err := filepath.Rel("./testdata", testPath)
|
|
if err != nil {
|
|
t.Fatalf("failed to relativize testdata path: %v", err)
|
|
}
|
|
t.Run(testName, func(t *testing.T) {
|
|
tr, ver, exp, err := testtrace.ParseFile(testPath)
|
|
if err != nil {
|
|
t.Fatalf("failed to parse test file at %s: %v", testPath, err)
|
|
}
|
|
v := testtrace.NewValidator()
|
|
v.GoVersion = ver
|
|
testReader(t, tr, v, exp)
|
|
})
|
|
}
|
|
}
|
|
|
|
func FuzzReader(f *testing.F) {
|
|
// Currently disabled because the parser doesn't do much validation and most
|
|
// getters can be made to panic. Turn this on once the parser is meant to
|
|
// reject invalid traces.
|
|
const testGetters = false
|
|
|
|
f.Fuzz(func(t *testing.T, b []byte) {
|
|
r, err := trace.NewReader(bytes.NewReader(b))
|
|
if err != nil {
|
|
return
|
|
}
|
|
for {
|
|
ev, err := r.ReadEvent()
|
|
if err != nil {
|
|
break
|
|
}
|
|
|
|
if !testGetters {
|
|
continue
|
|
}
|
|
// Make sure getters don't do anything that panics
|
|
switch ev.Kind() {
|
|
case trace.EventLabel:
|
|
ev.Label()
|
|
case trace.EventLog:
|
|
ev.Log()
|
|
case trace.EventMetric:
|
|
ev.Metric()
|
|
case trace.EventRangeActive, trace.EventRangeBegin:
|
|
ev.Range()
|
|
case trace.EventRangeEnd:
|
|
ev.Range()
|
|
ev.RangeAttributes()
|
|
case trace.EventStateTransition:
|
|
ev.StateTransition()
|
|
case trace.EventRegionBegin, trace.EventRegionEnd:
|
|
ev.Region()
|
|
case trace.EventTaskBegin, trace.EventTaskEnd:
|
|
ev.Task()
|
|
case trace.EventSync:
|
|
case trace.EventStackSample:
|
|
case trace.EventBad:
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func testReader(t *testing.T, tr io.Reader, v *testtrace.Validator, exp *testtrace.Expectation) {
|
|
r, err := trace.NewReader(tr)
|
|
if err != nil {
|
|
if err := exp.Check(err); err != nil {
|
|
t.Error(err)
|
|
}
|
|
return
|
|
}
|
|
for {
|
|
ev, err := r.ReadEvent()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
v.GoVersion = r.GoVersion()
|
|
if runtime.GOOS == "windows" || runtime.GOARCH == "wasm" {
|
|
v.SkipClockSnapshotChecks()
|
|
}
|
|
if err != nil {
|
|
if err := exp.Check(err); err != nil {
|
|
t.Error(err)
|
|
}
|
|
return
|
|
}
|
|
if *logEvents {
|
|
t.Log(ev.String())
|
|
}
|
|
if err := v.Event(ev); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
if err := exp.Check(nil); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestTraceGenSync(t *testing.T) {
|
|
type sync struct {
|
|
Time trace.Time
|
|
ClockSnapshot *trace.ClockSnapshot
|
|
}
|
|
runTest := func(testName string, wantSyncs []sync) {
|
|
t.Run(testName, func(t *testing.T) {
|
|
testPath := "testdata/tests/" + testName
|
|
r, _, _, err := testtrace.ParseFile(testPath)
|
|
if err != nil {
|
|
t.Fatalf("malformed test %s: bad trace file: %v", testPath, err)
|
|
}
|
|
tr, err := trace.NewReader(r)
|
|
if err != nil {
|
|
t.Fatalf("malformed test %s: bad trace file: %v", testPath, err)
|
|
}
|
|
var syncEvents []trace.Event
|
|
for {
|
|
ev, err := tr.ReadEvent()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("malformed test %s: bad trace file: %v", testPath, err)
|
|
}
|
|
if ev.Kind() == trace.EventSync {
|
|
syncEvents = append(syncEvents, ev)
|
|
}
|
|
}
|
|
|
|
if got, want := len(syncEvents), len(wantSyncs); got != want {
|
|
t.Errorf("got %d sync events, want %d", got, want)
|
|
}
|
|
|
|
for i, want := range wantSyncs {
|
|
got := syncEvents[i]
|
|
gotSync := syncEvents[i].Sync()
|
|
if got.Time() != want.Time {
|
|
t.Errorf("sync=%d got time %d, want %d", i+1, got.Time(), want.Time)
|
|
}
|
|
if gotSync.ClockSnapshot == nil && want.ClockSnapshot == nil {
|
|
continue
|
|
}
|
|
if gotSync.ClockSnapshot.Trace != want.ClockSnapshot.Trace {
|
|
t.Errorf("sync=%d got trace time %d, want %d", i+1, gotSync.ClockSnapshot.Trace, want.ClockSnapshot.Trace)
|
|
}
|
|
if !gotSync.ClockSnapshot.Wall.Equal(want.ClockSnapshot.Wall) {
|
|
t.Errorf("sync=%d got wall time %s, want %s", i+1, gotSync.ClockSnapshot.Wall, want.ClockSnapshot.Wall)
|
|
}
|
|
if gotSync.ClockSnapshot.Mono != want.ClockSnapshot.Mono {
|
|
t.Errorf("sync=%d got mono time %d, want %d", i+1, gotSync.ClockSnapshot.Mono, want.ClockSnapshot.Mono)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
runTest("go123-sync.test", []sync{
|
|
{10, nil},
|
|
{40, nil},
|
|
// The EvFrequency batch for generation 3 is emitted at trace.Time(80),
|
|
// but 60 is the minTs of the generation, see b30 in the go generator.
|
|
{60, nil},
|
|
{63, nil},
|
|
})
|
|
|
|
runTest("go125-sync.test", []sync{
|
|
{9, &trace.ClockSnapshot{Trace: 10, Mono: 99, Wall: time.Date(2025, 2, 28, 15, 4, 9, 123, time.UTC)}},
|
|
{38, &trace.ClockSnapshot{Trace: 40, Mono: 199, Wall: time.Date(2025, 2, 28, 15, 4, 10, 123, time.UTC)}},
|
|
{58, &trace.ClockSnapshot{Trace: 60, Mono: 299, Wall: time.Date(2025, 2, 28, 15, 4, 11, 123, time.UTC)}},
|
|
{83, nil},
|
|
})
|
|
}
|