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