diff options
Diffstat (limited to 'src/internal/trace/reader_test.go')
| -rw-r--r-- | src/internal/trace/reader_test.go | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/internal/trace/reader_test.go b/src/internal/trace/reader_test.go new file mode 100644 index 0000000000..37c21da667 --- /dev/null +++ b/src/internal/trace/reader_test.go @@ -0,0 +1,172 @@ +// 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" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "testing" + + "internal/trace" + "internal/trace/raw" + "internal/trace/testtrace" + "internal/trace/version" +) + +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 { + testPath := testPath + 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, exp, err := testtrace.ParseFile(testPath) + if err != nil { + t.Fatalf("failed to parse test file at %s: %v", testPath, err) + } + testReader(t, tr, 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, exp *testtrace.Expectation) { + r, err := trace.NewReader(tr) + if err != nil { + if err := exp.Check(err); err != nil { + t.Error(err) + } + return + } + v := testtrace.NewValidator() + for { + ev, err := r.ReadEvent() + if err == io.EOF { + break + } + 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 dumpTraceToText(t *testing.T, b []byte) string { + t.Helper() + + br, err := raw.NewReader(bytes.NewReader(b)) + if err != nil { + t.Fatalf("dumping trace: %v", err) + } + var sb strings.Builder + tw, err := raw.NewTextWriter(&sb, version.Current) + if err != nil { + t.Fatalf("dumping trace: %v", err) + } + for { + ev, err := br.ReadEvent() + if err == io.EOF { + break + } + if err != nil { + t.Fatalf("dumping trace: %v", err) + } + if err := tw.WriteEvent(ev); err != nil { + t.Fatalf("dumping trace: %v", err) + } + } + return sb.String() +} + +func dumpTraceToFile(t *testing.T, testName string, stress bool, b []byte) string { + t.Helper() + + desc := "default" + if stress { + desc = "stress" + } + name := fmt.Sprintf("%s.%s.trace.", testName, desc) + f, err := os.CreateTemp("", name) + if err != nil { + t.Fatalf("creating temp file: %v", err) + } + defer f.Close() + if _, err := io.Copy(f, bytes.NewReader(b)); err != nil { + t.Fatalf("writing trace dump to %q: %v", f.Name(), err) + } + return f.Name() +} |
