chromium/chrome/browser/win/chrome_elf_init_unittest.cc

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

#include "chrome/browser/win/chrome_elf_init.h"

#include <memory>
#include <string>

#include "base/metrics/field_trial.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_reg_util_win.h"
#include "chrome/chrome_elf/blocklist_constants.h"
#include "chrome/common/chrome_version.h"
#include "chrome/install_static/install_util.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

class ChromeBlocklistTrialTest : public testing::Test {
 public:
  ChromeBlocklistTrialTest(const ChromeBlocklistTrialTest&) = delete;
  ChromeBlocklistTrialTest& operator=(const ChromeBlocklistTrialTest&) = delete;

 protected:
  ChromeBlocklistTrialTest() {}
  ~ChromeBlocklistTrialTest() override {}

  void SetUp() override {
    testing::Test::SetUp();

    ASSERT_NO_FATAL_FAILURE(
        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));

    blocklist_registry_key_ = std::make_unique<base::win::RegKey>(
        HKEY_CURRENT_USER,
        install_static::GetRegistryPath()
            .append(blocklist::kRegistryBeaconKeyName)
            .c_str(),
        KEY_QUERY_VALUE | KEY_SET_VALUE);
  }

  DWORD GetBlocklistState() {
    DWORD blocklist_state = blocklist::BLOCKLIST_STATE_MAX;
    blocklist_registry_key_->ReadValueDW(blocklist::kBeaconState,
                                         &blocklist_state);

    return blocklist_state;
  }

  std::wstring GetBlocklistVersion() {
    std::wstring blocklist_version;
    blocklist_registry_key_->ReadValue(blocklist::kBeaconVersion,
                                       &blocklist_version);

    return blocklist_version;
  }

  std::unique_ptr<base::win::RegKey> blocklist_registry_key_;
  registry_util::RegistryOverrideManager override_manager_;
  content::BrowserTaskEnvironment task_environment_;
};

// Ensure that the default trial sets up the blocklist beacons.
TEST_F(ChromeBlocklistTrialTest, DefaultRun) {
  // Set some dummy values as beacons.
  blocklist_registry_key_->WriteValue(blocklist::kBeaconState,
                                      blocklist::BLOCKLIST_DISABLED);
  blocklist_registry_key_->WriteValue(blocklist::kBeaconVersion, L"Data");

  // This setup code should result in the default group, which should have
  // the blocklist set up.
  InitializeChromeElf();

  // Ensure the beacon values are now correct, indicating the
  // blocklist beacon was setup.
  ASSERT_EQ(static_cast<DWORD>(blocklist::BLOCKLIST_ENABLED),
            GetBlocklistState());
  std::wstring version(base::UTF8ToWide(version_info::GetVersionNumber()));
  ASSERT_EQ(version, GetBlocklistVersion());
}

// Ensure that the blocklist is disabled for any users in the
// "BlocklistDisabled" finch group.
TEST_F(ChromeBlocklistTrialTest, BlocklistDisabledRun) {
  // Set the beacons to enabled values.
  blocklist_registry_key_->WriteValue(blocklist::kBeaconState,
                                      blocklist::BLOCKLIST_ENABLED);
  blocklist_registry_key_->WriteValue(blocklist::kBeaconVersion, L"Data");

  scoped_refptr<base::FieldTrial> trial(
    base::FieldTrialList::CreateFieldTrial(
      kBrowserBlocklistTrialName, kBrowserBlocklistTrialDisabledGroupName));

  // This setup code should now delete any existing blocklist beacons.
  InitializeChromeElf();

  // Ensure invalid values are returned to indicate that the beacon
  // values are indeed gone.
  ASSERT_EQ(static_cast<DWORD>(blocklist::BLOCKLIST_STATE_MAX),
            GetBlocklistState());
  ASSERT_EQ(std::wstring(), GetBlocklistVersion());
}

TEST_F(ChromeBlocklistTrialTest, VerifyFirstRun) {
  BrowserBlocklistBeaconSetup();

  // Verify the state is properly set after the first run.
  ASSERT_EQ(static_cast<DWORD>(blocklist::BLOCKLIST_ENABLED),
            GetBlocklistState());

  std::wstring version(base::UTF8ToWide(version_info::GetVersionNumber()));
  ASSERT_EQ(version, GetBlocklistVersion());
}

TEST_F(ChromeBlocklistTrialTest, BlocklistFailed) {
  // Ensure when the blocklist set up failed we set the state to disabled for
  // future runs.
  blocklist_registry_key_->WriteValue(blocklist::kBeaconVersion,
                                      TEXT(CHROME_VERSION_STRING));
  blocklist_registry_key_->WriteValue(blocklist::kBeaconState,
                                      blocklist::BLOCKLIST_SETUP_FAILED);

  BrowserBlocklistBeaconSetup();

  ASSERT_EQ(static_cast<DWORD>(blocklist::BLOCKLIST_DISABLED),
            GetBlocklistState());
}

TEST_F(ChromeBlocklistTrialTest, VersionChanged) {
  // Mark the blocklist as disabled for an older version, it should
  // get enabled for this new version.  Also record a non-zero number of
  // setup failures, which should be reset to zero.
  blocklist_registry_key_->WriteValue(blocklist::kBeaconVersion,
                                      L"old_version");
  blocklist_registry_key_->WriteValue(blocklist::kBeaconState,
                                      blocklist::BLOCKLIST_DISABLED);
  blocklist_registry_key_->WriteValue(blocklist::kBeaconAttemptCount,
                                      blocklist::kBeaconMaxAttempts);

  BrowserBlocklistBeaconSetup();

  // The beacon should now be marked as enabled for the current version.
  ASSERT_EQ(static_cast<DWORD>(blocklist::BLOCKLIST_ENABLED),
            GetBlocklistState());

  std::wstring expected_version(
      base::UTF8ToWide(version_info::GetVersionNumber()));
  ASSERT_EQ(expected_version, GetBlocklistVersion());

  // The counter should be reset.
  DWORD attempt_count = blocklist::kBeaconMaxAttempts;
  blocklist_registry_key_->ReadValueDW(blocklist::kBeaconAttemptCount,
                                       &attempt_count);
  ASSERT_EQ(static_cast<DWORD>(0), attempt_count);
}

}  // namespace