1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package propagation_test
16
17 import (
18 "context"
19 "net/http"
20 "net/url"
21 "strings"
22 "testing"
23
24 "github.com/google/go-cmp/cmp"
25 "github.com/stretchr/testify/assert"
26
27 "go.opentelemetry.io/otel/baggage"
28 "go.opentelemetry.io/otel/propagation"
29 )
30
31 type property struct {
32 Key, Value string
33 }
34
35 type member struct {
36 Key, Value string
37
38 Properties []property
39 }
40
41 func (m member) Member(t *testing.T) baggage.Member {
42 props := make([]baggage.Property, 0, len(m.Properties))
43 for _, p := range m.Properties {
44 p, err := baggage.NewKeyValueProperty(p.Key, p.Value)
45 if err != nil {
46 t.Fatal(err)
47 }
48 props = append(props, p)
49 }
50 bMember, err := baggage.NewMember(m.Key, url.QueryEscape(m.Value), props...)
51 if err != nil {
52 t.Fatal(err)
53 }
54 return bMember
55 }
56
57 type members []member
58
59 func (m members) Baggage(t *testing.T) baggage.Baggage {
60 bMembers := make([]baggage.Member, 0, len(m))
61 for _, mem := range m {
62 bMembers = append(bMembers, mem.Member(t))
63 }
64 bag, err := baggage.New(bMembers...)
65 if err != nil {
66 t.Fatal(err)
67 }
68 return bag
69 }
70
71 func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
72 prop := propagation.TextMapPropagator(propagation.Baggage{})
73 tests := []struct {
74 name string
75 header string
76 want members
77 }{
78 {
79 name: "valid w3cHeader",
80 header: "key1=val1,key2=val2",
81 want: members{
82 {Key: "key1", Value: "val1"},
83 {Key: "key2", Value: "val2"},
84 },
85 },
86 {
87 name: "valid w3cHeader with spaces",
88 header: "key1 = val1, key2 =val2 ",
89 want: members{
90 {Key: "key1", Value: "val1"},
91 {Key: "key2", Value: "val2"},
92 },
93 },
94 {
95 name: "valid w3cHeader with properties",
96 header: "key1=val1,key2=val2;prop=1",
97 want: members{
98 {Key: "key1", Value: "val1"},
99 {
100 Key: "key2",
101 Value: "val2",
102 Properties: []property{
103 {Key: "prop", Value: "1"},
104 },
105 },
106 },
107 },
108 {
109 name: "valid header with an invalid header",
110 header: "key1=val1,key2=val2,a,val3",
111 want: members{},
112 },
113 {
114 name: "valid header with no value",
115 header: "key1=,key2=val2",
116 want: members{
117 {Key: "key1", Value: ""},
118 {Key: "key2", Value: "val2"},
119 },
120 },
121 {
122 name: "valid header with url encoded string",
123 header: "key1=val%252",
124 want: members{
125 {Key: "key1", Value: "val%2"},
126 },
127 },
128 }
129
130 for _, tt := range tests {
131 t.Run(tt.name, func(t *testing.T) {
132 req, _ := http.NewRequest("GET", "http://example.com", nil)
133 req.Header.Set("baggage", tt.header)
134
135 ctx := context.Background()
136 ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
137 expected := tt.want.Baggage(t)
138 assert.Equal(t, expected, baggage.FromContext(ctx))
139 })
140 }
141 }
142
143 func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
144 prop := propagation.TextMapPropagator(propagation.Baggage{})
145 tests := []struct {
146 name string
147 header string
148 has members
149 }{
150 {
151 name: "no key values",
152 header: "header1",
153 },
154 {
155 name: "invalid header with existing context",
156 header: "header2",
157 has: members{
158 {Key: "key1", Value: "val1"},
159 {Key: "key2", Value: "val2"},
160 },
161 },
162 {
163 name: "empty header value",
164 header: "",
165 has: members{
166 {Key: "key1", Value: "val1"},
167 {Key: "key2", Value: "val2"},
168 },
169 },
170 {
171 name: "with properties",
172 header: "key1=val1,key2=val2;prop=1",
173 has: members{
174 {Key: "key1", Value: "val1"},
175 {
176 Key: "key2",
177 Value: "val2",
178 Properties: []property{
179 {Key: "prop", Value: "1"},
180 },
181 },
182 },
183 },
184 }
185
186 for _, tt := range tests {
187 t.Run(tt.name, func(t *testing.T) {
188 req, _ := http.NewRequest("GET", "http://example.com", nil)
189 req.Header.Set("baggage", tt.header)
190
191 expected := tt.has.Baggage(t)
192 ctx := baggage.ContextWithBaggage(context.Background(), expected)
193 ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
194 assert.Equal(t, expected, baggage.FromContext(ctx))
195 })
196 }
197 }
198
199 func TestInjectBaggageToHTTPReq(t *testing.T) {
200 propagator := propagation.Baggage{}
201 tests := []struct {
202 name string
203 mems members
204 wantInHeader []string
205 }{
206 {
207 name: "two simple values",
208 mems: members{
209 {Key: "key1", Value: "val1"},
210 {Key: "key2", Value: "val2"},
211 },
212 wantInHeader: []string{"key1=val1", "key2=val2"},
213 },
214 {
215 name: "values with escaped chars",
216 mems: members{
217 {Key: "key2", Value: "val3=4"},
218 },
219 wantInHeader: []string{"key2=val3%3D4"},
220 },
221 {
222 name: "with properties",
223 mems: members{
224 {Key: "key1", Value: "val1"},
225 {
226 Key: "key2",
227 Value: "val2",
228 Properties: []property{
229 {Key: "prop", Value: "1"},
230 },
231 },
232 },
233 wantInHeader: []string{
234 "key1=val1",
235 "key2=val2;prop=1",
236 },
237 },
238 }
239 for _, tt := range tests {
240 t.Run(tt.name, func(t *testing.T) {
241 req, _ := http.NewRequest("GET", "http://example.com", nil)
242 ctx := baggage.ContextWithBaggage(context.Background(), tt.mems.Baggage(t))
243 propagator.Inject(ctx, propagation.HeaderCarrier(req.Header))
244
245 got := strings.Split(req.Header.Get("baggage"), ",")
246 assert.ElementsMatch(t, tt.wantInHeader, got)
247 })
248 }
249 }
250
251 func TestBaggagePropagatorGetAllKeys(t *testing.T) {
252 var propagator propagation.Baggage
253 want := []string{"baggage"}
254 got := propagator.Fields()
255 if diff := cmp.Diff(got, want); diff != "" {
256 t.Errorf("GetAllKeys: -got +want %s", diff)
257 }
258 }
259
View as plain text