1package lightstep_test
2
3import (
4	"bytes"
5	"encoding/json"
6	"io"
7	"strconv"
8	"strings"
9	"time"
10
11	"github.com/lightstep/lightstep-tracer-common/golang/gogo/collectorpb"
12	. "github.com/lightstep/lightstep-tracer-go"
13	. "github.com/onsi/ginkgo"
14	. "github.com/onsi/gomega"
15	"github.com/opentracing/opentracing-go"
16	"github.com/opentracing/opentracing-go/log"
17)
18
19// Interfaces
20
21type Reference interface {
22	GetSpanContext() SpanContext
23}
24
25type Span interface {
26	GetOperationName() string
27
28	GetSpanContext() SpanContext
29
30	GetTags() interface{}
31
32	GetReferences() interface{}
33
34	GetReference(i int) Reference
35
36	GetLogs() []interface{}
37}
38
39type fakeCollectorClient interface {
40	ConnectorFactory() ConnectorFactory
41
42	ReportCallCount() int
43
44	GetSpansLen() int
45
46	GetSpan(i int) Span
47}
48
49// Describe Test
50
51var _ = Describe("Tracer Transports", func() {
52	var options *Options
53	var tracer opentracing.Tracer
54	var fakeClient fakeCollectorClient
55	const port = 9090
56
57	BeforeEach(func() {
58		options = &Options{}
59	})
60
61	JustBeforeEach(func() {
62		options.ConnFactory = fakeClient.ConnectorFactory()
63		tracer = NewTracer(*options)
64		// make sure the fake client is working
65		Eventually(fakeClient.ReportCallCount).ShouldNot(BeZero())
66	})
67
68	AfterEach(func() {
69		closeTestTracer(tracer)
70	})
71
72	ItShouldBehaveLikeATracer := func(tracerTestOptions ...testOption) {
73		testOptions := toTestOptions(tracerTestOptions)
74		Context("with default options", func() {
75			BeforeEach(func() {
76				options.AccessToken = "0987654321"
77				options.Collector = Endpoint{Host: "localhost", Port: port, Plaintext: true}
78				options.ReportingPeriod = 1 * time.Millisecond
79				options.MinReportingPeriod = 1 * time.Millisecond
80				options.ReportTimeout = 10 * time.Millisecond
81			})
82
83			It("Should record baggage info internally", func() {
84				span := tracer.StartSpan("x")
85				span.SetBaggageItem("x", "y")
86				Expect(span.BaggageItem("x")).To(Equal("y"))
87			})
88
89			It("Should send span operation names to the collector", func() {
90				tracer.StartSpan("smooth").Finish()
91
92				Eventually(fakeClient.GetSpansLen).Should(Equal(1))
93				Expect(fakeClient.GetSpan(0).GetOperationName()).To(Equal("smooth"))
94			})
95
96			It("Should send tags back to the collector", func() {
97				span := tracer.StartSpan("brokay doogle")
98				span.SetTag("tag", "you're it!")
99				span.Finish()
100
101				Eventually(fakeClient.GetSpansLen).Should(Equal(1))
102				Expect(fakeClient.GetSpan(0).GetTags()).To(HaveKeyValues(KeyValue("tag", "you're it!")))
103			})
104
105			if testOptions.supportsBaggage {
106				It("Should send baggage info to the collector", func() {
107					span := tracer.StartSpan("x")
108					span.SetBaggageItem("x", "y")
109					span.Finish()
110
111					Eventually(fakeClient.GetSpansLen).Should(Equal(1))
112					Expect(fakeClient.GetSpan(0).GetSpanContext().Baggage).To(BeEquivalentTo(map[string]string{"x": "y"}))
113				})
114
115				It("ForeachBaggageItem", func() {
116					span := tracer.StartSpan("x")
117					span.SetBaggageItem("x", "y")
118					baggage := map[string]string{}
119					span.Context().ForeachBaggageItem(func(k, v string) bool {
120						baggage[k] = v
121						return true
122					})
123					Expect(baggage).To(BeEquivalentTo(map[string]string{"x": "y"}))
124
125					span.SetBaggageItem("a", "b")
126					baggage = map[string]string{}
127					span.Context().ForeachBaggageItem(func(k, v string) bool {
128						baggage[k] = v
129						return false // exit early
130					})
131					Expect(baggage).To(HaveLen(1))
132					span.Finish()
133
134					Eventually(fakeClient.GetSpansLen).Should(Equal(1))
135					Expect(fakeClient.GetSpan(0).GetSpanContext().Baggage).To(HaveLen(2))
136				})
137			}
138
139			Describe("CloseTracer", func() {
140				It("Should not explode when called twice", func() {
141					closeTestTracer(tracer)
142					closeTestTracer(tracer)
143				})
144
145				It("Should behave nicely", func() {
146					By("Not hanging")
147					closeTestTracer(tracer)
148
149					By("Stop communication with server")
150					lastCallCount := fakeClient.ReportCallCount()
151					Consistently(fakeClient.ReportCallCount, 0.5, 0.05).Should(Equal(lastCallCount))
152
153					By("Allowing other tracers to reconnect to the server")
154					tracer = NewTracer(*options)
155					Eventually(fakeClient.ReportCallCount).ShouldNot(Equal(lastCallCount))
156				})
157			})
158
159			Describe("Options", func() {
160				const expectedTraceID uint64 = 1
161				const expectedSpanID uint64 = 2
162				const expectedParentSpanID uint64 = 3
163
164				Context("when the TraceID is set", func() {
165					JustBeforeEach(func() {
166						tracer.StartSpan("x", SetTraceID(expectedTraceID)).Finish()
167					})
168
169					It("should set the specified options", func() {
170						Eventually(fakeClient.GetSpansLen).Should(Equal(1))
171						Expect(fakeClient.GetSpan(0).GetSpanContext().TraceID).To(Equal(expectedTraceID))
172						Expect(fakeClient.GetSpan(0).GetSpanContext().SpanID).ToNot(Equal(uint64(0)))
173						if testOptions.supportsReference {
174							Expect(fakeClient.GetSpan(0).GetReferences()).To(BeEmpty())
175						}
176					})
177				})
178
179				Context("when both the TraceID and SpanID are set", func() {
180					JustBeforeEach(func() {
181						tracer.StartSpan("x", SetTraceID(expectedTraceID), SetSpanID(expectedSpanID)).Finish()
182					})
183
184					It("Should set the specified options", func() {
185						Eventually(fakeClient.GetSpansLen).Should(Equal(1))
186						Expect(fakeClient.GetSpan(0).GetSpanContext().TraceID).To(Equal(expectedTraceID))
187						Expect(fakeClient.GetSpan(0).GetSpanContext().SpanID).To(Equal(expectedSpanID))
188						if testOptions.supportsReference {
189							Expect(fakeClient.GetSpan(0).GetReferences()).To(BeEmpty())
190						}
191					})
192				})
193
194				Context("when TraceID, SpanID, and ParentSpanID are set", func() {
195					JustBeforeEach(func() {
196						tracer.StartSpan("x", SetTraceID(expectedTraceID), SetSpanID(expectedSpanID), SetParentSpanID(expectedParentSpanID)).Finish()
197					})
198
199					It("Should set the specified options", func() {
200						Eventually(fakeClient.GetSpansLen).Should(Equal(1))
201						Expect(fakeClient.GetSpan(0).GetSpanContext().TraceID).To(Equal(expectedTraceID))
202						Expect(fakeClient.GetSpan(0).GetSpanContext().SpanID).To(Equal(expectedSpanID))
203						if testOptions.supportsReference {
204							Expect(fakeClient.GetSpan(0).GetReferences()).ToNot(BeEmpty())
205							Expect(fakeClient.GetSpan(0).GetReference(0).GetSpanContext().SpanID).To(Equal(expectedParentSpanID))
206						}
207					})
208				})
209			})
210
211			Describe("TextMap Carriers", func() {
212				var knownContext1 = SpanContext{
213					SpanID:  6397081719746291766,
214					TraceID: 506100417967962170,
215					Sampled: "true",
216					Baggage: map[string]string{"checked": "baggage"},
217				}
218
219				It("should extract SpanContext from carrier", func() {
220					textmap := opentracing.TextMapCarrier{}
221					err := tracer.Inject(knownContext1, opentracing.TextMap, textmap)
222					Expect(err).ToNot(HaveOccurred())
223
224					Expect(textmap["ot-tracer-spanid"]).To(Equal("58c6ffee509f6836"))
225					Expect(textmap["ot-tracer-traceid"]).To(Equal("70607a611a8383a"))
226					Expect(textmap["ot-tracer-sampled"]).To(Equal("true"))
227
228					context, err := tracer.Extract(opentracing.TextMap, textmap)
229					Expect(context).To(BeEquivalentTo(knownContext1))
230					Expect(err).To(BeNil())
231				})
232			})
233
234			Describe("Binary Carriers", func() {
235				const knownCarrier1 = "EigJOjioEaYHBgcRNmifUO7/xlgYASISCgdjaGVja2VkEgdiYWdnYWdl"
236				const knownCarrier2 = "EigJEX+FpwZ/EmYR2gfYQbxCMskYASISCgdjaGVja2VkEgdiYWdnYWdl"
237				const badCarrier1 = "Y3QbxCMskYASISCgdjaGVja2VkEgd"
238
239				var knownContext1 = SpanContext{
240					SpanID:  6397081719746291766,
241					TraceID: 506100417967962170,
242					Baggage: map[string]string{"checked": "baggage"},
243				}
244				var knownContext2 = SpanContext{
245					SpanID:  14497723526785009626,
246					TraceID: 7355080808006516497,
247					Baggage: map[string]string{"checked": "baggage"},
248				}
249				var testContext1 = SpanContext{
250					SpanID:  123,
251					TraceID: 456,
252					Baggage: nil,
253				}
254				var testContext2 = SpanContext{
255					SpanID:  123000000000,
256					TraceID: 456000000000,
257					Baggage: map[string]string{"a": "1", "b": "2", "c": "3"},
258				}
259
260				Context("tracer inject", func() {
261					var carrierString string
262					var carrierBytes []byte
263
264					BeforeEach(func() {
265						carrierString = ""
266						carrierBytes = []byte{}
267					})
268
269					It("Should support injecting into strings ", func() {
270						for _, origContext := range []SpanContext{knownContext1, knownContext2, testContext1, testContext2} {
271							err := tracer.Inject(origContext, opentracing.Binary, &carrierString)
272							Expect(err).ToNot(HaveOccurred())
273
274							context, err := tracer.Extract(opentracing.Binary, carrierString)
275							Expect(err).ToNot(HaveOccurred())
276							Expect(context).To(BeEquivalentTo(origContext))
277						}
278					})
279
280					It("Should support injecting into byte arrays", func() {
281						for _, origContext := range []SpanContext{knownContext1, knownContext2, testContext1, testContext2} {
282							err := tracer.Inject(origContext, opentracing.Binary, &carrierBytes)
283							Expect(err).ToNot(HaveOccurred())
284
285							context, err := tracer.Extract(opentracing.Binary, carrierBytes)
286							Expect(err).ToNot(HaveOccurred())
287							Expect(context).To(BeEquivalentTo(origContext))
288						}
289					})
290
291					It("Should support injecting into io.Writer", func() {
292						for _, origContext := range []SpanContext{knownContext1, knownContext2, testContext1, testContext2} {
293							buf := bytes.NewBuffer(nil)
294							err := tracer.Inject(origContext, opentracing.Binary, io.Writer(buf))
295							Expect(err).ToNot(HaveOccurred())
296
297							context, err := tracer.Extract(opentracing.Binary, io.Reader(buf))
298							Expect(err).ToNot(HaveOccurred())
299							Expect(context).To(BeEquivalentTo(origContext))
300						}
301					})
302					It("Should return nil for nil contexts", func() {
303						err := tracer.Inject(nil, opentracing.Binary, carrierString)
304						Expect(err).To(HaveOccurred())
305
306						err = tracer.Inject(nil, opentracing.Binary, carrierBytes)
307						Expect(err).To(HaveOccurred())
308					})
309				})
310
311				Context("tracer extract", func() {
312					It("Should extract SpanContext from carrier as string", func() {
313						context, err := tracer.Extract(opentracing.Binary, knownCarrier1)
314						Expect(context).To(BeEquivalentTo(knownContext1))
315						Expect(err).To(BeNil())
316
317						context, err = tracer.Extract(opentracing.Binary, knownCarrier2)
318						Expect(context).To(BeEquivalentTo(knownContext2))
319						Expect(err).To(BeNil())
320					})
321
322					It("Should extract SpanContext from carrier as []byte", func() {
323						context, err := tracer.Extract(opentracing.Binary, []byte(knownCarrier1))
324						Expect(context).To(BeEquivalentTo(knownContext1))
325						Expect(err).To(BeNil())
326
327						context, err = tracer.Extract(opentracing.Binary, []byte(knownCarrier2))
328						Expect(context).To(BeEquivalentTo(knownContext2))
329						Expect(err).To(BeNil())
330					})
331
332					It("Should extract SpanContext from carrier as io.Reader", func() {
333						buf := bytes.NewBuffer([]byte(knownCarrier1))
334						context, err := tracer.Extract(opentracing.Binary, io.Reader(buf))
335						Expect(context).To(BeEquivalentTo(knownContext1))
336						Expect(err).To(BeNil())
337
338						buf = bytes.NewBuffer([]byte(knownCarrier2))
339						context, err = tracer.Extract(opentracing.Binary, io.Reader(buf))
340						Expect(context).To(BeEquivalentTo(knownContext2))
341						Expect(err).To(BeNil())
342					})
343
344					It("Should return nil for bad carriers", func() {
345						for _, carrier := range []interface{}{badCarrier1, []byte(badCarrier1), "", []byte(nil)} {
346							context, err := tracer.Extract(opentracing.Binary, carrier)
347							Expect(context).To(BeNil())
348							Expect(err).To(HaveOccurred())
349						}
350					})
351				})
352			})
353		})
354
355		Context("With custom log length", func() {
356			BeforeEach(func() {
357				options.AccessToken = "0987654321"
358				options.Collector = Endpoint{Host: "localhost", Port: port, Plaintext: true}
359				options.ReportingPeriod = 1 * time.Millisecond
360				options.MinReportingPeriod = 1 * time.Millisecond
361				options.ReportTimeout = 10 * time.Millisecond
362				options.MaxLogKeyLen = 10
363				options.MaxLogValueLen = 11
364			})
365
366			Describe("Logging", func() {
367				JustBeforeEach(func() {
368					span := tracer.StartSpan("spantastic")
369					span.LogFields(
370						log.String("donut", "bacon"),
371						log.Object("key", []interface{}{"gr", 8}),
372						log.String("donut army"+strings.Repeat("O", 50), strings.Repeat("O", 110)),
373						log.Int("life", 42),
374					)
375					span.Finish()
376				})
377
378				It("Should send logs back to the collector", func() {
379					Eventually(fakeClient.GetSpansLen).Should(Equal(1))
380
381					obj, _ := json.Marshal([]interface{}{"gr", 8})
382
383					expectedKeyValues := []*collectorpb.KeyValue{KeyValue("donut", "bacon")}
384
385					if testOptions.supportsTypedValues {
386						expectedKeyValues = append(expectedKeyValues,
387							KeyValue("key", string(obj), true),
388							KeyValue("donut arm…", "OOOOOOOOOO…"),
389							KeyValue("life", 42),
390						)
391					} else {
392						expectedKeyValues = append(expectedKeyValues,
393							KeyValue("key", string(obj)),
394							KeyValue("donut arm…", "OOOOOOOOOO…"),
395							KeyValue("life", "42"),
396						)
397					}
398
399					Expect(fakeClient.GetSpan(0).GetLogs()).To(HaveLen(1))
400					Expect(fakeClient.GetSpan(0).GetLogs()[0]).To(HaveKeyValues(expectedKeyValues...))
401				})
402			})
403		})
404
405		Context("With custom MaxBufferedSpans", func() {
406			BeforeEach(func() {
407				options.AccessToken = "0987654321"
408				options.Collector = Endpoint{Host: "localhost", Port: port, Plaintext: true}
409				options.ReportingPeriod = 1 * time.Millisecond
410				options.MinReportingPeriod = 1 * time.Millisecond
411				options.ReportTimeout = 10 * time.Millisecond
412				options.MaxLogKeyLen = 10
413				options.MaxLogValueLen = 11
414				options.MaxBufferedSpans = 10
415			})
416
417			Describe("SpanBuffer", func() {
418				It("should respect MaxBufferedSpans", func() {
419					startNSpans(10, tracer)
420					Eventually(fakeClient.GetSpansLen).Should(Equal(10))
421
422					startNSpans(10, tracer)
423					Eventually(fakeClient.GetSpansLen).Should(Equal(10))
424				})
425			})
426		})
427
428		Context("With DropSpanLogs set", func() {
429			BeforeEach(func() {
430				options.AccessToken = "0987654321"
431				options.Collector = Endpoint{Host: "localhost", Port: port, Plaintext: true}
432				options.ReportingPeriod = 1 * time.Millisecond
433				options.MinReportingPeriod = 1 * time.Millisecond
434				options.ReportTimeout = 10 * time.Millisecond
435				options.DropSpanLogs = true
436			})
437
438			It("Should not record logs", func() {
439				span := tracer.StartSpan("x")
440				span.LogFields(log.String("Led", "Zeppelin"), log.Uint32("32bit", 4294967295))
441				span.SetTag("tag", "value")
442				span.Finish()
443
444				Eventually(fakeClient.GetSpansLen).Should(Equal(1))
445				Expect(fakeClient.GetSpan(0).GetOperationName()).To(Equal("x"))
446				Expect(fakeClient.GetSpan(0).GetTags()).To(HaveKeyValues(KeyValue("tag", "value")))
447				Expect(fakeClient.GetSpan(0).GetLogs()).To(BeEmpty())
448			})
449		})
450
451		Context("With MaxLogsPerSpan set", func() {
452			BeforeEach(func() {
453				options.AccessToken = "0987654321"
454				options.Collector = Endpoint{Host: "localhost", Port: port, Plaintext: true}
455				options.ReportingPeriod = 1 * time.Millisecond
456				options.MinReportingPeriod = 1 * time.Millisecond
457				options.ReportTimeout = 10 * time.Millisecond
458				options.MaxLogsPerSpan = 10
459			})
460
461			It("keeps all logs if they don't exceed MaxLogsPerSpan", func() {
462				const logCount = 10
463				span := tracer.StartSpan("span")
464				for i := 0; i < logCount; i++ {
465					span.LogKV("id", i)
466				}
467				span.Finish()
468
469				Eventually(fakeClient.GetSpansLen).Should(Equal(1))
470				Expect(fakeClient.GetSpan(0).GetOperationName()).To(Equal("span"))
471				Expect(fakeClient.GetSpan(0).GetLogs()).To(HaveLen(10))
472
473				for i, log := range fakeClient.GetSpan(0).GetLogs() {
474					if testOptions.supportsTypedValues {
475						Expect(log).To(HaveKeyValues(KeyValue("id", i)))
476					} else {
477						Expect(log).To(HaveKeyValues(KeyValue("id", strconv.FormatInt(int64(i), 10))))
478					}
479				}
480			})
481
482			It("throws away the middle logs when they exceed MaxLogsPerSpan", func() {
483				const logCount = 50
484				span := tracer.StartSpan("span")
485				for i := 0; i < logCount; i++ {
486					span.LogKV("id", i)
487				}
488				span.Finish()
489
490				Eventually(fakeClient.GetSpansLen).Should(Equal(1))
491				Expect(fakeClient.GetSpan(0).GetOperationName()).To(Equal("span"))
492				Expect(fakeClient.GetSpan(0).GetLogs()).To(HaveLen(10))
493
494				split := (len(fakeClient.GetSpan(0).GetLogs()) - 1) / 2
495				firstLogs := fakeClient.GetSpan(0).GetLogs()[:split]
496				for i, log := range firstLogs {
497					if testOptions.supportsTypedValues {
498						Expect(log).To(HaveKeyValues(KeyValue("id", i)))
499					} else {
500						Expect(log).To(HaveKeyValues(KeyValue("id", strconv.FormatInt(int64(i), 10))))
501					}
502				}
503
504				warnLog := fakeClient.GetSpan(0).GetLogs()[split]
505
506				expectedKeyValues := []*collectorpb.KeyValue{
507					KeyValue("event", "dropped Span logs"),
508				}
509
510				if testOptions.supportsTypedValues {
511					expectedKeyValues = append(expectedKeyValues,
512						KeyValue("dropped_log_count", logCount-len(fakeClient.GetSpan(0).GetLogs())+1),
513					)
514				} else {
515					expectedKeyValues = append(expectedKeyValues,
516						KeyValue("dropped_log_count", strconv.FormatInt(int64(logCount-len(fakeClient.GetSpan(0).GetLogs())+1), 10)),
517					)
518				}
519
520				expectedKeyValues = append(expectedKeyValues, KeyValue("component", "basictracer"))
521
522				Expect(warnLog).To(HaveKeyValues(expectedKeyValues...))
523
524				lastLogs := fakeClient.GetSpan(0).GetLogs()[split+1:]
525				for i, log := range lastLogs {
526					if testOptions.supportsTypedValues {
527						Expect(log).To(HaveKeyValues(KeyValue("id", logCount-len(lastLogs)+i)))
528					} else {
529						Expect(log).To(HaveKeyValues(KeyValue("id", strconv.FormatInt(int64(logCount-len(lastLogs)+i), 10))))
530					}
531				}
532			})
533		})
534		Context("With B3 headers set", func() {
535			var knownCarrier1 opentracing.TextMapCarrier
536
537			var knownContext1 = SpanContext{
538				SpanID:  6397081719746291766,
539				TraceID: 506100417967962170,
540				Baggage: map[string]string{"checked": "baggage"},
541			}
542
543			var knownContext2 = SpanContext{
544				SpanID:  506,
545				TraceID: 18446744073709551615,
546				Sampled: "true",
547				Baggage: map[string]string{
548					"checked": "baggage",
549				},
550			}
551
552			var knownContext3 = SpanContext{
553				SpanID:       120982392839283799,
554				TraceIDUpper: 1152921504606846975,
555				TraceID:      844674407370955165,
556				Sampled:      "1",
557				Baggage:      map[string]string{"checked": "more-baggage"},
558			}
559
560			BeforeEach(func() {
561				options.Propagators = map[opentracing.BuiltinFormat]Propagator{
562					opentracing.HTTPHeaders: B3Propagator,
563					opentracing.TextMap:     B3Propagator,
564				}
565				knownCarrier1 = opentracing.TextMapCarrier{}
566			})
567
568			It("should inject SpanContext into carrier", func() {
569				err := tracer.Inject(knownContext1, opentracing.TextMap, knownCarrier1)
570				Expect(err).ToNot(HaveOccurred())
571				Expect(knownCarrier1["x-b3-spanid"]).To(Equal("58c6ffee509f6836"))
572				Expect(knownCarrier1["x-b3-traceid"]).To(Equal("70607a611a8383a"))
573				Expect(knownCarrier1["x-b3-sampled"]).To(Equal("1"))
574				Expect(knownCarrier1["ot-baggage-checked"]).To(Equal("baggage"))
575			})
576
577			It("should extract SpanContext from carrier and propagate sampling decision", func() {
578				knownCarrier1.Set("x-b3-spanid", "1fa")
579				knownCarrier1.Set("x-b3-traceid", "ffffffffffffffff")
580				knownCarrier1.Set("x-b3-sampled", "true")
581				knownCarrier1.Set("ot-baggage-checked", "baggage")
582
583				context, err := tracer.Extract(opentracing.TextMap, knownCarrier1)
584				Expect(err).To(BeNil())
585				Expect(context).To(BeEquivalentTo(knownContext2))
586			})
587
588			It("should parse most significant 64 bits of a 128-bit TraceID into TraceIDUpper", func() {
589				knownCarrier1.Set("x-b3-spanid", "1add0d865432457")
590				knownCarrier1.Set("x-b3-traceid", "ffffffffffffffff0bb8e2e5f235999d")
591				knownCarrier1.Set("x-b3-sampled", "1")
592				knownCarrier1.Set("ot-baggage-checked", "more-baggage")
593
594				context, err := tracer.Extract(opentracing.TextMap, knownCarrier1)
595				Expect(err).To(BeNil())
596				Expect(context).To(BeEquivalentTo(knownContext3))
597			})
598
599			It("should error with a 31 character-long Trace ID", func() {
600				knownCarrier1.Set("x-b3-traceid", "fffffffffffffff0bb8e2e5f235999d")
601
602				context, err := tracer.Extract(opentracing.TextMap, knownCarrier1)
603				Expect(err).To(HaveOccurred())
604				Expect(context).To(BeNil())
605			})
606		})
607	}
608
609	Context("with http enabled", func() {
610		BeforeEach(func() {
611			options.UseHttp = true
612		})
613
614		// TODO(dolan) - Add http tests.
615	})
616
617	Context("with grpc enabled", func() {
618		BeforeEach(func() {
619			options.UseGRPC = true
620			fakeClient = newGrpcFakeClient()
621		})
622
623		ItShouldBehaveLikeATracer(
624			thatSupportsBaggage(),
625			thatSupportsReference(),
626			thatSupportsTypedValues(),
627		)
628	})
629})
630