@@ -161,19 +161,20 @@ class TestEncoders(TestCase):
161161
162162 def test_encode_traces_json (self ):
163163 # test encoding for JSON format
164- traces = []
165- traces .append (
164+ traces = [
166165 [
167166 Span (name = "client.testing" , tracer = None ),
168167 Span (name = "client.testing" , tracer = None ),
169- ]
170- )
171- traces .append (
168+ ],
172169 [
173170 Span (name = "client.testing" , tracer = None ),
174171 Span (name = "client.testing" , tracer = None ),
175- ]
176- )
172+ ],
173+ [
174+ Span (name = b"client.testing" , tracer = None ),
175+ Span (name = b"client.testing" , tracer = None ),
176+ ],
177+ ]
177178
178179 encoder = JSONEncoder ()
179180 spans = encoder .encode_traces (traces )
@@ -182,39 +183,42 @@ def test_encode_traces_json(self):
182183 # test the encoded output that should be a string
183184 # and the output must be flatten
184185 assert isinstance (spans , string_type )
185- assert len (items ) == 2
186+ assert len (items ) == 3
186187 assert len (items [0 ]) == 2
187188 assert len (items [1 ]) == 2
188- for i in range (2 ):
189+ assert len (items [2 ]) == 2
190+ for i in range (3 ):
189191 for j in range (2 ):
190192 assert "client.testing" == items [i ][j ]["name" ]
191193
192194 def test_encode_traces_json_v2 (self ):
193195 # test encoding for JSON format
194- traces = []
195- traces .append (
196+ traces = [
196197 [
197198 Span (name = "client.testing" , tracer = None , span_id = 0xAAAAAA ),
198199 Span (name = "client.testing" , tracer = None , span_id = 0xAAAAAA ),
199- ]
200- )
201- traces .append (
200+ ],
202201 [
203202 Span (name = "client.testing" , tracer = None , span_id = 0xAAAAAA ),
204203 Span (name = "client.testing" , tracer = None , span_id = 0xAAAAAA ),
205- ]
206- )
204+ ],
205+ [
206+ Span (name = b"client.testing" , tracer = None , span_id = 0xAAAAAA ),
207+ Span (name = b"client.testing" , tracer = None , span_id = 0xAAAAAA ),
208+ ],
209+ ]
207210
208211 encoder = JSONEncoderV2 ()
209212 spans = encoder .encode_traces (traces )
210213 items = json .loads (spans )["traces" ]
211214 # test the encoded output that should be a string
212215 # and the output must be flatten
213216 assert isinstance (spans , string_type )
214- assert len (items ) == 2
217+ assert len (items ) == 3
215218 assert len (items [0 ]) == 2
216219 assert len (items [1 ]) == 2
217- for i in range (2 ):
220+ assert len (items [2 ]) == 2
221+ for i in range (3 ):
218222 for j in range (2 ):
219223 assert "client.testing" == items [i ][j ]["name" ]
220224 assert isinstance (items [i ][j ]["span_id" ], string_type )
@@ -235,17 +239,24 @@ def test_encode_traces_msgpack_v03(self):
235239 Span (name = "client.testing" , tracer = None ),
236240 ]
237241 )
242+ encoder .put (
243+ [
244+ Span (name = b"client.testing" , tracer = None ),
245+ Span (name = b"client.testing" , tracer = None ),
246+ ]
247+ )
238248
239249 spans = encoder .encode ()
240250 items = encoder ._decode (spans )
241251
242252 # test the encoded output that should be a string
243253 # and the output must be flatten
244254 assert isinstance (spans , msgpack_type )
245- assert len (items ) == 2
255+ assert len (items ) == 3
246256 assert len (items [0 ]) == 2
247257 assert len (items [1 ]) == 2
248- for i in range (2 ):
258+ assert len (items [2 ]) == 2
259+ for i in range (3 ):
249260 for j in range (2 ):
250261 assert b"client.testing" == items [i ][j ][b"name" ]
251262
@@ -628,3 +639,53 @@ def run(self):
628639
629640 unpacked = decode (encoder .encode (), reconstruct = True )
630641 assert unpacked is not None
642+
643+
644+ @pytest .mark .parametrize ("encoder_cls" , ["JSONEncoder" , "JSONEncoderV2" ])
645+ def test_json_encoder_traces_bytes (encoder_cls , run_python_code_in_subprocess ):
646+ """
647+ Regression test for: https://github.com/DataDog/dd-trace-py/issues/3115
648+
649+ Ensure we properly decode `bytes` objects when encoding with the JSONEncoder
650+ """
651+ # Run test in a subprocess to test without setting file encoding to utf-8
652+ code = """
653+ import json
654+
655+ from ddtrace.internal.compat import PY3
656+ from ddtrace.internal.encoding import {0}
657+ from ddtrace.span import Span
658+
659+ encoder = {0}()
660+ data = encoder.encode_traces(
661+ [
662+ [
663+ Span(name=b"\\ x80span.a", tracer=None),
664+ Span(name=u"\\ x80span.b", tracer=None),
665+ Span(name="\\ x80span.b", tracer=None),
666+ ]
667+ ]
668+ )
669+ traces = json.loads(data)
670+ if "{0}" == "JSONEncoderV2":
671+ traces = traces["traces"]
672+
673+ assert len(traces) == 1
674+ span_a, span_b, span_c = traces[0]
675+
676+ if PY3:
677+ assert "\\ \\ x80span.a" == span_a["name"]
678+ assert u"\\ x80span.b" == span_b["name"]
679+ assert u"\\ x80span.b" == span_c["name"]
680+ else:
681+ assert u"\\ ufffdspan.a" == span_a["name"]
682+ assert u"\\ x80span.b" == span_b["name"]
683+ assert u"\\ ufffdspan.b" == span_c["name"]
684+ """ .format (
685+ encoder_cls
686+ )
687+
688+ out , err , status , pid = run_python_code_in_subprocess (code )
689+ assert status == 0 , err
690+ assert out == b""
691+ assert err == b""
0 commit comments