chromium/chrome/credential_provider/test/gcp_fakes.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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chrome/credential_provider/test/gcp_fakes.h"

#include <windows.h>

#include <atlcomcli.h>
#include <atlconv.h>
#include <lm.h>
#include <ntsecapi.h>
#include <ntstatus.h>
#include <process.h>
#include <sddl.h>

#include <string>

#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/win/scoped_handle.h"
#include "base/win/scoped_process_information.h"
#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/extension/extension_strings.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/mdm_utils.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace credential_provider {

namespace {

HRESULT CreateArbitrarySid(DWORD subauth0, PSID* sid) {
  SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NON_UNIQUE_AUTHORITY};
  if (!::AllocateAndInitializeSid(&Authority, 1, subauth0, 0, 0, 0, 0, 0, 0, 0,
                                  sid)) {
    return (HRESULT_FROM_WIN32(::GetLastError()));
  }
  return S_OK;
}

}  // namespace

///////////////////////////////////////////////////////////////////////////////

void InitializeRegistryOverrideForTesting(
    registry_util::RegistryOverrideManager* registry_override) {
  ASSERT_NO_FATAL_FAILURE(
      registry_override->OverrideRegistry(HKEY_LOCAL_MACHINE));
  base::win::RegKey key;
  ASSERT_EQ(ERROR_SUCCESS,
            key.Create(HKEY_LOCAL_MACHINE, kGcpRootKeyName, KEY_WRITE));
  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kRegMdmUrl, L""));
  ASSERT_EQ(ERROR_SUCCESS,
            SetMachineGuidForTesting(L"f418a124-4d92-469b-afa5-0f8af537b965"));
  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kRegDisablePasswordSync, 1));
  DWORD disable_cloud_association = 0;
  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"enable_cloud_association",
                                          disable_cloud_association));
  ASSERT_EQ(ERROR_SUCCESS,
            key.WriteValue(L"domains_allowed_to_login", L"test.com,gmail.com"));
}

///////////////////////////////////////////////////////////////////////////////

FakeOSProcessManager::FakeOSProcessManager()
    : original_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeOSProcessManager::~FakeOSProcessManager() {
  *GetInstanceStorage() = original_manager_;
}

HRESULT FakeOSProcessManager::GetTokenLogonSID(
    const base::win::ScopedHandle& token,
    PSID* sid) {
  // Make sure the token is valid, but otherwise ignore it.
  if (!token.IsValid()) {
    return E_INVALIDARG;
  }

  return CreateArbitrarySid(++next_rid_, sid);
}

HRESULT FakeOSProcessManager::SetupPermissionsForLogonSid(PSID sid) {
  // Ignore.
  return S_OK;
}

HRESULT FakeOSProcessManager::CreateProcessWithToken(
    const base::win::ScopedHandle& logon_token,
    const base::CommandLine& command_line,
    _STARTUPINFOW* startupinfo,
    base::win::ScopedProcessInformation* procinfo) {
  // Ignore the logon token and create a process as the current user.
  // If the startupinfo includes a desktop name, make sure to ignore.  In tests
  // the desktop has not been configured to allow a newly created process to
  // to access it.
  _STARTUPINFOW local_startupinfo = *startupinfo;
  local_startupinfo.lpDesktop = nullptr;

  PROCESS_INFORMATION new_procinfo = {};
  // Pass a copy of the command line string to CreateProcessW() because this
  // function could change the string.
  std::unique_ptr<wchar_t, void (*)(void*)> cmdline(
      _wcsdup(command_line.GetCommandLineString().c_str()), std::free);
  if (!::CreateProcessW(command_line.GetProgram().value().c_str(),
                        cmdline.get(), nullptr, nullptr, TRUE, CREATE_SUSPENDED,
                        nullptr, nullptr, &local_startupinfo, &new_procinfo)) {
    HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
    return hr;
  }
  procinfo->Set(new_procinfo);
  return S_OK;
}

///////////////////////////////////////////////////////////////////////////////

FakeOSUserManager::FakeOSUserManager()
    : original_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeOSUserManager::~FakeOSUserManager() {
  *GetInstanceStorage() = original_manager_;
}

HRESULT FakeOSUserManager::GenerateRandomPassword(wchar_t* password,
                                                  int length) {
  if (length < kMinPasswordLength) {
    return E_INVALIDARG;
  }

  // Make sure to generate a different password each time.  Actually randomness
  // is not important for tests.
  static int nonce = 0;
  EXPECT_NE(-1, swprintf_s(password, length, L"bad-password-%d", ++nonce));
  return S_OK;
}

HRESULT FakeOSUserManager::AddUser(const wchar_t* username,
                                   const wchar_t* password,
                                   const wchar_t* fullname,
                                   const wchar_t* comment,
                                   bool add_to_users_group,
                                   BSTR* sid,
                                   DWORD* error) {
  return AddUser(username, password, fullname, comment, add_to_users_group,
                 OSUserManager::GetLocalDomain().c_str(), sid, error);
}

HRESULT FakeOSUserManager::AddUser(const wchar_t* username,
                                   const wchar_t* password,
                                   const wchar_t* fullname,
                                   const wchar_t* comment,
                                   bool add_to_users_group,
                                   const wchar_t* domain,
                                   BSTR* sid,
                                   DWORD* error) {
  USES_CONVERSION;

  DCHECK(sid);

  if (error) {
    *error = 0;
  }

  if (failure_reasons_.find(FAILEDOPERATIONS::ADD_USER) !=
      failure_reasons_.end()) {
    return failure_reasons_[FAILEDOPERATIONS::ADD_USER];
  }

  // Username or password cannot be empty.
  if (username == nullptr || !username[0] || password == nullptr ||
      !password[0]) {
    return E_FAIL;
  }

  bool user_found = username_to_info_.count(username) > 0;

  if (user_found) {
    *sid = ::SysAllocString(W2COLE(username_to_info_[username].sid.c_str()));
    return HRESULT_FROM_WIN32(NERR_UserExists);
  }

  PSID psid = nullptr;
  HRESULT hr = CreateNewSID(&psid);
  if (FAILED(hr)) {
    return hr;
  }

  wchar_t* sidstr = nullptr;
  bool ok = ::ConvertSidToStringSid(psid, &sidstr);
  ::FreeSid(psid);
  if (!ok) {
    *sid = nullptr;
    return HRESULT_FROM_WIN32(NERR_ProgNeedsExtraMem);
  }

  *sid = ::SysAllocString(W2COLE(sidstr));
  username_to_info_.emplace(
      username, UserInfo(domain, password, fullname, comment, sidstr));
  ::LocalFree(sidstr);

  return S_OK;
}

