|
22 | 22 | #include <chrono>
|
23 | 23 | #include <ctime>
|
24 | 24 | #include <iosfwd>
|
| 25 | +#include <stdexcept> |
25 | 26 |
|
26 | 27 | #include "matchers.h"
|
27 | 28 | #include "mocks/collectors.h"
|
@@ -1175,3 +1176,116 @@ TEST_CASE(
|
1175 | 1176 | REQUIRE(found->second ==
|
1176 | 1177 | test_case.expected_error_prefix + test_case.tid_tag_value);
|
1177 | 1178 | }
|
| 1179 | + |
| 1180 | +TEST_CASE("heterogeneous extraction") { |
| 1181 | + // These test cases verify that when W3C is among the configured extraction |
| 1182 | + // styles, then non-Datadog and unexpected Datadog fields in an incoming |
| 1183 | + // `tracestate` are extracted, under certain conditions, even when trace |
| 1184 | + // context was extracted in a non-W3C style. |
| 1185 | + // |
| 1186 | + // The idea is that a tracer might be configured to extract, e.g., |
| 1187 | + // [DATADOG, B3, W3C] and to inject [DATADOG, W3C]. We want to make |
| 1188 | + // sure that no W3C-relevant information from the incoming request is lost in |
| 1189 | + // the outgoing W3C headers, even if trace context is extracted on account of |
| 1190 | + // DATADOG or B3. |
| 1191 | + // |
| 1192 | + // See the `TestCase` instances, below, for more information. |
| 1193 | + |
| 1194 | + class MockIDGenerator : public IDGenerator { |
| 1195 | + public: |
| 1196 | + TraceID trace_id(const TimePoint&) const override { |
| 1197 | + throw std::logic_error("This test should not generate a trace ID."); |
| 1198 | + } |
| 1199 | + std::uint64_t span_id() const override { return 0x2a; } |
| 1200 | + }; |
| 1201 | + |
| 1202 | + struct TestCase { |
| 1203 | + int line; |
| 1204 | + std::string description; |
| 1205 | + std::vector<PropagationStyle> extraction_styles; |
| 1206 | + std::vector<PropagationStyle> injection_styles; |
| 1207 | + std::unordered_map<std::string, std::string> extracted_headers; |
| 1208 | + std::unordered_map<std::string, std::string> expected_injected_headers; |
| 1209 | + }; |
| 1210 | + |
| 1211 | + // clang-format off |
| 1212 | + auto test_case = GENERATE(values<TestCase>({ |
| 1213 | + {__LINE__, "tracestate from primary style", |
| 1214 | + {PropagationStyle::W3C, PropagationStyle::DATADOG}, |
| 1215 | + {PropagationStyle::W3C}, |
| 1216 | + {{"traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"}, |
| 1217 | + {"tracestate", "dd=foo:bar,lol=wut"}}, |
| 1218 | + {{"traceparent", "00-4bf92f3577b34da6a3ce929d0e0e4736-000000000000002a-01"}, |
| 1219 | + {"tracestate", "dd=s:1;foo:bar,lol=wut"}}}, |
| 1220 | + |
| 1221 | + {__LINE__, "tracestate from subsequent style", |
| 1222 | + {PropagationStyle::DATADOG, PropagationStyle::W3C}, |
| 1223 | + {PropagationStyle::W3C}, |
| 1224 | + {{"x-datadog-trace-id", "48"}, {"x-datadog-parent-id", "64"}, |
| 1225 | + {"x-datadog-origin", "Kansas"}, {"x-datadog-sampling-priority", "2"}, |
| 1226 | + {"traceparent", "00-00000000000000000000000000000030-0000000000000040-01"}, |
| 1227 | + {"tracestate", "competitor=stuff,dd=o:Nebraska;s:1;ah:choo"}}, // origin is different |
| 1228 | + {{"traceparent", "00-00000000000000000000000000000030-000000000000002a-01"}, |
| 1229 | + {"tracestate", "dd=s:2;o:Kansas;ah:choo,competitor=stuff"}}}, |
| 1230 | + |
| 1231 | + {__LINE__, "ignore interlopers", |
| 1232 | + {PropagationStyle::DATADOG, PropagationStyle::B3, PropagationStyle::W3C}, |
| 1233 | + {PropagationStyle::W3C}, |
| 1234 | + {{"x-datadog-trace-id", "48"}, {"x-datadog-parent-id", "64"}, |
| 1235 | + {"x-datadog-origin", "Kansas"}, {"x-datadog-sampling-priority", "2"}, |
| 1236 | + {"x-b3-traceid", "00000000000000000000000000000030"}, |
| 1237 | + {"x-b3-parentspanid", "000000000000002a"}, |
| 1238 | + {"x-b3-sampled", "0"}, // sampling is different |
| 1239 | + {"traceparent", "00-00000000000000000000000000000030-0000000000000040-01"}, |
| 1240 | + {"tracestate", "competitor=stuff,dd=o:Nebraska;s:1;ah:choo"}}, |
| 1241 | + {{"traceparent", "00-00000000000000000000000000000030-000000000000002a-01"}, |
| 1242 | + {"tracestate", "dd=s:2;o:Kansas;ah:choo,competitor=stuff"}}}, |
| 1243 | + |
| 1244 | + {__LINE__, "don't take tracestate if trace ID doesn't match", |
| 1245 | + {PropagationStyle::DATADOG, PropagationStyle::W3C}, |
| 1246 | + {PropagationStyle::W3C}, |
| 1247 | + {{"x-datadog-trace-id", "48"}, {"x-datadog-parent-id", "64"}, |
| 1248 | + {"x-datadog-origin", "Kansas"}, {"x-datadog-sampling-priority", "2"}, |
| 1249 | + {"traceparent", "00-00000000000000000000000000000031-0000000000000040-01"}, |
| 1250 | + {"tracestate", "competitor=stuff,dd=o:Nebraska;s:1;ah:choo"}}, |
| 1251 | + {{"traceparent", "00-00000000000000000000000000000030-000000000000002a-01"}, |
| 1252 | + {"tracestate", "dd=s:2;o:Kansas"}}}, |
| 1253 | + |
| 1254 | + {__LINE__, "don't take tracestate if W3C extraction isn't configured", |
| 1255 | + {PropagationStyle::DATADOG, PropagationStyle::B3}, |
| 1256 | + {PropagationStyle::W3C}, |
| 1257 | + {{"x-datadog-trace-id", "48"}, {"x-datadog-parent-id", "64"}, |
| 1258 | + {"x-datadog-origin", "Kansas"}, {"x-datadog-sampling-priority", "2"}, |
| 1259 | + {"traceparent", "00-00000000000000000000000000000030-0000000000000040-01"}, |
| 1260 | + {"tracestate", "competitor=stuff,dd=o:Nebraska;s:1;ah:choo"}}, |
| 1261 | + {{"traceparent", "00-00000000000000000000000000000030-000000000000002a-01"}, |
| 1262 | + {"tracestate", "dd=s:2;o:Kansas"}}}, |
| 1263 | + })); |
| 1264 | + // clang-format on |
| 1265 | + |
| 1266 | + CAPTURE(test_case.line); |
| 1267 | + CAPTURE(test_case.description); |
| 1268 | + CAPTURE(to_json(test_case.extraction_styles)); |
| 1269 | + CAPTURE(to_json(test_case.injection_styles)); |
| 1270 | + CAPTURE(test_case.extracted_headers); |
| 1271 | + CAPTURE(test_case.expected_injected_headers); |
| 1272 | + |
| 1273 | + TracerConfig config; |
| 1274 | + config.defaults.service = "testsvc"; |
| 1275 | + config.extraction_styles = test_case.extraction_styles; |
| 1276 | + config.injection_styles = test_case.injection_styles; |
| 1277 | + config.logger = std::make_shared<NullLogger>(); |
| 1278 | + |
| 1279 | + auto finalized_config = finalize_config(config); |
| 1280 | + REQUIRE(finalized_config); |
| 1281 | + Tracer tracer{*finalized_config, std::make_shared<MockIDGenerator>()}; |
| 1282 | + |
| 1283 | + MockDictReader reader{test_case.extracted_headers}; |
| 1284 | + auto span = tracer.extract_span(reader); |
| 1285 | + REQUIRE(span); |
| 1286 | + |
| 1287 | + MockDictWriter writer; |
| 1288 | + span->inject(writer); |
| 1289 | + |
| 1290 | + REQUIRE(writer.items == test_case.expected_injected_headers); |
| 1291 | +} |
0 commit comments