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