HRESULT FakeOSUserManager::ChangeUserPassword(const wchar_t* domain,
                                              const wchar_t* username,
                                              const wchar_t* old_password,
                                              const wchar_t* new_password) {
  DCHECK(domain);
  DCHECK(username);
  DCHECK(old_password);
  DCHECK(new_password);

  if (failure_reasons_.find(FAILEDOPERATIONS::CHANGE_PASSWORD) !=
      failure_reasons_.end()) {
    return failure_reasons_[FAILEDOPERATIONS::CHANGE_PASSWORD];
  }

  if (username_to_info_.count(username) > 0) {
    if (username_to_info_[username].password != old_password) {
      return HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD);
    }

    username_to_info_[username].password = new_password;
    return S_OK;
  }

  return HRESULT_FROM_WIN32(NERR_UserNotFound);
}

HRESULT FakeOSUserManager::SetUserPassword(const wchar_t* domain,
                                           const wchar_t* username,
                                           const wchar_t* new_password) {
  DCHECK(domain);
  DCHECK(username);
  DCHECK(new_password);

  if (username_to_info_.count(username) > 0) {
    username_to_info_[username].password = new_password;
    return S_OK;
  }

  return HRESULT_FROM_WIN32(NERR_UserNotFound);
}

HRESULT FakeOSUserManager::SetUserFullname(const wchar_t* domain,
                                           const wchar_t* username,
                                           const wchar_t* full_name) {
  DCHECK(domain);
  DCHECK(username);
  DCHECK(full_name);

  if (failure_reasons_.find(FAILEDOPERATIONS::SET_USER_FULLNAME) !=
      failure_reasons_.end()) {
    return failure_reasons_[FAILEDOPERATIONS::SET_USER_FULLNAME];
  }

  if (username_to_info_.count(username) > 0) {
    username_to_info_[username].fullname = full_name;
    return S_OK;
  }

  return HRESULT_FROM_WIN32(NERR_UserNotFound);
}

HRESULT FakeOSUserManager::IsWindowsPasswordValid(const wchar_t* domain,
                                                  const wchar_t* username,
                                                  const wchar_t* password) {
  DCHECK(domain);
  DCHECK(username);
  DCHECK(password);

  if (username_to_info_.count(username) > 0) {
    const UserInfo& info = username_to_info_[username];
    if (info.domain != domain) {
      return HRESULT_FROM_WIN32(NERR_UserNotFound);
    }

    return info.password == password ? S_OK : S_FALSE;
  }

  return HRESULT_FROM_WIN32(NERR_UserNotFound);
}

HRESULT FakeOSUserManager::CreateLogonToken(const wchar_t* domain,
                                            const wchar_t* username,
                                            const wchar_t* password,
                                            bool /*interactive*/,
                                            base::win::ScopedHandle* token) {
  DCHECK(domain);
  DCHECK(username);
  DCHECK(password);

  if (username_to_info_.count(username) == 0) {
    return HRESULT_FROM_WIN32(NERR_BadUsername);
  } else if (username_to_info_[username].password != password) {
    return HRESULT_FROM_WIN32(NERR_UserExists);
  }

  const UserInfo& info = username_to_info_[username];
  if (info.domain != domain) {
    return HRESULT_FROM_WIN32(NERR_BadUsername);
  }

  // Create a token with a dummy handle value.
  base::FilePath path;
  if (!base::CreateTemporaryFile(&path)) {
    return HRESULT_FROM_WIN32(::GetLastError());
  }

  token->Set(CreateFile(path.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0,
                        nullptr, CREATE_ALWAYS,
                        FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
                        nullptr));
  return token->IsValid() ? S_OK : HRESULT_FROM_WIN32(::GetLastError());
}

bool FakeOSUserManager::IsDeviceDomainJoined() {
  return is_device_domain_joined_;
}

HRESULT FakeOSUserManager::GetUserSID(const wchar_t* domain,
                                      const wchar_t* username,
                                      PSID* sid) {
  DCHECK(domain);
  DCHECK(username);
  DCHECK(sid);
  if (username_to_info_.count(username) > 0) {
    const UserInfo& info = username_to_info_[username];
    if (info.domain == domain) {
      if (!::ConvertStringSidToSid(info.sid.c_str(), sid)) {
        return HRESULT_FROM_WIN32(NERR_ProgNeedsExtraMem);
      }

      return S_OK;
    }
  }

  return HRESULT_FROM_WIN32(NERR_UserNotFound);
}

HRESULT FakeOSUserManager::FindUserBySID(const wchar_t* sid,
                                         wchar_t* username,
                                         DWORD username_size,
                                         wchar_t* domain,
                                         DWORD domain_size) {
  auto it = to_be_failed_find_user_sids_.find(sid);
  if (it != to_be_failed_find_user_sids_.end()) {
    to_be_failed_find_user_sids_[sid]--;
    if (to_be_failed_find_user_sids_[sid] == 0) {
      to_be_failed_find_user_sids_.erase(it);
    }

    return E_FAIL;
  }

  for (auto& kv : username_to_info_) {
    if (kv.second.sid == sid) {
      if (username) {
        wcscpy_s(username, username_size, kv.first.c_str());
      }
      if (domain) {
        wcscpy_s(domain, domain_size, kv.second.domain.c_str());
      }
      return S_OK;
    }
  }

  return HRESULT_FROM_WIN32(ERROR_NONE_MAPPED);
}

void FakeOSUserManager::FailFindUserBySID(const wchar_t* sid,
                                          int number_of_failures) {
  to_be_failed_find_user_sids_[sid] = number_of_failures;
}

HRESULT FakeOSUserManager::RemoveUser(const wchar_t* username,
                                      const wchar_t* password) {
  username_to_info_.erase(username);
  return S_OK;
}

