1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <memory>
16 #include <string>
17 #include <thread> // NOLINT(build/c++11)
18
19 #include "gtest/gtest.h"
20 #include "fcp/tracing/test/tracing_schema.h"
21 #include "fcp/tracing/test_tracing_recorder.h"
22 #include "fcp/tracing/tracing_severity.h"
23 #include "flatbuffers/flatbuffers.h"
24
25 namespace fcp {
26 namespace {
27
28 using flatbuffers::FlatBufferBuilder;
29 using flatbuffers::GetRoot;
30 using testing::_;
31 using testing::ElementsAre;
32 using testing::Eq;
33 using testing::Gt;
34 using testing::Not;
35 using testing::SizeIs;
36 using testing::UnorderedElementsAre;
37
TEST(Tracing,TraitsTag)38 TEST(Tracing, TraitsTag) {
39 EXPECT_EQ(TracingTraits<SpanWithId>::kTag.str(), "SWID");
40 EXPECT_EQ(TracingTraits<EventBar>::kTag.str(), "EBAR");
41 }
42
TEST(Tracing,TracingSeverity)43 TEST(Tracing, TracingSeverity) {
44 EXPECT_EQ(TracingTraits<SpanWithId>::kSeverity, fcp::TracingSeverity::kInfo);
45 EXPECT_EQ(TracingTraits<ErrorEvent>::kSeverity, fcp::TracingSeverity::kError);
46 EXPECT_EQ(TracingTraits<EventWithNoData>::kSeverity,
47 fcp::TracingSeverity::kWarning);
48 }
49
TEST(Tracing,TraitsCreate)50 TEST(Tracing, TraitsCreate) {
51 FlatBufferBuilder fbb_foo;
52 fbb_foo.Finish(TracingTraits<EventFoo>::Create(222, 333, &fbb_foo));
53 auto foo = GetRoot<EventFoo>(fbb_foo.GetBufferPointer());
54 EXPECT_EQ(foo->first(), 222);
55 EXPECT_EQ(foo->second(), 333);
56
57 // Creating a flat buffer involving a string field has different codegen
58 // path, testing this as well:
59 FlatBufferBuilder fbb_bar;
60 fbb_bar.Finish(
61 TracingTraits<EventBar>::Create(444, "Hello world!", &fbb_bar));
62 auto bar = GetRoot<EventBar>(fbb_bar.GetBufferPointer());
63 EXPECT_EQ(bar->first(), 444);
64 EXPECT_EQ(bar->second()->str(), "Hello world!");
65
66 // Also make sure that a flatbuf involving a string field can be created using
67 // a std::string.
68 FlatBufferBuilder fbb_baz;
69 std::string hello_str = "Hello world!";
70 fbb_baz.Finish(TracingTraits<EventBar>::Create(444, hello_str, &fbb_baz));
71 auto baz = GetRoot<EventBar>(fbb_baz.GetBufferPointer());
72 EXPECT_EQ(baz->first(), 444);
73 EXPECT_EQ(baz->second()->str(), "Hello world!");
74 }
75
TEST(Tracing,TraitsCreateFieldOrder)76 TEST(Tracing, TraitsCreateFieldOrder) {
77 int first_i = -333;
78 int second_i = 444;
79 FlatBufferBuilder fbb_foo;
80 fbb_foo.Finish(
81 TracingTraits<FieldOrder>::Create(first_i, second_i, "hello", &fbb_foo));
82 auto foo = GetRoot<FieldOrder>(fbb_foo.GetBufferPointer());
83 EXPECT_EQ(foo->fieldz(), first_i);
84 EXPECT_EQ(foo->fieldy(), second_i);
85 EXPECT_EQ(foo->fieldx()->str(), "hello");
86
87 FlatBufferBuilder fbb_bar;
88 fbb_bar.Finish(TracingTraits<OrderWithIds>::Create("hello", first_i, second_i,
89 &fbb_bar));
90 auto bar = GetRoot<OrderWithIds>(fbb_bar.GetBufferPointer());
91 EXPECT_EQ(bar->fieldz(), first_i);
92 EXPECT_EQ(bar->fieldy(), second_i);
93 EXPECT_EQ(bar->fieldx()->str(), "hello");
94 }
95
TEST(Tracing,TraitsCreateAllTypes)96 TEST(Tracing, TraitsCreateAllTypes) {
97 FlatBufferBuilder fbb;
98 std::int8_t byte = -1;
99 std::uint8_t ubyte = 1;
100 std::int16_t short_i = -256;
101 std::uint16_t ushort_i = 256;
102 int i = -333;
103 unsigned int ui = 444;
104 float f = 1.1;
105 std::int64_t li = -4294967296;
106 std::uint64_t uli = 4294967296;
107 double d = 12312318.99999999;
108 fbb.Finish(TracingTraits<AllTypes>::Create(byte, ubyte, true, short_i,
109 ushort_i, i, ui, f, li, uli, d,
110 "hello", &fbb));
111 auto foo = GetRoot<AllTypes>(fbb.GetBufferPointer());
112 EXPECT_EQ(foo->fieldz(), byte);
113 EXPECT_EQ(foo->fieldy(), ubyte);
114 EXPECT_EQ(foo->fieldx(), true);
115 EXPECT_EQ(foo->fieldw(), short_i);
116 EXPECT_EQ(foo->fieldv(), ushort_i);
117 EXPECT_EQ(foo->fieldu(), i);
118 EXPECT_EQ(foo->fieldt(), ui);
119 EXPECT_EQ(foo->fields(), f);
120 EXPECT_EQ(foo->fieldr(), li);
121 EXPECT_EQ(foo->fieldq(), uli);
122 EXPECT_EQ(foo->fieldp(), d);
123 EXPECT_EQ(foo->fieldo()->str(), "hello");
124 }
125
TEST(Tracing,TraitsCreateEnum)126 TEST(Tracing, TraitsCreateEnum) {
127 FlatBufferBuilder fbb;
128 fbb.Finish(TracingTraits<ColorEnum>::Create(Color_Blue, &fbb));
129 auto foo = GetRoot<ColorEnum>(fbb.GetBufferPointer());
130 EXPECT_EQ(foo->color(), Color_Blue);
131 }
132
TEST(Tracing,TraitsCreateDeprecatedField)133 TEST(Tracing, TraitsCreateDeprecatedField) {
134 FlatBufferBuilder fbb_foo;
135 fbb_foo.Finish(TracingTraits<DeprecatedInt>::Create(222, &fbb_foo));
136 auto foo = GetRoot<EventFoo>(fbb_foo.GetBufferPointer());
137 EXPECT_EQ(foo->second(), 222);
138 }
139
TEST(Tracing,LookupTraitByTag)140 TEST(Tracing, LookupTraitByTag) {
141 EXPECT_EQ(TracingTraitsBase::Lookup(TracingTag("SWID"))->Name(),
142 "SpanWithId");
143 EXPECT_EQ(TracingTraitsBase::Lookup(TracingTag("EBAR"))->Name(), "EventBar");
144 }
145
TEST(Tracing,IntegrationTest)146 TEST(Tracing, IntegrationTest) {
147 TestTracingRecorder tracing_recorder;
148 {
149 TracingSpan<SpanWithId> inner(111);
150 Trace<EventFoo>(222, 333);
151 Trace<EventBar>(444, "Hello world!");
152 Trace<EventFoo>(555, 666);
153 }
154 {
155 TracingSpan<SpanWithNoData> inner;
156 Trace<EventWithNoData>();
157 }
158 EXPECT_THAT(
159 tracing_recorder.root(),
160 ElementsAre(AllOf(IsSpan<SpanWithId>(),
161 ElementsAre(IsEvent<EventFoo>(222, 333),
162 IsEvent<EventBar>(444, "Hello world!"),
163 IsEvent<EventFoo>(555, 666))),
164 AllOf(IsSpan<SpanWithNoData>(),
165 ElementsAre(IsEvent<EventWithNoData>()))))
166 << "Tracing span/events structure and content must match";
167 }
168
TEST(Tracing,UnscopedSpanIntegrationTest)169 TEST(Tracing, UnscopedSpanIntegrationTest) {
170 TestTracingRecorder tracing_recorder;
171 auto outer = std::make_unique<UnscopedTracingSpan<SpanWithId>>(111);
172 auto inner =
173 std::make_unique<UnscopedTracingSpan<SpanWithId>>(outer->Ref(), 222);
174 {
175 TracingSpan<SpanWithNoData> child_of_inner(inner->Ref());
176 Trace<EventFoo>(333, 444);
177 }
178 {
179 TracingSpan<SpanWithNoData> another_child_of_inner(inner->Ref());
180 Trace<EventFoo>(555, 666);
181 Trace<EventBar>(inner->Ref(), 1, "Trace in unscoped span!");
182 Trace<EventBar>(another_child_of_inner.Ref(), 1,
183 "Trace in explicitly specified tracing span!");
184 }
185 TracingSpan<SpanWithNoData> unrelated_span;
186 Trace<EventBar>(777, "Hello world!");
187
188 EXPECT_THAT(
189 tracing_recorder.root(),
190 ElementsAre(
191 AllOf(IsSpan<SpanWithId>(111),
192 ElementsAre(AllOf(
193 IsSpan<SpanWithId>(222),
194 ElementsAre(
195 AllOf(IsSpan<SpanWithNoData>(),
196 ElementsAre(IsEvent<EventFoo>(333, 444))),
197 AllOf(IsSpan<SpanWithNoData>(),
198 ElementsAre(IsEvent<EventFoo>(555, 666),
199 IsEvent<EventBar>(
200 1,
201 "Trace in explicitly specified "
202 "tracing span!"))),
203 IsEvent<EventBar>(1, "Trace in unscoped span!"))))),
204 AllOf(IsSpan<SpanWithNoData>(),
205 ElementsAre(IsEvent<EventBar>(777, "Hello world!")))))
206 << "Tracing span/events structure and content must match";
207 }
208
TEST(Tracing,ThreadingUnscopedIntegrationTest)209 TEST(Tracing, ThreadingUnscopedIntegrationTest) {
210 TestTracingRecorder tracing_recorder;
211 auto outer = std::make_unique<UnscopedTracingSpan<SpanWithId>>(111);
212 std::thread thread1([ref = outer->Ref()]() {
213 TracingSpan<SpanWithNoData> child_of_outer(ref);
214 Trace<EventFoo>(333, 444);
215 });
216 std::thread thread2([ref = outer->Ref()]() {
217 TracingSpan<SpanWithNoData> another_child_of_outer(ref);
218 Trace<EventFoo>(555, 666);
219 Trace<EventBar>(ref, 1, "Trace in unscoped span!");
220 Trace<EventBar>(another_child_of_outer.Ref(), 1, "Trace in local span!");
221 });
222 TracingSpan<SpanWithNoData> unrelated_span;
223 Trace<EventBar>(777, "Hello world!");
224 thread1.join();
225 thread2.join();
226
227 EXPECT_THAT(
228 tracing_recorder.root(),
229 ElementsAre(AllOf(IsSpan<SpanWithId>(111),
230 UnorderedElementsAre(
231 AllOf(IsSpan<SpanWithNoData>(),
232 ElementsAre(IsEvent<EventFoo>(333, 444))),
233 AllOf(IsSpan<SpanWithNoData>(),
234 ElementsAre(IsEvent<EventFoo>(555, 666),
235 IsEvent<EventBar>(
236 1, "Trace in local span!"))),
237 IsEvent<EventBar>(1, "Trace in unscoped span!"))),
238 AllOf(IsSpan<SpanWithNoData>(),
239 ElementsAre(IsEvent<EventBar>(777, "Hello world!")))))
240 << "Tracing span/events structure and content must match";
241 }
242
TEST(Tracing,ThreadingScopedIntegrationTest)243 TEST(Tracing, ThreadingScopedIntegrationTest) {
244 TestTracingRecorder tracing_recorder;
245 TracingSpan<SpanWithId> outer(111);
246 std::thread thread1([ref = outer.Ref()]() {
247 TracingSpan<SpanWithNoData> child_of_outer(ref);
248 Trace<EventFoo>(333, 444);
249 });
250 std::thread thread2([ref = outer.Ref()]() {
251 TracingSpan<SpanWithNoData> another_child_of_outer(ref);
252 Trace<EventFoo>(555, 666);
253 Trace<EventBar>(ref, 1, "Trace in unscoped span!");
254 Trace<EventBar>(1, "Trace in local span!");
255 });
256 TracingSpan<SpanWithNoData> unrelated_span;
257 Trace<EventBar>(777, "Hello world!");
258 thread1.join();
259 thread2.join();
260
261 EXPECT_THAT(
262 tracing_recorder.root(),
263 ElementsAre(AllOf(
264 IsSpan<SpanWithId>(111),
265 UnorderedElementsAre(
266 AllOf(IsSpan<SpanWithNoData>(),
267 ElementsAre(IsEvent<EventFoo>(333, 444))),
268 AllOf(IsSpan<SpanWithNoData>(),
269 ElementsAre(IsEvent<EventFoo>(555, 666),
270 IsEvent<EventBar>(1, "Trace in local span!"))),
271 IsEvent<EventBar>(1, "Trace in unscoped span!"),
272 AllOf(IsSpan<SpanWithNoData>(),
273 ElementsAre(IsEvent<EventBar>(777, "Hello world!")))))))
274 << "Tracing span/events structure and content must match";
275 }
276
TEST(Tracing,AdvancedMatching)277 TEST(Tracing, AdvancedMatching) {
278 TestTracingRecorder tracing_recorder;
279 {
280 TracingSpan<SpanWithId> span(111);
281 Trace<EventBar>(222, "Hello world!");
282 }
283
284 auto span = tracing_recorder.root()[0];
285 auto event = span[0];
286 EXPECT_THAT(span, IsSpan<SpanWithId>());
287 EXPECT_THAT(event, IsEvent<EventBar>());
288 EXPECT_THAT(span,
289 AllOf(IsSpan<SpanWithId>(), ElementsAre(IsEvent<EventBar>())));
290 EXPECT_THAT(span, IsSpan<SpanWithId>(_));
291 EXPECT_THAT(span, IsSpan<SpanWithId>(Eq(111)));
292 EXPECT_THAT(span, IsSpan<SpanWithId>(Gt(100)));
293 EXPECT_THAT(event, IsEvent<EventBar>(Eq(222), Eq("Hello world!")));
294 EXPECT_THAT(event, IsEvent<EventBar>(_, Eq("Hello world!")));
295 EXPECT_THAT(event, IsEvent<EventBar>(_, _));
296 EXPECT_THAT(event, IsEvent<EventBar>(Eq(222), _));
297 EXPECT_THAT(event, IsEvent<EventBar>(Not(Eq(666)), _));
298 EXPECT_THAT(event, Not(IsEvent<EventBar>(Eq(666), _)));
299 EXPECT_THAT(event, Not(IsEvent<EventFoo>()));
300 }
301
TEST(Tracing,MultipleRecorders)302 TEST(Tracing, MultipleRecorders) {
303 // NOTE: it is not a recommended scenario to have multiple instances of
304 // TestTracingRecorder per unit test, but this code path is enforced to
305 // ensure correct behavior of cleaning up global state so it is not carried
306 // over between tests.
307 {
308 TestTracingRecorder tracing_recorder;
309 Trace<EventFoo>(222, 333);
310 EXPECT_THAT(tracing_recorder.root()[0], IsEvent<EventFoo>(222, 333));
311 }
312 {
313 TestTracingRecorder tracing_recorder;
314 Trace<EventFoo>(444, 555);
315 EXPECT_THAT(tracing_recorder.root()[0], IsEvent<EventFoo>(444, 555));
316 }
317 }
318
TEST(Tracing,TraceError)319 TEST(Tracing, TraceError) {
320 TestTracingRecorder tracing_recorder;
321 tracing_recorder.ExpectError<ErrorEvent>();
322 {
323 TracingSpan<SpanWithId> inner(111);
324 Error err = TraceError<ErrorEvent>("there was a bug");
325 (void)err;
326 }
327 }
328
TEST(Tracing,FindOnlySpan)329 TEST(Tracing, FindOnlySpan) {
330 TestTracingRecorder tracing_recorder;
331 {
332 TracingSpan<SpanWithNoData> outer;
333 { TracingSpan<SpanWithId> inner(111); }
334 EXPECT_EQ(tracing_recorder.FindOnlySpan<SpanWithId>().data()->id(), 111);
335 }
336 }
337
TEST(Tracing,FindAllSpans)338 TEST(Tracing, FindAllSpans) {
339 TestTracingRecorder tracing_recorder;
340 {
341 TracingSpan<SpanWithNoData> outer;
342 {
343 TracingSpan<SpanWithId> inner1(111);
344 { TracingSpan<SpanWithId> inner2(222); }
345 }
346 EXPECT_THAT(tracing_recorder.FindAllSpans<SpanWithId>(),
347 ElementsAre(IsSpan<SpanWithId>(), IsSpan<SpanWithId>()));
348 EXPECT_THAT(tracing_recorder.FindAllSpans<SpanNeverLogged>(), SizeIs(0));
349 }
350 }
351
TEST(Tracing,FindOnlyEvent)352 TEST(Tracing, FindOnlyEvent) {
353 TestTracingRecorder tracing_recorder;
354 {
355 TracingSpan<SpanWithNoData> outer;
356 { Trace<EventFoo>(111, 222); }
357 EXPECT_EQ(tracing_recorder.FindOnlyEvent<EventFoo>().data()->first(), 111);
358 EXPECT_EQ(tracing_recorder.FindOnlyEvent<EventFoo>().data()->second(), 222);
359 }
360 }
361
TEST(Tracing,FindAllEvents)362 TEST(Tracing, FindAllEvents) {
363 TestTracingRecorder tracing_recorder;
364 {
365 TracingSpan<SpanWithNoData> outer;
366 {
367 Trace<EventFoo>(111, 222);
368 TracingSpan<SpanWithNoData> inner;
369 { Trace<EventFoo>(333, 444); }
370 }
371 EXPECT_THAT(tracing_recorder.FindAllEvents<EventFoo>(),
372 ElementsAre(IsEvent<EventFoo>(), IsEvent<EventFoo>()));
373 EXPECT_THAT(tracing_recorder.FindAllEvents<EventNeverLogged>(), SizeIs(0));
374 }
375 }
TEST(Tracing,CreateJsonString)376 TEST(Tracing, CreateJsonString) {
377 FlatBufferBuilder fbb_foo;
378 fbb_foo.Finish(TracingTraits<EventFoo>::Create(222, 333, &fbb_foo));
379 auto foo_buf = fbb_foo.GetBufferPointer();
380 auto foo = GetRoot<EventFoo>(fbb_foo.GetBufferPointer());
381 EXPECT_EQ(foo->first(), 222);
382 EXPECT_EQ(foo->second(), 333);
383
384 TracingTraits<EventFoo> tracing_traits;
385 std::string expected = "{\n first: 222,\n second: 333\n}\n";
386 std::string json_gen = tracing_traits.JsonStringFormat(foo_buf);
387 EXPECT_EQ(expected, json_gen);
388 }
389
390 // TODO(team) Add Testing for when the flatbuf has a package name
391
392 } // namespace
393 } // namespace fcp
394