]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // Copyright The OpenTelemetry Authors |
2 | // SPDX-License-Identifier: Apache-2.0 | |
3 | ||
4 | #include "opentelemetry/ext/zpages/tracez_data_aggregator.h" | |
5 | ||
6 | #include <gtest/gtest.h> | |
7 | ||
8 | #include "opentelemetry/ext/zpages/tracez_processor.h" | |
9 | #include "opentelemetry/sdk/resource/resource.h" | |
10 | #include "opentelemetry/sdk/trace/recordable.h" | |
11 | #include "opentelemetry/sdk/trace/tracer.h" | |
12 | ||
13 | using namespace opentelemetry::sdk::trace; | |
14 | using namespace opentelemetry::ext::zpages; | |
15 | namespace nostd = opentelemetry::nostd; | |
16 | namespace common = opentelemetry::common; | |
17 | using opentelemetry::common::SteadyTimestamp; | |
18 | using opentelemetry::trace::Span; | |
19 | ||
20 | const std::string span_name1 = "span 1"; | |
21 | const std::string span_name2 = "span 2"; | |
22 | const std::string span_name3 = "span 3"; | |
23 | ||
24 | /** | |
25 | * TODO: Due to the absence of way to simulate the passing of time in the | |
26 | * testing framework, synthetic delays had to be added in the tests to get the | |
27 | * object in question to perform correctly. Later on if something like this is | |
28 | * added the tests should be modified accordingly so that there is no external | |
29 | * dependency. | |
30 | * Additionally later on it would be better check for the span id(when set) | |
31 | * rather than span name. | |
32 | */ | |
33 | ||
34 | /** Test fixture for setting up the data aggregator and tracer for each test **/ | |
35 | class TracezDataAggregatorTest : public ::testing::Test | |
36 | { | |
37 | protected: | |
38 | void SetUp() override | |
39 | { | |
40 | std::shared_ptr<TracezSharedData> shared_data(new TracezSharedData()); | |
41 | auto resource = opentelemetry::sdk::resource::Resource::Create({}); | |
42 | std::unique_ptr<SpanProcessor> processor(new TracezSpanProcessor(shared_data)); | |
43 | std::vector<std::unique_ptr<SpanProcessor>> processors; | |
44 | processors.push_back(std::move(processor)); | |
45 | ||
46 | auto context = std::make_shared<TracerContext>(std::move(processors), resource); | |
47 | tracer = std::shared_ptr<opentelemetry::trace::Tracer>(new Tracer(context)); | |
48 | tracez_data_aggregator = std::unique_ptr<TracezDataAggregator>( | |
49 | new TracezDataAggregator(shared_data, milliseconds(10))); | |
50 | } | |
51 | ||
52 | std::unique_ptr<TracezDataAggregator> tracez_data_aggregator; | |
53 | std::shared_ptr<opentelemetry::trace::Tracer> tracer; | |
54 | }; | |
55 | ||
56 | /** | |
57 | * Helper function to check if the counts of running, error and latency spans | |
58 | * match what is expected | |
59 | */ | |
60 | void VerifySpanCountsInTracezData( | |
61 | const std::string &span_name, | |
62 | const TracezData &aggregated_data, | |
63 | size_t running_span_count, | |
64 | size_t error_span_count, | |
65 | std::array<unsigned int, kLatencyBoundaries.size()> completed_span_count_per_latency_bucket) | |
66 | { | |
67 | // Asserts are needed to check the size of the container because they may need | |
68 | // to be checked and if size checks fail it must be stopped | |
69 | EXPECT_EQ(aggregated_data.running_span_count, running_span_count) | |
70 | << " Count of running spans incorrect for " << span_name << "\n"; | |
71 | ||
72 | EXPECT_EQ(aggregated_data.sample_running_spans.size(), | |
73 | std::min<size_t>(running_span_count, kMaxNumberOfSampleSpans)) | |
74 | << " Size of sample running spans incorrect for " << span_name << "\n"; | |
75 | ||
76 | EXPECT_EQ(aggregated_data.error_span_count, error_span_count) | |
77 | << " Count of error spans incorrect for " << span_name << "\n"; | |
78 | ||
79 | EXPECT_EQ(aggregated_data.sample_error_spans.size(), | |
80 | std::min<size_t>(error_span_count, kMaxNumberOfSampleSpans)) | |
81 | << " Count of running spans incorrect for " << span_name << "\n"; | |
82 | ||
83 | for (unsigned int boundary = 0; boundary < kLatencyBoundaries.size(); boundary++) | |
84 | { | |
85 | EXPECT_EQ(aggregated_data.completed_span_count_per_latency_bucket[boundary], | |
86 | completed_span_count_per_latency_bucket[boundary]) | |
87 | << " Count of completed spans in latency boundary " << boundary << " incorrect for " | |
88 | << span_name << "\n"; | |
89 | EXPECT_EQ(aggregated_data.sample_latency_spans[boundary].size(), | |
90 | std::min<size_t>(completed_span_count_per_latency_bucket[boundary], | |
91 | kMaxNumberOfSampleSpans)) | |
92 | << " Count of sample completed spans in latency boundary " << boundary << " incorrect for " | |
93 | << span_name << "\n"; | |
94 | } | |
95 | } | |
96 | ||
97 | /**************************** No Span Test ************************************/ | |
98 | ||
99 | /** Test to check if data aggregator works as expected when there are no spans | |
100 | * **/ | |
101 | TEST_F(TracezDataAggregatorTest, NoSpans) | |
102 | { | |
103 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
104 | ASSERT_EQ(data.size(), 0); | |
105 | } | |
106 | ||
107 | /*********************** Single span tests ************************************/ | |
108 | ||
109 | /** Test to check if data aggregator works as expected when there are | |
110 | * is exactly a single running span **/ | |
111 | TEST_F(TracezDataAggregatorTest, SingleRunningSpan) | |
112 | { | |
113 | // Start the span get the data | |
114 | auto span_first = tracer->StartSpan(span_name1); | |
115 | std::this_thread::sleep_for(milliseconds(500)); | |
116 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
117 | ||
118 | // Check to see if span name exists | |
119 | ASSERT_EQ(data.size(), 1); | |
120 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
121 | auto &aggregated_data = data.at(span_name1); | |
122 | ||
123 | // Verify span counts then content of spans | |
124 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 1, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
125 | ||
126 | ASSERT_EQ(aggregated_data.sample_running_spans.size(), 1); | |
127 | ASSERT_EQ(aggregated_data.sample_running_spans.front().GetName().data(), span_name1); | |
128 | span_first->End(); | |
129 | } | |
130 | ||
131 | /** Test to check if data aggregator works as expected when there is exactly one | |
132 | * completed span **/ | |
133 | TEST_F(TracezDataAggregatorTest, SingleCompletedSpan) | |
134 | { | |
135 | // Start and end the span at a specified times | |
136 | opentelemetry::trace::StartSpanOptions start; | |
137 | start.start_steady_time = SteadyTimestamp(nanoseconds(10)); | |
138 | opentelemetry::trace::EndSpanOptions end; | |
139 | end.end_steady_time = SteadyTimestamp(nanoseconds(40)); | |
140 | tracer->StartSpan(span_name1, start)->End(end); | |
141 | ||
142 | // Get the data and make sure span name exists in the data | |
143 | std::this_thread::sleep_for(milliseconds(500)); | |
144 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
145 | ASSERT_EQ(data.size(), 1); | |
146 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
147 | ||
148 | auto &aggregated_data = data.at(span_name1); | |
149 | // Make sure counts of spans are in order | |
150 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 0, 0, {1, 0, 0, 0, 0, 0, 0, 0, 0}); | |
151 | ||
152 | // Check if the span is correctly updated in the first boundary | |
153 | ASSERT_EQ(aggregated_data.sample_latency_spans[LatencyBoundary::k0MicroTo10Micro].size(), 1); | |
154 | ASSERT_EQ(aggregated_data.sample_latency_spans[LatencyBoundary::k0MicroTo10Micro] | |
155 | .front() | |
156 | .GetDuration() | |
157 | .count(), | |
158 | 30); | |
159 | } | |
160 | ||
161 | /** Test to check if data aggregator works as expected when there is exactly | |
162 | * one error span **/ | |
163 | TEST_F(TracezDataAggregatorTest, SingleErrorSpan) | |
164 | { | |
165 | // Start and end a single error span | |
166 | auto span = tracer->StartSpan(span_name1); | |
167 | span->SetStatus(opentelemetry::trace::StatusCode::kError, "span cancelled"); | |
168 | span->End(); | |
169 | std::this_thread::sleep_for(milliseconds(500)); | |
170 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
171 | ||
172 | // Check to see if span name can be found in aggregation | |
173 | ASSERT_EQ(data.size(), 1); | |
174 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
175 | ||
176 | auto &aggregated_data = data.at(span_name1); | |
177 | // Make sure counts of spans are in order | |
178 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 0, 1, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
179 | ||
180 | // Check the value of the error span introduced | |
181 | ASSERT_EQ(aggregated_data.sample_error_spans.size(), 1); | |
182 | ASSERT_EQ(aggregated_data.sample_error_spans.front().GetName().data(), span_name1); | |
183 | } | |
184 | ||
185 | /************************* Multiple span tests ********************************/ | |
186 | ||
187 | /** Test to check if multiple running spans behaves as expected**/ | |
188 | TEST_F(TracezDataAggregatorTest, MultipleRunningSpans) | |
189 | { | |
190 | // A container that maps a span name to the number of spans to start with that | |
191 | // span name | |
192 | std::unordered_map<std::string, int> running_span_name_to_count({ | |
193 | {span_name1, 1}, | |
194 | {span_name2, 2}, | |
195 | {span_name3, 3}, | |
196 | }); | |
197 | ||
198 | // Start and store spans based on the above map | |
199 | std::vector<nostd::shared_ptr<Span>> running_span_container; | |
200 | for (auto span_name : running_span_name_to_count) | |
201 | { | |
202 | for (int count = 0; count < span_name.second; count++) | |
203 | running_span_container.push_back(tracer->StartSpan(span_name.first)); | |
204 | } | |
205 | ||
206 | // give time for aggregation and then get data | |
207 | std::this_thread::sleep_for(milliseconds(500)); | |
208 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
209 | ASSERT_EQ(data.size(), running_span_name_to_count.size()); | |
210 | ||
211 | // Check to see if the running span counts were updated correctly | |
212 | for (auto &span_name : running_span_name_to_count) | |
213 | { | |
214 | ASSERT_TRUE(data.find(span_name.first) != data.end()); | |
215 | ||
216 | // Make sure counts of spans are in order | |
217 | VerifySpanCountsInTracezData(span_name.first, data.at(span_name.first), span_name.second, 0, | |
218 | {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
219 | ||
220 | ASSERT_EQ(data.at(span_name.first).sample_running_spans.size(), span_name.second); | |
221 | for (auto &span_sample : data.at(span_name.first).sample_running_spans) | |
222 | { | |
223 | ASSERT_EQ(span_sample.GetName().data(), span_name.first); | |
224 | } | |
225 | } | |
226 | ||
227 | for (auto i = running_span_container.begin(); i != running_span_container.end(); i++) | |
228 | (*i)->End(); | |
229 | } | |
230 | ||
231 | /** Test to check if multiple completed spans updates the aggregated data | |
232 | * correctly **/ | |
233 | TEST_F(TracezDataAggregatorTest, MultipleCompletedSpan) | |
234 | { | |
235 | // Start spans with span name and the corresponding durations in one of the 9 | |
236 | // latency buckets | |
237 | const std::unordered_map<std::string, std::vector<std::vector<nanoseconds>>> | |
238 | span_name_to_duration( | |
239 | {{span_name1, {{nanoseconds(10), nanoseconds(4600)}, {}, {}, {}, {}, {}, {}, {}, {}}}, | |
240 | {span_name2, | |
241 | {{}, | |
242 | {nanoseconds(38888), nanoseconds(98768)}, | |
243 | {nanoseconds(983251)}, | |
244 | {}, | |
245 | {}, | |
246 | {}, | |
247 | {}, | |
248 | {}, | |
249 | {}}}, | |
250 | {span_name3, | |
251 | {{}, | |
252 | {}, | |
253 | {}, | |
254 | {nanoseconds(1234567), nanoseconds(1234567)}, | |
255 | {}, | |
256 | {}, | |
257 | {}, | |
258 | {}, | |
259 | {nanoseconds(9999999999999)}}}}); | |
260 | opentelemetry::trace::StartSpanOptions start; | |
261 | opentelemetry::trace::EndSpanOptions end; | |
262 | for (auto &span : span_name_to_duration) | |
263 | { | |
264 | for (auto &buckets : span.second) | |
265 | { | |
266 | for (auto &duration : buckets) | |
267 | { | |
268 | long long int end_time = duration.count() + 1; | |
269 | start.start_steady_time = SteadyTimestamp(nanoseconds(1)); | |
270 | end.end_steady_time = SteadyTimestamp(nanoseconds(end_time)); | |
271 | tracer->StartSpan(span.first, start)->End(end); | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | // Give time for aggregation and get data | |
277 | std::this_thread::sleep_for(milliseconds(500)); | |
278 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
279 | ||
280 | ASSERT_EQ(data.size(), span_name_to_duration.size()); | |
281 | ||
282 | for (auto &span : span_name_to_duration) | |
283 | { | |
284 | ASSERT_TRUE(data.find(span.first) != data.end()); | |
285 | auto &aggregated_data = data.at(span.first); | |
286 | ||
287 | // Make sure counts of spans are in order | |
288 | VerifySpanCountsInTracezData( | |
289 | span.first, aggregated_data, 0, 0, | |
290 | {(unsigned int)span.second[0].size(), (unsigned int)span.second[1].size(), | |
291 | (unsigned int)span.second[2].size(), (unsigned int)span.second[3].size(), | |
292 | (unsigned int)span.second[4].size(), (unsigned int)span.second[5].size(), | |
293 | (unsigned int)span.second[6].size(), (unsigned int)span.second[7].size(), | |
294 | (unsigned int)span.second[8].size()}); | |
295 | ||
296 | for (unsigned int boundary = 0; boundary < kLatencyBoundaries.size(); boundary++) | |
297 | { | |
298 | ASSERT_EQ(aggregated_data.sample_latency_spans[boundary].size(), | |
299 | span.second[boundary].size()); | |
300 | auto latency_sample = aggregated_data.sample_latency_spans[boundary].begin(); | |
301 | for (unsigned int idx = 0; idx < span.second[boundary].size(); idx++) | |
302 | { | |
303 | ASSERT_EQ(span.second[boundary][idx].count(), latency_sample->GetDuration().count()); | |
304 | latency_sample = std::next(latency_sample); | |
305 | } | |
306 | } | |
307 | } | |
308 | } | |
309 | ||
310 | /** | |
311 | * This test checks to see if the aggregated data is updated correctly | |
312 | * when there are multiple error spans. | |
313 | * It checks both the count of error spans and the error samples | |
314 | */ | |
315 | TEST_F(TracezDataAggregatorTest, MultipleErrorSpans) | |
316 | { | |
317 | // Container to store the span names --> error messges for the span name | |
318 | std::unordered_map<std::string, std::vector<std::string>> span_name_to_error( | |
319 | {{span_name1, {"span 1 error"}}, | |
320 | {span_name2, {"span 2 error 1", "span 2 error 2"}}, | |
321 | {span_name3, | |
322 | {"span 3 error 1", "span 3 error 2", "span 3 error 3", "span 3 error 4", | |
323 | "span 3 error 5"}}}); | |
324 | ||
325 | // Start spans with the error messages based on the map | |
326 | for (auto &span_error : span_name_to_error) | |
327 | { | |
328 | for (auto error_desc : span_error.second) | |
329 | { | |
330 | auto span = tracer->StartSpan(span_error.first); | |
331 | span->SetStatus(opentelemetry::trace::StatusCode::kError, error_desc); | |
332 | span->End(); | |
333 | } | |
334 | } | |
335 | ||
336 | // Give some time and then get data | |
337 | std::this_thread::sleep_for(milliseconds(500)); | |
338 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
339 | ASSERT_EQ(data.size(), span_name_to_error.size()); | |
340 | ||
341 | // Check if error spans were updated correctly for the different span names | |
342 | for (auto &span_error : span_name_to_error) | |
343 | { | |
344 | // First try to find the span name in aggregation, then check the count of | |
345 | // the error spans and then check values | |
346 | ASSERT_TRUE(data.find(span_error.first) != data.end()); | |
347 | ||
348 | auto &aggregated_data = data.at(span_error.first); | |
349 | ||
350 | // Make sure counts of spans are in order | |
351 | VerifySpanCountsInTracezData(span_error.first, aggregated_data, 0, span_error.second.size(), | |
352 | {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
353 | ASSERT_EQ(aggregated_data.error_span_count, span_error.second.size()); | |
354 | ||
355 | auto error_sample = aggregated_data.sample_error_spans.begin(); | |
356 | for (unsigned int idx = 0; idx < span_error.second.size(); idx++) | |
357 | { | |
358 | ASSERT_EQ(span_error.second[idx], error_sample->GetDescription()); | |
359 | error_sample = std::next(error_sample); | |
360 | } | |
361 | } | |
362 | } | |
363 | ||
364 | /************************ Sample spans tests **********************************/ | |
365 | ||
366 | /** | |
367 | * This test checks to see that the maximum number of running samples(5) for a | |
368 | * bucket is not exceeded. If there are more spans than this for a single bucket | |
369 | * it removes the earliest span that was received | |
370 | */ | |
371 | TEST_F(TracezDataAggregatorTest, RunningSampleSpansOverCapacity) | |
372 | { | |
373 | int running_span_count = 6; | |
374 | // Start and store spans based on the above map | |
375 | std::vector<nostd::shared_ptr<Span>> running_span_container; | |
376 | for (int count = 0; count < running_span_count; count++) | |
377 | running_span_container.push_back(tracer->StartSpan(span_name1)); | |
378 | ||
379 | std::this_thread::sleep_for(milliseconds(500)); | |
380 | // Fetch data and check if span name is spresent | |
381 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
382 | ASSERT_EQ(data.size(), 1); | |
383 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
384 | ||
385 | // Check if error spans are updated according to spans started | |
386 | auto &aggregated_data = data.at(span_name1); | |
387 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 6, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
388 | ||
389 | ASSERT_EQ(aggregated_data.sample_running_spans.size(), kMaxNumberOfSampleSpans); | |
390 | ||
391 | for (auto i = running_span_container.begin(); i != running_span_container.end(); i++) | |
392 | { | |
393 | (*i)->End(); | |
394 | } | |
395 | } | |
396 | ||
397 | /** | |
398 | * This test checks to see that the maximum number of error samples(5) for a | |
399 | * bucket is not exceeded. If there are more spans than this for a single bucket | |
400 | * it removes the earliest span that was received | |
401 | */ | |
402 | TEST_F(TracezDataAggregatorTest, ErrorSampleSpansOverCapacity) | |
403 | { | |
404 | // Create error spans with the descriptions in the vector | |
405 | std::vector<std::string> span_error_descriptions = {"error span 1", "error span 2", | |
406 | "error span 3", "error span 4", | |
407 | "error span 5", "error span 6"}; | |
408 | for (auto span_error_description : span_error_descriptions) | |
409 | { | |
410 | auto span = tracer->StartSpan(span_name1); | |
411 | span->SetStatus(opentelemetry::trace::StatusCode::kError, span_error_description); | |
412 | span->End(); | |
413 | } | |
414 | ||
415 | std::this_thread::sleep_for(milliseconds(500)); | |
416 | ||
417 | // Fetch data and check if span name is spresent | |
418 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
419 | ASSERT_EQ(data.size(), 1); | |
420 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
421 | ||
422 | std::this_thread::sleep_for(milliseconds(500)); | |
423 | ||
424 | // Check if error spans are updated according to spans started | |
425 | auto &aggregated_data = data.at(span_name1); | |
426 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 0, span_error_descriptions.size(), | |
427 | {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
428 | ||
429 | // Check if the latest 5 error spans exist out of the total 6 that were | |
430 | // introduced | |
431 | auto error_sample = aggregated_data.sample_error_spans.begin(); | |
432 | for (unsigned int idx = 1; idx < span_error_descriptions.size(); idx++) | |
433 | { | |
434 | ASSERT_EQ(error_sample->GetDescription(), span_error_descriptions[idx]); | |
435 | error_sample = std::next(error_sample); | |
436 | } | |
437 | } | |
438 | ||
439 | /** | |
440 | * This test checks to see that the maximum number of latency samples(5) for a | |
441 | * bucket is not exceeded. If there are more spans than this for a single bucket | |
442 | * it removes the earliest span that was received | |
443 | */ | |
444 | TEST_F(TracezDataAggregatorTest, CompletedSampleSpansOverCapacity) | |
445 | { | |
446 | opentelemetry::trace::StartSpanOptions start; | |
447 | opentelemetry::trace::EndSpanOptions end; | |
448 | ||
449 | // Start and end 6 spans with the same name that fall into the first latency | |
450 | // bucket | |
451 | std::vector<std::pair<nanoseconds, nanoseconds>> timestamps = { | |
452 | make_pair(nanoseconds(10), nanoseconds(100)), | |
453 | make_pair(nanoseconds(1), nanoseconds(10000)), | |
454 | make_pair(nanoseconds(1000), nanoseconds(3000)), | |
455 | make_pair(nanoseconds(12), nanoseconds(12)), | |
456 | make_pair(nanoseconds(10), nanoseconds(5000)), | |
457 | make_pair(nanoseconds(10), nanoseconds(60))}; | |
458 | for (auto timestamp : timestamps) | |
459 | { | |
460 | start.start_steady_time = SteadyTimestamp(timestamp.first); | |
461 | end.end_steady_time = SteadyTimestamp(timestamp.second); | |
462 | tracer->StartSpan(span_name1, start)->End(end); | |
463 | } | |
464 | ||
465 | // Give some time and get data | |
466 | std::this_thread::sleep_for(milliseconds(500)); | |
467 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
468 | ||
469 | ASSERT_EQ(data.size(), 1); | |
470 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
471 | ||
472 | std::this_thread::sleep_for(milliseconds(500)); | |
473 | auto &aggregated_data = data.at(span_name1); | |
474 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 0, 0, | |
475 | {(unsigned int)timestamps.size(), 0, 0, 0, 0, 0, 0, 0, 0}); | |
476 | ||
477 | // Check the count of completed spans in the buckets and the samples stored | |
478 | auto latency_sample = | |
479 | aggregated_data.sample_latency_spans[LatencyBoundary::k0MicroTo10Micro].begin(); | |
480 | ||
481 | // idx starts from 1 and not 0 because there are 6 completed spans in the same | |
482 | // bucket the and the first one is removed | |
483 | for (unsigned int idx = 1; idx < timestamps.size(); idx++) | |
484 | { | |
485 | ASSERT_EQ(latency_sample->GetDuration().count(), | |
486 | timestamps[idx].second.count() - timestamps[idx].first.count()); | |
487 | latency_sample = std::next(latency_sample); | |
488 | } | |
489 | } | |
490 | ||
491 | /************************* Miscellaneous tests ********************************/ | |
492 | ||
493 | /** Test to see if the span names are in alphabetical order **/ | |
494 | TEST_F(TracezDataAggregatorTest, SpanNameInAlphabeticalOrder) | |
495 | { | |
496 | std::vector<std::string> span_names = {span_name1, span_name2, span_name3}; | |
497 | ||
498 | auto span_first = tracer->StartSpan(span_name2); | |
499 | tracer->StartSpan(span_name1)->End(); | |
500 | auto span_third = tracer->StartSpan(span_name3); | |
501 | span_third->SetStatus(opentelemetry::trace::StatusCode::kError, "span cancelled"); | |
502 | span_third->End(); | |
503 | std::this_thread::sleep_for(milliseconds(500)); | |
504 | // Get data and check if span name exists in aggregation | |
505 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
506 | ASSERT_EQ(data.size(), span_names.size()); | |
507 | ||
508 | int span_names_idx = 0; | |
509 | for (auto &spans : data) | |
510 | { | |
511 | ASSERT_EQ(spans.first, span_names[span_names_idx]); | |
512 | span_names_idx++; | |
513 | } | |
514 | span_first->End(); | |
515 | } | |
516 | ||
517 | /** This test checks to see that there is no double counting of running spans | |
518 | * when get aggregated data is called twice**/ | |
519 | TEST_F(TracezDataAggregatorTest, AdditionToRunningSpans) | |
520 | { | |
521 | // Start a span and check the data | |
522 | auto span_first = tracer->StartSpan(span_name1); | |
523 | std::this_thread::sleep_for(milliseconds(500)); | |
524 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
525 | ASSERT_EQ(data.size(), 1); | |
526 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
527 | VerifySpanCountsInTracezData(span_name1, data.at(span_name1), 1, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
528 | ||
529 | // Start another span and check to see if there is no double counting of spans | |
530 | auto span_second = tracer->StartSpan(span_name1); | |
531 | ||
532 | // Give some time and get updated data | |
533 | std::this_thread::sleep_for(milliseconds(500)); | |
534 | data = tracez_data_aggregator->GetAggregatedTracezData(); | |
535 | ASSERT_EQ(data.size(), 1); | |
536 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
537 | auto &aggregated_data = data.at(span_name1); | |
538 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 2, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
539 | ||
540 | ASSERT_EQ(aggregated_data.sample_running_spans.size(), 2); | |
541 | for (auto &sample_span : aggregated_data.sample_running_spans) | |
542 | { | |
543 | ASSERT_EQ(sample_span.GetName().data(), span_name1); | |
544 | } | |
545 | span_first->End(); | |
546 | span_second->End(); | |
547 | } | |
548 | ||
549 | /** This test checks to see that once a running span is completed it the | |
550 | * aggregated data is updated correctly **/ | |
551 | TEST_F(TracezDataAggregatorTest, RemovalOfRunningSpanWhenCompleted) | |
552 | { | |
553 | opentelemetry::trace::StartSpanOptions start; | |
554 | start.start_steady_time = SteadyTimestamp(nanoseconds(10)); | |
555 | opentelemetry::trace::EndSpanOptions end; | |
556 | end.end_steady_time = SteadyTimestamp(nanoseconds(40)); | |
557 | ||
558 | // Start a span and make sure data is updated | |
559 | auto span_first = tracer->StartSpan(span_name1, start); | |
560 | std::this_thread::sleep_for(milliseconds(500)); | |
561 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
562 | ASSERT_EQ(data.size(), 1); | |
563 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
564 | VerifySpanCountsInTracezData(span_name1, data.at(span_name1), 1, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
565 | ASSERT_EQ(data.at(span_name1).sample_running_spans.front().GetName().data(), span_name1); | |
566 | // End the span and make sure running span is removed and completed span is | |
567 | // updated, there should be only one completed span | |
568 | span_first->End(end); | |
569 | std::this_thread::sleep_for(milliseconds(500)); | |
570 | ||
571 | // Make sure sample span still exists before next aggregation | |
572 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
573 | ASSERT_EQ(data.at(span_name1).sample_running_spans.front().GetName().data(), span_name1); | |
574 | ||
575 | data = tracez_data_aggregator->GetAggregatedTracezData(); | |
576 | ||
577 | ASSERT_EQ(data.size(), 1); | |
578 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
579 | ||
580 | // Check if completed span fields are correctly updated | |
581 | auto &aggregated_data = data.at(span_name1); | |
582 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 0, 0, {1, 0, 0, 0, 0, 0, 0, 0, 0}); | |
583 | ASSERT_EQ(aggregated_data.sample_latency_spans[LatencyBoundary::k0MicroTo10Micro] | |
584 | .front() | |
585 | .GetDuration() | |
586 | .count(), | |
587 | 30); | |
588 | } | |
589 | ||
590 | TEST_F(TracezDataAggregatorTest, RunningSpanChangesNameBeforeCompletion) | |
591 | { | |
592 | opentelemetry::trace::StartSpanOptions start; | |
593 | start.start_steady_time = SteadyTimestamp(nanoseconds(10)); | |
594 | opentelemetry::trace::EndSpanOptions end; | |
595 | end.end_steady_time = SteadyTimestamp(nanoseconds(40)); | |
596 | ||
597 | // Start a span and make sure data is updated | |
598 | auto span_first = tracer->StartSpan(span_name1, start); | |
599 | std::this_thread::sleep_for(milliseconds(500)); | |
600 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
601 | ASSERT_EQ(data.size(), 1); | |
602 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
603 | VerifySpanCountsInTracezData(span_name1, data.at(span_name1), 1, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
604 | ASSERT_EQ(data.at(span_name1).sample_running_spans.front().GetName().data(), span_name1); | |
605 | ||
606 | // End the span and make sure running span is removed and completed span is | |
607 | // updated, there should be only one completed span | |
608 | span_first->UpdateName(span_name2); | |
609 | span_first->End(end); | |
610 | ||
611 | // Check if sample span is present before fetching updated data | |
612 | std::this_thread::sleep_for(milliseconds(500)); | |
613 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
614 | ASSERT_EQ(data.at(span_name1).sample_running_spans.front().GetName(), span_name1); | |
615 | ||
616 | data = tracez_data_aggregator->GetAggregatedTracezData(); | |
617 | ||
618 | ASSERT_EQ(data.size(), 1); | |
619 | ASSERT_TRUE(data.find(span_name2) != data.end()); | |
620 | ||
621 | // Check if completed span fields are correctly updated | |
622 | auto &aggregated_data = data.at(span_name2); | |
623 | VerifySpanCountsInTracezData(span_name2, aggregated_data, 0, 0, {1, 0, 0, 0, 0, 0, 0, 0, 0}); | |
624 | ASSERT_EQ(aggregated_data.sample_latency_spans[LatencyBoundary::k0MicroTo10Micro] | |
625 | .front() | |
626 | .GetDuration() | |
627 | .count(), | |
628 | 30); | |
629 | } | |
630 | ||
631 | /** Test to check if the span latencies with duration at the edge of boundaries | |
632 | * fall in the correct bucket **/ | |
633 | TEST_F(TracezDataAggregatorTest, EdgeSpanLatenciesFallInCorrectBoundaries) | |
634 | { | |
635 | opentelemetry::trace::StartSpanOptions start; | |
636 | opentelemetry::trace::EndSpanOptions end; | |
637 | ||
638 | // Start and end 6 spans with the same name that fall into the first latency | |
639 | // bucket | |
640 | std::vector<nanoseconds> durations = { | |
641 | nanoseconds(0), nanoseconds(10000), nanoseconds(100000), | |
642 | nanoseconds(1000000), nanoseconds(10000000), nanoseconds(100000000), | |
643 | nanoseconds(1000000000), nanoseconds(10000000000), nanoseconds(100000000000)}; | |
644 | for (auto duration : durations) | |
645 | { | |
646 | start.start_steady_time = SteadyTimestamp(nanoseconds(1)); | |
647 | end.end_steady_time = SteadyTimestamp(nanoseconds(duration.count() + 1)); | |
648 | tracer->StartSpan(span_name1, start)->End(end); | |
649 | } | |
650 | ||
651 | std::this_thread::sleep_for(milliseconds(500)); | |
652 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
653 | ASSERT_EQ(data.size(), 1); | |
654 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
655 | ||
656 | std::this_thread::sleep_for(milliseconds(500)); | |
657 | auto &aggregated_data = data.at(span_name1); | |
658 | VerifySpanCountsInTracezData(span_name1, aggregated_data, 0, 0, {1, 1, 1, 1, 1, 1, 1, 1, 1}); | |
659 | ||
660 | // Check if the latency boundary is updated correctly | |
661 | for (unsigned int boundary = 0; boundary < kLatencyBoundaries.size(); boundary++) | |
662 | { | |
663 | ASSERT_EQ(aggregated_data.sample_latency_spans[boundary].front().GetDuration().count(), | |
664 | durations[boundary].count()); | |
665 | } | |
666 | } | |
667 | ||
668 | /** This test makes sure that the data is consistent when there are multiple | |
669 | * calls to the data aggegator with no change in data **/ | |
670 | TEST_F(TracezDataAggregatorTest, NoChangeInBetweenCallsToAggregator) | |
671 | { | |
672 | opentelemetry::trace::StartSpanOptions start; | |
673 | start.start_steady_time = SteadyTimestamp(nanoseconds(1)); | |
674 | ||
675 | opentelemetry::trace::EndSpanOptions end; | |
676 | end.end_steady_time = SteadyTimestamp(nanoseconds(1)); | |
677 | ||
678 | tracer->StartSpan(span_name1, start)->End(end); | |
679 | auto running_span = tracer->StartSpan(span_name2); | |
680 | auto span = tracer->StartSpan(span_name3); | |
681 | span->SetStatus(opentelemetry::trace::StatusCode::kError, "span cancelled"); | |
682 | span->End(); | |
683 | std::this_thread::sleep_for(milliseconds(500)); | |
684 | auto data = tracez_data_aggregator->GetAggregatedTracezData(); | |
685 | std::this_thread::sleep_for(milliseconds(500)); | |
686 | // Get data and check if span name exists in aggregation | |
687 | data = tracez_data_aggregator->GetAggregatedTracezData(); | |
688 | ASSERT_TRUE(data.find(span_name1) != data.end()); | |
689 | VerifySpanCountsInTracezData(span_name1, data.at(span_name1), 0, 0, {1, 0, 0, 0, 0, 0, 0, 0, 0}); | |
690 | ||
691 | ASSERT_TRUE(data.find(span_name2) != data.end()); | |
692 | VerifySpanCountsInTracezData(span_name2, data.at(span_name2), 1, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
693 | ||
694 | ASSERT_TRUE(data.find(span_name3) != data.end()); | |
695 | VerifySpanCountsInTracezData(span_name3, data.at(span_name3), 0, 1, {0, 0, 0, 0, 0, 0, 0, 0, 0}); | |
696 | ||
697 | running_span->End(); | |
698 | } |