HRESULT FakeOSUserManager::GetUserFullname(const wchar_t* domain,
                                           const wchar_t* username,
                                           std::wstring* fullname) {
  DCHECK(domain);
  DCHECK(username);
  DCHECK(fullname);

  if (failure_reasons_.find(FAILEDOPERATIONS::GET_USER_FULLNAME) !=
      failure_reasons_.end()) {
    return failure_reasons_[FAILEDOPERATIONS::GET_USER_FULLNAME];
  }

  if (username_to_info_.count(username) > 0) {
    const UserInfo& info = username_to_info_[username];
    if (info.domain == domain) {
      *fullname = info.fullname;
      return S_OK;
    }
  }

  return HRESULT_FROM_WIN32(NERR_UserNotFound);
}

HRESULT FakeOSUserManager::ModifyUserAccessWithLogonHours(
    const wchar_t* domain,
    const wchar_t* username,
    bool allow) {
  return S_OK;
}

HRESULT FakeOSUserManager::SetDefaultPasswordChangePolicies(
    const wchar_t* domain,
    const wchar_t* username) {
  return S_OK;
}

FakeOSUserManager::UserInfo::UserInfo(const wchar_t* domain,
                                      const wchar_t* password,
                                      const wchar_t* fullname,
                                      const wchar_t* comment,
                                      const wchar_t* sid)
    : domain(domain),
      password(password),
      fullname(fullname),
      comment(comment),
      sid(sid) {}

FakeOSUserManager::UserInfo::UserInfo() {}

FakeOSUserManager::UserInfo::UserInfo(const UserInfo& other) = default;

FakeOSUserManager::UserInfo::~UserInfo() {}

bool FakeOSUserManager::UserInfo::operator==(const UserInfo& other) const {
  return domain == other.domain && password == other.password &&
         fullname == other.fullname && comment == other.comment &&
         sid == other.sid;
}

const FakeOSUserManager::UserInfo FakeOSUserManager::GetUserInfo(
    const wchar_t* username) {
  return (username_to_info_.count(username) > 0) ? username_to_info_[username]
                                                 : UserInfo();
}

HRESULT FakeOSUserManager::CreateNewSID(PSID* sid) {
  return CreateArbitrarySid(++next_rid_, sid);
}

// Creates a test OS user using the local domain.
HRESULT FakeOSUserManager::CreateTestOSUser(const std::wstring& username,
                                            const std::wstring& password,
                                            const std::wstring& fullname,
                                            const std::wstring& comment,
                                            const std::wstring& gaia_id,
                                            const std::wstring& email,
                                            BSTR* sid) {
  return CreateTestOSUser(username, password, fullname, comment, gaia_id, email,
                          OSUserManager::GetLocalDomain(), sid);
}

HRESULT FakeOSUserManager::CreateTestOSUser(const std::wstring& username,
                                            const std::wstring& password,
                                            const std::wstring& fullname,
                                            const std::wstring& comment,
                                            const std::wstring& gaia_id,
                                            const std::wstring& email,
                                            const std::wstring& domain,
                                            BSTR* sid) {
  DWORD error;
  HRESULT hr = AddUser(username.c_str(), password.c_str(), fullname.c_str(),
                       comment.c_str(), true, domain.c_str(), sid, &error);
  if (FAILED(hr)) {
    return hr;
  }

  if (!gaia_id.empty()) {
    hr = SetUserProperty(OLE2CW(*sid), kUserId, gaia_id);
    if (FAILED(hr)) {
      return hr;
    }

    hr = SetUserProperty(OLE2CW(*sid), kUserTokenHandle, L"token_handle");
    if (FAILED(hr)) {
      return hr;
    }
  }

  if (!email.empty()) {
    hr = SetUserProperty(OLE2CW(*sid), kUserEmail, email);
    if (FAILED(hr)) {
      return hr;
    }
  }

  return S_OK;
}

std::vector<std::pair<std::wstring, std::wstring>> FakeOSUserManager::GetUsers()
    const {
  std::vector<std::pair<std::wstring, std::wstring>> users;

  for (auto& kv : username_to_info_) {
    users.emplace_back(std::make_pair(kv.second.sid, kv.first));
  }

  return users;
}

///////////////////////////////////////////////////////////////////////////////

FakeScopedLsaPolicyFactory::FakeScopedLsaPolicyFactory()
    : original_creator_(*ScopedLsaPolicy::GetCreatorCallbackStorage()) {
  *ScopedLsaPolicy::GetCreatorCallbackStorage() = GetCreatorCallback();
}

FakeScopedLsaPolicyFactory::~FakeScopedLsaPolicyFactory() {
  *ScopedLsaPolicy::GetCreatorCallbackStorage() = original_creator_;
}

ScopedLsaPolicy::CreatorCallback
FakeScopedLsaPolicyFactory::GetCreatorCallback() {
  return base::BindRepeating(&FakeScopedLsaPolicyFactory::Create,
                             base::Unretained(this));
}

std::unique_ptr<ScopedLsaPolicy> FakeScopedLsaPolicyFactory::Create(
    ACCESS_MASK mask) {
  return std::unique_ptr<ScopedLsaPolicy>(new FakeScopedLsaPolicy(this));
}

FakeScopedLsaPolicy::FakeScopedLsaPolicy(FakeScopedLsaPolicyFactory* factory)
    : ScopedLsaPolicy(STANDARD_RIGHTS_READ), factory_(factory) {
  // The base class ctor will fail to initialize because these tests are not
  // running elevated.  That's OK, everything is faked out anyway.
}

FakeScopedLsaPolicy::~FakeScopedLsaPolicy() {}

HRESULT FakeScopedLsaPolicy::StorePrivateData(const wchar_t* key,
                                              const wchar_t* value) {
  private_data()[key] = value;
  return S_OK;
}

HRESULT FakeScopedLsaPolicy::RemovePrivateData(const wchar_t* key) {
  private_data().erase(key);
  return S_OK;
}

HRESULT FakeScopedLsaPolicy::RetrievePrivateData(const wchar_t* key,
                                                 wchar_t* value,
                                                 size_t length) {
  if (private_data().count(key) == 0) {
    if (wcscmp(key, kLsaKeyGaiaSid) == 0) {
      return HRESULT_FROM_NT(STATUS_OBJECT_NAME_NOT_FOUND);
    } else {
      return E_INVALIDARG;
    }
  }

  errno_t err = wcscpy_s(value, length, private_data()[key].c_str());
  if (err != 0) {
    return E_FAIL;
  }

  return S_OK;
}

bool FakeScopedLsaPolicy::PrivateDataExists(const wchar_t* key) {
  return private_data().count(key) != 0;
}

