blob: fe01884b4fc98790061b4333cf2fa3d7d79ead4f [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/files/scoped_temp_dir.h"
#include "base/functional/callback_helpers.h"
#include "base/path_service.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_proto_loader.h"
#include "base/threading/thread_restrictions.h"
#include "base/token.h"
#include "base/values.h"
#include "build/build_config.h"
#include "content/browser/tracing/background_tracing_manager_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/tracing_delegate.h"
#include "content/public/common/content_client.h"
#include "content/public/test/browser_task_environment.h"
#include "net/base/network_change_notifier.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/zlib/google/compression_utils.h"
namespace content {
namespace {
const char kDummyTrace[] = "Trace bytes as serialized proto";
class MockNetworkChangeNotifier : public net::NetworkChangeNotifier {
public:
ConnectionType GetCurrentConnectionType() const override { return type_; }
void set_type(ConnectionType type) { type_ = type; }
private:
ConnectionType type_;
};
class TestBackgroundTracingHelper
: public BackgroundTracingManager::EnabledStateTestObserver {
public:
TestBackgroundTracingHelper() {
BackgroundTracingManagerImpl::GetInstance()
.AddEnabledStateObserverForTesting(this);
}
~TestBackgroundTracingHelper() {
BackgroundTracingManagerImpl::GetInstance()
.RemoveEnabledStateObserverForTesting(this);
}
void OnTraceSaved() override { wait_for_trace_saved_.Quit(); }
void WaitForTraceSaved() { wait_for_trace_saved_.Run(); }
private:
base::RunLoop wait_for_trace_saved_;
};
perfetto::protos::gen::ChromeFieldTracingConfig ParseFieldTracingConfigFromText(
const std::string& proto_text) {
base::ScopedAllowBlockingForTesting allow_blocking;
base::TestProtoLoader config_loader(
base::PathService::CheckedGet(base::DIR_GEN_TEST_DATA_ROOT)
.Append(
FILE_PATH_LITERAL("third_party/perfetto/protos/perfetto/"
"config/chrome/scenario_config.descriptor")),
"perfetto.protos.ChromeFieldTracingConfig");
std::string serialized_message;
config_loader.ParseFromText(proto_text, serialized_message);
perfetto::protos::gen::ChromeFieldTracingConfig destination;
destination.ParseFromString(serialized_message);
return destination;
}
class MockBrowserClient : public content::ContentBrowserClient {
public:
MockBrowserClient(base::FilePath traces_dir) : traces_dir_(traces_dir) {}
~MockBrowserClient() override {}
std::optional<base::FilePath> GetLocalTracesDirectory() override {
return traces_dir_;
}
private:
base::FilePath traces_dir_;
};
} // namespace
class BackgroundTracingManagerTest : public testing::Test {
public:
BackgroundTracingManagerTest() {
background_tracing_manager_ =
std::make_unique<BackgroundTracingManagerImpl>(&tracing_delegate_);
}
protected:
BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
content::TracingDelegate tracing_delegate_;
std::unique_ptr<content::BackgroundTracingManagerImpl>
background_tracing_manager_;
};
TEST_F(BackgroundTracingManagerTest, HasTraceToUpload) {
background_tracing_manager_->SetUploadLimitsForTesting(2, 1);
{
std::string trace_content(1500, 'a');
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
std::move(trace_content), "test_scenario", "test_rule",
base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
MockNetworkChangeNotifier notifier;
notifier.set_type(net::NetworkChangeNotifier::CONNECTION_2G);
#if BUILDFLAG(IS_ANDROID)
EXPECT_FALSE(background_tracing_manager_->HasTraceToUpload());
#endif
notifier.set_type(net::NetworkChangeNotifier::CONNECTION_WIFI);
EXPECT_TRUE(background_tracing_manager_->HasTraceToUpload());
}
TEST_F(BackgroundTracingManagerTest, GetTraceToUpload) {
{
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_TRUE(background_tracing_manager_->HasTraceToUpload());
std::string compressed_trace;
base::RunLoop run_loop;
background_tracing_manager_->GetTraceToUpload(
base::BindLambdaForTesting([&](std::optional<std::string> trace_content,
std::optional<std::string> system_profile,
base::OnceClosure upload_complete) {
ASSERT_TRUE(trace_content);
compressed_trace = std::move(*trace_content);
std::move(upload_complete).Run();
run_loop.Quit();
}));
run_loop.Run();
std::string serialized_trace;
ASSERT_TRUE(compression::GzipUncompress(compressed_trace, &serialized_trace));
EXPECT_EQ(kDummyTrace, serialized_trace);
EXPECT_FALSE(background_tracing_manager_->HasTraceToUpload());
}
TEST_F(BackgroundTracingManagerTest, SavedCountPreventsStart) {
constexpr const char kScenarioConfig[] = R"pb(
scenarios: {
scenario_name: "test_scenario"
start_rules: {
name: "start_trigger"
manual_trigger_name: "start_trigger"
}
trace_config: {
data_sources: { config: { name: "org.chromium.trace_metadata2" } }
}
}
)pb";
constexpr size_t kNumSavedTraces = 200;
for (size_t i = 0; i < kNumSavedTraces; ++i) {
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_EQ(kNumSavedTraces,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
background_tracing_manager_->InitializeFieldScenarios(
ParseFieldTracingConfigFromText(kScenarioConfig),
BackgroundTracingManager::NO_DATA_FILTERING, false, 0);
EXPECT_FALSE(base::trace_event::EmitNamedTrigger("start_trigger"));
}
TEST_F(BackgroundTracingManagerTest, SavedCountAfterClean) {
{
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_EQ(1U,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
task_environment_.FastForwardBy(base::Days(15));
EXPECT_EQ(0U,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
}
TEST_F(BackgroundTracingManagerTest, SavedCountAfterDelete) {
{
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_EQ(1U,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
background_tracing_manager_->DeleteTracesInDateRange(
base::Time::Now() - base::Days(1), base::Time::Now());
task_environment_.RunUntilIdle();
EXPECT_EQ(0U,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
}
TEST_F(BackgroundTracingManagerTest, UploadScenarioQuotaExceeded) {
{
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_TRUE(background_tracing_manager_->HasTraceToUpload());
base::RunLoop run_loop;
background_tracing_manager_->GetTraceToUpload(
base::BindLambdaForTesting([&](std::optional<std::string> trace_content,
std::optional<std::string> system_profile,
base::OnceClosure upload_complete) {
std::move(upload_complete).Run();
run_loop.Quit();
}));
run_loop.Run();
{
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_FALSE(background_tracing_manager_->HasTraceToUpload());
}
TEST_F(BackgroundTracingManagerTest, UploadScenarioQuotaReset) {
{
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_TRUE(background_tracing_manager_->HasTraceToUpload());
base::RunLoop run_loop;
background_tracing_manager_->GetTraceToUpload(
base::IgnoreArgs<std::optional<std::string>, std::optional<std::string>,
base::OnceClosure>(run_loop.QuitClosure()));
run_loop.Run();
task_environment_.FastForwardBy(base::Days(8));
{
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager_->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
}
EXPECT_TRUE(background_tracing_manager_->HasTraceToUpload());
}
TEST(BackgroundTracingManagerPersistentTest, DeleteTracesInDateRange) {
BrowserTaskEnvironment task_environment{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
base::ScopedTempDir traces_dir;
ASSERT_TRUE(traces_dir.CreateUniqueTempDir());
content::ContentClient content_client;
MockBrowserClient browser_client(traces_dir.GetPath());
content::SetContentClient(&content_client);
content::SetBrowserClientForTesting(&browser_client);
{
content::TracingDelegate tracing_delegate;
std::unique_ptr<content::BackgroundTracingManager>
background_tracing_manager =
content::BackgroundTracingManager::CreateInstance(
&tracing_delegate);
BackgroundTracingManagerImpl::GetInstance().InitializeTraceReportDatabase();
TestBackgroundTracingHelper background_tracing_helper;
background_tracing_manager->SaveTraceForTesting(
kDummyTrace, "test_scenario", "test_rule", base::Token::CreateRandom());
background_tracing_helper.WaitForTraceSaved();
EXPECT_EQ(1U,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
}
// Ensure the database tear down completed.
task_environment.RunUntilIdle();
{
content::TracingDelegate tracing_delegate;
std::unique_ptr<content::BackgroundTracingManager>
background_tracing_manager =
content::BackgroundTracingManager::CreateInstance(
&tracing_delegate);
BackgroundTracingManagerImpl::GetInstance().InitializeTraceReportDatabase();
task_environment.RunUntilIdle();
EXPECT_EQ(1U,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
}
// Ensure the database tear down completed.
task_environment.RunUntilIdle();
{
content::TracingDelegate tracing_delegate;
std::unique_ptr<content::BackgroundTracingManager>
background_tracing_manager =
content::BackgroundTracingManager::CreateInstance(
&tracing_delegate);
BackgroundTracingManagerImpl::GetInstance().InitializeTraceReportDatabase();
auto now = base::Time::Now();
background_tracing_manager->DeleteTracesInDateRange(now - base::Days(1),
now);
task_environment.RunUntilIdle();
EXPECT_EQ(0U,
BackgroundTracingManagerImpl::GetInstance().GetScenarioSavedCount(
"test_scenario"));
}
content::SetBrowserClientForTesting(nullptr);
content::SetContentClient(nullptr);
}
} // namespace content