| // Copyright 2015 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/json/json_reader.h" | 
 | #include "base/json/json_writer.h" | 
 | #include "base/message_loop/message_loop.h" | 
 | #include "base/values.h" | 
 | #include "content/browser/tracing/background_tracing_config_impl.h" | 
 | #include "content/browser/tracing/background_tracing_rule.h" | 
 | #include "content/public/test/test_browser_thread.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace content { | 
 |  | 
 | class BackgroundTracingConfigTest : public testing::Test { | 
 |  public: | 
 |   BackgroundTracingConfigTest() | 
 |       : ui_thread_(BrowserThread::UI, &message_loop_) {} | 
 |  | 
 |  protected: | 
 |   base::MessageLoop message_loop_; | 
 |   TestBrowserThread ui_thread_; | 
 | }; | 
 |  | 
 | std::unique_ptr<BackgroundTracingConfigImpl> ReadFromJSONString( | 
 |     const std::string& json_text) { | 
 |   std::unique_ptr<base::Value> json_value(base::JSONReader::Read(json_text)); | 
 |  | 
 |   base::DictionaryValue* dict = NULL; | 
 |   if (json_value) | 
 |     json_value->GetAsDictionary(&dict); | 
 |  | 
 |   std::unique_ptr<BackgroundTracingConfigImpl> config( | 
 |       static_cast<BackgroundTracingConfigImpl*>( | 
 |           BackgroundTracingConfig::FromDict(dict).release())); | 
 |   return config; | 
 | } | 
 |  | 
 | std::string ConfigToString(const BackgroundTracingConfig* config) { | 
 |   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |  | 
 |   config->IntoDict(dict.get()); | 
 |  | 
 |   std::string results; | 
 |   if (base::JSONWriter::Write(*dict.get(), &results)) | 
 |     return results; | 
 |   return ""; | 
 | } | 
 |  | 
 | std::string RuleToString(const BackgroundTracingRule* rule) { | 
 |   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |  | 
 |   rule->IntoDict(dict.get()); | 
 |  | 
 |   std::string results; | 
 |   if (base::JSONWriter::Write(*dict.get(), &results)) | 
 |     return results; | 
 |   return ""; | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, ConfigFromInvalidString) { | 
 |   // Missing or invalid mode | 
 |   EXPECT_FALSE(ReadFromJSONString("{}")); | 
 |   EXPECT_FALSE(ReadFromJSONString("{\"mode\":\"invalid\"}")); | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, PreemptiveConfigFromInvalidString) { | 
 |   // Missing or invalid category | 
 |   EXPECT_FALSE(ReadFromJSONString("{\"mode\":\"preemptive\"}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"invalid\"}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"invalid\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"trigger_name\":\"foo\"}]}")); | 
 |  | 
 |   // Missing rules. | 
 |   EXPECT_FALSE( | 
 |       ReadFromJSONString("{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |                          "\"BENCHMARK\",\"configs\": []}")); | 
 |  | 
 |   // Missing or invalid configs | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"," | 
 |       "\"configs\": \"\"}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"," | 
 |       "\"configs\": {}}")); | 
 |  | 
 |   // Invalid config entries | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"," | 
 |       "\"configs\": [{}]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"," | 
 |       "\"configs\": [\"invalid\"]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"," | 
 |       "\"configs\": [[]]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"," | 
 |       "\"configs\": [{\"rule\": \"invalid\"}]}")); | 
 |  | 
 |   // Missing or invalid keys for a named trigger. | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"preemptive\", \"category\": \"benchmark\"," | 
 |       "\"configs\": [{\"rule\": \"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"}]}")); | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, ReactiveConfigFromInvalidString) { | 
 |   // Missing or invalid configs | 
 |   EXPECT_FALSE(ReadFromJSONString("{\"mode\":\"reactive\"}")); | 
 |   EXPECT_FALSE( | 
 |       ReadFromJSONString("{\"mode\":\"reactive\", \"configs\": \"invalid\"}")); | 
 |   EXPECT_FALSE(ReadFromJSONString("{\"mode\":\"reactive\", \"configs\": {}}")); | 
 |  | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"REACTIVE_TRACING_MODE\", \"configs\": []}")); | 
 |  | 
 |   // Invalid config entries | 
 |   EXPECT_FALSE( | 
 |       ReadFromJSONString("{\"mode\":\"reactive\", \"configs\": [{}]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\", \"configs\": [\"invalid\"]}")); | 
 |  | 
 |   // Invalid tracing rule type | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\"," | 
 |       "\"configs\": [{\"rule\": []}]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\"," | 
 |       "\"configs\": [{\"rule\": \"\"}]}")); | 
 |   EXPECT_FALSE( | 
 |       ReadFromJSONString("{\"mode\":\"reactive\"," | 
 |                          "\"configs\": [{\"rule\": " | 
 |                          "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"}]}")); | 
 |  | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\"," | 
 |       "\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " | 
 |       "[]}]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\"," | 
 |       "\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " | 
 |       "\"\"}]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\"," | 
 |       "\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " | 
 |       "\"benchmark\"}]}")); | 
 |  | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\"," | 
 |       "\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " | 
 |       "\"benchmark\", \"trigger_name\": []}]}")); | 
 |   EXPECT_FALSE(ReadFromJSONString( | 
 |       "{\"mode\":\"reactive\"," | 
 |       "\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", \"category\": " | 
 |       "\"benchmark\", \"trigger_name\": 0}]}")); | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, PreemptiveConfigFromValidString) { | 
 |   std::unique_ptr<BackgroundTracingConfigImpl> config; | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"BENCHMARK\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"trigger_name\":\"foo\"}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::PREEMPTIVE); | 
 |   EXPECT_EQ(config->category_preset(), BackgroundTracingConfigImpl::BENCHMARK); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"rule\":\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," | 
 |             "\"trigger_name\":\"foo\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"BENCHMARK\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\", " | 
 |       "\"histogram_name\":\"foo\", \"histogram_value\": 1}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::PREEMPTIVE); | 
 |   EXPECT_EQ(config->category_preset(), BackgroundTracingConfigImpl::BENCHMARK); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"histogram_lower_value\":1,\"histogram_name\":\"foo\"," | 
 |             "\"histogram_repeat\":true,\"histogram_upper_value\":2147483647," | 
 |             "\"rule\":\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"BENCHMARK\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\", " | 
 |       "\"histogram_name\":\"foo\", \"histogram_value\": 1, " | 
 |       "\"histogram_repeat\":false}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::PREEMPTIVE); | 
 |   EXPECT_EQ(config->category_preset(), BackgroundTracingConfigImpl::BENCHMARK); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"histogram_lower_value\":1,\"histogram_name\":\"foo\"," | 
 |             "\"histogram_repeat\":false,\"histogram_upper_value\":2147483647," | 
 |             "\"rule\":\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"BENCHMARK\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\", " | 
 |       "\"histogram_name\":\"foo\", \"histogram_lower_value\": 1, " | 
 |       "\"histogram_upper_value\": 2}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::PREEMPTIVE); | 
 |   EXPECT_EQ(config->category_preset(), BackgroundTracingConfigImpl::BENCHMARK); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"histogram_lower_value\":1,\"histogram_name\":\"foo\"," | 
 |             "\"histogram_repeat\":true,\"histogram_upper_value\":2,\"rule\":" | 
 |             "\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"BENCHMARK\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\", " | 
 |       "\"histogram_name\":\"foo\", \"histogram_lower_value\": 1, " | 
 |       "\"histogram_upper_value\": 2, \"histogram_repeat\":false}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::PREEMPTIVE); | 
 |   EXPECT_EQ(config->category_preset(), BackgroundTracingConfigImpl::BENCHMARK); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"histogram_lower_value\":1,\"histogram_name\":\"foo\"," | 
 |             "\"histogram_repeat\":false,\"histogram_upper_value\":2,\"rule\":" | 
 |             "\"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"BENCHMARK\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"trigger_name\":\"foo1\"}, " | 
 |       "{\"rule\": \"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", " | 
 |       "\"trigger_name\":\"foo2\"}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::PREEMPTIVE); | 
 |   EXPECT_EQ(config->category_preset(), BackgroundTracingConfigImpl::BENCHMARK); | 
 |   EXPECT_EQ(config->rules().size(), 2u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"rule\":\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," | 
 |             "\"trigger_name\":\"foo1\"}"); | 
 |   EXPECT_EQ(RuleToString(config->rules()[1]), | 
 |             "{\"rule\":\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," | 
 |             "\"trigger_name\":\"foo2\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"category\":\"BENCHMARK_DEEP\",\"configs\":[{\"rule\":" | 
 |       "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\",\"trigger_name\":" | 
 |       "\"foo1\"}],\"disable_blink_features\":\"SlowerWeb1,SlowerWeb2\"," | 
 |       "\"enable_blink_features\":\"FasterWeb1,FasterWeb2\"," | 
 |       "\"mode\":\"PREEMPTIVE_TRACING_MODE\"," | 
 |       "\"scenario_name\":\"my_awesome_experiment\"}"); | 
 |   EXPECT_EQ(config->enable_blink_features(), "FasterWeb1,FasterWeb2"); | 
 |   EXPECT_EQ(config->disable_blink_features(), "SlowerWeb1,SlowerWeb2"); | 
 |   EXPECT_EQ(config->scenario_name(), "my_awesome_experiment"); | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, ValidPreemptiveCategoryToString) { | 
 |   std::unique_ptr<BackgroundTracingConfigImpl> config = ReadFromJSONString( | 
 |       "{\"mode\":\"PREEMPTIVE_TRACING_MODE\", \"category\": " | 
 |       "\"BENCHMARK\",\"configs\": [{\"rule\": " | 
 |       "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\", \"trigger_name\":\"foo\"}]}"); | 
 |  | 
 |   BackgroundTracingConfigImpl::CategoryPreset categories[] = { | 
 |       BackgroundTracingConfigImpl::BENCHMARK, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_DEEP, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_GPU, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_IPC, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_STARTUP, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_BLINK_GC, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_MEMORY_HEAVY, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_MEMORY_LIGHT, | 
 |       BackgroundTracingConfigImpl::BENCHMARK_EXECUTION_METRIC, | 
 |       BackgroundTracingConfigImpl::BLINK_STYLE, | 
 |   }; | 
 |  | 
 |   const char* category_strings[] = {"BENCHMARK", | 
 |                                     "BENCHMARK_DEEP", | 
 |                                     "BENCHMARK_GPU", | 
 |                                     "BENCHMARK_IPC", | 
 |                                     "BENCHMARK_STARTUP", | 
 |                                     "BENCHMARK_BLINK_GC", | 
 |                                     "BENCHMARK_MEMORY_HEAVY", | 
 |                                     "BENCHMARK_MEMORY_LIGHT", | 
 |                                     "BENCHMARK_EXECUTION_METRIC", | 
 |                                     "BLINK_STYLE"}; | 
 |   for (size_t i = 0; | 
 |        i < | 
 |        sizeof(categories) / sizeof(BackgroundTracingConfigImpl::CategoryPreset); | 
 |        i++) { | 
 |     config->set_category_preset(categories[i]); | 
 |     std::string expected = | 
 |         std::string("{\"category\":\"") + category_strings[i] + | 
 |         std::string( | 
 |             "\",\"configs\":[{\"rule\":" | 
 |             "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\",\"trigger_name\":" | 
 |             "\"foo\"}],\"mode\":\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |     EXPECT_EQ(ConfigToString(config.get()), expected.c_str()); | 
 |     std::unique_ptr<BackgroundTracingConfigImpl> config2 = | 
 |         ReadFromJSONString(expected); | 
 |     EXPECT_EQ(config->category_preset(), config2->category_preset()); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, ReactiveConfigFromValidString) { | 
 |   std::unique_ptr<BackgroundTracingConfigImpl> config; | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " | 
 |       "\"category\": \"BENCHMARK\",\"trigger_delay\":30," | 
 |       "\"trigger_name\": \"foo\"}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"category\":\"BENCHMARK\"," | 
 |             "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," | 
 |             "\"trigger_delay\":30,\"trigger_name\":\"foo\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " | 
 |       "\"category\": \"BENCHMARK_DEEP\", \"trigger_delay\":30, " | 
 |       "\"trigger_name\": \"foo\"}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"category\":\"BENCHMARK_DEEP\"," | 
 |             "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," | 
 |             "\"trigger_delay\":30,\"trigger_name\":\"foo\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " | 
 |       "\"category\": \"BENCHMARK_DEEP\",\"trigger_delay\":30," | 
 |       "\"trigger_name\": \"foo\",\"trigger_delay\":30," | 
 |       "\"trigger_chance\": 0.5}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"category\":\"BENCHMARK_DEEP\"," | 
 |             "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," | 
 |             "\"trigger_chance\":0.5,\"trigger_delay\":30," | 
 |             "\"trigger_name\":\"foo\"}"); | 
 |  | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " | 
 |       "\"category\": \"BENCHMARK_DEEP\", \"trigger_name\": " | 
 |       "\"foo1\"},{\"rule\": " | 
 |       "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\", " | 
 |       "\"category\": \"BENCHMARK_DEEP\", \"trigger_name\": \"foo2\"}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); | 
 |   EXPECT_EQ(config->rules().size(), 2u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"category\":\"BENCHMARK_DEEP\"," | 
 |             "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," | 
 |             "\"trigger_delay\":30,\"trigger_name\":\"foo1\"}"); | 
 |   EXPECT_EQ(RuleToString(config->rules()[1]), | 
 |             "{\"category\":\"BENCHMARK_DEEP\"," | 
 |             "\"rule\":\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\"," | 
 |             "\"trigger_delay\":30,\"trigger_name\":\"foo2\"}"); | 
 |   config = ReadFromJSONString( | 
 |       "{\"mode\":\"REACTIVE_TRACING_MODE\",\"configs\": [{\"rule\": " | 
 |       "\"TRACE_AT_RANDOM_INTERVALS\"," | 
 |       "\"stop_tracing_on_repeated_reactive\": true," | 
 |       "\"category\": \"BENCHMARK_DEEP\"," | 
 |       "\"timeout_min\":10, \"timeout_max\":20}]}"); | 
 |   EXPECT_TRUE(config); | 
 |   EXPECT_EQ(config->tracing_mode(), BackgroundTracingConfig::REACTIVE); | 
 |   EXPECT_EQ(config->rules().size(), 1u); | 
 |   EXPECT_EQ(RuleToString(config->rules()[0]), | 
 |             "{\"category\":\"BENCHMARK_DEEP\",\"rule\":\"TRACE_AT_RANDOM_" | 
 |             "INTERVALS\",\"stop_tracing_on_repeated_reactive\":true," | 
 |             "\"timeout_max\":20,\"timeout_min\":10}"); | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, ValidPreemptiveConfigToString) { | 
 |   std::unique_ptr<BackgroundTracingConfigImpl> config( | 
 |       new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |  | 
 |   // Default values | 
 |   EXPECT_EQ(ConfigToString(config.get()), | 
 |             "{\"category\":\"BENCHMARK\",\"configs\":[],\"mode\":\"PREEMPTIVE_" | 
 |             "TRACING_MODE\"}"); | 
 |  | 
 |   // Change category_preset | 
 |   config->set_category_preset(BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |   EXPECT_EQ(ConfigToString(config.get()), | 
 |             "{\"category\":\"BENCHMARK_DEEP\",\"configs\":[],\"mode\":" | 
 |             "\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |     config->set_category_preset(BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |     dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); | 
 |     dict->SetString("trigger_name", "foo"); | 
 |     config->AddPreemptiveRule(dict.get()); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK_DEEP\",\"configs\":[{\"rule\":" | 
 |               "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\",\"trigger_name\":" | 
 |               "\"foo\"}],\"mode\":\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |     config->set_category_preset(BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |     dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); | 
 |     dict->SetString("trigger_name", "foo"); | 
 |     dict->SetDouble("trigger_chance", 0.5); | 
 |     config->AddPreemptiveRule(dict.get()); | 
 |  | 
 |     EXPECT_EQ( | 
 |         ConfigToString(config.get()), | 
 |         "{\"category\":\"BENCHMARK_DEEP\",\"configs\":[{\"rule\":" | 
 |         "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\",\"trigger_chance\":0.5," | 
 |         "\"trigger_name\":\"foo\"}],\"mode\":\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |     config->set_category_preset(BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |     dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); | 
 |     dict->SetString("trigger_name", "foo1"); | 
 |     config->AddPreemptiveRule(dict.get()); | 
 |  | 
 |     dict->SetString("trigger_name", "foo2"); | 
 |     config->AddPreemptiveRule(dict.get()); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK_DEEP\",\"configs\":[{\"rule\":" | 
 |               "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\",\"trigger_name\":" | 
 |               "\"foo1\"},{\"rule\":\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\"," | 
 |               "\"trigger_name\":\"foo2\"}],\"mode\":\"PREEMPTIVE_TRACING_" | 
 |               "MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> second_dict( | 
 |         new base::DictionaryValue()); | 
 |     second_dict->SetString( | 
 |         "rule", "MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE"); | 
 |     second_dict->SetString("histogram_name", "foo"); | 
 |     second_dict->SetInteger("histogram_lower_value", 1); | 
 |     second_dict->SetInteger("histogram_upper_value", 2); | 
 |     config->AddPreemptiveRule(second_dict.get()); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK\",\"configs\":[{\"histogram_lower_" | 
 |               "value\":1,\"histogram_name\":\"foo\",\"histogram_repeat\":true," | 
 |               "\"histogram_upper_value\":2,\"rule\":\"MONITOR_AND_DUMP_WHEN_" | 
 |               "SPECIFIC_HISTOGRAM_AND_VALUE\"}],\"mode\":\"PREEMPTIVE_TRACING_" | 
 |               "MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> second_dict( | 
 |         new base::DictionaryValue()); | 
 |     second_dict->SetString( | 
 |         "rule", "MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE"); | 
 |     second_dict->SetString("histogram_name", "foo"); | 
 |     second_dict->SetInteger("histogram_lower_value", 1); | 
 |     second_dict->SetInteger("histogram_upper_value", 2); | 
 |     second_dict->SetInteger("trigger_delay", 10); | 
 |     config->AddPreemptiveRule(second_dict.get()); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK\",\"configs\":[{\"histogram_lower_" | 
 |               "value\":1,\"histogram_name\":\"foo\",\"histogram_repeat\":true," | 
 |               "\"histogram_upper_value\":2,\"rule\":\"MONITOR_AND_DUMP_WHEN_" | 
 |               "SPECIFIC_HISTOGRAM_AND_VALUE\",\"trigger_delay\":10}],\"mode\":" | 
 |               "\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |     config->set_category_preset(BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |     dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED"); | 
 |     dict->SetString("trigger_name", "foo1"); | 
 |     config->AddPreemptiveRule(dict.get()); | 
 |  | 
 |     config->scenario_name_ = "my_awesome_experiment"; | 
 |     config->enable_blink_features_ = "FasterWeb1,FasterWeb2"; | 
 |     config->disable_blink_features_ = "SlowerWeb1,SlowerWeb2"; | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK_DEEP\",\"configs\":[{\"rule\":" | 
 |               "\"MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED\",\"trigger_name\":" | 
 |               "\"foo1\"}],\"disable_blink_features\":\"SlowerWeb1,SlowerWeb2\"," | 
 |               "\"enable_blink_features\":\"FasterWeb1,FasterWeb2\"," | 
 |               "\"mode\":\"PREEMPTIVE_TRACING_MODE\"," | 
 |               "\"scenario_name\":\"my_awesome_experiment\"}"); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, InvalidPreemptiveConfigToString) { | 
 |   std::unique_ptr<BackgroundTracingConfigImpl> config; | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |     dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_BROWSER_STARTUP_COMPLETE"); | 
 |     config->AddPreemptiveRule(dict.get()); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK\",\"configs\":[],\"mode\":" | 
 |               "\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> second_dict( | 
 |         new base::DictionaryValue()); | 
 |     second_dict->SetString( | 
 |         "rule", "MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE"); | 
 |     second_dict->SetString("histogram_name", "foo"); | 
 |     second_dict->SetInteger("histogram_lower_value", 1); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK\",\"configs\":[],\"mode\":" | 
 |               "\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::PREEMPTIVE)); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> second_dict( | 
 |         new base::DictionaryValue()); | 
 |     second_dict->SetString( | 
 |         "rule", "MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE"); | 
 |     second_dict->SetString("histogram_name", "foo"); | 
 |     second_dict->SetInteger("histogram_lower_value", 1); | 
 |     second_dict->SetInteger("histogram_upper_value", 1); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"category\":\"BENCHMARK\",\"configs\":[],\"mode\":" | 
 |               "\"PREEMPTIVE_TRACING_MODE\"}"); | 
 |   } | 
 | } | 
 |  | 
 | TEST_F(BackgroundTracingConfigTest, ValidReactiveConfigToString) { | 
 |   std::unique_ptr<BackgroundTracingConfigImpl> config( | 
 |       new BackgroundTracingConfigImpl(BackgroundTracingConfig::REACTIVE)); | 
 |  | 
 |   // Default values | 
 |   EXPECT_EQ(ConfigToString(config.get()), | 
 |             "{\"configs\":[],\"mode\":\"REACTIVE_TRACING_MODE\"}"); | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::REACTIVE)); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |     dict->SetString("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL"); | 
 |     dict->SetString("trigger_name", "foo"); | 
 |     config->AddReactiveRule(dict.get(), | 
 |                             BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |  | 
 |     EXPECT_EQ(ConfigToString(config.get()), | 
 |               "{\"configs\":[{\"category\":\"BENCHMARK_DEEP\",\"rule\":\"TRACE_" | 
 |               "ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\",\"trigger_delay\":30," | 
 |               "\"trigger_name\":\"foo\"}],\"mode\":\"REACTIVE_TRACING_MODE\"}"); | 
 |   } | 
 |  | 
 |   { | 
 |     config.reset( | 
 |         new BackgroundTracingConfigImpl(BackgroundTracingConfig::REACTIVE)); | 
 |  | 
 |     std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |     dict->SetString("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL"); | 
 |     dict->SetString("trigger_name", "foo1"); | 
 |     config->AddReactiveRule(dict.get(), | 
 |                             BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |  | 
 |     dict->SetString("trigger_name", "foo2"); | 
 |     config->AddReactiveRule(dict.get(), | 
 |                             BackgroundTracingConfigImpl::BENCHMARK_DEEP); | 
 |  | 
 |     EXPECT_EQ( | 
 |         ConfigToString(config.get()), | 
 |         "{\"configs\":[{\"category\":\"BENCHMARK_DEEP\",\"rule\":\"TRACE_" | 
 |         "ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\",\"trigger_delay\":30," | 
 |         "\"trigger_name\":\"foo1\"},{\"category\":\"BENCHMARK_DEEP\",\"rule\":" | 
 |         "\"TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL\",\"trigger_delay\":30," | 
 |         "\"trigger_name\":\"foo2\"}],\"mode\":\"REACTIVE_TRACING_MODE\"}"); | 
 |   } | 
 | } | 
 |  | 
 | }  // namspace content |