HRESULT FakeScopedLsaPolicy::AddAccountRights(
    PSID sid,
    const std::vector<std::wstring>& rights) {
  return S_OK;
}

HRESULT FakeScopedLsaPolicy::RemoveAccountRights(
    PSID sid,
    const std::vector<std::wstring>& rights) {
  return S_OK;
}

HRESULT FakeScopedLsaPolicy::RemoveAccount(PSID sid) {
  return S_OK;
}

///////////////////////////////////////////////////////////////////////////////

FakeScopedUserProfileFactory::FakeScopedUserProfileFactory()
    : original_creator_(*ScopedUserProfile::GetCreatorFunctionStorage()) {
  *ScopedUserProfile::GetCreatorFunctionStorage() = base::BindRepeating(
      &FakeScopedUserProfileFactory::Create, base::Unretained(this));
}

FakeScopedUserProfileFactory::~FakeScopedUserProfileFactory() {
  *ScopedUserProfile::GetCreatorFunctionStorage() = original_creator_;
}

std::unique_ptr<ScopedUserProfile> FakeScopedUserProfileFactory::Create(
    const std::wstring& sid,
    const std::wstring& domain,
    const std::wstring& username,
    const std::wstring& password) {
  return std::unique_ptr<ScopedUserProfile>(
      new FakeScopedUserProfile(sid, domain, username, password));
}

FakeScopedUserProfile::FakeScopedUserProfile(const std::wstring& sid,
                                             const std::wstring& domain,
                                             const std::wstring& username,
                                             const std::wstring& password) {
  is_valid_ = OSUserManager::Get()->IsWindowsPasswordValid(
                  domain.c_str(), username.c_str(), password.c_str()) == S_OK;
}

FakeScopedUserProfile::~FakeScopedUserProfile() {}

HRESULT FakeScopedUserProfile::SaveAccountInfo(
    const base::Value::Dict& properties) {
  if (!is_valid_) {
    return E_INVALIDARG;
  }

  std::wstring sid;
  std::wstring id;
  std::wstring email;
  std::wstring token_handle;
  std::wstring last_successful_online_login_millis;

  HRESULT hr = ExtractAssociationInformation(properties, &sid, &id, &email,
                                             &token_handle);
  if (FAILED(hr)) {
    return hr;
  }

  hr = RegisterAssociation(sid, id, email, token_handle,
                           last_successful_online_login_millis);

  if (FAILED(hr)) {
    return hr;
  }

  return S_OK;
}

///////////////////////////////////////////////////////////////////////////////

FakeWinHttpUrlFetcherFactory::RequestData::RequestData()
    : timeout_in_millis(-1) {}  // Set default timeout to an invalid value.

FakeWinHttpUrlFetcherFactory::RequestData::RequestData(const RequestData& rhs)
    : headers(rhs.headers),
      body(rhs.body),
      timeout_in_millis(rhs.timeout_in_millis) {}

FakeWinHttpUrlFetcherFactory::RequestData::~RequestData() = default;

FakeWinHttpUrlFetcherFactory::Response::Response() {}

FakeWinHttpUrlFetcherFactory::Response::Response(const Response& rhs)
    : headers(rhs.headers),
      response(rhs.response),
      send_response_event_handle(rhs.send_response_event_handle) {}

FakeWinHttpUrlFetcherFactory::Response::Response(
    const WinHttpUrlFetcher::Headers& new_headers,
    const std::string& new_response,
    HANDLE new_send_response_event_handle)
    : headers(new_headers),
      response(new_response),
      send_response_event_handle(new_send_response_event_handle) {}

FakeWinHttpUrlFetcherFactory::Response::~Response() = default;

FakeWinHttpUrlFetcherFactory::FakeWinHttpUrlFetcherFactory()
    : original_creator_(*WinHttpUrlFetcher::GetCreatorFunctionStorage()) {
  fake_creator_ = base::BindRepeating(&FakeWinHttpUrlFetcherFactory::Create,
                                      base::Unretained(this));
  *WinHttpUrlFetcher::GetCreatorFunctionStorage() = fake_creator_;
}

FakeWinHttpUrlFetcherFactory::~FakeWinHttpUrlFetcherFactory() {
  *WinHttpUrlFetcher::GetCreatorFunctionStorage() = original_creator_;
}

WinHttpUrlFetcher::CreatorCallback
FakeWinHttpUrlFetcherFactory::GetCreatorCallback() {
  return fake_creator_;
}

void FakeWinHttpUrlFetcherFactory::SetFakeResponse(
    const GURL& url,
    const WinHttpUrlFetcher::Headers& headers,
    const std::string& response,
    HANDLE send_response_event_handle /*=INVALID_HANDLE_VALUE*/) {
  fake_responses_[url].clear();
  fake_responses_[url].push_back(
      Response(headers, response, send_response_event_handle));
  remove_fake_response_when_created_ = false;
}

void FakeWinHttpUrlFetcherFactory::SetFakeResponseForSpecifiedNumRequests(
    const GURL& url,
    const WinHttpUrlFetcher::Headers& headers,
    const std::string& response,
    unsigned int num_requests,
    HANDLE send_response_event_handle /* =INVALID_HANDLE_VALUE */) {
  if (fake_responses_.find(url) == fake_responses_.end()) {
    fake_responses_[url] = std::deque<Response>();
  }
  for (unsigned int i = 0; i < num_requests; ++i) {
    fake_responses_[url].push_back(
        Response(headers, response, send_response_event_handle));
  }
  remove_fake_response_when_created_ = true;
}

void FakeWinHttpUrlFetcherFactory::SetFakeFailedResponse(const GURL& url,
                                                         HRESULT failed_hr) {
  // Make sure that the HRESULT set is a failed attempt.
  DCHECK(FAILED(failed_hr));
  failed_http_fetch_hr_[url] = failed_hr;
}

FakeWinHttpUrlFetcherFactory::RequestData
FakeWinHttpUrlFetcherFactory::GetRequestData(size_t request_index) const {
  if (request_index < requests_data_.size()) {
    return requests_data_[request_index];
  }
  return RequestData();
}

