chromium/ash/webui/shimless_rma/backend/version_updater_unittest.cc

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

#include "ash/webui/shimless_rma/backend/version_updater.h"

#include <memory>

#include "ash/constants/ash_features.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/components/dbus/update_engine/fake_update_engine_client.h"
#include "chromeos/ash/components/dbus/update_engine/update_engine.pb.h"
#include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
#include "chromeos/ash/components/network/managed_network_configuration_handler.h"
#include "chromeos/ash/components/network/network_cert_loader.h"
#include "chromeos/ash/components/network/network_certificate_handler.h"
#include "chromeos/ash/components/network/network_configuration_handler.h"
#include "chromeos/ash/components/network/network_device_handler.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_profile_handler.h"
#include "chromeos/ash/components/network/network_state_test_helper.h"
#include "chromeos/ash/components/network/onc/network_onc_utils.h"
#include "chromeos/ash/components/network/proxy/ui_proxy_config_service.h"
#include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "chromeos/services/network_config/public/mojom/network_types.mojom-shared.h"
#include "components/onc/onc_constants.h"
#include "components/onc/onc_pref_names.h"
#include "components/prefs/testing_pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {
namespace shimless_rma {

namespace {
class VersionUpdaterTest : public testing::Test {
 public:
  VersionUpdaterTest() {
    fake_update_engine_client_ = UpdateEngineClient::InitializeFakeForTest();
    cros_network_config_test_helper_ =
        std::make_unique<network_config::CrosNetworkConfigTestHelper>(false);
    InitializeManagedNetworkConfigurationHandler();
    cros_network_config_test_helper().Initialize(
        managed_network_configuration_handler_.get());
    NetworkHandler::Initialize();
    version_updater_ = std::make_unique<VersionUpdater>();
    base::RunLoop().RunUntilIdle();
  }

  ~VersionUpdaterTest() override {
    base::RunLoop().RunUntilIdle();
    version_updater_.reset();
    NetworkHandler::Shutdown();
    cros_network_config_test_helper_.reset();
    managed_network_configuration_handler_.reset();
    network_configuration_handler_.reset();
    network_profile_handler_.reset();
    ui_proxy_config_service_.reset();
    UpdateEngineClient::Shutdown();
  }

 protected:
  void SetupWiFiNetwork() {
    network_state_helper().ConfigureService(
        R"({"GUID": "wifi1_guid", "Type": "wifi", "State": "online",
            "Strength": 50, "AutoConnect": true, "WiFi.HiddenSSID":
            false})");

    base::RunLoop().RunUntilIdle();
  }

  void SetupMeteredNetwork() {
    network_state_helper().ConfigureService(
        R"({"GUID": "cellular_guid", "Type": "cellular", "Technology": "LTE",
            "State": "online"})");

    base::RunLoop().RunUntilIdle();
  }

  void SetCallback() {
    version_updater().SetOsUpdateStatusCallback(
        base::BindRepeating(&VersionUpdaterTest::OnOsUpdateStatusCallback,
                            weak_ptr_factory_.GetWeakPtr()));
  }

  VersionUpdater& version_updater() { return *version_updater_; }
  network_config::CrosNetworkConfigTestHelper&
  cros_network_config_test_helper() {
    return *cros_network_config_test_helper_;
  }

  NetworkStateTestHelper& network_state_helper() {
    return cros_network_config_test_helper_->network_state_helper();
  }

  void InitializeManagedNetworkConfigurationHandler() {
    network_profile_handler_ = NetworkProfileHandler::InitializeForTesting();
    network_configuration_handler_ =
        NetworkConfigurationHandler::InitializeForTest(
            network_state_helper().network_state_handler(),
            cros_network_config_test_helper().network_device_handler());

    PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry());
    PrefProxyConfigTrackerImpl::RegisterPrefs(local_state_.registry());
    ::onc::RegisterProfilePrefs(user_prefs_.registry());
    ::onc::RegisterPrefs(local_state_.registry());

    ui_proxy_config_service_ = std::make_unique<UIProxyConfigService>(
        &user_prefs_, &local_state_,
        network_state_helper().network_state_handler(),
        network_profile_handler_.get());

    managed_network_configuration_handler_ =
        ManagedNetworkConfigurationHandler::InitializeForTesting(
            network_state_helper().network_state_handler(),
            network_profile_handler_.get(),
            cros_network_config_test_helper().network_device_handler(),
            network_configuration_handler_.get(),
            ui_proxy_config_service_.get());

