xref: /aosp_15_r20/external/cronet/base/trace_event/trace_config_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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