// Copyright 2020 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/updater/win/installer_api.h"
#include <optional>
#include <string>
#include "base/strings/utf_string_conversions.h"
#include "base/test/test_reg_util_win.h"
#include "base/win/registry.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/util/win_util.h"
#include "components/update_client/update_client.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace updater {
namespace {
constexpr char kAppId[] = "{55d6c27c-8b97-4b76-a691-2df8810004ed}";
} // namespace
class InstallerAPITest : public ::testing::TestWithParam<UpdaterScope> {
protected:
const UpdaterScope updater_scope_ = GetParam();
registry_util::RegistryOverrideManager registry_override_;
};
INSTANTIATE_TEST_SUITE_P(UpdaterScope,
InstallerAPITest,
testing::Values(UpdaterScope::kUser,
UpdaterScope::kSystem));
TEST_P(InstallerAPITest, InstallerProgress) {
ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(
UpdaterScopeToHKeyRoot(updater_scope_)));
ClientStateAppKeyDelete(updater_scope_, kAppId);
EXPECT_EQ(GetInstallerProgress(updater_scope_, kAppId), -1);
SetInstallerProgressForTesting(updater_scope_, kAppId, 0);
EXPECT_EQ(GetInstallerProgress(updater_scope_, kAppId), 0);
SetInstallerProgressForTesting(updater_scope_, kAppId, 50);
EXPECT_EQ(GetInstallerProgress(updater_scope_, kAppId), 50);
SetInstallerProgressForTesting(updater_scope_, kAppId, 100);
EXPECT_EQ(GetInstallerProgress(updater_scope_, kAppId), 100);
SetInstallerProgressForTesting(updater_scope_, kAppId, 200);
EXPECT_EQ(GetInstallerProgress(updater_scope_, kAppId), 100);
EXPECT_TRUE(ClientStateAppKeyDelete(updater_scope_, kAppId));
}
TEST_P(InstallerAPITest, GetInstallerOutcome) {
ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(
UpdaterScopeToHKeyRoot(updater_scope_)));
ClientStateAppKeyDelete(updater_scope_, kAppId);
// No installer outcome if the ClientState for the app it does not exist.
EXPECT_FALSE(GetInstallerOutcome(updater_scope_, kAppId));
EXPECT_FALSE(GetClientStateKeyLastInstallerOutcome(updater_scope_, kAppId));
EXPECT_FALSE(GetUpdaterKeyLastInstallerOutcome(updater_scope_));
{
InstallerOutcome installer_outcome;
installer_outcome.installer_result = InstallerApiResult::kSystemError;
installer_outcome.installer_error = 1;
installer_outcome.installer_extracode1 = -2;
installer_outcome.installer_text = "some text";
installer_outcome.installer_cmd_line = "some cmd line";
EXPECT_TRUE(SetInstallerOutcomeForTesting(updater_scope_, kAppId,
installer_outcome));
}
std::optional<InstallerOutcome> installer_outcome =
GetInstallerOutcome(updater_scope_, kAppId);
ASSERT_TRUE(installer_outcome);
EXPECT_EQ(installer_outcome->installer_result,
InstallerApiResult::kSystemError);
EXPECT_EQ(installer_outcome->installer_error, 1);
EXPECT_EQ(installer_outcome->installer_extracode1, -2);
EXPECT_STREQ(installer_outcome->installer_text->c_str(), "some text");
EXPECT_STREQ(installer_outcome->installer_cmd_line->c_str(), "some cmd line");
// Checks that LastInstallerXXX values match the installer outcome.
for (std::optional<InstallerOutcome> last_installer_outcome :
{GetClientStateKeyLastInstallerOutcome(updater_scope_, kAppId),
GetUpdaterKeyLastInstallerOutcome(updater_scope_)}) {
ASSERT_TRUE(last_installer_outcome);
EXPECT_EQ(last_installer_outcome->installer_result,
installer_outcome->installer_result);
EXPECT_EQ(last_installer_outcome->installer_error,
installer_outcome->installer_error);
EXPECT_EQ(last_installer_outcome->installer_extracode1,
installer_outcome->installer_extracode1);
EXPECT_EQ(*last_installer_outcome->installer_text,
*installer_outcome->installer_text);
EXPECT_EQ(*last_installer_outcome->installer_cmd_line,
*installer_outcome->installer_cmd_line);
}
// Checks that the previous call to `GetInstallerOutcome` cleared the
// installer outcome.
installer_outcome = GetInstallerOutcome(updater_scope_, kAppId);
ASSERT_TRUE(installer_outcome);
EXPECT_FALSE(installer_outcome->installer_result);
EXPECT_FALSE(installer_outcome->installer_error);
EXPECT_FALSE(installer_outcome->installer_extracode1);
EXPECT_FALSE(installer_outcome->installer_text);
EXPECT_FALSE(installer_outcome->installer_cmd_line);
{
InstallerOutcome installer_outcome_for_deletion;
installer_outcome_for_deletion.installer_result =
InstallerApiResult::kSystemError;
installer_outcome_for_deletion.installer_error = 1;
installer_outcome_for_deletion.installer_extracode1 = -2;
installer_outcome_for_deletion.installer_text = "some text";
installer_outcome_for_deletion.installer_cmd_line = "some cmd line";
EXPECT_TRUE(SetInstallerOutcomeForTesting(updater_scope_, kAppId,
installer_outcome_for_deletion));
}
// No installer outcome values after clearing the installer outcome.
EXPECT_TRUE(DeleteInstallerOutput(updater_scope_, kAppId));
installer_outcome = GetInstallerOutcome(updater_scope_, kAppId);
ASSERT_TRUE(installer_outcome);
EXPECT_FALSE(installer_outcome->installer_result);
EXPECT_FALSE(installer_outcome->installer_error);
EXPECT_FALSE(installer_outcome->installer_extracode1);
EXPECT_FALSE(installer_outcome->installer_text);
EXPECT_FALSE(installer_outcome->installer_cmd_line);
EXPECT_TRUE(ClientStateAppKeyDelete(updater_scope_, kAppId));
}
TEST_P(InstallerAPITest, MakeInstallerResult) {
{
InstallerOutcome installer_outcome;
installer_outcome.installer_result = InstallerApiResult::kSuccess;
installer_outcome.installer_error = 1;
installer_outcome.installer_extracode1 = -2;
installer_outcome.installer_text = "some text";
installer_outcome.installer_cmd_line = "some cmd line";
const auto installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kNone);
EXPECT_EQ(installer_result.result.code_, 0);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_TRUE(installer_result.installer_text.empty());
EXPECT_STREQ(installer_result.installer_cmd_line.c_str(), "some cmd line");
}
{
InstallerOutcome installer_outcome;
installer_outcome.installer_result = InstallerApiResult::kCustomError;
installer_outcome.installer_error = 1;
installer_outcome.installer_extracode1 = -2;
installer_outcome.installer_text = "some text";
installer_outcome.installer_cmd_line = "some cmd line";
auto installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 1);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_STREQ(installer_result.installer_text.c_str(), "some text");
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
installer_outcome.installer_error = std::nullopt;
installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 10);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_STREQ(installer_result.installer_text.c_str(), "some text");
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
}
{
InstallerOutcome installer_outcome;
installer_outcome.installer_result = InstallerApiResult::kMsiError;
installer_outcome.installer_error = 1;
installer_outcome.installer_extracode1 = -2;
installer_outcome.installer_text = "some text";
installer_outcome.installer_cmd_line = "some cmd line";
auto installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 1);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_FALSE(installer_result.installer_text.empty());
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
installer_outcome.installer_error = std::nullopt;
installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 10);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_FALSE(installer_result.installer_text.empty());
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
}
{
InstallerOutcome installer_outcome;
installer_outcome.installer_result = InstallerApiResult::kSystemError;
installer_outcome.installer_error = 1;
installer_outcome.installer_extracode1 = -2;
installer_outcome.installer_text = "some text";
installer_outcome.installer_cmd_line = "some cmd line";
auto installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 1);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_FALSE(installer_result.installer_text.empty());
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
installer_outcome.installer_error = std::nullopt;
installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 10);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_FALSE(installer_result.installer_text.empty());
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
}
{
InstallerOutcome installer_outcome;
installer_outcome.installer_result = InstallerApiResult::kExitCode;
installer_outcome.installer_error = 1;
installer_outcome.installer_extracode1 = -2;
installer_outcome.installer_text = "some text";
installer_outcome.installer_cmd_line = "some cmd line";
auto installer_result = MakeInstallerResult(installer_outcome, 0);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 1);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_EQ(installer_result.installer_text, "some text");
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
// `installer_outcome` overrides the exit code.
installer_result = MakeInstallerResult(installer_outcome, 10);
EXPECT_EQ(installer_result.result.category_,
update_client::ErrorCategory::kInstaller);
EXPECT_EQ(installer_result.result.code_, 1);
EXPECT_EQ(installer_result.result.extra_, -2);
EXPECT_EQ(installer_result.installer_text, "some text");
EXPECT_TRUE(installer_result.installer_cmd_line.empty());
}
}
TEST_P(InstallerAPITest, ClientStateAppKeyOpen) {
ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(
UpdaterScopeToHKeyRoot(updater_scope_)));
EXPECT_FALSE(
ClientStateAppKeyOpen(updater_scope_, "invalid-app-id", KEY_READ));
SetInstallerProgressForTesting(updater_scope_, kAppId, 0);
EXPECT_TRUE(ClientStateAppKeyOpen(updater_scope_, kAppId, KEY_READ));
}
} // namespace updater