• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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