chromium/components/variations/variations_crash_keys_unittest.cc

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

#include "components/variations/variations_crash_keys.h"

#include <string>

#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "components/crash/core/common/crash_key.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/hashing.h"
#include "components/variations/synthetic_trial_registry.h"
#include "components/variations/synthetic_trials_active_group_id_provider.h"
#include "components/variations/variations_switches.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace variations {

namespace {

std::string GetVariationsCrashKey() {
  return crash_reporter::GetCrashKeyValue("variations");
}

std::string GetNumExperimentsCrashKey() {
  return crash_reporter::GetCrashKeyValue("num-experiments");
}

std::string GetVariationsSeedVersionCrashKey() {
  return crash_reporter::GetCrashKeyValue("variations-seed-version");
}

class VariationsCrashKeysTest : public ::testing::Test {
 public:
  VariationsCrashKeysTest() {
    crash_reporter::ResetCrashKeysForTesting();
    crash_reporter::InitializeCrashKeysForTesting();
  }

  VariationsCrashKeysTest(const VariationsCrashKeysTest&) = delete;
  VariationsCrashKeysTest& operator=(const VariationsCrashKeysTest&) = delete;

  ~VariationsCrashKeysTest() override {
    SyntheticTrialsActiveGroupIdProvider::GetInstance()->ResetForTesting();
    ClearCrashKeysInstanceForTesting();
    crash_reporter::ResetCrashKeysForTesting();
  }

 private:
  base::test::TaskEnvironment task_environment_;
};

}  // namespace

TEST_F(VariationsCrashKeysTest, BasicFunctionality) {
  SyntheticTrialRegistry registry;
  registry.AddObserver(SyntheticTrialsActiveGroupIdProvider::GetInstance());

  // Start with 2 trials, one active and one not
  base::FieldTrialList::CreateFieldTrial("Trial1", "Group1")->Activate();
  base::FieldTrialList::CreateFieldTrial("Trial2", "Group2");

  InitCrashKeys();

  EXPECT_EQ("1", GetNumExperimentsCrashKey());
  EXPECT_EQ("8e7abfb0-c16397b7,", GetVariationsCrashKey());

  ExperimentListInfo info = GetExperimentListInfo();
  EXPECT_EQ(1, info.num_experiments);
  EXPECT_EQ("8e7abfb0-c16397b7,", info.experiment_list);

  // Now, active Trial2.
  EXPECT_EQ("Group2", base::FieldTrialList::FindFullName("Trial2"));
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ("2", GetNumExperimentsCrashKey());
  EXPECT_EQ("8e7abfb0-c16397b7,277f2a3d-d77354d0,", GetVariationsCrashKey());
  info = GetExperimentListInfo();
  EXPECT_EQ(2, info.num_experiments);
  EXPECT_EQ("8e7abfb0-c16397b7,277f2a3d-d77354d0,", info.experiment_list);

  // Add two synthetic trials and confirm that they show up in the list.
  SyntheticTrialGroup synth_trial(
      "Trial3", "Group3", variations::SyntheticTrialAnnotationMode::kNextLog);
  registry.RegisterSyntheticFieldTrial(synth_trial);

  EXPECT_EQ("3", GetNumExperimentsCrashKey());
  EXPECT_EQ("8e7abfb0-c16397b7,277f2a3d-d77354d0,9f339c9d-746c2ad4,",
            GetVariationsCrashKey());
  info = GetExperimentListInfo();
  EXPECT_EQ(3, info.num_experiments);
  EXPECT_EQ("8e7abfb0-c16397b7,277f2a3d-d77354d0,9f339c9d-746c2ad4,",
            info.experiment_list);

  // Add another regular trial.
  base::FieldTrialList::CreateFieldTrial("Trial4", "Group4")->Activate();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ("4", GetNumExperimentsCrashKey());
  EXPECT_EQ(
      "8e7abfb0-c16397b7,277f2a3d-d77354d0,21710f4c-99b90b01,"
      "9f339c9d-746c2ad4,",
      GetVariationsCrashKey());
  info = GetExperimentListInfo();
  EXPECT_EQ(4, info.num_experiments);
  EXPECT_EQ(
      "8e7abfb0-c16397b7,277f2a3d-d77354d0,21710f4c-99b90b01,"
      "9f339c9d-746c2ad4,",
      info.experiment_list);

  // Replace synthetic trial group and add one more.
  SyntheticTrialGroup synth_trial2(
      "Trial3", "Group3_A", variations::SyntheticTrialAnnotationMode::kNextLog);
  registry.RegisterSyntheticFieldTrial(synth_trial2);
  SyntheticTrialGroup synth_trial3(
      "Trial4", "Group4", variations::SyntheticTrialAnnotationMode::kNextLog);
  registry.RegisterSyntheticFieldTrial(synth_trial3);

  EXPECT_EQ("5", GetNumExperimentsCrashKey());
  EXPECT_EQ(
      "8e7abfb0-c16397b7,277f2a3d-d77354d0,21710f4c-99b90b01,"
      "9f339c9d-3250dddc,21710f4c-99b90b01,",
      GetVariationsCrashKey());
  info = GetExperimentListInfo();
  EXPECT_EQ(5, info.num_experiments);
  EXPECT_EQ(
      "8e7abfb0-c16397b7,277f2a3d-d77354d0,21710f4c-99b90b01,"
      "9f339c9d-3250dddc,21710f4c-99b90b01,",
      info.experiment_list);
}

TEST_F(VariationsCrashKeysTest, SeedVersionFromParsedSeed) {
  SetSeedVersion("version-123");
  InitCrashKeys();
  EXPECT_EQ("version-123", GetVariationsSeedVersionCrashKey());
}

TEST_F(VariationsCrashKeysTest, SeedVersionFromCommandLineSwitch) {
  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
      variations::switches::kVariationsSeedVersion, "version-456");
  InitCrashKeys();
  EXPECT_EQ("version-456", GetVariationsSeedVersionCrashKey());
}

TEST_F(VariationsCrashKeysTest, OverriddenFieldTrial) {
  base::FieldTrialList::CreateFieldTrial("Trial1", "Group1",
                                         /*is_low_anonymity=*/false,
                                         /*is_overridden=*/true)
      ->Activate();

  InitCrashKeys();

  // Because the trial is overridden, it has a different group variation ID.
  EXPECT_EQ("1", GetNumExperimentsCrashKey());
  EXPECT_EQ("2a140065", HashNameAsHexString("Group1_MANUALLY_FORCED"));
  EXPECT_EQ("8e7abfb0-2a140065,", GetVariationsCrashKey());
}

}  // namespace variations