1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package tracetransform
16
17 import (
18 "testing"
19 "time"
20
21 "github.com/google/go-cmp/cmp"
22 "github.com/stretchr/testify/assert"
23 "github.com/stretchr/testify/require"
24 "google.golang.org/protobuf/proto"
25
26 "go.opentelemetry.io/otel/attribute"
27 "go.opentelemetry.io/otel/codes"
28 "go.opentelemetry.io/otel/sdk/instrumentation"
29 "go.opentelemetry.io/otel/sdk/resource"
30 tracesdk "go.opentelemetry.io/otel/sdk/trace"
31 "go.opentelemetry.io/otel/sdk/trace/tracetest"
32 semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
33 "go.opentelemetry.io/otel/trace"
34 tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
35 )
36
37 func TestSpanKind(t *testing.T) {
38 for _, test := range []struct {
39 kind trace.SpanKind
40 expected tracepb.Span_SpanKind
41 }{
42 {
43 trace.SpanKindInternal,
44 tracepb.Span_SPAN_KIND_INTERNAL,
45 },
46 {
47 trace.SpanKindClient,
48 tracepb.Span_SPAN_KIND_CLIENT,
49 },
50 {
51 trace.SpanKindServer,
52 tracepb.Span_SPAN_KIND_SERVER,
53 },
54 {
55 trace.SpanKindProducer,
56 tracepb.Span_SPAN_KIND_PRODUCER,
57 },
58 {
59 trace.SpanKindConsumer,
60 tracepb.Span_SPAN_KIND_CONSUMER,
61 },
62 {
63 trace.SpanKind(-1),
64 tracepb.Span_SPAN_KIND_UNSPECIFIED,
65 },
66 } {
67 assert.Equal(t, test.expected, spanKind(test.kind))
68 }
69 }
70
71 func TestNilSpanEvent(t *testing.T) {
72 assert.Nil(t, spanEvents(nil))
73 }
74
75 func TestEmptySpanEvent(t *testing.T) {
76 assert.Nil(t, spanEvents([]tracesdk.Event{}))
77 }
78
79 func TestSpanEvent(t *testing.T) {
80 attrs := []attribute.KeyValue{attribute.Int("one", 1), attribute.Int("two", 2)}
81 eventTime := time.Date(2020, 5, 20, 0, 0, 0, 0, time.UTC)
82 got := spanEvents([]tracesdk.Event{
83 {
84 Name: "test 1",
85 Attributes: []attribute.KeyValue{},
86 Time: eventTime,
87 },
88 {
89 Name: "test 2",
90 Attributes: attrs,
91 Time: eventTime,
92 DroppedAttributeCount: 2,
93 },
94 })
95 if !assert.Len(t, got, 2) {
96 return
97 }
98 eventTimestamp := uint64(1589932800 * 1e9)
99 assert.Equal(t, &tracepb.Span_Event{Name: "test 1", Attributes: nil, TimeUnixNano: eventTimestamp}, got[0])
100
101 assert.Equal(t, &tracepb.Span_Event{Name: "test 2", Attributes: KeyValues(attrs), TimeUnixNano: eventTimestamp, DroppedAttributesCount: 2}, got[1])
102 }
103
104 func TestNilLinks(t *testing.T) {
105 assert.Nil(t, links(nil))
106 }
107
108 func TestEmptyLinks(t *testing.T) {
109 assert.Nil(t, links([]tracesdk.Link{}))
110 }
111
112 func TestLinks(t *testing.T) {
113 attrs := []attribute.KeyValue{attribute.Int("one", 1), attribute.Int("two", 2)}
114 l := []tracesdk.Link{
115 {
116 DroppedAttributeCount: 3,
117 },
118 {
119 SpanContext: trace.SpanContext{},
120 Attributes: attrs,
121 DroppedAttributeCount: 3,
122 },
123 }
124 got := links(l)
125
126
127 if !assert.Len(t, got, 2) {
128 return
129 }
130
131
132 expected := &tracepb.Span_Link{
133 TraceId: []uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
134 SpanId: []uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
135 DroppedAttributesCount: 3,
136 }
137 assert.Equal(t, expected, got[0])
138
139
140 expected.Attributes = KeyValues(attrs)
141 assert.Equal(t, expected, got[1])
142
143
144 l[1].SpanContext = l[1].SpanContext.WithTraceID(trace.TraceID{})
145 assert.Equal(t, expected, got[1])
146 assert.Equal(t, l[1].DroppedAttributeCount, int(got[1].DroppedAttributesCount))
147 }
148
149 func TestStatus(t *testing.T) {
150 for _, test := range []struct {
151 code codes.Code
152 message string
153 otlpStatus tracepb.Status_StatusCode
154 }{
155 {
156 codes.Ok,
157 "test Ok",
158 tracepb.Status_STATUS_CODE_OK,
159 },
160 {
161 codes.Unset,
162 "test Unset",
163 tracepb.Status_STATUS_CODE_UNSET,
164 },
165 {
166 message: "default code is unset",
167 otlpStatus: tracepb.Status_STATUS_CODE_UNSET,
168 },
169 {
170 codes.Error,
171 "test Error",
172 tracepb.Status_STATUS_CODE_ERROR,
173 },
174 } {
175 expected := &tracepb.Status{Code: test.otlpStatus, Message: test.message}
176 assert.Equal(t, expected, status(test.code, test.message))
177 }
178 }
179
180 func TestNilSpan(t *testing.T) {
181 assert.Nil(t, span(nil))
182 }
183
184 func TestNilSpanData(t *testing.T) {
185 assert.Nil(t, Spans(nil))
186 }
187
188 func TestEmptySpanData(t *testing.T) {
189 assert.Nil(t, Spans(nil))
190 }
191
192 func TestSpanData(t *testing.T) {
193
194
195
196 startTime := time.Unix(1585674086, 1234)
197 endTime := startTime.Add(10 * time.Second)
198 traceState, _ := trace.ParseTraceState("key1=val1,key2=val2")
199 spanData := tracetest.SpanStub{
200 SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
201 TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
202 SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
203 TraceState: traceState,
204 }),
205 Parent: trace.NewSpanContext(trace.SpanContextConfig{
206 TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
207 SpanID: trace.SpanID{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
208 TraceState: traceState,
209 Remote: true,
210 }),
211 SpanKind: trace.SpanKindServer,
212 Name: "span data to span data",
213 StartTime: startTime,
214 EndTime: endTime,
215 Events: []tracesdk.Event{
216 {
217 Time: startTime,
218 Attributes: []attribute.KeyValue{
219 attribute.Int64("CompressedByteSize", 512),
220 },
221 },
222 {
223 Time: endTime,
224 Attributes: []attribute.KeyValue{
225 attribute.String("EventType", "Recv"),
226 },
227 },
228 },
229 Links: []tracesdk.Link{
230 {
231 SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
232 TraceID: trace.TraceID{0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF},
233 SpanID: trace.SpanID{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
234 TraceFlags: 0,
235 }),
236 Attributes: []attribute.KeyValue{
237 attribute.String("LinkType", "Parent"),
238 },
239 DroppedAttributeCount: 0,
240 },
241 {
242 SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
243 TraceID: trace.TraceID{0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF},
244 SpanID: trace.SpanID{0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7},
245 TraceFlags: 0,
246 }),
247 Attributes: []attribute.KeyValue{
248 attribute.String("LinkType", "Child"),
249 },
250 DroppedAttributeCount: 0,
251 },
252 },
253 Status: tracesdk.Status{
254 Code: codes.Error,
255 Description: "utterly unrecognized",
256 },
257 Attributes: []attribute.KeyValue{
258 attribute.Int64("timeout_ns", 12e9),
259 },
260 DroppedAttributes: 1,
261 DroppedEvents: 2,
262 DroppedLinks: 3,
263 Resource: resource.NewWithAttributes(
264 "http://example.com/custom-resource-schema",
265 attribute.String("rk1", "rv1"),
266 attribute.Int64("rk2", 5),
267 attribute.StringSlice("rk3", []string{"sv1", "sv2"}),
268 ),
269 InstrumentationLibrary: instrumentation.Scope{
270 Name: "go.opentelemetry.io/test/otel",
271 Version: "v0.0.1",
272 SchemaURL: semconv.SchemaURL,
273 },
274 }
275
276
277
278
279 expectedSpan := &tracepb.Span{
280 TraceId: []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
281 SpanId: []byte{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
282 ParentSpanId: []byte{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
283 TraceState: "key1=val1,key2=val2",
284 Name: spanData.Name,
285 Kind: tracepb.Span_SPAN_KIND_SERVER,
286 StartTimeUnixNano: uint64(startTime.UnixNano()),
287 EndTimeUnixNano: uint64(endTime.UnixNano()),
288 Status: status(spanData.Status.Code, spanData.Status.Description),
289 Events: spanEvents(spanData.Events),
290 Links: links(spanData.Links),
291 Attributes: KeyValues(spanData.Attributes),
292 DroppedAttributesCount: 1,
293 DroppedEventsCount: 2,
294 DroppedLinksCount: 3,
295 }
296
297 got := Spans(tracetest.SpanStubs{spanData}.Snapshots())
298 require.Len(t, got, 1)
299
300 assert.Equal(t, got[0].GetResource(), Resource(spanData.Resource))
301 assert.Equal(t, got[0].SchemaUrl, spanData.Resource.SchemaURL())
302 scopeSpans := got[0].GetScopeSpans()
303 require.Len(t, scopeSpans, 1)
304 assert.Equal(t, scopeSpans[0].SchemaUrl, spanData.InstrumentationLibrary.SchemaURL)
305 assert.Equal(t, scopeSpans[0].GetScope(), InstrumentationScope(spanData.InstrumentationLibrary))
306 require.Len(t, scopeSpans[0].Spans, 1)
307 actualSpan := scopeSpans[0].Spans[0]
308
309 if diff := cmp.Diff(expectedSpan, actualSpan, cmp.Comparer(proto.Equal)); diff != "" {
310 t.Fatalf("transformed span differs %v\n", diff)
311 }
312 }
313
314
315 func TestRootSpanData(t *testing.T) {
316 sd := Spans(tracetest.SpanStubs{
317 {},
318 }.Snapshots())
319 require.Len(t, sd, 1)
320 rs := sd[0]
321 scopeSpans := rs.GetScopeSpans()
322 require.Len(t, scopeSpans, 1)
323 got := scopeSpans[0].GetSpans()[0].GetParentSpanId()
324
325
326 assert.Nil(t, got, "incorrect transform of root parent span ID")
327 }
328
329 func TestSpanDataNilResource(t *testing.T) {
330 assert.NotPanics(t, func() {
331 Spans(tracetest.SpanStubs{
332 {},
333 }.Snapshots())
334 })
335 }
336
View as plain text