std::unique_ptr<WinHttpUrlFetcher> FakeWinHttpUrlFetcherFactory::Create(
    const GURL& url) {
  if (fake_responses_.count(url) == 0 &&
      failed_http_fetch_hr_.count(url) == 0) {
    return nullptr;
  }

  FakeWinHttpUrlFetcher* fetcher = new FakeWinHttpUrlFetcher(url);

  if (fake_responses_.count(url) != 0) {
    const Response& response = fake_responses_[url].front();

    fetcher->response_headers_ = response.headers;
    fetcher->response_ = response.response;
    fetcher->send_response_event_handle_ = response.send_response_event_handle;

    if (remove_fake_response_when_created_) {
      fake_responses_[url].pop_front();
      if (fake_responses_[url].empty()) {
        fake_responses_.erase(url);
      }
    }
  } else {
    DCHECK(failed_http_fetch_hr_.count(url) > 0);
    fetcher->response_hr_ = failed_http_fetch_hr_[url];
  }

  if (collect_request_data_) {
    requests_data_.push_back(RequestData());
    fetcher->request_data_ = &requests_data_.back();
  }

  ++requests_created_;

  return std::unique_ptr<WinHttpUrlFetcher>(fetcher);
}

FakeWinHttpUrlFetcher::FakeWinHttpUrlFetcher(const GURL& url)
    : WinHttpUrlFetcher() {}

FakeWinHttpUrlFetcher::~FakeWinHttpUrlFetcher() {}

bool FakeWinHttpUrlFetcher::IsValid() const {
  return true;
}

HRESULT FakeWinHttpUrlFetcher::Fetch(std::vector<char>* response) {
  if (FAILED(response_hr_)) {
    return response_hr_;
  }

  if (send_response_event_handle_ != INVALID_HANDLE_VALUE) {
    ::WaitForSingleObject(send_response_event_handle_, INFINITE);
  }

  response->resize(response_.size());
  memcpy(response->data(), response_.c_str(), response->size());
  return S_OK;
}

HRESULT FakeWinHttpUrlFetcher::Close() {
  return S_OK;
}

HRESULT FakeWinHttpUrlFetcher::SetRequestHeader(const char* name,
                                                const char* value) {
  if (request_data_) {
    request_data_->headers[name] = value;
  }
  return S_OK;
}

HRESULT FakeWinHttpUrlFetcher::SetRequestBody(const char* body) {
  if (request_data_) {
    request_data_->body = body;
  }
  return S_OK;
}

HRESULT FakeWinHttpUrlFetcher::SetHttpRequestTimeout(
    const int timeout_in_millis) {
  if (request_data_) {
    request_data_->timeout_in_millis = timeout_in_millis;
  }
  return S_OK;
}

///////////////////////////////////////////////////////////////////////////////

FakeAssociatedUserValidator::FakeAssociatedUserValidator()
    : AssociatedUserValidator(
          AssociatedUserValidator::kDefaultTokenHandleValidationTimeout),
      original_validator_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeAssociatedUserValidator::FakeAssociatedUserValidator(
    base::TimeDelta validation_timeout)
    : AssociatedUserValidator(validation_timeout),
      original_validator_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeAssociatedUserValidator::~FakeAssociatedUserValidator() {
  *GetInstanceStorage() = original_validator_;
}

///////////////////////////////////////////////////////////////////////////////

FakeChromeAvailabilityChecker::FakeChromeAvailabilityChecker(
    HasSupportedChromeCheckType has_supported_chrome /*=kChromeForceYes*/)
    : original_checker_(*GetInstanceStorage()),
      has_supported_chrome_(has_supported_chrome) {
  *GetInstanceStorage() = this;
}

FakeChromeAvailabilityChecker::~FakeChromeAvailabilityChecker() {
  *GetInstanceStorage() = original_checker_;
}

bool FakeChromeAvailabilityChecker::HasSupportedChromeVersion() {
  if (has_supported_chrome_ == kChromeDontForce) {
    return original_checker_->HasSupportedChromeVersion();
  }
  return has_supported_chrome_ == kChromeForceYes;
}

void FakeChromeAvailabilityChecker::SetHasSupportedChrome(
    HasSupportedChromeCheckType has_supported_chrome) {
  has_supported_chrome_ = has_supported_chrome;
}

///////////////////////////////////////////////////////////////////////////////

FakeInternetAvailabilityChecker::FakeInternetAvailabilityChecker(
    HasInternetConnectionCheckType has_internet_connection /*=kHicForceYes*/)
    : original_checker_(*GetInstanceStorage()),
      has_internet_connection_(has_internet_connection) {
  *GetInstanceStorage() = this;
}

FakeInternetAvailabilityChecker::~FakeInternetAvailabilityChecker() {
  *GetInstanceStorage() = original_checker_;
}

bool FakeInternetAvailabilityChecker::HasInternetConnection() {
  return has_internet_connection_ == kHicForceYes;
}

void FakeInternetAvailabilityChecker::SetHasInternetConnection(
    HasInternetConnectionCheckType has_internet_connection) {
  has_internet_connection_ = has_internet_connection;
}

///////////////////////////////////////////////////////////////////////////////

FakePasswordRecoveryManager::FakePasswordRecoveryManager()
    : FakePasswordRecoveryManager(
          PasswordRecoveryManager::
              kDefaultEscrowServiceEncryptionKeyRequestTimeout,
          PasswordRecoveryManager::
              kDefaultEscrowServiceDecryptionKeyRequestTimeout) {}

FakePasswordRecoveryManager::FakePasswordRecoveryManager(
    base::TimeDelta encryption_key_request_timeout,
    base::TimeDelta decryption_key_request_timeout)
    : PasswordRecoveryManager(encryption_key_request_timeout,
                              decryption_key_request_timeout),
      original_validator_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakePasswordRecoveryManager::~FakePasswordRecoveryManager() {
  *GetInstanceStorage() = original_validator_;
}

///////////////////////////////////////////////////////////////////////////////

FakeGemDeviceDetailsManager::FakeGemDeviceDetailsManager()
    : FakeGemDeviceDetailsManager(
          GemDeviceDetailsManager::kDefaultUploadDeviceDetailsRequestTimeout) {}

FakeGemDeviceDetailsManager::FakeGemDeviceDetailsManager(
    base::TimeDelta upload_device_details_request_timeout)
    : GemDeviceDetailsManager(upload_device_details_request_timeout),
      original_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeGemDeviceDetailsManager::~FakeGemDeviceDetailsManager() {
  *GetInstanceStorage() = original_manager_;
}

///////////////////////////////////////////////////////////////////////////////

