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