910e62b5创建于 1月15日历史提交
// 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/app/app_server.h"

#include <optional>
#include <string>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/scoped_command_line.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/prefs.h"
#include "chrome/updater/test/test_scope.h"
#include "chrome/updater/update_service.h"
#include "chrome/updater/update_service_internal.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util/util.h"
#include "components/prefs/pref_service.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace updater {
namespace {

using ::testing::Invoke;
using ::testing::Return;

class AppServerTest : public AppServer {
 public:
  AppServerTest() {
    ON_CALL(*this, ActiveDuty)
        .WillByDefault(Invoke(this, &AppServerTest::Shutdown0));
    ON_CALL(*this, ActiveDutyInternal)
        .WillByDefault(Invoke(this, &AppServerTest::Shutdown0));
  }

  MOCK_METHOD(void, ActiveDuty, (scoped_refptr<UpdateService>), (override));
  MOCK_METHOD(void,
              ActiveDutyInternal,
              (scoped_refptr<UpdateServiceInternal>),
              (override));
  MOCK_METHOD(bool, SwapInNewVersion, (), (override));
  MOCK_METHOD(void, RepairUpdater, (UpdaterScope, bool), (override));
  MOCK_METHOD(void, UninstallSelf, (), (override));
  MOCK_METHOD(bool, ShutdownIfIdleAfterTask, (), (override));
  MOCK_METHOD(void, OnDelayedTaskComplete, (), (override));

 private:
  ~AppServerTest() override = default;

  UpdaterScope updater_scope() const override {
    return GetUpdaterScopeForTesting();
  }

  void Shutdown0() { Shutdown(0); }
};

void ClearPrefs() {
  const UpdaterScope updater_scope = GetUpdaterScopeForTesting();
  for (const std::optional<base::FilePath>& path :
       {GetInstallDirectory(updater_scope),
        GetVersionedInstallDirectory(updater_scope)}) {
    ASSERT_TRUE(path);
    ASSERT_TRUE(
        base::DeleteFile(path->Append(FILE_PATH_LITERAL("prefs.json"))));
  }
}

class AppServerTestCase : public testing::Test {
 public:
  void SetUp() override {
#if BUILDFLAG(IS_MAC)
    if (GetUpdaterScopeForTesting() == UpdaterScope::kSystem) {
      GTEST_SKIP();
    }
#endif  // BUILDFLAG(IS_MAC)
    ClearPrefs();
  }

 private:
  base::test::TaskEnvironment environment_;
};

}  // namespace

TEST_F(AppServerTestCase, SelfUninstall) {
  base::test::ScopedCommandLine command_line;
  command_line.GetProcessCommandLine()->AppendSwitchUTF8(
      kServerServiceSwitch, kServerUpdateServiceInternalSwitchValue);
  {
    scoped_refptr<GlobalPrefs> global_prefs =
        CreateGlobalPrefs(GetUpdaterScopeForTesting());
    global_prefs->SetActiveVersion("9999999");
    PrefsCommitPendingWrites(global_prefs->GetPrefService());
    scoped_refptr<LocalPrefs> local_prefs =
        CreateLocalPrefs(GetUpdaterScopeForTesting());
    local_prefs->SetQualified(true);
    PrefsCommitPendingWrites(local_prefs->GetPrefService());
  }
  auto app = base::MakeRefCounted<AppServerTest>();

  // Expect the app to ActiveDutyInternal then SelfUninstall.
  EXPECT_CALL(*app, ActiveDuty).Times(0);
  EXPECT_CALL(*app, ActiveDutyInternal);
  EXPECT_CALL(*app, SwapInNewVersion).Times(0);
  EXPECT_CALL(*app, UninstallSelf);
  EXPECT_EQ(app->Run(), 0);
  EXPECT_TRUE(CreateLocalPrefs(GetUpdaterScopeForTesting())->GetQualified());
}

TEST_F(AppServerTestCase, SelfPromote) {
  {
    scoped_refptr<LocalPrefs> local_prefs =
        CreateLocalPrefs(GetUpdaterScopeForTesting());
    local_prefs->SetQualified(true);
    PrefsCommitPendingWrites(local_prefs->GetPrefService());
  }
  {
    auto app = base::MakeRefCounted<AppServerTest>();

    // Expect the app to SwapInNewVersion and then ActiveDuty then
    // Shutdown(0).
    EXPECT_CALL(*app, ActiveDuty);
    EXPECT_CALL(*app, SwapInNewVersion).WillOnce(Return(true));
    EXPECT_CALL(*app, UninstallSelf).Times(0);
    EXPECT_EQ(app->Run(), 0);
  }
  scoped_refptr<GlobalPrefs> global_prefs =
      CreateGlobalPrefs(GetUpdaterScopeForTesting());
  EXPECT_FALSE(global_prefs->GetSwapping());
  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
}

TEST_F(AppServerTestCase, InstallAutoPromotes) {
  {
    auto app = base::MakeRefCounted<AppServerTest>();

    // Expect the app to SwapInNewVersion and then ActiveDuty then
    // Shutdown(0). In this case it bypasses qualification.
    EXPECT_CALL(*app, ActiveDuty);
    EXPECT_CALL(*app, SwapInNewVersion).WillOnce(Return(true));
    EXPECT_CALL(*app, UninstallSelf).Times(0);
    EXPECT_EQ(app->Run(), 0);
    EXPECT_FALSE(CreateLocalPrefs(GetUpdaterScopeForTesting())->GetQualified());
  }
  scoped_refptr<GlobalPrefs> global_prefs =
      CreateGlobalPrefs(GetUpdaterScopeForTesting());
  EXPECT_FALSE(global_prefs->GetSwapping());
  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
}