EVT_HANDLE FakeEventLoggingApiManager::EvtQuery(EVT_HANDLE session,
                                                LPCWSTR path,
                                                LPCWSTR query,
                                                DWORD flags) {
  EXPECT_EQ(session, nullptr);  // local session only.
  EXPECT_EQ(path, nullptr);
  DCHECK(query);
  EXPECT_TRUE((flags & EvtQueryChannelPath) > 0);

  query_handle_ = reinterpret_cast<EVT_HANDLE>(&query_handle_);
  last_error_ = ERROR_SUCCESS;
  return query_handle_;
}

EVT_HANDLE FakeEventLoggingApiManager::EvtOpenPublisherMetadata(
    EVT_HANDLE session,
    LPCWSTR publisher_id,
    LPCWSTR log_file_path,
    LCID locale,
    DWORD flags) {
  EXPECT_EQ(session, nullptr);
  EXPECT_EQ(std::wstring(publisher_id), std::wstring(L"GCPW"));
  EXPECT_EQ(log_file_path, nullptr);
  EXPECT_EQ(locale, DWORD(0));  // local locale.
  EXPECT_EQ(flags, DWORD(0));

  publisher_metadata_ = reinterpret_cast<EVT_HANDLE>(&publisher_metadata_);
  last_error_ = ERROR_SUCCESS;
  return publisher_metadata_;
}

EVT_HANDLE FakeEventLoggingApiManager::EvtCreateRenderContext(
    DWORD value_paths_count,
    LPCWSTR* value_paths,
    DWORD flags) {
  EXPECT_TRUE(value_paths_count >= 2);
  DCHECK(value_paths);
  EXPECT_TRUE(std::wstring(value_paths[0]).find(L"EventRecordID") !=
              std::wstring::npos);
  EXPECT_TRUE(std::wstring(value_paths[1]).find(L"TimeCreated") !=
              std::wstring::npos);
  EXPECT_EQ(flags, EvtRenderContextValues);

  render_context_ = reinterpret_cast<EVT_HANDLE>(&render_context_);
  last_error_ = ERROR_SUCCESS;
  return render_context_;
}

BOOL FakeEventLoggingApiManager::EvtNext(EVT_HANDLE result_set,
                                         DWORD events_size,
                                         PEVT_HANDLE events,
                                         DWORD timeout,
                                         DWORD flags,
                                         PDWORD num_returned) {
  EXPECT_EQ(result_set, query_handle_);
  EXPECT_TRUE(events_size > 0);
  DCHECK(events);

  if (next_event_idx_ >= logs_->size()) {
    last_error_ = ERROR_NO_MORE_ITEMS;
    return FALSE;
  }

  *num_returned = 0;
  for (; (next_event_idx_ < logs_->size()) && (*num_returned < events_size);
       ++next_event_idx_) {
    event_handles_.push_back(EVT_HANDLE());
    size_t last_idx = event_handles_.size() - 1;
    event_handles_[last_idx] = &event_handles_[last_idx];

    events[*num_returned] = event_handles_[last_idx];
    handle_to_index_map_[event_handles_[last_idx]] = next_event_idx_;

    (*num_returned)++;
  }

  last_error_ = ERROR_SUCCESS;
  return TRUE;
}

BOOL FakeEventLoggingApiManager::EvtGetQueryInfo(
    EVT_HANDLE query,
    EVT_QUERY_PROPERTY_ID property_id,
    DWORD value_buffer_size,
    PEVT_VARIANT value_buffer,
    PDWORD value_buffer_used) {
  EXPECT_EQ(query, query_handle_);
  EXPECT_TRUE((property_id == EvtQueryStatuses) ||
              (property_id == EvtQueryNames));

  const wchar_t channel_name[] = L"Application";
  const DWORD mem_size = sizeof(channel_name) + sizeof(EVT_VARIANT);
  *value_buffer_used = mem_size;

  if (value_buffer_size == 0) {
    last_error_ = ERROR_INSUFFICIENT_BUFFER;
    return FALSE;
  }

  EXPECT_TRUE(value_buffer_size >= mem_size);
  value_buffer->Count = 1;
  char* addr = reinterpret_cast<char*>(value_buffer) + sizeof(EVT_VARIANT);

  if (property_id == EvtQueryStatuses) {
    value_buffer->UInt32Arr = reinterpret_cast<UINT32*>(addr);
    value_buffer->UInt32Arr[0] = ERROR_SUCCESS;
  } else if (property_id == EvtQueryNames) {
    value_buffer->StringArr = reinterpret_cast<LPWSTR*>(addr);
    memcpy(value_buffer->StringArr, channel_name, sizeof(channel_name));
  }
  last_error_ = ERROR_SUCCESS;
  return TRUE;
}

BOOL FakeEventLoggingApiManager::EvtRender(EVT_HANDLE context,
                                           EVT_HANDLE evt_handle,
                                           DWORD flags,
                                           DWORD buffer_size,
                                           PVOID buffer,
                                           PDWORD buffer_used,
                                           PDWORD property_count) {
  EXPECT_EQ(context, render_context_);
  EXPECT_TRUE(handle_to_index_map_.find(evt_handle) !=
              handle_to_index_map_.end());
  EXPECT_EQ(flags, EvtRenderEventValues);

  size_t idx = handle_to_index_map_.find(evt_handle)->second;
  const size_t num_properties = 2;
  const size_t mem_needed = num_properties * sizeof(EVT_VARIANT);
  *buffer_used = mem_needed;

  if (buffer_size < mem_needed) {
    last_error_ = ERROR_INSUFFICIENT_BUFFER;
    return FALSE;
  }

  EVT_VARIANT* data = reinterpret_cast<EVT_VARIANT*>(buffer);
  data[0].UInt64Val = (*logs_)[idx].event_id;

  // Convert to Windows ticks.
  ULONGLONG timestamp_ticks =
      ((*logs_)[idx].created_ts.seconds + 11644473600LL) * 10000000;
  timestamp_ticks += ((*logs_)[idx].created_ts.nanos / 100);

  data[1].FileTimeVal = timestamp_ticks;
  *property_count = num_properties;
  last_error_ = ERROR_SUCCESS;
  return TRUE;
}

