1// Copyright (c) 2017 Uber Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package zipkin
16
17import (
18	"strconv"
19	"testing"
20
21	opentracing "github.com/opentracing/opentracing-go"
22	"github.com/stretchr/testify/assert"
23	"github.com/stretchr/testify/require"
24	"github.com/uber/jaeger-client-go"
25)
26
27var (
28	rootSampled       = newSpanContext(1, 2, 0, true, map[string]string{"foo": "bar"})
29	nonRootSampled    = newSpanContext(1, 2, 1, true, nil)
30	nonRootNonSampled = newSpanContext(1, 2, 1, false, nil)
31)
32
33var (
34	rootSampledHeader = opentracing.TextMapCarrier{
35		"x-b3-traceid": "0000000000000001",
36		"x-b3-spanid":  "2",
37		"x-b3-sampled": "1",
38		"baggage-foo":  "bar",
39	}
40	nonRootSampledHeader = opentracing.TextMapCarrier{
41		"x-b3-traceid":      "0000000000000001",
42		"x-b3-spanid":       "2",
43		"x-b3-parentspanid": "1",
44		"x-b3-sampled":      "1",
45	}
46	nonRootNonSampledHeader = opentracing.TextMapCarrier{
47		"x-b3-traceid":      "0000000000000001",
48		"x-b3-spanid":       "2",
49		"x-b3-parentspanid": "1",
50		"x-b3-sampled":      "0",
51	}
52	rootSampledBooleanHeader = opentracing.TextMapCarrier{
53		"x-b3-traceid": "0000000000000001",
54		"x-b3-spanid":  "2",
55		"x-b3-sampled": "true",
56		"baggage-foo":  "bar",
57	}
58	nonRootSampledBooleanHeader = opentracing.TextMapCarrier{
59		"x-b3-traceid":      "0000000000000001",
60		"x-b3-spanid":       "2",
61		"x-b3-parentspanid": "1",
62		"x-b3-sampled":      "true",
63	}
64	invalidHeader = opentracing.TextMapCarrier{
65		"x-b3-traceid":      "jdkafhsd",
66		"x-b3-spanid":       "afsdfsdf",
67		"x-b3-parentspanid": "hiagggdf",
68		"x-b3-sampled":      "sdfgsdfg",
69	}
70	sampled128bitTraceID = opentracing.TextMapCarrier{
71		"x-b3-traceid": "463ac35c9f6413ad48485a3953bb6124",
72		"x-b3-spanid":  "2",
73		"x-b3-sampled": "1",
74	}
75	invalidTraceID = opentracing.TextMapCarrier{
76		"x-b3-traceid": "00000000000000000000000000000000",
77		"x-b3-spanid":  "2",
78		"x-b3-sampled": "1",
79	}
80)
81
82var (
83	propagator = NewZipkinB3HTTPHeaderPropagator()
84)
85
86func newSpanContext(traceID, spanID, parentID uint64, sampled bool, baggage map[string]string) jaeger.SpanContext {
87	return jaeger.NewSpanContext(
88		jaeger.TraceID{Low: traceID},
89		jaeger.SpanID(spanID),
90		jaeger.SpanID(parentID),
91		sampled,
92		baggage,
93	)
94}
95
96func TestExtractorInvalid(t *testing.T) {
97	_, err := propagator.Extract(invalidHeader)
98	assert.Error(t, err)
99}
100
101func TestExtractorRootSampled(t *testing.T) {
102	ctx, err := propagator.Extract(rootSampledHeader)
103	assert.Nil(t, err)
104	assert.EqualValues(t, rootSampled, ctx)
105}
106
107func TestExtractorNonRootSampled(t *testing.T) {
108	ctx, err := propagator.Extract(nonRootSampledHeader)
109	assert.Nil(t, err)
110	assert.EqualValues(t, nonRootSampled, ctx)
111}
112
113func TestExtractorNonRootNonSampled(t *testing.T) {
114	ctx, err := propagator.Extract(nonRootNonSampledHeader)
115	assert.Nil(t, err)
116	assert.EqualValues(t, nonRootNonSampled, ctx)
117}
118
119func TestExtractorRootSampledBoolean(t *testing.T) {
120	ctx, err := propagator.Extract(rootSampledBooleanHeader)
121	assert.Nil(t, err)
122	assert.EqualValues(t, rootSampled, ctx)
123}
124
125func TestExtractorNonRootSampledBoolean(t *testing.T) {
126	ctx, err := propagator.Extract(nonRootSampledBooleanHeader)
127	assert.Nil(t, err)
128	assert.EqualValues(t, nonRootSampled, ctx)
129}
130
131func TestInjectorRootSampled(t *testing.T) {
132	hdr := opentracing.TextMapCarrier{}
133	err := propagator.Inject(rootSampled, hdr)
134	assert.Nil(t, err)
135	assert.EqualValues(t, rootSampledHeader, hdr)
136}
137
138func TestInjectorNonRootSampled(t *testing.T) {
139	hdr := opentracing.TextMapCarrier{}
140	err := propagator.Inject(nonRootSampled, hdr)
141	assert.Nil(t, err)
142	assert.EqualValues(t, nonRootSampledHeader, hdr)
143}
144
145func TestInjectorNonRootNonSampled(t *testing.T) {
146	hdr := opentracing.TextMapCarrier{}
147	err := propagator.Inject(nonRootNonSampled, hdr)
148	assert.Nil(t, err)
149	assert.EqualValues(t, nonRootNonSampledHeader, hdr)
150}
151
152func TestCustomBaggagePrefix(t *testing.T) {
153	propag := NewZipkinB3HTTPHeaderPropagator(BaggagePrefix("emoji:)"))
154	hdr := opentracing.TextMapCarrier{}
155	sc := newSpanContext(1, 2, 0, true, map[string]string{"foo": "bar"})
156	err := propag.Inject(sc, hdr)
157	assert.Nil(t, err)
158	m := opentracing.TextMapCarrier{
159		"x-b3-traceid": "0000000000000001",
160		"x-b3-spanid":  "2",
161		"x-b3-sampled": "1",
162		"emoji:)foo":   "bar",
163	}
164	assert.EqualValues(t, m, hdr)
165
166	sc, err = propag.Extract(m)
167	require.NoError(t, err)
168	sc.ForeachBaggageItem(func(k, v string) bool {
169		assert.Equal(t, "foo", k)
170		assert.Equal(t, "bar", v)
171		return true
172	})
173}
174
175func Test128bitTraceID(t *testing.T) {
176	spanCtx, err := propagator.Extract(sampled128bitTraceID)
177	assert.Nil(t, err)
178
179	high, _ := strconv.ParseUint("463ac35c9f6413ad", 16, 64)
180	low, _ := strconv.ParseUint("48485a3953bb6124", 16, 64)
181	assert.EqualValues(t, jaeger.TraceID{High: high, Low: low}, spanCtx.TraceID())
182
183	hdr := opentracing.TextMapCarrier{}
184	err = propagator.Inject(spanCtx, hdr)
185	assert.Nil(t, err)
186	assert.EqualValues(t, sampled128bitTraceID["x-b3-traceid"], hdr["x-b3-traceid"])
187}
188
189func TestInvalid128bitTraceID(t *testing.T) {
190	_, err := propagator.Extract(invalidTraceID)
191	assert.EqualError(t, err, opentracing.ErrSpanContextNotFound.Error())
192}
193