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