BOOL FakeEventLoggingApiManager::EvtFormatMessage(EVT_HANDLE publisher_metadata,
                                                  EVT_HANDLE event,
                                                  DWORD message_id,
                                                  DWORD value_count,
                                                  PEVT_VARIANT values,
                                                  DWORD flags,
                                                  DWORD buffer_size,
                                                  LPWSTR buffer,
                                                  PDWORD buffer_used) {
  EXPECT_EQ(publisher_metadata, publisher_metadata_);
  EXPECT_TRUE(handle_to_index_map_.find(event) != handle_to_index_map_.end());
  EXPECT_EQ(value_count, DWORD(0));
  EXPECT_EQ(values, nullptr);
  EXPECT_TRUE((flags == EvtFormatMessageEvent) ||
              (flags == EvtFormatMessageLevel));
  DCHECK(buffer_used);

  size_t idx = handle_to_index_map_.find(event)->second;

  std::wstring data;
  if (flags == EvtFormatMessageEvent) {
    data = (*logs_)[idx].data;
  } else if (flags == EvtFormatMessageLevel) {
    switch ((*logs_)[idx].severity_level) {
      case 1:
        data = L"Critical";
        break;
      case 2:
        data = L"Error";
        break;
      case 3:
        data = L"Warning";
        break;
      case 4:
        data = L"Information";
        break;
      case 5:
        data = L"Verbose";
        break;
      default:
        data = L"Unknown";
        break;
    }
  }

  const size_t mem_needed =
      sizeof(std::wstring::value_type) * (data.size() + 1);

  *buffer_used = mem_needed;
  if (buffer_size < mem_needed) {
    last_error_ = ERROR_INSUFFICIENT_BUFFER;
    return FALSE;
  }

  DCHECK(buffer);
  ::memcpy(buffer, data.c_str(),
           data.size() * sizeof(std::wstring::value_type));
  last_error_ = ERROR_SUCCESS;

  return TRUE;
}

BOOL FakeEventLoggingApiManager::EvtClose(EVT_HANDLE handle) {
  DCHECK(handle);
  last_error_ = ERROR_SUCCESS;
  if (handle == &query_handle_) {
    query_handle_ = nullptr;
    return TRUE;
  } else if (handle == &publisher_metadata_) {
    publisher_metadata_ = nullptr;
    return TRUE;
  } else if (handle == &render_context_) {
    render_context_ = nullptr;
    return TRUE;
  }

  if (handle_to_index_map_.find(handle) != handle_to_index_map_.end()) {
    size_t idx = handle_to_index_map_.find(handle)->second;
    event_handles_[idx] = nullptr;
    return TRUE;
  }

  last_error_ = ERROR_INVALID_HANDLE;
  return FALSE;
}

DWORD FakeEventLoggingApiManager::GetLastError() {
  return last_error_;
}

FakeEventLoggingApiManager::FakeEventLoggingApiManager(
    const std::vector<EventLogEntry>& logs)
    : original_manager_(*GetInstanceStorage()),
      logs_(logs),
      query_handle_(nullptr),
      publisher_metadata_(nullptr),
      render_context_(nullptr),
      last_error_(ERROR_SUCCESS),
      next_event_idx_(0) {
  *GetInstanceStorage() = this;
}

FakeEventLoggingApiManager::~FakeEventLoggingApiManager() {
  *GetInstanceStorage() = original_manager_;
  EXPECT_EQ(query_handle_, nullptr);
  EXPECT_EQ(publisher_metadata_, nullptr);
  EXPECT_EQ(render_context_, nullptr);

  for (size_t i = 0; i < event_handles_.size(); ++i) {
    EXPECT_EQ(event_handles_[i], nullptr);
  }
}

FakeEventLogsUploadManager::FakeEventLogsUploadManager(
    const std::vector<EventLogEntry>& logs)
    : original_manager_(*GetInstanceStorage()), api_manager_(logs) {
  *GetInstanceStorage() = this;
}

FakeEventLogsUploadManager::~FakeEventLogsUploadManager() {
  *GetInstanceStorage() = original_manager_;
}

HRESULT FakeEventLogsUploadManager::GetUploadStatus() {
  return upload_status_;
}

uint64_t FakeEventLogsUploadManager::GetNumLogsUploaded() {
  return num_event_logs_uploaded_;
}

///////////////////////////////////////////////////////////////////////////////

FakeUserPoliciesManager::FakeUserPoliciesManager()
    : original_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeUserPoliciesManager::FakeUserPoliciesManager(bool cloud_policies_enabled)
    : original_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
  SetCloudPoliciesEnabledForTesting(cloud_policies_enabled);
}

FakeUserPoliciesManager::~FakeUserPoliciesManager() {
  *GetInstanceStorage() = original_manager_;
}

HRESULT FakeUserPoliciesManager::FetchAndStoreCloudUserPolicies(
    const std::wstring& sid,
    const std::string& access_token) {
  ++num_times_fetch_called_;
  fetch_status_ =
      original_manager_->FetchAndStoreCloudUserPolicies(sid, access_token);
  return fetch_status_;
}

void FakeUserPoliciesManager::SetUserPolicies(const std::wstring& sid,
                                              const UserPolicies& policies) {
  user_policies_[sid] = policies;
  user_policies_stale_[sid] = false;
}

bool FakeUserPoliciesManager::GetUserPolicies(const std::wstring& sid,
                                              UserPolicies* policies) const {
  if (user_policies_.find(sid) != user_policies_.end()) {
    *policies = user_policies_.at(sid);
    return true;
  }

  return false;
}

void FakeUserPoliciesManager::SetUserPolicyStaleOrMissing(
    const std::wstring& sid,
    bool status) {
  user_policies_stale_[sid] = status;
}

bool FakeUserPoliciesManager::IsUserPolicyStaleOrMissing(
    const std::wstring& sid) const {
  if (user_policies_stale_.find(sid) != user_policies_stale_.end()) {
    return user_policies_stale_.at(sid);
  }

  return true;
}

int FakeUserPoliciesManager::GetNumTimesFetchAndStoreCalled() const {
  return num_times_fetch_called_;
}

///////////////////////////////////////////////////////////////////////////////

FakeDevicePoliciesManager::FakeDevicePoliciesManager(
    bool cloud_policies_enabled)
    : original_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
  UserPoliciesManager::Get()->SetCloudPoliciesEnabledForTesting(
      cloud_policies_enabled);
}

FakeDevicePoliciesManager::~FakeDevicePoliciesManager() {
  *GetInstanceStorage() = original_manager_;
}

void FakeDevicePoliciesManager::SetDevicePolicies(
    const DevicePolicies& policies) {
  device_policies_ = policies;
}

