blob: 7f2ab1bc15245c87e660b908392a291a10d6e21d [file] [log] [blame]
// 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 <stddef.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/metrics/histogram_macros.h"
#include "base/run_loop.h"
#include "base/strings/pattern.h"
#include "base/task/post_task.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "content/browser/devtools/protocol/devtools_protocol_test_support.h"
#include "content/browser/tracing/background_startup_tracing_observer.h"
#include "content/browser/tracing/background_tracing_active_scenario.h"
#include "content/browser/tracing/background_tracing_manager_impl.h"
#include "content/browser/tracing/background_tracing_rule.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "services/tracing/public/cpp/tracing_features.h"
#include "third_party/zlib/zlib.h"
using base::trace_event::TraceLog;
namespace content {
namespace {
class TestStartupPreferenceManagerImpl
: public BackgroundStartupTracingObserver::PreferenceManager {
public:
void SetBackgroundStartupTracingEnabled(bool enabled) override {
enabled_ = enabled;
}
bool GetBackgroundStartupTracingEnabled() const override { return enabled_; }
private:
bool enabled_ = false;
};
// Wait until |condition| returns true.
void WaitForCondition(base::RepeatingCallback<bool()> condition,
const std::string& description) {
const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(30);
const base::TimeTicks start_time = base::TimeTicks::Now();
while (!condition.Run() && (base::TimeTicks::Now() - start_time < kTimeout)) {
base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
run_loop.Run();
}
ASSERT_TRUE(condition.Run())
<< "Timeout waiting for condition: " << description;
}
// An helper class that observes tracing states transition and allows
// synchronisation with tests. The class adds itself as a tracelog
// enable state observer and provides methods to wait for a given state.
//
// Usage:
// TestTraceLogHelper tracelog_helper;
// [... start tracing ...]
// tracelog_helper.WaitForStartTracing();
// [... stop tracing ...]
// tracing_controller->StopTracing();
// tracelog_helper.WaitForStopTracing();
class TestTraceLogHelper : public TraceLog::EnabledStateObserver {
public:
TestTraceLogHelper() {
EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
TraceLog::GetInstance()->AddEnabledStateObserver(this);
}
~TestTraceLogHelper() override {
EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
// Ensures tracing got enabled/disabled only once.
EXPECT_EQ(1, enable_count);
EXPECT_EQ(1, disable_count);
}
void OnTraceLogEnabled() override {
wait_for_start_tracing_.QuitWhenIdle();
enable_count++;
}
void OnTraceLogDisabled() override {
wait_for_stop_tracing_.QuitWhenIdle();
disable_count++;
}
void WaitForStartTracing() { wait_for_start_tracing_.Run(); }
void WaitForStopTracing() { wait_for_stop_tracing_.Run(); }
private:
int enable_count = 0;
int disable_count = 0;
base::RunLoop wait_for_start_tracing_;
base::RunLoop wait_for_stop_tracing_;
};
// An helper class that observes background tracing states transition and
// allows synchronisation with tests. The class adds itself as a backgrond
// tracing enabled state observer. It provides methods to wait for a given
// state.
//
// Usage:
// TestBackgroundTracingHelper background_tracing_helper;
// [... set a background tracing scenario ...]
// background_tracing_helper.WaitForScenarioActivated();
// [... trigger an event ...]
// background_tracing_helper->WaitForTracingEnabled();
// [... abort ...]
// background_tracing_helper->WaitForScenarioAborted();
class TestBackgroundTracingHelper
: public BackgroundTracingManagerImpl::EnabledStateObserver {
public:
TestBackgroundTracingHelper() {
BackgroundTracingManagerImpl::GetInstance()->AddEnabledStateObserver(this);
}
~TestBackgroundTracingHelper() override {
BackgroundTracingManagerImpl::GetInstance()->RemoveEnabledStateObserver(
this);
EXPECT_FALSE(is_scenario_active_);
}
void OnScenarioActivated(const BackgroundTracingConfigImpl* config) override {
is_scenario_active_ = true;
wait_for_scenario_activated_.Quit();
}
void OnScenarioAborted() override {
is_scenario_active_ = false;
wait_for_scenario_aborted_.Quit();
}
void OnTracingEnabled(
BackgroundTracingConfigImpl::CategoryPreset preset) override {
wait_for_tracing_enabled_.Quit();
}
void WaitForScenarioActivated() { wait_for_scenario_activated_.Run(); }
void WaitForScenarioAborted() { wait_for_scenario_aborted_.Run(); }
void WaitForTracingEnabled() { wait_for_tracing_enabled_.Run(); }
private:
bool is_scenario_active_ = false;
base::RunLoop wait_for_scenario_activated_;
base::RunLoop wait_for_scenario_aborted_;
base::RunLoop wait_for_tracing_enabled_;
};
// An helper class that receives uploaded trace. It allows synchronisation with
// tests.
//
// Usage:
// TestTraceReceiverHelper trace_receiver_helper;
// [... do tracing stuff ...]
// trace_receiver_helper.WaitForTraceReceived();
class TestTraceReceiverHelper {
public:
BackgroundTracingManager::ReceiveCallback get_receive_callback() {
return base::BindRepeating(&TestTraceReceiverHelper::Upload,
base::Unretained(this));
}
void WaitForTraceReceived() { wait_for_trace_received_.Run(); }
bool trace_received() const { return trace_received_; }
bool TraceHasMatchingString(const char* text) const {
return file_contents_.find(text) != std::string::npos;
}
void Upload(
const scoped_refptr<base::RefCountedString>& file_contents,
std::unique_ptr<const base::DictionaryValue> metadata,
BackgroundTracingManager::FinishedProcessingCallback done_callback) {
// Receive the trace.
EXPECT_TRUE(file_contents);
EXPECT_FALSE(trace_received_);
trace_received_ = true;
// Uncompress the trace content.
size_t compressed_length = file_contents->data().length();
const size_t kOutputBufferLength = 10 * 1024 * 1024;
std::vector<char> output_str(kOutputBufferLength);
z_stream stream = {nullptr};
stream.avail_in = compressed_length;
stream.avail_out = kOutputBufferLength;
stream.next_in = reinterpret_cast<Bytef*>(&file_contents->data()[0]);
stream.next_out = reinterpret_cast<Bytef*>(output_str.data());
// 16 + MAX_WBITS means only decoding gzip encoded streams, and using
// the biggest window size, according to zlib.h
int result = inflateInit2(&stream, 16 + MAX_WBITS);
EXPECT_EQ(Z_OK, result);
result = inflate(&stream, Z_FINISH);
int bytes_written = kOutputBufferLength - stream.avail_out;
inflateEnd(&stream);
EXPECT_EQ(Z_STREAM_END, result);
file_contents_.assign(output_str.data(), bytes_written);
// Post the callbacks.
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
base::BindOnce(std::move(done_callback), true));
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
wait_for_trace_received_.QuitWhenIdleClosure());
}
private:
base::RunLoop wait_for_trace_received_;
bool trace_received_ = false;
std::string file_contents_;
};
// An helper class that receives multiple traces through the same callback.
class TestMultipleTraceReceiverHelper {
public:
BackgroundTracingManager::ReceiveCallback get_receive_callback() {
return base::BindRepeating(&TestMultipleTraceReceiverHelper::Upload,
base::Unretained(this));
}
void WaitForTraceReceived(size_t offset) {
trace_receivers_[offset].WaitForTraceReceived();
}
bool trace_received(size_t offset) {
return trace_receivers_[offset].trace_received();
}
void Upload(
const scoped_refptr<base::RefCountedString>& file_contents,
std::unique_ptr<const base::DictionaryValue> metadata,
BackgroundTracingManager::FinishedProcessingCallback done_callback) {
trace_receivers_[current_receiver_offset_].Upload(
file_contents, std::move(metadata), std::move(done_callback));
current_receiver_offset_++;
}
private:
std::map<size_t, TestTraceReceiverHelper> trace_receivers_;
int current_receiver_offset_ = 0;
};
// An helper class accepts a slow-report trigger callback.
//
// Usage:
// TestTriggerHelper test_trigger_helper;
// BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
// handle, trigger_helper.receive_closure(true));
// test_trigger_helper.WaitForTriggerReceived();
class TestTriggerHelper {
public:
BackgroundTracingManager::StartedFinalizingCallback receive_closure(
bool expected) {
return base::BindRepeating(&TestTriggerHelper::OnTriggerReceive,
base::Unretained(this), expected);
}
void WaitForTriggerReceived() { wait_for_trigger_received_.Run(); }
private:
void OnTriggerReceive(bool expected, bool value) {
EXPECT_EQ(expected, value);
wait_for_trigger_received_.QuitWhenIdle();
}
base::RunLoop wait_for_trigger_received_;
};
} // namespace
class BackgroundTracingManagerBrowserTest : public ContentBrowserTest {
public:
BackgroundTracingManagerBrowserTest() {}
void PreRunTestOnMainThread() override {
BackgroundTracingManagerImpl::GetInstance()
->InvalidateTriggerHandlesForTesting();
ContentBrowserTest::PreRunTestOnMainThread();
}
private:
DISALLOW_COPY_AND_ASSIGN(BackgroundTracingManagerBrowserTest);
};
std::unique_ptr<BackgroundTracingConfig> CreatePreemptiveConfig() {
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
rules_dict->SetString("trigger_name", "preemptive_test");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
return config;
}
std::unique_ptr<BackgroundTracingConfig> CreateReactiveConfig() {
base::DictionaryValue dict;
dict.SetString("mode", "REACTIVE_TRACING_MODE");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL");
rules_dict->SetString("trigger_name", "reactive_test");
rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", true);
rules_dict->SetString("category", "BENCHMARK");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
return config;
}
// This tests that the endpoint receives the final trace data.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReceiveTraceFinalContentsOnTrigger) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
BackgroundTracingManager::TriggerHandle handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests triggering more than once still only gathers once.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
CallTriggersMoreThanOnceOnlyGatherOnce) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(false));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that non-whitelisted args get stripped if required.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
NotWhitelistedArgsStripped) {
TestTraceReceiverHelper trace_receiver_helper;
TestBackgroundTracingHelper background_tracing_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::ANONYMIZE_DATA));
background_tracing_helper.WaitForTracingEnabled();
{
TRACE_EVENT1("benchmark", "TestWhitelist", "test_whitelist", "abc");
TRACE_EVENT1("benchmark", "TestNotWhitelist", "test_not_whitelist", "abc");
}
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trigger_helper.WaitForTriggerReceived();
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
EXPECT_TRUE(trace_receiver_helper.TraceHasMatchingString("{"));
EXPECT_TRUE(trace_receiver_helper.TraceHasMatchingString("test_whitelist"));
EXPECT_FALSE(
trace_receiver_helper.TraceHasMatchingString("test_not_whitelist"));
}
// Tests that events emitted by the browser process immediately after the
// SetActiveScenario call does get included in the trace, without waiting for
// the full WaitForTracingEnabled() callback (background tracing will directly
// enable the TraceLog so we get events prior to waiting for the whole IPC
// sequence to enable tracing coming back from the tracing service).
// Temporarily disabled startup tracing on Android to be able to unblock
// Perfetto-based background tracing: https://crbug.com/941318
#if defined(OS_ANDROID)
#define MAYBE_EarlyTraceEventsInTrace DISABLED_EarlyTraceEventsInTrace
#else
#define MAYBE_EarlyTraceEventsInTrace EarlyTraceEventsInTrace
#endif
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
MAYBE_EarlyTraceEventsInTrace) {
TestTraceReceiverHelper trace_receiver_helper;
TestBackgroundTracingHelper background_tracing_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::ANONYMIZE_DATA));
{ TRACE_EVENT0("benchmark", "TestEarlyEvent"); }
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trigger_helper.WaitForTriggerReceived();
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
EXPECT_TRUE(trace_receiver_helper.TraceHasMatchingString("{"));
EXPECT_TRUE(trace_receiver_helper.TraceHasMatchingString("TestEarlyEvent"));
}
// This tests that browser metadata gets included in the trace.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
TraceMetadataInTrace) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::ANONYMIZE_DATA));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
EXPECT_TRUE(trace_receiver_helper.TraceHasMatchingString("cpu-brand"));
EXPECT_TRUE(trace_receiver_helper.TraceHasMatchingString("network-type"));
EXPECT_TRUE(trace_receiver_helper.TraceHasMatchingString("user-agent"));
}
// Flaky on android, linux, and windows: https://crbug.com/639706 and
// https://crbug.com/643415.
// This tests subprocesses (like a navigating renderer) which gets told to
// provide a argument-filtered trace and has no predicate in place to do the
// filtering (in this case, only the browser process gets it set), will crash
// rather than return potential PII.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
DISABLED_CrashWhenSubprocessWithoutArgumentFilter) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::ANONYMIZE_DATA));
background_tracing_helper.WaitForScenarioActivated();
NavigateToURL(shell(), GetTestUrl("", "about:blank"));
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
// We should *not* receive anything at all from the renderer,
// the process should've crashed rather than letting that happen.
EXPECT_FALSE(trace_receiver_helper.TraceHasMatchingString("CrRendererMain"));
}
// This tests multiple triggers still only gathers once.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
CallMultipleTriggersOnlyGatherOnce) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
rules_dict->SetString("trigger_name", "test1");
rules_list->Append(std::move(rules_dict));
}
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
rules_dict->SetString("trigger_name", "test2");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
BackgroundTracingManager::TriggerHandle handle1 =
BackgroundTracingManager::GetInstance()->RegisterTriggerType("test1");
BackgroundTracingManager::TriggerHandle handle2 =
BackgroundTracingManager::GetInstance()->RegisterTriggerType("test2");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle1, trigger_helper.receive_closure(true));
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle2, trigger_helper.receive_closure(false));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that delayed histogram triggers work as expected
// with preemptive scenarios.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
CallPreemptiveTriggerWithDelay) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule",
"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE");
rules_dict->SetString("histogram_name", "fake");
rules_dict->SetInteger("histogram_value", 1);
rules_dict->SetInteger("trigger_delay", 10);
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
base::RunLoop rule_triggered_runloop;
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
BackgroundTracingManagerImpl::GetInstance()
->GetActiveScenarioForTesting()
->SetRuleTriggeredCallbackForTesting(
rule_triggered_runloop.QuitClosure());
// Our reference value is "1", so a value of "2" should trigger a trace.
LOCAL_HISTOGRAM_COUNTS("fake", 2);
rule_triggered_runloop.Run();
// Since we specified a delay in the scenario, we should still be tracing
// at this point.
EXPECT_TRUE(
BackgroundTracingManagerImpl::GetInstance()->IsTracingForTesting());
// Fake the timer firing.
BackgroundTracingManagerImpl::GetInstance()
->GetActiveScenarioForTesting()
->FireTimerForTesting();
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that you can't trigger without a scenario set.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
CannotTriggerWithoutScenarioSet) {
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(false));
trigger_helper.WaitForTriggerReceived();
}
// This tests that no trace is triggered with a handle that isn't specified
// in the config.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
DoesNotTriggerWithWrongHandle) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"does_not_exist");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(false));
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_FALSE(trace_receiver_helper.trace_received());
}
// This tests that no trace is triggered with an invalid handle.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
DoesNotTriggerWithInvalidHandle) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
content::BackgroundTracingManager::TriggerHandle handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
BackgroundTracingManagerImpl::GetInstance()
->InvalidateTriggerHandlesForTesting();
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(false));
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_FALSE(trace_receiver_helper.trace_received());
}
// This tests that no preemptive trace is triggered with 0 chance set.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
PreemptiveNotTriggerWithZeroChance) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
rules_dict->SetString("trigger_name", "preemptive_test");
rules_dict->SetDouble("trigger_chance", 0.0);
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(false));
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_FALSE(trace_receiver_helper.trace_received());
}
// This tests that no reactive trace is triggered with 0 chance set.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReactiveNotTriggerWithZeroChance) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "REACTIVE_TRACING_MODE");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL");
rules_dict->SetString("trigger_name", "reactive_test1");
rules_dict->SetString("category", "BENCHMARK");
rules_dict->SetDouble("trigger_chance", 0.0);
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
content::BackgroundTracingManager::TriggerHandle handle =
content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(false));
trigger_helper.WaitForTriggerReceived();
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_FALSE(trace_receiver_helper.trace_received());
}
// This tests that histogram triggers for preemptive mode configs.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReceiveTraceSucceedsOnHigherHistogramSample) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule",
"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE");
rules_dict->SetString("histogram_name", "fake");
rules_dict->SetInteger("histogram_value", 1);
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
// Our reference value is "1", so a value of "2" should trigger a trace.
LOCAL_HISTOGRAM_COUNTS("fake", 2);
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that histogram triggers for reactive mode configs.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReceiveReactiveTraceSucceedsOnHigherHistogramSample) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "REACTIVE_TRACING_MODE");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule",
"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE");
rules_dict->SetString("histogram_name", "fake");
rules_dict->SetInteger("histogram_value", 1);
rules_dict->SetString("category", "BENCHMARK");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForScenarioActivated();
// Our reference value is "1", so a value of "2" should trigger a trace.
LOCAL_HISTOGRAM_COUNTS("fake", 2);
trace_receiver_helper.WaitForTraceReceived();
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that histogram values < reference value don't trigger.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReceiveTraceFailsOnLowerHistogramSample) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule",
"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE");
rules_dict->SetString("histogram_name", "fake");
rules_dict->SetInteger("histogram_value", 1);
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
// This should fail to trigger a trace since the sample value < the
// the reference value above.
LOCAL_HISTOGRAM_COUNTS("fake", 0);
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_FALSE(trace_receiver_helper.trace_received());
}
// This tests that histogram values > upper reference value don't trigger.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReceiveTraceFailsOnHigherHistogramSample) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule",
"MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE");
rules_dict->SetString("histogram_name", "fake");
rules_dict->SetInteger("histogram_lower_value", 1);
rules_dict->SetInteger("histogram_upper_value", 3);
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
EXPECT_TRUE(config);
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
// This should fail to trigger a trace since the sample value > the
// the upper reference value above.
LOCAL_HISTOGRAM_COUNTS("fake", 0);
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_FALSE(trace_receiver_helper.trace_received());
}
// This tests that invalid preemptive mode configs will fail.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
SetActiveScenarioFailsWithInvalidPreemptiveConfig) {
base::DictionaryValue dict;
dict.SetString("mode", "PREEMPTIVE_TRACING_MODE");
dict.SetString("category", "BENCHMARK");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "INVALID_RULE");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
// An invalid config should always return a nullptr here.
EXPECT_FALSE(config);
}
// This tests that reactive mode records and terminates with timeout.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReactiveTimeoutTermination) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreateReactiveConfig();
BackgroundTracingManager::TriggerHandle handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"reactive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
BackgroundTracingManagerImpl::GetInstance()
->GetActiveScenarioForTesting()
->FireTimerForTesting();
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that reactive mode records and terminates with a second trigger.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReactiveSecondTriggerTermination) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreateReactiveConfig();
BackgroundTracingManager::TriggerHandle handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"reactive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
// second trigger to terminate.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that reactive mode uploads on a second set of triggers.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReactiveSecondUpload) {
TestBackgroundTracingHelper background_tracing_helper;
TestMultipleTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreateReactiveConfig();
BackgroundTracingManager::TriggerHandle handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"reactive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForScenarioActivated();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
// second trigger to terminate.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trace_receiver_helper.WaitForTraceReceived(0);
EXPECT_TRUE(trace_receiver_helper.trace_received(0));
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
// second trigger to terminate.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
trace_receiver_helper.WaitForTraceReceived(1);
EXPECT_TRUE(trace_receiver_helper.trace_received(1));
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
}
// This tests that reactive mode only terminates with the same trigger.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReactiveSecondTriggerMustMatchForTermination) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "REACTIVE_TRACING_MODE");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL");
rules_dict->SetString("trigger_name", "reactive_test1");
rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", true);
rules_dict->SetInteger("trigger_delay", 10);
rules_dict->SetString("category", "BENCHMARK");
rules_list->Append(std::move(rules_dict));
}
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL");
rules_dict->SetString("trigger_name", "reactive_test2");
rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", true);
rules_dict->SetInteger("trigger_delay", 10);
rules_dict->SetString("category", "BENCHMARK");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
BackgroundTracingManager::TriggerHandle handle1 =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"reactive_test1");
BackgroundTracingManager::TriggerHandle handle2 =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"reactive_test2");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForScenarioActivated();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle1, trigger_helper.receive_closure(true));
// This is expected to fail since we triggered with handle1.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle2, trigger_helper.receive_closure(false));
// second trigger to terminate.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle1, trigger_helper.receive_closure(true));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests a third trigger in reactive more does not start another trace.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReactiveThirdTriggerTimeout) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreateReactiveConfig();
BackgroundTracingManager::TriggerHandle handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"reactive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForScenarioActivated();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
// second trigger to terminate.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
// third trigger to trigger again, fails as it is still gathering.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(false));
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
// This tests that reactive mode only terminates with a repeated trigger
// if the config specifies that it should.
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
ReactiveSecondTriggerIgnored) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
base::DictionaryValue dict;
dict.SetString("mode", "REACTIVE_TRACING_MODE");
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "TRACE_ON_NAVIGATION_UNTIL_TRIGGER_OR_FULL");
rules_dict->SetString("trigger_name", "reactive_test");
rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", false);
rules_dict->SetInteger("trigger_delay", 10);
rules_dict->SetString("category", "BENCHMARK");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::FromDict(&dict));
BackgroundTracingManager::TriggerHandle trigger_handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"reactive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
trigger_handle, trigger_helper.receive_closure(true));
background_tracing_helper.WaitForTracingEnabled();
// This is expected to fail since we already triggered.
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
trigger_handle, trigger_helper.receive_closure(false));
// Since we specified a delay in the scenario, we should still be tracing
// at this point.
EXPECT_TRUE(
BackgroundTracingManagerImpl::GetInstance()->IsTracingForTesting());
BackgroundTracingManagerImpl::GetInstance()
->GetActiveScenarioForTesting()
->FireTimerForTesting();
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
}
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
SetupStartupTracing) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<TestStartupPreferenceManagerImpl> preferences_moved(
new TestStartupPreferenceManagerImpl);
TestStartupPreferenceManagerImpl* preferences = preferences_moved.get();
BackgroundStartupTracingObserver::GetInstance()
->SetPreferenceManagerForTesting(std::move(preferences_moved));
preferences->SetBackgroundStartupTracingEnabled(false);
base::DictionaryValue dict;
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
rules_dict->SetString("trigger_name", "startup-config");
rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", false);
rules_dict->SetInteger("trigger_delay", 600);
rules_dict->SetString("category", "BENCHMARK_STARTUP");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::ReactiveFromDict(&dict));
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForScenarioActivated();
// Since we specified a delay in the scenario, we should still be tracing
// at this point.
EXPECT_FALSE(
BackgroundTracingManagerImpl::GetInstance()->IsTracingForTesting());
EXPECT_TRUE(preferences->GetBackgroundStartupTracingEnabled());
// Abort the scenario.
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_FALSE(trace_receiver_helper.trace_received());
}
IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest, RunStartupTracing) {
TestTraceLogHelper tracelog_helper;
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<TestStartupPreferenceManagerImpl> preferences_moved(
new TestStartupPreferenceManagerImpl);
TestStartupPreferenceManagerImpl* preferences = preferences_moved.get();
BackgroundStartupTracingObserver::GetInstance()
->SetPreferenceManagerForTesting(std::move(preferences_moved));
preferences->SetBackgroundStartupTracingEnabled(true);
base::DictionaryValue dict;
std::unique_ptr<base::ListValue> rules_list(new base::ListValue());
{
std::unique_ptr<base::DictionaryValue> rules_dict(
new base::DictionaryValue());
rules_dict->SetString("rule", "MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED");
rules_dict->SetString("trigger_name", "gpu-config");
rules_dict->SetBoolean("stop_tracing_on_repeated_reactive", false);
rules_dict->SetInteger("trigger_delay", 10);
rules_dict->SetString("category", "BENCHMARK_GPU");
rules_list->Append(std::move(rules_dict));
}
dict.Set("configs", std::move(rules_list));
std::unique_ptr<BackgroundTracingConfig> config(
BackgroundTracingConfigImpl::ReactiveFromDict(&dict));
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
tracelog_helper.WaitForStartTracing();
background_tracing_helper.WaitForTracingEnabled();
EXPECT_TRUE(BackgroundTracingManagerImpl::GetInstance()
->GetActiveScenarioForTesting()
->requires_anonymized_data());
EXPECT_TRUE(base::trace_event::TraceLog::GetInstance()
->GetCurrentTraceConfig()
.IsArgumentFilterEnabled());
// Since we specified a delay in the scenario, we should still be tracing
// at this point.
EXPECT_TRUE(
BackgroundTracingManagerImpl::GetInstance()->IsTracingForTesting());
BackgroundTracingManagerImpl::GetInstance()
->GetActiveScenarioForTesting()
->FireTimerForTesting();
trace_receiver_helper.WaitForTraceReceived();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(trace_receiver_helper.trace_received());
EXPECT_FALSE(preferences->GetBackgroundStartupTracingEnabled());
}
namespace {
class ProtoBackgroundTracingTest : public DevToolsProtocolTest {
public:
ProtoBackgroundTracingTest() {
scoped_feature_list_.InitWithFeatures(
/*enabled_features=*/{features::kTracingPerfettoBackend,
features::kBackgroundTracingProtoOutput},
/*disabled_features=*/{});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
} // namespace
IN_PROC_BROWSER_TEST_F(ProtoBackgroundTracingTest,
DevtoolsInterruptsBackgroundTracing) {
TestBackgroundTracingHelper background_tracing_helper;
TestTraceReceiverHelper trace_receiver_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), trace_receiver_helper.get_receive_callback(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1);
Attach();
base::Value* start_tracing_result =
SendCommand("Tracing.start", nullptr, true);
ASSERT_TRUE(start_tracing_result);
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
}
IN_PROC_BROWSER_TEST_F(ProtoBackgroundTracingTest, ProtoTraceReceived) {
TestBackgroundTracingHelper background_tracing_helper;
std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig();
BackgroundTracingManager::TriggerHandle handle =
BackgroundTracingManager::GetInstance()->RegisterTriggerType(
"preemptive_test");
EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
std::move(config), base::DoNothing(),
BackgroundTracingManager::NO_DATA_FILTERING));
background_tracing_helper.WaitForTracingEnabled();
TestTriggerHelper trigger_helper;
BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
handle, trigger_helper.receive_closure(true));
WaitForCondition(
base::BindRepeating([]() {
return BackgroundTracingManager::GetInstance()->HasTraceToUpload();
}),
"trace received");
std::string trace_data =
BackgroundTracingManager::GetInstance()->GetLatestTraceToUpload();
BackgroundTracingManager::GetInstance()->AbortScenarioForTesting();
background_tracing_helper.WaitForScenarioAborted();
EXPECT_TRUE(!trace_data.empty());
}
} // namespace content