1
2
3
4
5 package trace_test
6
7 import (
8 "bytes"
9 "flag"
10 "fmt"
11 "io"
12 "os"
13 "path/filepath"
14 "strings"
15 "testing"
16
17 "internal/trace"
18 "internal/trace/raw"
19 "internal/trace/testtrace"
20 "internal/trace/version"
21 )
22
23 var (
24 logEvents = flag.Bool("log-events", false, "whether to log high-level events; significantly slows down tests")
25 dumpTraces = flag.Bool("dump-traces", false, "dump traces even on success")
26 )
27
28 func TestReaderGolden(t *testing.T) {
29 matches, err := filepath.Glob("./testdata/tests/*.test")
30 if err != nil {
31 t.Fatalf("failed to glob for tests: %v", err)
32 }
33 for _, testPath := range matches {
34 testPath := testPath
35 testName, err := filepath.Rel("./testdata", testPath)
36 if err != nil {
37 t.Fatalf("failed to relativize testdata path: %v", err)
38 }
39 t.Run(testName, func(t *testing.T) {
40 tr, exp, err := testtrace.ParseFile(testPath)
41 if err != nil {
42 t.Fatalf("failed to parse test file at %s: %v", testPath, err)
43 }
44 testReader(t, tr, exp)
45 })
46 }
47 }
48
49 func FuzzReader(f *testing.F) {
50
51
52
53 const testGetters = false
54
55 f.Fuzz(func(t *testing.T, b []byte) {
56 r, err := trace.NewReader(bytes.NewReader(b))
57 if err != nil {
58 return
59 }
60 for {
61 ev, err := r.ReadEvent()
62 if err != nil {
63 break
64 }
65
66 if !testGetters {
67 continue
68 }
69
70 switch ev.Kind() {
71 case trace.EventLabel:
72 ev.Label()
73 case trace.EventLog:
74 ev.Log()
75 case trace.EventMetric:
76 ev.Metric()
77 case trace.EventRangeActive, trace.EventRangeBegin:
78 ev.Range()
79 case trace.EventRangeEnd:
80 ev.Range()
81 ev.RangeAttributes()
82 case trace.EventStateTransition:
83 ev.StateTransition()
84 case trace.EventRegionBegin, trace.EventRegionEnd:
85 ev.Region()
86 case trace.EventTaskBegin, trace.EventTaskEnd:
87 ev.Task()
88 case trace.EventSync:
89 case trace.EventStackSample:
90 case trace.EventBad:
91 }
92 }
93 })
94 }
95
96 func testReader(t *testing.T, tr io.Reader, exp *testtrace.Expectation) {
97 r, err := trace.NewReader(tr)
98 if err != nil {
99 if err := exp.Check(err); err != nil {
100 t.Error(err)
101 }
102 return
103 }
104 v := testtrace.NewValidator()
105 for {
106 ev, err := r.ReadEvent()
107 if err == io.EOF {
108 break
109 }
110 if err != nil {
111 if err := exp.Check(err); err != nil {
112 t.Error(err)
113 }
114 return
115 }
116 if *logEvents {
117 t.Log(ev.String())
118 }
119 if err := v.Event(ev); err != nil {
120 t.Error(err)
121 }
122 }
123 if err := exp.Check(nil); err != nil {
124 t.Error(err)
125 }
126 }
127
128 func dumpTraceToText(t *testing.T, b []byte) string {
129 t.Helper()
130
131 br, err := raw.NewReader(bytes.NewReader(b))
132 if err != nil {
133 t.Fatalf("dumping trace: %v", err)
134 }
135 var sb strings.Builder
136 tw, err := raw.NewTextWriter(&sb, version.Current)
137 if err != nil {
138 t.Fatalf("dumping trace: %v", err)
139 }
140 for {
141 ev, err := br.ReadEvent()
142 if err == io.EOF {
143 break
144 }
145 if err != nil {
146 t.Fatalf("dumping trace: %v", err)
147 }
148 if err := tw.WriteEvent(ev); err != nil {
149 t.Fatalf("dumping trace: %v", err)
150 }
151 }
152 return sb.String()
153 }
154
155 func dumpTraceToFile(t *testing.T, testName string, stress bool, b []byte) string {
156 t.Helper()
157
158 desc := "default"
159 if stress {
160 desc = "stress"
161 }
162 name := fmt.Sprintf("%s.%s.trace.", testName, desc)
163 f, err := os.CreateTemp("", name)
164 if err != nil {
165 t.Fatalf("creating temp file: %v", err)
166 }
167 defer f.Close()
168 if _, err := io.Copy(f, bytes.NewReader(b)); err != nil {
169 t.Fatalf("writing trace dump to %q: %v", f.Name(), err)
170 }
171 return f.Name()
172 }
173
View as plain text