aboutsummaryrefslogtreecommitdiff
path: root/src/internal/trace/reader_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/trace/reader_test.go')
-rw-r--r--src/internal/trace/reader_test.go172
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()
+}