22
22
23
23
24
24
def get_as_list (
25
- dict_object : typing .Dict [str , str ], key : str
25
+ dict_object : typing .Dict [str , typing . List [ str ] ], key : str
26
26
) -> typing .List [str ]:
27
27
value = dict_object .get (key )
28
- return [ value ] if value is not None else []
28
+ return value if value is not None else []
29
29
30
30
31
31
class TestTraceContextFormat (unittest .TestCase ):
@@ -40,64 +40,10 @@ def test_no_traceparent_header(self):
40
40
41
41
If no traceparent header is received, the vendor creates a new trace-id and parent-id that represents the current request.
42
42
"""
43
- output = {} # type:typing.Dict[str, str]
43
+ output = {} # type:typing.Dict[str, typing.List[ str] ]
44
44
span_context = FORMAT .extract (get_as_list , output )
45
45
self .assertTrue (isinstance (span_context , trace .SpanContext ))
46
46
47
- def test_from_headers_tracestate_entry_limit (self ):
48
- """If more than 33 entries are passed, allow them.
49
-
50
- We are explicitly choosing not to limit the list members
51
- as outlined in RFC 3.3.1.1
52
-
53
- RFC 3.3.1.1
54
-
55
- There can be a maximum of 32 list-members in a list.
56
- """
57
-
58
- span_context = FORMAT .extract (
59
- get_as_list ,
60
- {
61
- "traceparent" : "00-12345678901234567890123456789012-1234567890123456-00" ,
62
- "tracestate" : "," .join (
63
- [
64
- "a00=0,a01=1,a02=2,a03=3,a04=4,a05=5,a06=6,a07=7,a08=8,a09=9" ,
65
- "b00=0,b01=1,b02=2,b03=3,b04=4,b05=5,b06=6,b07=7,b08=8,b09=9" ,
66
- "c00=0,c01=1,c02=2,c03=3,c04=4,c05=5,c06=6,c07=7,c08=8,c09=9" ,
67
- "d00=0,d01=1,d02=2" ,
68
- ]
69
- ),
70
- },
71
- )
72
- self .assertEqual (len (span_context .trace_state ), 33 )
73
-
74
- def test_from_headers_tracestate_duplicated_keys (self ):
75
- """If a duplicate tracestate header is present, the most recent entry
76
- is used.
77
-
78
- RFC 3.3.1.4
79
-
80
- Only one entry per key is allowed because the entry represents that last position in the trace.
81
- Hence vendors must overwrite their entry upon reentry to their tracing system.
82
-
83
- For example, if a vendor name is Congo and a trace started in their system and then went through
84
- a system named Rojo and later returned to Congo, the tracestate value would not be:
85
-
86
- congo=congosFirstPosition,rojo=rojosFirstPosition,congo=congosSecondPosition
87
-
88
- Instead, the entry would be rewritten to only include the most recent position:
89
-
90
- congo=congosSecondPosition,rojo=rojosFirstPosition
91
- """
92
- span_context = FORMAT .extract (
93
- get_as_list ,
94
- {
95
- "traceparent" : "00-12345678901234567890123456789012-1234567890123456-00" ,
96
- "tracestate" : "foo=1,bar=2,foo=3" ,
97
- },
98
- )
99
- self .assertEqual (span_context .trace_state , {"foo" : "3" , "bar" : "2" })
100
-
101
47
def test_headers_with_tracestate (self ):
102
48
"""When there is a traceparent and tracestate header, data from
103
49
both should be addded to the SpanContext.
@@ -109,7 +55,10 @@ def test_headers_with_tracestate(self):
109
55
tracestate_value = "foo=1,bar=2,baz=3"
110
56
span_context = FORMAT .extract (
111
57
get_as_list ,
112
- {"traceparent" : traceparent_value , "tracestate" : tracestate_value },
58
+ {
59
+ "traceparent" : [traceparent_value ],
60
+ "tracestate" : [tracestate_value ],
61
+ },
113
62
)
114
63
self .assertEqual (span_context .trace_id , self .TRACE_ID )
115
64
self .assertEqual (span_context .span_id , self .SPAN_ID )
@@ -125,7 +74,8 @@ def test_headers_with_tracestate(self):
125
74
self .assertEqual (output ["tracestate" ].count ("," ), 2 )
126
75
127
76
def test_invalid_trace_id (self ):
128
- """If the trace id is invalid, we must ignore the full traceparent header.
77
+ """If the trace id is invalid, we must ignore the full traceparent header,
78
+ and return a random, valid trace.
129
79
130
80
Also ignore any tracestate.
131
81
@@ -142,8 +92,10 @@ def test_invalid_trace_id(self):
142
92
span_context = FORMAT .extract (
143
93
get_as_list ,
144
94
{
145
- "traceparent" : "00-00000000000000000000000000000000-1234567890123456-00" ,
146
- "tracestate" : "foo=1,bar=2,foo=3" ,
95
+ "traceparent" : [
96
+ "00-00000000000000000000000000000000-1234567890123456-00"
97
+ ],
98
+ "tracestate" : ["foo=1,bar=2,foo=3" ],
147
99
},
148
100
)
149
101
self .assertEqual (span_context , trace .INVALID_SPAN_CONTEXT )
@@ -166,8 +118,10 @@ def test_invalid_parent_id(self):
166
118
span_context = FORMAT .extract (
167
119
get_as_list ,
168
120
{
169
- "traceparent" : "00-00000000000000000000000000000000-0000000000000000-00" ,
170
- "tracestate" : "foo=1,bar=2,foo=3" ,
121
+ "traceparent" : [
122
+ "00-00000000000000000000000000000000-0000000000000000-00"
123
+ ],
124
+ "tracestate" : ["foo=1,bar=2,foo=3" ],
171
125
},
172
126
)
173
127
self .assertEqual (span_context , trace .INVALID_SPAN_CONTEXT )
@@ -195,14 +149,15 @@ def test_format_not_supported(self):
195
149
196
150
RFC 4.3
197
151
198
- If the version cannot be parsed, the vendor creates a new traceparent header and
199
- deletes tracestate.
152
+ If the version cannot be parsed, return an invalid trace header.
200
153
"""
201
154
span_context = FORMAT .extract (
202
155
get_as_list ,
203
156
{
204
- "traceparent" : "00-12345678901234567890123456789012-1234567890123456-00-residue" ,
205
- "tracestate" : "foo=1,bar=2,foo=3" ,
157
+ "traceparent" : [
158
+ "00-12345678901234567890123456789012-1234567890123456-00-residue"
159
+ ],
160
+ "tracestate" : ["foo=1,bar=2,foo=3" ],
206
161
},
207
162
)
208
163
self .assertEqual (span_context , trace .INVALID_SPAN_CONTEXT )
@@ -213,3 +168,30 @@ def test_propagate_invalid_context(self):
213
168
output = {} # type:typing.Dict[str, str]
214
169
FORMAT .inject (trace .INVALID_SPAN_CONTEXT , dict .__setitem__ , output )
215
170
self .assertFalse ("traceparent" in output )
171
+
172
+ def test_tracestate_empty_header (self ):
173
+ """Test tracestate with an additional empty header (should be ignored)"""
174
+ span_context = FORMAT .extract (
175
+ get_as_list ,
176
+ {
177
+ "traceparent" : [
178
+ "00-12345678901234567890123456789012-1234567890123456-00"
179
+ ],
180
+ "tracestate" : ["foo=1" , "" ],
181
+ },
182
+ )
183
+ self .assertEqual (span_context .trace_state ["foo" ], "1" )
184
+
185
+ def test_tracestate_header_with_trailing_comma (self ):
186
+ """Do not propagate invalid trace context.
187
+ """
188
+ span_context = FORMAT .extract (
189
+ get_as_list ,
190
+ {
191
+ "traceparent" : [
192
+ "00-12345678901234567890123456789012-1234567890123456-00"
193
+ ],
194
+ "tracestate" : ["foo=1," ],
195
+ },
196
+ )
197
+ self .assertEqual (span_context .trace_state ["foo" ], "1" )
0 commit comments