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