chromium/android_webview/browser/tracing/background_tracing_field_trial_unittest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/tracing/background_tracing_field_trial.h"

#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_param_associator.h"

#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/test/scoped_command_line.h"
#include "base/test/test_proto_loader.h"
#include "base/threading/thread_restrictions.h"
#include "components/tracing/common/background_tracing_utils.h"
#include "components/tracing/common/tracing_switches.h"
#include "content/public/browser/background_tracing_config.h"
#include "content/public/browser/background_tracing_manager.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/test/browser_task_environment.h"

#include "testing/gtest/include/gtest/gtest.h"

namespace {

const std::string kTrialName = "BackgroundWebviewTracing";
const std::string kGroupName = "BackgroundWebviewTracing1";
const char kTestConfigReactiveMode[] = R"(
  {
    "scenario_name": "BackgroundTracing",
    "configs": [
      {
        "rule": "MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE",
        "histogram_name": "Android.WebView.LoadUrl.UrlScheme",
        "histogram_lower_value": 0
      }
    ],
    "mode": "REACTIVE_TRACING_MODE"
  }
)";

const char kTestConfigPreemptiveMode[] = R"(
  {
    "scenario_name": "BackgroundTracing",
    "custom_categories": "toplevel",
    "configs": [
      {
        "rule": "MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE",
        "histogram_name": "Android.WebView.LoadUrl.UrlScheme",
        "histogram_lower_value": 0
      }
    ],
    "mode": "PREEMPTIVE_TRACING_MODE"
  }
)";

const char kValidProtoTracingConfig[] = R"pb(
  scenarios: {
    scenario_name: "test_scenario"
    start_rules: { name: "start_trigger" manual_trigger_name: "start_trigger" }
    upload_rules: {
      name: "upload_trigger"
      manual_trigger_name: "upload_trigger"
    }
    trace_config: {
      data_sources: { config: { name: "org.chromium.trace_metadata" } }
    }
  }
)pb";

std::string GetFieldTracingConfigFromText(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);
  return serialized_message;
}

class BackgroundTracingTest : public testing::Test {
 public:
  BackgroundTracingTest() {
    content::SetContentClient(&content_client_);
    content::SetBrowserClientForTesting(&browser_client_);
    background_tracing_manager_ =
        content::BackgroundTracingManager::CreateInstance();
  }

  void TearDown() override {
    background_tracing_manager_.reset();
    content::SetBrowserClientForTesting(nullptr);
    content::SetContentClient(nullptr);
    base::FieldTrialParamAssociator::GetInstance()->ClearParamsForTesting(
        kTrialName, kGroupName);
  }

 private:
  content::BrowserTaskEnvironment task_environment_;
  content::ContentClient content_client_;
  content::ContentBrowserClient browser_client_;
  std::unique_ptr<content::BackgroundTracingManager>
      background_tracing_manager_;
};

}  // namespace

TEST_F(BackgroundTracingTest, ReactiveConfigSystemSetup) {
  base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
      kTrialName, kGroupName, {{"config", kTestConfigReactiveMode}});
  base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);

  EXPECT_FALSE(
      content::BackgroundTracingManager::GetInstance().HasActiveScenario());

  EXPECT_FALSE(android_webview::MaybeSetupSystemTracingFromFieldTrial());

  // Config (reactive) and method call (system) mismatch, nothing should be set
  // up.
  EXPECT_FALSE(
      content::BackgroundTracingManager::GetInstance().HasActiveScenario());
}

TEST_F(BackgroundTracingTest, ReactiveConfigWebViewOnlySetup) {
  base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
      kTrialName, kGroupName, {{"config", kTestConfigReactiveMode}});
  base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);

  EXPECT_FALSE(
      content::BackgroundTracingManager::GetInstance().HasActiveScenario());

  EXPECT_TRUE(android_webview::MaybeSetupWebViewOnlyTracingFromFieldTrial());

  // Config (reactive) and method call (webview-only) match.
  EXPECT_TRUE(
      content::BackgroundTracingManager::GetInstance().HasActiveScenario());
}

TEST_F(BackgroundTracingTest, PreemptiveConfigSystemSetup) {
  base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
      kTrialName, kGroupName, {{"config", kTestConfigPreemptiveMode}});
  base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);

  EXPECT_FALSE(
      content::BackgroundTracingManager::GetInstance().HasActiveScenario());

  EXPECT_FALSE(android_webview::MaybeSetupSystemTracingFromFieldTrial());

  // Config (preemptive) and method call (system) mismatch, nothing should be
  // set up.
  EXPECT_FALSE(
      content::BackgroundTracingManager::GetInstance().HasActiveScenario());
}

TEST_F(BackgroundTracingTest, SetupBackgroundTracingFromProtoConfigFile) {
  base::ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
  base::FilePath file_path = temp_dir.GetPath().AppendASCII("config.pb");
  base::WriteFile(file_path,
                  GetFieldTracingConfigFromText(kValidProtoTracingConfig));

  base::test::ScopedCommandLine scoped_command_line;
  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
  command_line->AppendSwitchPath(switches::kBackgroundTracingOutputPath,
                                 temp_dir.GetPath());
  command_line->AppendSwitchPath(switches::kEnableBackgroundTracing, file_path);

  ASSERT_EQ(tracing::GetBackgroundTracingSetupMode(),
            tracing::BackgroundTracingSetupMode::kFromProtoConfigFile);
  EXPECT_FALSE(android_webview::MaybeSetupSystemTracingFromFieldTrial());
  EXPECT_FALSE(android_webview::MaybeSetupWebViewOnlyTracingFromFieldTrial());
}