void FakeDevicePoliciesManager::GetDevicePolicies(
    DevicePolicies* device_policies) {
  *device_policies = device_policies_;
}

///////////////////////////////////////////////////////////////////////////////

FakeGCPWFiles::FakeGCPWFiles() : original_files(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeGCPWFiles::~FakeGCPWFiles() {
  *GetInstanceStorage() = original_files;
}

// Installable files are sanitized for testing due to
// differences between build artifacts file location and the way they are being
// packaged. When tests are running, they are checking the build artifacts which
// doesn't reflect foldering structure within 7zip archive.
std::vector<base::FilePath::StringType>
FakeGCPWFiles::GetEffectiveInstallFiles() {
  auto effective_files = original_files->GetEffectiveInstallFiles();

  std::vector<base::FilePath::StringType> sanitized_files;
  for (auto& install_file : effective_files) {
    size_t found = install_file.find_last_of('\\');
    if (found != std::wstring::npos) {
      sanitized_files.push_back(install_file.substr(found + 1));
    } else {
      sanitized_files.push_back(install_file);
    }
  }

  return sanitized_files;
}

///////////////////////////////////////////////////////////////////////////////

FakeOSServiceManager::FakeOSServiceManager()
    : os_service_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeOSServiceManager::~FakeOSServiceManager() {
  *GetInstanceStorage() = os_service_manager_;
}

unsigned __stdcall ServiceLauncher(void* service_main) {
  LPSERVICE_MAIN_FUNCTION sm = (LPSERVICE_MAIN_FUNCTION)service_main;
  DWORD flags = 0;
  (*sm)(flags, nullptr);
  return 0;
}

DWORD FakeOSServiceManager::StartServiceCtrlDispatcher(
    LPSERVICE_MAIN_FUNCTION service_main) {
  if (service_lookup_from_name_.find(extension::kGCPWExtensionServiceName) ==
      service_lookup_from_name_.end()) {
    return ERROR_INVALID_DATA;
  }
  LOGFN(INFO);

  uintptr_t wait_thread =
      _beginthreadex(0, 0, ServiceLauncher, (void*)service_main, 0, 0);

  while (true) {
    // Service looks for control requests so that it calls the service's control
    // handler.
    DWORD control_request = GetControlRequestForTesting();
    LOGFN(INFO) << "Received control: " << control_request;

    // This is a custom control to end the service process main when service is
    // supposed to stop.
    if (control_request == 100) {
      break;
    }

    service_lookup_from_name_[extension::kGCPWExtensionServiceName]
        .control_handler_cb_(control_request);
  }
  ::CloseHandle(reinterpret_cast<HANDLE>(wait_thread));

  return ERROR_SUCCESS;
}

DWORD FakeOSServiceManager::RegisterCtrlHandler(
    LPHANDLER_FUNCTION handler_proc,
    SERVICE_STATUS_HANDLE* service_status_handle) {
  if (service_lookup_from_name_.find(extension::kGCPWExtensionServiceName) ==
      service_lookup_from_name_.end()) {
    return ERROR_SERVICE_DOES_NOT_EXIST;
  }

  service_lookup_from_name_[extension::kGCPWExtensionServiceName]
      .control_handler_cb_ = handler_proc;
  // Set some random integer here. Not needed in the tests.
  *service_status_handle = (SERVICE_STATUS_HANDLE)1;

  return ERROR_SUCCESS;
}

DWORD FakeOSServiceManager::SetServiceStatus(
    SERVICE_STATUS_HANDLE service_status_handle,
    SERVICE_STATUS service) {
  LOGFN(INFO) << "Service state: " << service.dwCurrentState;
  if (service_lookup_from_name_.find(extension::kGCPWExtensionServiceName) ==
      service_lookup_from_name_.end()) {
    return ERROR_SERVICE_DOES_NOT_EXIST;
  }
  service_lookup_from_name_[extension::kGCPWExtensionServiceName]
      .service_status_ = service;

  if (service.dwCurrentState == SERVICE_STOPPED) {
    SendControlRequestForTesting(100);
  }
  return ERROR_SUCCESS;
}

DWORD FakeOSServiceManager::InstallService(
    const base::FilePath& service_binary_path,
    extension::ScopedScHandle* sc_handle) {
  LOGFN(INFO);

  service_lookup_from_name_[extension::kGCPWExtensionServiceName]
      .service_status_.dwCurrentState = SERVICE_STOPPED;
  return ERROR_SUCCESS;
}

DWORD FakeOSServiceManager::GetServiceStatus(SERVICE_STATUS* service_status) {
  LOGFN(INFO);
  if (service_lookup_from_name_.find(extension::kGCPWExtensionServiceName) ==
      service_lookup_from_name_.end()) {
    return ERROR_SERVICE_DOES_NOT_EXIST;
  }
  *service_status =
      service_lookup_from_name_[extension::kGCPWExtensionServiceName]
          .service_status_;
  return ERROR_SUCCESS;
}

DWORD FakeOSServiceManager::DeleteService() {
  service_lookup_from_name_.erase(extension::kGCPWExtensionServiceName);
  return ERROR_SUCCESS;
}

DWORD FakeOSServiceManager::ChangeServiceConfig(DWORD dwServiceType,
                                                DWORD dwStartType,
                                                DWORD dwErrorControl) {
  return ERROR_SUCCESS;
}

///////////////////////////////////////////////////////////////////////////////

FakeTaskManager::FakeTaskManager() : task_manager_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeTaskManager::~FakeTaskManager() {
  *GetInstanceStorage() = task_manager_;
}

void FakeTaskManager::ExecuteTask(
    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
    const std::string& task_name) {
  num_of_times_executed_[task_name]++;

  TaskManager::ExecuteTask(task_runner, task_name);
}

///////////////////////////////////////////////////////////////////////////////

FakeTokenGenerator::FakeTokenGenerator()
    : token_generator_(*GetInstanceStorage()) {
  *GetInstanceStorage() = this;
}

FakeTokenGenerator::~FakeTokenGenerator() {
  *GetInstanceStorage() = token_generator_;
}

std::string FakeTokenGenerator::GenerateToken() {
  auto token = test_tokens_.front();
  test_tokens_.erase(test_tokens_.begin());
  return token;
}

void FakeTokenGenerator::SetTokensForTesting(
    const std::vector<std::string>& test_tokens) {
  test_tokens_ = test_tokens;
}

}  // namespace credential_provider