    managed_network_configuration_handler_->SetPolicy(
        ::onc::ONC_SOURCE_DEVICE_POLICY,
        /*userhash=*/std::string(),
        /*network_configs_onc=*/base::Value::List(),
        /*global_network_config=*/base::Value::Dict());

    // Wait until the |managed_network_configuration_handler_| is initialized
    // and set up.
    base::RunLoop().RunUntilIdle();
  }

  void OnOsUpdateStatusCallback(update_engine::Operation operation,
                                double progress,
                                bool rollback,
                                bool powerwash,
                                const std::string& version,
                                int64_t update_size,
                                update_engine::ErrorCode error_code) {
    callback_count_++;
    error_code_ = error_code;
  }

  uint32_t callback_count_ = 0;
  FakeUpdateEngineClient& fake_update_engine_client() {
    return *fake_update_engine_client_;
  }

  update_engine::ErrorCode error_code() { return error_code_; }

 private:
  std::unique_ptr<VersionUpdater> version_updater_;
  std::unique_ptr<network_config::CrosNetworkConfigTestHelper>
      cros_network_config_test_helper_;

  std::unique_ptr<ManagedNetworkConfigurationHandler>
      managed_network_configuration_handler_;
  std::unique_ptr<NetworkConfigurationHandler> network_configuration_handler_;
  std::unique_ptr<NetworkProfileHandler> network_profile_handler_;
  std::unique_ptr<UIProxyConfigService> ui_proxy_config_service_;
  sync_preferences::TestingPrefServiceSyncable user_prefs_;
  TestingPrefServiceSimple local_state_;
  raw_ptr<FakeUpdateEngineClient, DanglingUntriaged> fake_update_engine_client_;
  update_engine::ErrorCode error_code_;

  base::test::TaskEnvironment task_environment_;

  // Note: This should remain the last member so it'll be destroyed and
  // invalidate its weak pointers before any other members are destroyed.
  base::WeakPtrFactory<VersionUpdaterTest> weak_ptr_factory_{this};
};

TEST_F(VersionUpdaterTest, IsIdleWhenUpdateEngineIdle) {
  update_engine::StatusResult status;
  status.set_current_operation(update_engine::Operation::IDLE);
  fake_update_engine_client().set_default_status(status);
  EXPECT_TRUE(version_updater().IsUpdateEngineIdle());
}

TEST_F(VersionUpdaterTest, IsNotIdleWhenUpdateEngineNotIdle) {
  update_engine::StatusResult status;
  status.set_current_operation(update_engine::Operation::DOWNLOADING);
  fake_update_engine_client().set_default_status(status);
  EXPECT_FALSE(version_updater().IsUpdateEngineIdle());
}

TEST_F(VersionUpdaterTest, WithoutNetworkUpdateOsFails) {
  SetCallback();
  EXPECT_FALSE(version_updater().UpdateOs());
}

TEST_F(VersionUpdaterTest, WithNetworkUpdateOsOk) {
  SetCallback();
  SetupWiFiNetwork();
  EXPECT_TRUE(version_updater().UpdateOs());
}

TEST_F(VersionUpdaterTest, WithMeteredNetworkUpdateOsFails) {
  SetCallback();
  SetupMeteredNetwork();
  EXPECT_FALSE(version_updater().UpdateOs());
}

TEST_F(VersionUpdaterTest, CallbackFiresWhenUpdateEngineStatusChanges) {
  if (!features::IsShimlessRMAOsUpdateEnabled()) {
    return;
  }

  SetCallback();
  SetupWiFiNetwork();
  update_engine::StatusResult status;
  status.set_current_operation(update_engine::Operation::CHECKING_FOR_UPDATE);
  fake_update_engine_client().NotifyObserversThatStatusChanged(status);
  EXPECT_EQ(1u, callback_count_);
}

TEST_F(VersionUpdaterTest, UpdateStatusChangedGetError) {
  SetCallback();
  update_engine::StatusResult status;
  status.set_current_operation(update_engine::Operation::REPORTING_ERROR_EVENT);
  status.set_last_attempt_error(
      static_cast<int32_t>(update_engine::ErrorCode::kError));
  version_updater().UpdateStatusChangedForTesting(status);
  EXPECT_EQ(1u, callback_count_);
  EXPECT_EQ(update_engine::ErrorCode::kError, error_code());
}

}  // namespace
}  // namespace shimless_rma
}  // namespace ash