TEST_F(AppServerTestCase, SelfPromoteFails) {
  {
    scoped_refptr<LocalPrefs> local_prefs =
        CreateLocalPrefs(GetUpdaterScopeForTesting());
    local_prefs->SetQualified(true);
    PrefsCommitPendingWrites(local_prefs->GetPrefService());
  }
  {
    auto app = base::MakeRefCounted<AppServerTest>();

    // Expect the app to SwapInNewVersion and then Shutdown(2).
    EXPECT_CALL(*app, ActiveDuty).Times(0);
    EXPECT_CALL(*app, SwapInNewVersion).WillOnce(Return(false));
    EXPECT_CALL(*app, UninstallSelf).Times(0);
    EXPECT_EQ(app->Run(), kErrorFailedToSwap);
  }
  scoped_refptr<GlobalPrefs> global_prefs =
      CreateGlobalPrefs(GetUpdaterScopeForTesting());
  EXPECT_TRUE(global_prefs->GetSwapping());
  EXPECT_EQ(global_prefs->GetActiveVersion(), "0");
}

TEST_F(AppServerTestCase, ActiveDutyAlready) {
  {
    scoped_refptr<GlobalPrefs> global_prefs =
        CreateGlobalPrefs(GetUpdaterScopeForTesting());
    global_prefs->SetActiveVersion(kUpdaterVersion);
    PrefsCommitPendingWrites(global_prefs->GetPrefService());
    scoped_refptr<LocalPrefs> local_prefs =
        CreateLocalPrefs(GetUpdaterScopeForTesting());
    local_prefs->SetQualified(true);
    PrefsCommitPendingWrites(local_prefs->GetPrefService());
  }
  {
    auto app = base::MakeRefCounted<AppServerTest>();

    // Expect the app to ActiveDuty and then Shutdown(0).
    EXPECT_CALL(*app, ActiveDuty);
    EXPECT_CALL(*app, SwapInNewVersion).Times(0);
    EXPECT_CALL(*app, UninstallSelf).Times(0);
    EXPECT_EQ(app->Run(), 0);
  }
  scoped_refptr<GlobalPrefs> global_prefs =
      CreateGlobalPrefs(GetUpdaterScopeForTesting());
  EXPECT_FALSE(global_prefs->GetSwapping());
  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
}

TEST_F(AppServerTestCase, StateDirty) {
  {
    scoped_refptr<GlobalPrefs> global_prefs =
        CreateGlobalPrefs(GetUpdaterScopeForTesting());
    global_prefs->SetActiveVersion(kUpdaterVersion);
    global_prefs->SetSwapping(true);
    PrefsCommitPendingWrites(global_prefs->GetPrefService());
    scoped_refptr<LocalPrefs> local_prefs =
        CreateLocalPrefs(GetUpdaterScopeForTesting());
    local_prefs->SetQualified(true);
    PrefsCommitPendingWrites(local_prefs->GetPrefService());
  }
  {
    auto app = base::MakeRefCounted<AppServerTest>();

    // Expect the app to SwapInNewVersion and then ActiveDuty and then
    // Shutdown(0).
    EXPECT_CALL(*app, ActiveDuty);
    EXPECT_CALL(*app, SwapInNewVersion).WillOnce(Return(true));
    EXPECT_CALL(*app, UninstallSelf).Times(0);
    EXPECT_EQ(app->Run(), 0);
  }
  scoped_refptr<GlobalPrefs> global_prefs =
      CreateGlobalPrefs(GetUpdaterScopeForTesting());
  EXPECT_FALSE(global_prefs->GetSwapping());
  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
}

TEST_F(AppServerTestCase, StateDirtySwapFails) {
  {
    scoped_refptr<GlobalPrefs> global_prefs =
        CreateGlobalPrefs(GetUpdaterScopeForTesting());
    global_prefs->SetActiveVersion(kUpdaterVersion);
    global_prefs->SetSwapping(true);
    PrefsCommitPendingWrites(global_prefs->GetPrefService());
    scoped_refptr<LocalPrefs> local_prefs =
        CreateLocalPrefs(GetUpdaterScopeForTesting());
    local_prefs->SetQualified(true);
    PrefsCommitPendingWrites(local_prefs->GetPrefService());
  }
  {
    auto app = base::MakeRefCounted<AppServerTest>();

    // Expect the app to SwapInNewVersion and Shutdown(2).
    EXPECT_CALL(*app, ActiveDuty).Times(0);
    EXPECT_CALL(*app, SwapInNewVersion).WillOnce(Return(false));
    EXPECT_CALL(*app, UninstallSelf).Times(0);
    EXPECT_EQ(app->Run(), kErrorFailedToSwap);
  }
  scoped_refptr<GlobalPrefs> global_prefs =
      CreateGlobalPrefs(GetUpdaterScopeForTesting());
  EXPECT_TRUE(global_prefs->GetSwapping());
  EXPECT_EQ(global_prefs->GetActiveVersion(), kUpdaterVersion);
}

}  // namespace updater