@@ -15,19 +15,24 @@ import (
1515
1616var _ trace.SpanExporter = & Collector {}
1717
18+ // Collector can be used as a trace batcher to provide traces to, we collect
19+ // individual spans and then extract useful data out of them for test assertions
1820type Collector struct {
1921 Spans tracetest.SpanStubs
2022}
2123
24+ // ExportSpans receives the ReadOnlySpans from the batch provider
2225func (c * Collector ) ExportSpans (ctx context.Context , spans []trace.ReadOnlySpan ) error {
2326 c .Spans = tracetest .SpanStubsFromReadOnlySpans (spans )
2427 return nil
2528}
2629
30+ // Shutdown is a noop, we don't need to do anything fancy
2731func (c * Collector ) Shutdown (ctx context.Context ) error {
2832 return nil
2933}
3034
35+ // FindSpans returns a list of spans by their name
3136func (c Collector ) FindSpans (name string ) tracetest.SpanStubs {
3237 var found = tracetest.SpanStubs {}
3338 for _ , s := range c .Spans {
@@ -38,8 +43,9 @@ func (c Collector) FindSpans(name string) tracetest.SpanStubs {
3843 return found
3944}
4045
41- // TracesToString returns an array of traces represented as strings with each
42- // span in the trace identified by name separated by a '->'
46+ // TracesToString returns an array of all traces represented as strings with each
47+ // span in the trace identified by name and its number (within the parent span)
48+ // in parens, separated by a '->'. e.g. `"foo(0)->bar(0)","foo(0)->bar(1)"`
4349func (c Collector ) TracesToStrings () []string {
4450 return c .tracesToString ("" , c .FindParentSpans (), "" , func (_ tracetest.SpanStub ) {})
4551}
@@ -67,14 +73,23 @@ func (c Collector) tracesToString(trace string, spans tracetest.SpanStubs, match
6773 return traces
6874}
6975
70- func (c Collector ) FindSpanByTraceString (trace string ) tracetest.SpanStubs {
71- var found = tracetest.SpanStubs {}
76+ // FindSpanByTraceString is similar to FindSpans but returns a single span
77+ // identified by its trace string as described in TracesToStrings. Note that
78+ // this string can also be a partial of a complete trace, e.g. just `"foo(0)"`
79+ // without any children to fetch the parent span.
80+ func (c Collector ) FindSpanByTraceString (trace string ) tracetest.SpanStub {
81+ var found tracetest.SpanStub
7282 c .tracesToString ("" , c .FindParentSpans (), trace , func (span tracetest.SpanStub ) {
73- found = append (found , span )
83+ if found .Name != "" {
84+ panic ("found more than one span with the same trace string" )
85+ }
86+ found = span
7487 })
7588 return found
7689}
7790
91+ // FindParentSpans finds spans that have no parents, they are at the top any
92+ // stack.
7893func (c Collector ) FindParentSpans () tracetest.SpanStubs {
7994 var found = tracetest.SpanStubs {}
8095 for _ , s := range c .Spans {
@@ -85,6 +100,7 @@ func (c Collector) FindParentSpans() tracetest.SpanStubs {
85100 return found
86101}
87102
103+ // FindSpansWithParent finds spans that are children of the provided span.
88104func (c Collector ) FindSpansWithParent (stub tracetest.SpanStub ) tracetest.SpanStubs {
89105 var found = tracetest.SpanStubs {}
90106 for _ , s := range c .Spans {
@@ -95,22 +111,29 @@ func (c Collector) FindSpansWithParent(stub tracetest.SpanStub) tracetest.SpanSt
95111 return found
96112}
97113
114+ // SingleExceptionEvent is a test helper that asserts that a span, identified by a
115+ // trace string (see TracesToStrings) contains a single exception, identified by
116+ // the type (regexp) and message (regexp). If errorCode is true, then we also assert
117+ // that the span has an error status code, with the same message (regexp)
98118func (c Collector ) SingleExceptionEvent (t * testing.T , trace string , typeRe string , messageRe string , errorCode bool ) {
99119 t .Helper ()
100120
101121 // has ContextCancelError exception recorded in the right place
102122 et := c .FindSpanByTraceString (trace )
103- require .Len (t , et , 1 , "expected one span with trace %v" , trace )
104- require .Len (t , et [0 ].Events , 1 , "expected one event in span %v" , trace )
105- ex := EventAsException (t , EventInTraceSpan (t , et [0 ], "exception" ))
123+ require .Len (t , et .Events , 1 , "expected one event in span %v" , trace )
124+ ex := EventAsException (t , EventInTraceSpan (t , et , "exception" ))
106125 require .Regexp (t , typeRe , ex .Type )
107126 require .Regexp (t , messageRe , ex .Message )
108127 if errorCode {
109- require .Equal (t , codes .Error , et [ 0 ] .Status .Code )
110- require .Regexp (t , messageRe , et [ 0 ] .Status .Description )
128+ require .Equal (t , codes .Error , et .Status .Code )
129+ require .Regexp (t , messageRe , et .Status .Description )
111130 }
112131}
113132
133+ // SetupTracing returns a test helper that can will collect all spans within
134+ // a Collector. The returned helper function should be called at the point in
135+ // a test where the spans are ready to be analyzed. Any spans not properly
136+ // completed at that point won't be represented in the Collector.
114137func SetupTracing () func (t * testing.T ) * Collector {
115138 collector := & Collector {}
116139 tp := trace .NewTracerProvider (trace .WithBatcher (collector ))
@@ -126,6 +149,9 @@ func SetupTracing() func(t *testing.T) *Collector {
126149 return collect
127150}
128151
152+ // AttributeValueInTraceSpan is a test helper that asserts that at a span
153+ // contains an attribute with the name provided, and returns the value of
154+ // that attribute for further inspection.
129155func AttributeValueInTraceSpan (t * testing.T , stub tracetest.SpanStub , attributeName string ) attribute.Value {
130156 t .Helper ()
131157
@@ -138,6 +164,9 @@ func AttributeValueInTraceSpan(t *testing.T, stub tracetest.SpanStub, attributeN
138164 return attribute.Value {}
139165}
140166
167+ // EventInTraceSpan is a test helper that asserts that at a span
168+ // contains an event with the name provided, and returns the value of
169+ // that event for further inspection.
141170func EventInTraceSpan (t * testing.T , stub tracetest.SpanStub , eventName string ) trace.Event {
142171 t .Helper ()
143172
@@ -150,11 +179,14 @@ func EventInTraceSpan(t *testing.T, stub tracetest.SpanStub, eventName string) t
150179 return trace.Event {}
151180}
152181
182+ // ExceptionEvent is a simplistic string form representation of an event
153183type ExceptionEvent struct {
154184 Type string
155185 Message string
156186}
157187
188+ // EventAsException is a test helper that converts a trace event to an ExceptionEvent
189+ // for easier inspection.
158190func EventAsException (t * testing.T , evt trace.Event ) ExceptionEvent {
159191 t .Helper ()
160192
0 commit comments