1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/trace_event/memory_dump_manager.h"
10 #include "base/trace_event/trace_config.h"
11 #include "base/trace_event/trace_config_memory_test_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/abseil-cpp/absl/types/optional.h"
14
15 namespace base::trace_event {
16
17 namespace {
18
19 const char kDefaultTraceConfigString[] =
20 "{"
21 "\"enable_argument_filter\":false,"
22 "\"enable_package_name_filter\":false,"
23 "\"enable_systrace\":false,"
24 "\"record_mode\":\"record-until-full\""
25 "}";
26
27 const char kCustomTraceConfigString[] =
28 "{"
29 "\"enable_argument_filter\":true,"
30 "\"enable_package_name_filter\":true,"
31 "\"enable_systrace\":true,"
32 "\"event_filters\":["
33 "{"
34 "\"excluded_categories\":[\"unfiltered_cat\"],"
35 "\"filter_args\":{\"event_name_allowlist\":[\"a snake\",\"a dog\"]},"
36 "\"filter_predicate\":\"event_whitelist_predicate\","
37 "\"included_categories\":[\"*\"]"
38 "}"
39 "],"
40 "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
41 "\"histogram_names\":[\"uma1\",\"uma2\"],"
42 "\"included_categories\":["
43 "\"included\","
44 "\"inc_pattern*\","
45 "\"disabled-by-default-cc\","
46 "\"disabled-by-default-memory-infra\"],"
47 "\"memory_dump_config\":{"
48 "\"allowed_dump_modes\":[\"background\",\"light\",\"detailed\"],"
49 "\"heap_profiler_options\":{"
50 "\"breakdown_threshold_bytes\":10240"
51 "},"
52 "\"triggers\":["
53 "{"
54 "\"min_time_between_dumps_ms\":50,"
55 "\"mode\":\"light\","
56 "\"type\":\"periodic_interval\""
57 "},"
58 "{"
59 "\"min_time_between_dumps_ms\":1000,"
60 "\"mode\":\"detailed\","
61 "\"type\":\"periodic_interval\""
62 "}"
63 "]"
64 "},"
65 "\"record_mode\":\"record-continuously\","
66 "\"trace_buffer_size_in_events\":100"
67 "}";
68
CheckDefaultTraceConfigBehavior(const TraceConfig & tc)69 void CheckDefaultTraceConfigBehavior(const TraceConfig& tc) {
70 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
71 EXPECT_FALSE(tc.IsSystraceEnabled());
72 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
73 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
74
75 // Default trace config enables every category filter except the
76 // disabled-by-default-* ones.
77 EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1"));
78 EXPECT_TRUE(tc.IsCategoryGroupEnabled("not-excluded-category"));
79 EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
80
81 EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,not-excluded-category"));
82 EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,disabled-by-default-cc"));
83 EXPECT_FALSE(tc.IsCategoryGroupEnabled(
84 "disabled-by-default-cc,disabled-by-default-cc2"));
85 }
86
87 // Returns an string in which word1 and word2 are swapped. word1 and word2 must
88 // be non-overlapping substrings of the input string and word1 must be before
89 // word2.
SwapWords(const std::string & in_str,const std::string & word1,const std::string & word2)90 std::string SwapWords(const std::string& in_str,
91 const std::string& word1,
92 const std::string& word2) {
93 size_t pos1 = in_str.find(word1);
94 size_t len1 = word1.size();
95 size_t pos2 = in_str.find(word2);
96 size_t len2 = word2.size();
97 return in_str.substr(0, pos1) + word2 +
98 in_str.substr(pos1 + len1, pos2 - pos1 - len1) + word1 +
99 in_str.substr(pos2 + len2);
100 }
101
102 } // namespace
103
TEST(TraceConfigTest,TraceConfigFromValidLegacyFormat)104 TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
105 // From trace options strings
106 TraceConfig config("", "record-until-full");
107 EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
108 EXPECT_FALSE(config.IsSystraceEnabled());
109 EXPECT_FALSE(config.IsArgumentFilterEnabled());
110 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
111 EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
112
113 config = TraceConfig("", "record-continuously");
114 EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
115 EXPECT_FALSE(config.IsSystraceEnabled());
116 EXPECT_FALSE(config.IsArgumentFilterEnabled());
117 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
118 EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
119
120 config = TraceConfig("", "trace-to-console");
121 EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
122 EXPECT_FALSE(config.IsSystraceEnabled());
123 EXPECT_FALSE(config.IsArgumentFilterEnabled());
124 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
125 EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
126
127 config = TraceConfig("", "record-as-much-as-possible");
128 EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
129 EXPECT_FALSE(config.IsSystraceEnabled());
130 EXPECT_FALSE(config.IsArgumentFilterEnabled());
131 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
132 EXPECT_STREQ("record-as-much-as-possible",
133 config.ToTraceOptionsString().c_str());
134
135 config = TraceConfig("", "enable-systrace, record-continuously");
136 EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
137 EXPECT_TRUE(config.IsSystraceEnabled());
138 EXPECT_FALSE(config.IsArgumentFilterEnabled());
139 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
140 EXPECT_STREQ("record-continuously,enable-systrace",
141 config.ToTraceOptionsString().c_str());
142
143 config = TraceConfig("", "enable-argument-filter,record-as-much-as-possible");
144 EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
145 EXPECT_FALSE(config.IsSystraceEnabled());
146 EXPECT_TRUE(config.IsArgumentFilterEnabled());
147 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
148 EXPECT_STREQ("record-as-much-as-possible,enable-argument-filter",
149 config.ToTraceOptionsString().c_str());
150
151 config = TraceConfig(
152 "",
153 "enable-systrace,trace-to-console,enable-argument-filter");
154 EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
155 EXPECT_TRUE(config.IsSystraceEnabled());
156 EXPECT_TRUE(config.IsArgumentFilterEnabled());
157 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
158 EXPECT_STREQ(
159 "trace-to-console,enable-systrace,enable-argument-filter",
160 config.ToTraceOptionsString().c_str());
161
162 config = TraceConfig(
163 "", "record-continuously, record-until-full, trace-to-console");
164 EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
165 EXPECT_FALSE(config.IsSystraceEnabled());
166 EXPECT_FALSE(config.IsArgumentFilterEnabled());
167 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
168 EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
169
170 // From TraceRecordMode
171 config = TraceConfig("", RECORD_UNTIL_FULL);
172 EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
173 EXPECT_FALSE(config.IsSystraceEnabled());
174 EXPECT_FALSE(config.IsArgumentFilterEnabled());
175 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
176 EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
177
178 config = TraceConfig("", RECORD_CONTINUOUSLY);
179 EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
180 EXPECT_FALSE(config.IsSystraceEnabled());
181 EXPECT_FALSE(config.IsArgumentFilterEnabled());
182 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
183 EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
184
185 config = TraceConfig("", ECHO_TO_CONSOLE);
186 EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
187 EXPECT_FALSE(config.IsSystraceEnabled());
188 EXPECT_FALSE(config.IsArgumentFilterEnabled());
189 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
190 EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
191
192 config = TraceConfig("", RECORD_AS_MUCH_AS_POSSIBLE);
193 EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
194 EXPECT_FALSE(config.IsSystraceEnabled());
195 EXPECT_FALSE(config.IsArgumentFilterEnabled());
196 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
197 EXPECT_STREQ("record-as-much-as-possible",
198 config.ToTraceOptionsString().c_str());
199
200 // From category filter strings
201 config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*", "");
202 EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
203 config.ToCategoryFilterString().c_str());
204
205 config = TraceConfig("only_inc_cat", "");
206 EXPECT_STREQ("only_inc_cat", config.ToCategoryFilterString().c_str());
207
208 config = TraceConfig("-only_exc_cat", "");
209 EXPECT_STREQ("-only_exc_cat", config.ToCategoryFilterString().c_str());
210
211 config = TraceConfig("disabled-by-default-cc,-excluded", "");
212 EXPECT_STREQ("disabled-by-default-cc,-excluded",
213 config.ToCategoryFilterString().c_str());
214
215 config = TraceConfig("disabled-by-default-cc,included", "");
216 EXPECT_STREQ("included,disabled-by-default-cc",
217 config.ToCategoryFilterString().c_str());
218
219 // From both trace options and category filter strings
220 config = TraceConfig("", "");
221 EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
222 EXPECT_FALSE(config.IsSystraceEnabled());
223 EXPECT_FALSE(config.IsArgumentFilterEnabled());
224 EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
225 EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
226
227 config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
228 "enable-systrace, trace-to-console");
229 EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
230 EXPECT_TRUE(config.IsSystraceEnabled());
231 EXPECT_FALSE(config.IsArgumentFilterEnabled());
232 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
233 EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
234 config.ToCategoryFilterString().c_str());
235 EXPECT_STREQ("trace-to-console,enable-systrace",
236 config.ToTraceOptionsString().c_str());
237
238 // From both trace options and category filter strings with spaces.
239 config = TraceConfig(" included , -excluded, inc_pattern*, ,-exc_pattern* ",
240 "enable-systrace, ,trace-to-console ");
241 EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
242 EXPECT_TRUE(config.IsSystraceEnabled());
243 EXPECT_FALSE(config.IsArgumentFilterEnabled());
244 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
245 EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
246 config.ToCategoryFilterString().c_str());
247 EXPECT_STREQ("trace-to-console,enable-systrace",
248 config.ToTraceOptionsString().c_str());
249
250 // From category filter string and TraceRecordMode
251 config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
252 RECORD_CONTINUOUSLY);
253 EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
254 EXPECT_FALSE(config.IsSystraceEnabled());
255 EXPECT_FALSE(config.IsArgumentFilterEnabled());
256 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
257 EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
258 config.ToCategoryFilterString().c_str());
259 EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
260 }
261
TEST(TraceConfigTest,TraceConfigFromInvalidLegacyStrings)262 TEST(TraceConfigTest, TraceConfigFromInvalidLegacyStrings) {
263 TraceConfig config("", "foo-bar-baz");
264 EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
265 EXPECT_FALSE(config.IsSystraceEnabled());
266 EXPECT_FALSE(config.IsArgumentFilterEnabled());
267 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
268 EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
269 EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
270
271 config = TraceConfig("arbitrary-category", "foo-bar-baz, enable-systrace");
272 EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
273 EXPECT_TRUE(config.IsSystraceEnabled());
274 EXPECT_FALSE(config.IsArgumentFilterEnabled());
275 EXPECT_FALSE(config.IsEventPackageNameFilterEnabled());
276 EXPECT_STREQ("arbitrary-category", config.ToCategoryFilterString().c_str());
277 EXPECT_STREQ("record-until-full,enable-systrace",
278 config.ToTraceOptionsString().c_str());
279 }
280
TEST(TraceConfigTest,ConstructDefaultTraceConfig)281 TEST(TraceConfigTest, ConstructDefaultTraceConfig) {
282 TraceConfig tc;
283 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
284 EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
285 CheckDefaultTraceConfigBehavior(tc);
286
287 // Constructors from category filter string and trace option string.
288 TraceConfig tc_asterisk("*", "");
289 EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str());
290 CheckDefaultTraceConfigBehavior(tc_asterisk);
291
292 TraceConfig tc_empty_category_filter("", "");
293 EXPECT_STREQ("", tc_empty_category_filter.ToCategoryFilterString().c_str());
294 EXPECT_STREQ(kDefaultTraceConfigString,
295 tc_empty_category_filter.ToString().c_str());
296 CheckDefaultTraceConfigBehavior(tc_empty_category_filter);
297
298 // Constructor from JSON formatted config string.
299 TraceConfig tc_empty_json_string("");
300 EXPECT_STREQ("", tc_empty_json_string.ToCategoryFilterString().c_str());
301 EXPECT_STREQ(kDefaultTraceConfigString,
302 tc_empty_json_string.ToString().c_str());
303 CheckDefaultTraceConfigBehavior(tc_empty_json_string);
304
305 // Constructor from dictionary value.
306 TraceConfig tc_dict(Value::Dict{});
307 EXPECT_STREQ("", tc_dict.ToCategoryFilterString().c_str());
308 EXPECT_STREQ(kDefaultTraceConfigString, tc_dict.ToString().c_str());
309 CheckDefaultTraceConfigBehavior(tc_dict);
310 }
311
TEST(TraceConfigTest,EmptyAndAsteriskCategoryFilterString)312 TEST(TraceConfigTest, EmptyAndAsteriskCategoryFilterString) {
313 TraceConfig tc_empty("", "");
314 TraceConfig tc_asterisk("*", "");
315
316 EXPECT_STREQ("", tc_empty.ToCategoryFilterString().c_str());
317 EXPECT_STREQ("*", tc_asterisk.ToCategoryFilterString().c_str());
318
319 // Both fall back to default config.
320 CheckDefaultTraceConfigBehavior(tc_empty);
321 CheckDefaultTraceConfigBehavior(tc_asterisk);
322
323 // They differ only for internal checking.
324 EXPECT_FALSE(tc_empty.category_filter().IsCategoryEnabled("Category1"));
325 EXPECT_FALSE(
326 tc_empty.category_filter().IsCategoryEnabled("not-excluded-category"));
327 EXPECT_TRUE(tc_asterisk.category_filter().IsCategoryEnabled("Category1"));
328 EXPECT_TRUE(
329 tc_asterisk.category_filter().IsCategoryEnabled("not-excluded-category"));
330 }
331
TEST(TraceConfigTest,DisabledByDefaultCategoryFilterString)332 TEST(TraceConfigTest, DisabledByDefaultCategoryFilterString) {
333 TraceConfig tc("foo,disabled-by-default-foo", "");
334 EXPECT_STREQ("foo,disabled-by-default-foo",
335 tc.ToCategoryFilterString().c_str());
336 EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo"));
337 EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo"));
338 EXPECT_FALSE(tc.IsCategoryGroupEnabled("bar"));
339 EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar"));
340
341 EXPECT_TRUE(tc.event_filters().empty());
342 // Enabling only the disabled-by-default-* category means the default ones
343 // are also enabled.
344 tc = TraceConfig("disabled-by-default-foo", "");
345 EXPECT_STREQ("disabled-by-default-foo", tc.ToCategoryFilterString().c_str());
346 EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-foo"));
347 EXPECT_TRUE(tc.IsCategoryGroupEnabled("foo"));
348 EXPECT_TRUE(tc.IsCategoryGroupEnabled("bar"));
349 EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-bar"));
350 }
351
TEST(TraceConfigTest,TraceConfigFromDict)352 TEST(TraceConfigTest, TraceConfigFromDict) {
353 // Passing in empty dictionary will result in default trace config.
354 TraceConfig tc(Value::Dict{});
355 EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
356 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
357 EXPECT_FALSE(tc.IsSystraceEnabled());
358 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
359 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
360 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
361
362 absl::optional<Value> default_value =
363 JSONReader::Read(kDefaultTraceConfigString);
364 ASSERT_TRUE(default_value);
365 ASSERT_TRUE(default_value->is_dict());
366 TraceConfig default_tc(default_value->GetDict());
367 EXPECT_STREQ(kDefaultTraceConfigString, default_tc.ToString().c_str());
368 EXPECT_EQ(RECORD_UNTIL_FULL, default_tc.GetTraceRecordMode());
369 EXPECT_FALSE(default_tc.IsSystraceEnabled());
370 EXPECT_FALSE(default_tc.IsEventPackageNameFilterEnabled());
371 EXPECT_FALSE(default_tc.IsArgumentFilterEnabled());
372 EXPECT_STREQ("", default_tc.ToCategoryFilterString().c_str());
373
374 absl::optional<Value> custom_value =
375 JSONReader::Read(kCustomTraceConfigString);
376 ASSERT_TRUE(custom_value);
377 ASSERT_TRUE(custom_value->is_dict());
378 TraceConfig custom_tc(custom_value->GetDict());
379 std::string custom_tc_str = custom_tc.ToString();
380 EXPECT_TRUE(custom_tc_str == kCustomTraceConfigString ||
381 custom_tc_str ==
382 SwapWords(kCustomTraceConfigString, "uma1", "uma2"));
383 EXPECT_EQ(RECORD_CONTINUOUSLY, custom_tc.GetTraceRecordMode());
384 EXPECT_TRUE(custom_tc.IsSystraceEnabled());
385 EXPECT_TRUE(custom_tc.IsArgumentFilterEnabled());
386 EXPECT_TRUE(custom_tc.IsEventPackageNameFilterEnabled());
387 EXPECT_EQ(100u, custom_tc.GetTraceBufferSizeInEvents());
388 EXPECT_STREQ(
389 "included,inc_pattern*,"
390 "disabled-by-default-cc,disabled-by-default-memory-infra,"
391 "-excluded,-exc_pattern*",
392 custom_tc.ToCategoryFilterString().c_str());
393 }
394
TEST(TraceConfigTest,TraceConfigFromValidString)395 TEST(TraceConfigTest, TraceConfigFromValidString) {
396 // Using some non-empty config string.
397 const char config_string[] =
398 "{"
399 "\"enable_argument_filter\":true,"
400 "\"enable_package_name_filter\":false,"
401 "\"enable_systrace\":true,"
402 "\"event_filters\":["
403 "{"
404 "\"excluded_categories\":[\"unfiltered_cat\"],"
405 "\"filter_args\":{\"event_name_allowlist\":[\"a snake\",\"a dog\"]},"
406 "\"filter_predicate\":\"event_whitelist_predicate\","
407 "\"included_categories\":[\"*\"]"
408 "}"
409 "],"
410 "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
411 "\"included_categories\":[\"included\","
412 "\"inc_pattern*\","
413 "\"disabled-by-default-cc\"],"
414 "\"record_mode\":\"record-continuously\""
415 "}";
416 TraceConfig tc(config_string);
417
418 EXPECT_STREQ(config_string, tc.ToString().c_str());
419 EXPECT_EQ(RECORD_CONTINUOUSLY, tc.GetTraceRecordMode());
420 EXPECT_TRUE(tc.IsSystraceEnabled());
421 EXPECT_TRUE(tc.IsArgumentFilterEnabled());
422 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
423 EXPECT_STREQ(
424 "included,inc_pattern*,disabled-by-default-cc,-excluded,"
425 "-exc_pattern*",
426 tc.ToCategoryFilterString().c_str());
427
428 EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("included"));
429 EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("inc_pattern_category"));
430 EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("disabled-by-default-cc"));
431 EXPECT_FALSE(tc.category_filter().IsCategoryEnabled("excluded"));
432 EXPECT_FALSE(tc.category_filter().IsCategoryEnabled("exc_pattern_category"));
433 EXPECT_FALSE(
434 tc.category_filter().IsCategoryEnabled("disabled-by-default-others"));
435 EXPECT_FALSE(
436 tc.category_filter().IsCategoryEnabled("not-excluded-nor-included"));
437
438 EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
439 EXPECT_TRUE(tc.IsCategoryGroupEnabled("inc_pattern_category"));
440 EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
441 EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
442 EXPECT_FALSE(tc.IsCategoryGroupEnabled("exc_pattern_category"));
443 EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-others"));
444 EXPECT_FALSE(tc.IsCategoryGroupEnabled("not-excluded-nor-included"));
445
446 EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,excluded"));
447 EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,exc_pattern_category"));
448 EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
449
450 EXPECT_EQ(tc.event_filters().size(), 1u);
451 const TraceConfig::EventFilterConfig& event_filter = tc.event_filters()[0];
452 EXPECT_STREQ("event_whitelist_predicate",
453 event_filter.predicate_name().c_str());
454 EXPECT_EQ(1u, event_filter.category_filter().included_categories().size());
455 EXPECT_STREQ("*",
456 event_filter.category_filter().included_categories()[0].c_str());
457 EXPECT_EQ(1u, event_filter.category_filter().excluded_categories().size());
458 EXPECT_STREQ("unfiltered_cat",
459 event_filter.category_filter().excluded_categories()[0].c_str());
460 EXPECT_FALSE(event_filter.filter_args().empty());
461
462 std::string json_out;
463 base::JSONWriter::Write(event_filter.filter_args(), &json_out);
464 EXPECT_STREQ(json_out.c_str(),
465 "{\"event_name_allowlist\":[\"a snake\",\"a dog\"]}");
466 std::unordered_set<std::string> filter_values;
467 EXPECT_TRUE(event_filter.GetArgAsSet("event_name_allowlist", &filter_values));
468 EXPECT_EQ(2u, filter_values.size());
469 EXPECT_EQ(1u, filter_values.count("a snake"));
470 EXPECT_EQ(1u, filter_values.count("a dog"));
471
472 const char config_string_2[] = "{\"included_categories\":[\"*\"]}";
473 TraceConfig tc2(config_string_2);
474 EXPECT_TRUE(tc2.category_filter().IsCategoryEnabled(
475 "non-disabled-by-default-pattern"));
476 EXPECT_FALSE(
477 tc2.category_filter().IsCategoryEnabled("disabled-by-default-pattern"));
478 EXPECT_TRUE(tc2.IsCategoryGroupEnabled("non-disabled-by-default-pattern"));
479 EXPECT_FALSE(tc2.IsCategoryGroupEnabled("disabled-by-default-pattern"));
480
481 // Clear
482 tc.Clear();
483 EXPECT_STREQ(tc.ToString().c_str(),
484 "{"
485 "\"enable_argument_filter\":false,"
486 "\"enable_package_name_filter\":false,"
487 "\"enable_systrace\":false,"
488 "\"record_mode\":\"record-until-full\""
489 "}");
490 }
491
TEST(TraceConfigTest,TraceConfigFromInvalidString)492 TEST(TraceConfigTest, TraceConfigFromInvalidString) {
493 // The config string needs to be a dictionary correctly formatted as a JSON
494 // string. Otherwise, it will fall back to the default initialization.
495 TraceConfig tc("");
496 EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
497 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
498 EXPECT_FALSE(tc.IsSystraceEnabled());
499 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
500 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
501 CheckDefaultTraceConfigBehavior(tc);
502
503 tc = TraceConfig("This is an invalid config string.");
504 EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
505 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
506 EXPECT_FALSE(tc.IsSystraceEnabled());
507 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
508 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
509 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
510 CheckDefaultTraceConfigBehavior(tc);
511
512 tc = TraceConfig("[\"This\", \"is\", \"not\", \"a\", \"dictionary\"]");
513 EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
514 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
515 EXPECT_FALSE(tc.IsSystraceEnabled());
516 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
517 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
518 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
519 CheckDefaultTraceConfigBehavior(tc);
520
521 tc = TraceConfig("{\"record_mode\": invalid-value-needs-double-quote}");
522 EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
523 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
524 EXPECT_FALSE(tc.IsSystraceEnabled());
525 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
526 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
527 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
528 CheckDefaultTraceConfigBehavior(tc);
529
530 // If the config string a dictionary formatted as a JSON string, it will
531 // initialize TraceConfig with best effort.
532 tc = TraceConfig("{}");
533 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
534 EXPECT_FALSE(tc.IsSystraceEnabled());
535 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
536 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
537 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
538 CheckDefaultTraceConfigBehavior(tc);
539
540 tc = TraceConfig("{\"arbitrary-key\":\"arbitrary-value\"}");
541 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
542 EXPECT_FALSE(tc.IsSystraceEnabled());
543 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
544 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
545 EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
546 CheckDefaultTraceConfigBehavior(tc);
547
548 const char invalid_config_string[] =
549 "{"
550 "\"enable_systrace\":1,"
551 "\"excluded_categories\":[\"excluded\"],"
552 "\"included_categories\":\"not a list\","
553 "\"record_mode\":\"arbitrary-mode\""
554 "}";
555 tc = TraceConfig(invalid_config_string);
556 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
557 EXPECT_FALSE(tc.IsSystraceEnabled());
558 EXPECT_FALSE(tc.IsArgumentFilterEnabled());
559 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
560
561 const char invalid_config_string_2[] =
562 "{"
563 "\"included_categories\":[\"category\",\"disabled-by-default-pattern\"],"
564 "\"excluded_categories\":[\"category\",\"disabled-by-default-pattern\"]"
565 "}";
566 tc = TraceConfig(invalid_config_string_2);
567 EXPECT_TRUE(tc.category_filter().IsCategoryEnabled("category"));
568 EXPECT_TRUE(
569 tc.category_filter().IsCategoryEnabled("disabled-by-default-pattern"));
570 EXPECT_TRUE(tc.IsCategoryGroupEnabled("category"));
571 EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-pattern"));
572 }
573
TEST(TraceConfigTest,MergingTraceConfigs)574 TEST(TraceConfigTest, MergingTraceConfigs) {
575 // Merge
576 TraceConfig tc;
577 TraceConfig tc2("included,-excluded,inc_pattern*,-exc_pattern*", "");
578 tc.Merge(tc2);
579 EXPECT_STREQ(
580 "{"
581 "\"enable_argument_filter\":false,"
582 "\"enable_package_name_filter\":false,"
583 "\"enable_systrace\":false,"
584 "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
585 "\"record_mode\":\"record-until-full\""
586 "}",
587 tc.ToString().c_str());
588 }
589
TEST(TraceConfigTest,IsCategoryGroupEnabled)590 TEST(TraceConfigTest, IsCategoryGroupEnabled) {
591 // Enabling a disabled- category does not require all categories to be traced
592 // to be included.
593 TraceConfig tc("disabled-by-default-cc,-excluded", "");
594 EXPECT_STREQ("disabled-by-default-cc,-excluded",
595 tc.ToCategoryFilterString().c_str());
596 EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
597 EXPECT_TRUE(tc.IsCategoryGroupEnabled("some_other_group"));
598 EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
599
600 // Enabled a disabled- category and also including makes all categories to
601 // be traced require including.
602 tc = TraceConfig("disabled-by-default-cc,included", "");
603 EXPECT_STREQ("included,disabled-by-default-cc",
604 tc.ToCategoryFilterString().c_str());
605 EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
606 EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
607 EXPECT_FALSE(tc.IsCategoryGroupEnabled("other_included"));
608
609 // Excluding categories won't enable disabled-by-default ones with the
610 // excluded category is also present in the group.
611 tc = TraceConfig("-excluded", "");
612 EXPECT_STREQ("-excluded", tc.ToCategoryFilterString().c_str());
613 EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,disabled-by-default-cc"));
614 }
615
TEST(TraceConfigTest,IsCategoryNameAllowed)616 TEST(TraceConfigTest, IsCategoryNameAllowed) {
617 // Test that IsCategoryNameAllowed actually catches categories that are
618 // explicitly forbidden. This method is called in a DCHECK to assert that we
619 // don't have these types of strings as categories.
620 EXPECT_FALSE(
621 TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category "));
622 EXPECT_FALSE(
623 TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category"));
624 EXPECT_FALSE(
625 TraceConfigCategoryFilter::IsCategoryNameAllowed("bad_category "));
626 EXPECT_FALSE(
627 TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category"));
628 EXPECT_FALSE(
629 TraceConfigCategoryFilter::IsCategoryNameAllowed("bad_category "));
630 EXPECT_FALSE(
631 TraceConfigCategoryFilter::IsCategoryNameAllowed(" bad_category "));
632 EXPECT_FALSE(TraceConfigCategoryFilter::IsCategoryNameAllowed(""));
633 EXPECT_TRUE(
634 TraceConfigCategoryFilter::IsCategoryNameAllowed("good_category"));
635 }
636
TEST(TraceConfigTest,SetTraceOptionValues)637 TEST(TraceConfigTest, SetTraceOptionValues) {
638 TraceConfig tc;
639 EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
640 EXPECT_FALSE(tc.IsSystraceEnabled());
641 EXPECT_FALSE(tc.IsEventPackageNameFilterEnabled());
642
643 tc.SetTraceRecordMode(RECORD_AS_MUCH_AS_POSSIBLE);
644 EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, tc.GetTraceRecordMode());
645
646 tc.EnableSystrace();
647 EXPECT_TRUE(tc.IsSystraceEnabled());
648
649 tc.SetEventPackageNameFilterEnabled(true);
650 EXPECT_TRUE(tc.IsEventPackageNameFilterEnabled());
651 }
652
TEST(TraceConfigTest,TraceConfigFromMemoryConfigString)653 TEST(TraceConfigTest, TraceConfigFromMemoryConfigString) {
654 std::string tc_str1 =
655 TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(200, 2000);
656 TraceConfig tc1(tc_str1);
657 EXPECT_EQ(tc_str1, tc1.ToString());
658 TraceConfig tc2(
659 TraceConfigMemoryTestUtil::GetTraceConfig_LegacyPeriodicTriggers(200,
660 2000));
661 EXPECT_EQ(tc_str1, tc2.ToString());
662
663 EXPECT_TRUE(tc1.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
664 ASSERT_EQ(2u, tc1.memory_dump_config().triggers.size());
665
666 EXPECT_EQ(200u,
667 tc1.memory_dump_config().triggers[0].min_time_between_dumps_ms);
668 EXPECT_EQ(MemoryDumpLevelOfDetail::kLight,
669 tc1.memory_dump_config().triggers[0].level_of_detail);
670
671 EXPECT_EQ(2000u,
672 tc1.memory_dump_config().triggers[1].min_time_between_dumps_ms);
673 EXPECT_EQ(MemoryDumpLevelOfDetail::kDetailed,
674 tc1.memory_dump_config().triggers[1].level_of_detail);
675 EXPECT_EQ(
676 2048u,
677 tc1.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes);
678
679 std::string tc_str3 =
680 TraceConfigMemoryTestUtil::GetTraceConfig_BackgroundTrigger(
681 1 /* period_ms */);
682 TraceConfig tc3(tc_str3);
683 EXPECT_EQ(tc_str3, tc3.ToString());
684 EXPECT_TRUE(tc3.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
685 ASSERT_EQ(1u, tc3.memory_dump_config().triggers.size());
686 EXPECT_EQ(1u, tc3.memory_dump_config().triggers[0].min_time_between_dumps_ms);
687 EXPECT_EQ(MemoryDumpLevelOfDetail::kBackground,
688 tc3.memory_dump_config().triggers[0].level_of_detail);
689 }
690
TEST(TraceConfigTest,EmptyMemoryDumpConfigTest)691 TEST(TraceConfigTest, EmptyMemoryDumpConfigTest) {
692 // Empty trigger list should also be specified when converting back to string.
693 TraceConfig tc(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
694 EXPECT_EQ(TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers(),
695 tc.ToString());
696 EXPECT_EQ(0u, tc.memory_dump_config().triggers.size());
697 EXPECT_EQ(
698 static_cast<uint32_t>(TraceConfig::MemoryDumpConfig::HeapProfiler::
699 kDefaultBreakdownThresholdBytes),
700 tc.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes);
701 }
702
TEST(TraceConfigTest,LegacyStringToMemoryDumpConfig)703 TEST(TraceConfigTest, LegacyStringToMemoryDumpConfig) {
704 TraceConfig tc(MemoryDumpManager::kTraceCategory, "");
705 EXPECT_TRUE(tc.IsCategoryGroupEnabled(MemoryDumpManager::kTraceCategory));
706 EXPECT_NE(std::string::npos, tc.ToString().find("memory_dump_config"));
707 EXPECT_EQ(0u, tc.memory_dump_config().triggers.size());
708 EXPECT_EQ(
709 static_cast<uint32_t>(TraceConfig::MemoryDumpConfig::HeapProfiler::
710 kDefaultBreakdownThresholdBytes),
711 tc.memory_dump_config().heap_profiler_options.breakdown_threshold_bytes);
712 }
713
TEST(TraceConfigTest,SystraceEventsSerialization)714 TEST(TraceConfigTest, SystraceEventsSerialization) {
715 TraceConfig tc(MemoryDumpManager::kTraceCategory, "");
716 tc.EnableSystrace();
717 EXPECT_EQ(0U, tc.systrace_events().size());
718 tc.EnableSystraceEvent("power"); // As a events category
719 tc.EnableSystraceEvent("timer:tick_stop"); // As an event
720 EXPECT_EQ(2U, tc.systrace_events().size());
721
722 const TraceConfig tc1(MemoryDumpManager::kTraceCategory,
723 tc.ToTraceOptionsString());
724 EXPECT_EQ(2U, tc1.systrace_events().size());
725 EXPECT_TRUE(tc1.systrace_events().count("power"));
726 EXPECT_TRUE(tc1.systrace_events().count("timer:tick_stop"));
727
728 const TraceConfig tc2(tc.ToString());
729 EXPECT_EQ(2U, tc2.systrace_events().size());
730 EXPECT_TRUE(tc2.systrace_events().count("power"));
731 EXPECT_TRUE(tc2.systrace_events().count("timer:tick_stop"));
732 }
733
TEST(TraceConfigTest,IsConfigEquivalent)734 TEST(TraceConfigTest, IsConfigEquivalent) {
735 TraceConfig tc1("foo,bar", "");
736 TraceConfig tc2("bar,foo", "");
737 EXPECT_TRUE(tc1.IsEquivalentTo(tc2));
738
739 tc1.EnableHistogram("Foo.Bar1");
740 tc1.EnableHistogram("Foo.Bar2");
741 tc2.EnableHistogram("Foo.Bar2");
742 tc2.EnableHistogram("Foo.Bar1");
743 EXPECT_TRUE(tc1.IsEquivalentTo(tc2));
744
745 tc1.SetEventPackageNameFilterEnabled(true);
746 EXPECT_FALSE(tc1.IsEquivalentTo(tc2));
747
748 // This is an example of a config that comes from Perfetto UI. Check that
749 // it is still equivalent after converting to a string and back (this is
750 // important for startup session adoption).
751 TraceConfig tc3(
752 "{\"record_mode\":\"record-until-full\","
753 "\"included_categories\":[\"foo,bar\"],"
754 "\"excluded_categories\":[\"*\"],\"memory_dump_config\":{}}");
755 TraceConfig tc4(tc3.ToString());
756 EXPECT_TRUE(tc3.IsEquivalentTo(tc4));
757 }
758
759 } // namespace base::trace_event
760