1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package tracecontext
16
17 import (
18 "fmt"
19 "net/http"
20 "reflect"
21 "strings"
22 "testing"
23
24 "go.opencensus.io/trace"
25 "go.opencensus.io/trace/tracestate"
26 )
27
28 var (
29 tpHeader = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
30 traceID = trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54}
31 spanID = trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183}
32 traceOpt = trace.TraceOptions(1)
33 oversizeValue = strings.Repeat("a", maxTracestateLen/2)
34 oversizeEntry1 = tracestate.Entry{Key: "foo", Value: oversizeValue}
35 oversizeEntry2 = tracestate.Entry{Key: "hello", Value: oversizeValue}
36 entry1 = tracestate.Entry{Key: "foo", Value: "bar"}
37 entry2 = tracestate.Entry{Key: "hello", Value: "world example"}
38 oversizeTs, _ = tracestate.New(nil, oversizeEntry1, oversizeEntry2)
39 defaultTs, _ = tracestate.New(nil, nil...)
40 nonDefaultTs, _ = tracestate.New(nil, entry1, entry2)
41 )
42
43 func TestHTTPFormat_FromRequest(t *testing.T) {
44 tests := []struct {
45 name string
46 header string
47 wantSc trace.SpanContext
48 wantOk bool
49 }{
50 {
51 name: "future version",
52 header: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
53 wantSc: trace.SpanContext{
54 TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
55 SpanID: trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
56 TraceOptions: trace.TraceOptions(1),
57 },
58 wantOk: true,
59 },
60 {
61 name: "zero trace ID and span ID",
62 header: "00-00000000000000000000000000000000-0000000000000000-01",
63 wantSc: trace.SpanContext{},
64 wantOk: false,
65 },
66 {
67 name: "valid header",
68 header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
69 wantSc: trace.SpanContext{
70 TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
71 SpanID: trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
72 TraceOptions: trace.TraceOptions(1),
73 },
74 wantOk: true,
75 },
76 {
77 name: "missing options",
78 header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
79 wantSc: trace.SpanContext{},
80 wantOk: false,
81 },
82 {
83 name: "empty options",
84 header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
85 wantSc: trace.SpanContext{},
86 wantOk: false,
87 },
88 }
89
90 f := &HTTPFormat{}
91 for _, tt := range tests {
92 t.Run(tt.name, func(t *testing.T) {
93 req, _ := http.NewRequest("GET", "http://example.com", nil)
94 req.Header.Set("traceparent", tt.header)
95
96 gotSc, gotOk := f.SpanContextFromRequest(req)
97 if !reflect.DeepEqual(gotSc, tt.wantSc) {
98 t.Errorf("HTTPFormat.FromRequest() gotSc = %v, want %v", gotSc, tt.wantSc)
99 }
100 if gotOk != tt.wantOk {
101 t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
102 }
103
104 gotSc, gotOk = f.SpanContextFromHeaders(tt.header, "")
105 if !reflect.DeepEqual(gotSc, tt.wantSc) {
106 t.Errorf("HTTPFormat.SpanContextFromHeaders() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
107 }
108 if gotOk != tt.wantOk {
109 t.Errorf("HTTPFormat.SpanContextFromHeaders() gotOk = %v, want %v", gotOk, tt.wantOk)
110 }
111 })
112 }
113 }
114
115 func TestHTTPFormat_ToRequest(t *testing.T) {
116 tests := []struct {
117 sc trace.SpanContext
118 wantHeader string
119 }{
120 {
121 sc: trace.SpanContext{
122 TraceID: trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
123 SpanID: trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
124 TraceOptions: trace.TraceOptions(1),
125 },
126 wantHeader: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
127 },
128 }
129 for _, tt := range tests {
130 t.Run(tt.wantHeader, func(t *testing.T) {
131 f := &HTTPFormat{}
132 req, _ := http.NewRequest("GET", "http://example.com", nil)
133 f.SpanContextToRequest(tt.sc, req)
134
135 h := req.Header.Get("traceparent")
136 if got, want := h, tt.wantHeader; got != want {
137 t.Errorf("HTTPFormat.ToRequest() header = %v, want %v", got, want)
138 }
139
140 gotTp, _ := f.SpanContextToHeaders(tt.sc)
141 if gotTp != tt.wantHeader {
142 t.Errorf("HTTPFormat.SpanContextToHeaders() tracestate header = %v, want %v", gotTp, tt.wantHeader)
143 }
144 })
145 }
146 }
147
148 func TestHTTPFormatTracestate_FromRequest(t *testing.T) {
149 scWithNonDefaultTracestate := trace.SpanContext{
150 TraceID: traceID,
151 SpanID: spanID,
152 TraceOptions: traceOpt,
153 Tracestate: nonDefaultTs,
154 }
155
156 scWithDefaultTracestate := trace.SpanContext{
157 TraceID: traceID,
158 SpanID: spanID,
159 TraceOptions: traceOpt,
160 Tracestate: defaultTs,
161 }
162
163 tests := []struct {
164 name string
165 tpHeader string
166 tsHeader string
167 wantSc trace.SpanContext
168 wantOk bool
169 }{
170 {
171 name: "tracestate invalid entries delimiter",
172 tpHeader: tpHeader,
173 tsHeader: "foo=bar;hello=world",
174 wantSc: scWithDefaultTracestate,
175 wantOk: true,
176 },
177 {
178 name: "tracestate invalid key-value delimiter",
179 tpHeader: tpHeader,
180 tsHeader: "foo=bar,hello-world",
181 wantSc: scWithDefaultTracestate,
182 wantOk: true,
183 },
184 {
185 name: "tracestate invalid value character",
186 tpHeader: tpHeader,
187 tsHeader: "foo=bar,hello=world example \u00a0 ",
188 wantSc: scWithDefaultTracestate,
189 wantOk: true,
190 },
191 {
192 name: "tracestate blank key-value",
193 tpHeader: tpHeader,
194 tsHeader: "foo=bar, ",
195 wantSc: scWithDefaultTracestate,
196 wantOk: true,
197 },
198 {
199 name: "tracestate oversize header",
200 tpHeader: tpHeader,
201 tsHeader: fmt.Sprintf("foo=%s,hello=%s", oversizeValue, oversizeValue),
202 wantSc: scWithDefaultTracestate,
203 wantOk: true,
204 },
205 {
206 name: "tracestate valid",
207 tpHeader: tpHeader,
208 tsHeader: "foo=bar , hello=world example",
209 wantSc: scWithNonDefaultTracestate,
210 wantOk: true,
211 },
212 }
213
214 f := &HTTPFormat{}
215 for _, tt := range tests {
216 t.Run(tt.name, func(t *testing.T) {
217 req, _ := http.NewRequest("GET", "http://example.com", nil)
218 req.Header.Set("traceparent", tt.tpHeader)
219 req.Header.Set("tracestate", tt.tsHeader)
220
221 gotSc, gotOk := f.SpanContextFromRequest(req)
222 if !reflect.DeepEqual(gotSc, tt.wantSc) {
223 t.Errorf("HTTPFormat.FromRequest() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
224 }
225 if gotOk != tt.wantOk {
226 t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
227 }
228
229 gotSc, gotOk = f.SpanContextFromHeaders(tt.tpHeader, tt.tsHeader)
230 if !reflect.DeepEqual(gotSc, tt.wantSc) {
231 t.Errorf("HTTPFormat.SpanContextFromHeaders() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
232 }
233 if gotOk != tt.wantOk {
234 t.Errorf("HTTPFormat.SpanContextFromHeaders() gotOk = %v, want %v", gotOk, tt.wantOk)
235 }
236 })
237 }
238 }
239
240 func TestHTTPFormatTracestate_ToRequest(t *testing.T) {
241 tests := []struct {
242 name string
243 sc trace.SpanContext
244 wantHeader string
245 }{
246 {
247 name: "valid span context with default tracestate",
248 sc: trace.SpanContext{
249 TraceID: traceID,
250 SpanID: spanID,
251 TraceOptions: traceOpt,
252 },
253 wantHeader: "",
254 },
255 {
256 name: "valid span context with non default tracestate",
257 sc: trace.SpanContext{
258 TraceID: traceID,
259 SpanID: spanID,
260 TraceOptions: traceOpt,
261 Tracestate: nonDefaultTs,
262 },
263 wantHeader: "foo=bar,hello=world example",
264 },
265 {
266 name: "valid span context with oversize tracestate",
267 sc: trace.SpanContext{
268 TraceID: traceID,
269 SpanID: spanID,
270 TraceOptions: traceOpt,
271 Tracestate: oversizeTs,
272 },
273 wantHeader: "",
274 },
275 }
276 for _, tt := range tests {
277 t.Run(tt.name, func(t *testing.T) {
278 f := &HTTPFormat{}
279 req, _ := http.NewRequest("GET", "http://example.com", nil)
280 f.SpanContextToRequest(tt.sc, req)
281
282 h := req.Header.Get("tracestate")
283 if got, want := h, tt.wantHeader; got != want {
284 t.Errorf("HTTPFormat.ToRequest() tracestate header = %v, want %v", got, want)
285 }
286
287 _, gotTs := f.SpanContextToHeaders(tt.sc)
288 if gotTs != tt.wantHeader {
289 t.Errorf("HTTPFormat.SpanContextToHeaders() tracestate header = %v, want %v", gotTs, tt.wantHeader)
290 }
291 })
292 }
293 }
294
View as plain text