chromium/chromeos/ash/components/network/cellular_esim_installer_unittest.cc

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

#include "chromeos/ash/components/network/cellular_esim_installer.h"

#include <memory>

#include "base/containers/contains.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/components/dbus/hermes/hermes_clients.h"
#include "chromeos/ash/components/dbus/hermes/hermes_euicc_client.h"
#include "chromeos/ash/components/dbus/hermes/hermes_manager_client.h"
#include "chromeos/ash/components/dbus/hermes/hermes_profile_client.h"
#include "chromeos/ash/components/dbus/hermes/hermes_response_status.h"
#include "chromeos/ash/components/dbus/shill/fake_shill_manager_client.h"
#include "chromeos/ash/components/dbus/shill/shill_clients.h"
#include "chromeos/ash/components/dbus/shill/shill_device_client.h"
#include "chromeos/ash/components/dbus/shill/shill_manager_client.h"
#include "chromeos/ash/components/network/cellular_connection_handler.h"
#include "chromeos/ash/components/network/cellular_inhibitor.h"
#include "chromeos/ash/components/network/fake_network_connection_handler.h"
#include "chromeos/ash/components/network/fake_stub_cellular_networks_provider.h"
#include "chromeos/ash/components/network/metrics/cellular_network_metrics_logger.h"
#include "chromeos/ash/components/network/metrics/cellular_network_metrics_test_helper.h"
#include "chromeos/ash/components/network/network_connection_handler.h"
#include "chromeos/ash/components/network/network_device_handler.h"
#include "chromeos/ash/components/network/network_profile_handler.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/network_ui_data.h"
#include "chromeos/ash/components/network/test_cellular_esim_profile_handler.h"
#include "chromeos/ash/services/cellular_setup/public/mojom/esim_manager.mojom.h"
#include "dbus/object_path.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"

using InstallResultTuple = std::tuple<ash::HermesResponseStatus,
                                      std::optional<dbus::ObjectPath>,
                                      std::optional<std::string>>;

using ash::cellular_setup::mojom::ProfileInstallMethod;

namespace ash {
namespace {

const char kTestEuiccPath[] = "/org/chromium/Hermes/Euicc/0";
const char kTestEid[] = "12345678901234567890123456789012";
const char kTestCellularServicePath[] = "/service/cellular101";
const char kInstallViaQrCodeHistogram[] =
    "Network.Cellular.ESim.InstallViaQrCode.Result";
const char kInstallViaQrCodeDBusResultHistogram[] =
    "Network.Cellular.ESim.InstallViaQrCode.DBusResult";
const char kESimInstallNonUserErrorSuccessRate[] =
    "Network.Cellular.ESim.Installation.NonUserErrorSuccessRate";

const char kESimProfileDownloadLatencyHistogram[] =
    "Network.Cellular.ESim.ProfileDownload.ActivationCode.Latency";

base::Value::Dict GetPolicyShillProperties() {
  base::Value::Dict new_shill_properties;
  std::unique_ptr<NetworkUIData> ui_data =
      NetworkUIData::CreateFromONC(::onc::ONCSource::ONC_SOURCE_DEVICE_POLICY);
  new_shill_properties.Set(shill::kUIDataProperty, ui_data->GetAsJson());
  return new_shill_properties;
}

}  // namespace

class CellularESimInstallerTest : public testing::Test {
 protected:
  ~CellularESimInstallerTest() override = default;

  // testing::Test:
  void SetUp() override {
    shill_clients::InitializeFakes();
    hermes_clients::InitializeFakes();

    network_state_handler_ = NetworkStateHandler::InitializeForTest();
    network_device_handler_ = NetworkDeviceHandler::InitializeForTesting(
        network_state_handler_.get());
    network_connection_handler_ =
        std::make_unique<FakeNetworkConnectionHandler>();
    network_profile_handler_ = NetworkProfileHandler::InitializeForTesting();
    cellular_inhibitor_ = std::make_unique<CellularInhibitor>();
    cellular_inhibitor_->Init(network_state_handler_.get(),
                              network_device_handler_.get());
    cellular_esim_profile_handler_ =
        std::make_unique<TestCellularESimProfileHandler>();
    cellular_esim_profile_handler_->Init(network_state_handler_.get(),
                                         cellular_inhibitor_.get());
    cellular_connection_handler_ =
        std::make_unique<CellularConnectionHandler>();
    cellular_connection_handler_->Init(network_state_handler_.get(),
                                       cellular_inhibitor_.get(),
                                       cellular_esim_profile_handler_.get());
    cellular_esim_installer_ = std::make_unique<CellularESimInstaller>();
    cellular_esim_installer_->Init(
        cellular_connection_handler_.get(), cellular_inhibitor_.get(),
        network_connection_handler_.get(), network_profile_handler_.get(),
        network_state_handler_.get());
    stub_cellular_networks_provider_ =
        std::make_unique<FakeStubCellularNetworksProvider>();
    network_state_handler_->set_stub_cellular_networks_provider(
        stub_cellular_networks_provider_.get());
    SetupEuicc();
  }

  void SetupEuicc() {
    HermesManagerClient::Get()->GetTestInterface()->ClearEuiccs();
    HermesManagerClient::Get()->GetTestInterface()->AddEuicc(
        dbus::ObjectPath(kTestEuiccPath), kTestEid, /*is_active=*/true,
        /*physical_slot=*/0);

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

  // testing::Test:
  void TearDown() override {
    stub_cellular_networks_provider_.reset();
    cellular_esim_installer_.reset();
    cellular_esim_profile_handler_.reset();
    cellular_connection_handler_.reset();
    cellular_inhibitor_.reset();
    network_profile_handler_.reset();
    network_device_handler_.reset();
    network_state_handler_.reset();
    network_connection_handler_.reset();

    hermes_clients::Shutdown();
    shill_clients::Shutdown();
  }

  InstallResultTuple InstallProfileFromActivationCode(
      const std::string& activation_code,
      const std::string& confirmation_code,
      const dbus::ObjectPath euicc_path,
      base::Value::Dict new_shill_properties,
      bool wait_for_connect,
      bool fail_connect,
      bool is_initial_install = true,
      ProfileInstallMethod install_method =
          ProfileInstallMethod::kViaActivationCodeAfterSmds,
      bool auto_connected = false) {
    HermesResponseStatus out_install_result;
    std::optional<dbus::ObjectPath> out_esim_profile_path;
    std::optional<std::string> out_service_path;

    base::RunLoop run_loop;
    cellular_esim_installer_->InstallProfileFromActivationCode(
        activation_code, confirmation_code, euicc_path,
        std::move(new_shill_properties),
        base::BindLambdaForTesting(
            [&](HermesResponseStatus install_result,
                std::optional<dbus::ObjectPath> esim_profile_path,
                std::optional<std::string> service_path) {
              out_install_result = install_result;
              out_esim_profile_path = esim_profile_path;
              out_service_path = service_path;
              run_loop.Quit();
            }),
        is_initial_install, install_method);

    FastForwardProfileRefreshDelay();

    if (wait_for_connect) {
      if (auto_connected) {
        ShillServiceClient::Get()->GetTestInterface()->SetServiceProperty(
            kTestCellularServicePath, shill::kStateProperty,
            base::Value(shill::kStateOnline));
      } else {
        FastForwardAutoConnectWaiting();
        base::RunLoop().RunUntilIdle();
        EXPECT_LE(1u, network_connection_handler_->connect_calls().size());
        if (fail_connect) {
          network_connection_handler_->connect_calls()
              .back()
              .InvokeErrorCallback("fake_error_name");
        } else {
          network_connection_handler_->connect_calls()
              .back()
              .InvokeSuccessCallback();
        }
      }
    }

    run_loop.Run();
    return std::make_tuple(out_install_result, out_esim_profile_path,
                           out_service_path);
  }

  std::optional<dbus::ObjectPath> ConfigureESimService(
      const dbus::ObjectPath euicc_path,
      const dbus::ObjectPath& profile_path,
      base::Value::Dict& new_shill_properties) {
    std::optional<dbus::ObjectPath> service_path_out;
    base::RunLoop run_loop;
    cellular_esim_installer_->ConfigureESimService(
        new_shill_properties, euicc_path, profile_path,
        base::BindLambdaForTesting(
            [&](std::optional<dbus::ObjectPath> service_path) {
              service_path_out = service_path;
              run_loop.Quit();
            }));
    run_loop.Run();
    return service_path_out;
  }

  void CheckInstallSuccess(const InstallResultTuple& actual_result_tuple) {
    EXPECT_EQ(HermesResponseStatus::kSuccess, std::get<0>(actual_result_tuple));
    EXPECT_NE(std::get<1>(actual_result_tuple), std::nullopt);
    EXPECT_NE(std::get<2>(actual_result_tuple), std::nullopt);
    const base::Value::Dict* properties =
        ShillServiceClient::Get()->GetTestInterface()->GetServiceProperties(
            *std::get<2>(actual_result_tuple));
    ASSERT_TRUE(properties);
    const std::string* type = properties->FindString(shill::kTypeProperty);
    EXPECT_EQ(shill::kTypeCellular, *type);
    const std::string* iccid = properties->FindString(shill::kIccidProperty);
    EXPECT_NE(std::string(), *iccid);
  }

  void CheckESimInstallHistograms(
      int expected_count,
      HermesResponseStatus expected_hermes_status,
      CellularESimInstaller::InstallESimProfileResult expected_install_result) {
    histogram_tester()->ExpectBucketCount(
        kInstallViaQrCodeHistogram, expected_hermes_status, expected_count);

    if (expected_hermes_status == HermesResponseStatus::kSuccess ||
        !base::Contains(kHermesUserErrorCodes, expected_hermes_status)) {
      histogram_tester()->ExpectBucketCount(kESimInstallNonUserErrorSuccessRate,
                                            expected_hermes_status,
                                            expected_count);
    } else {
      histogram_tester()->ExpectBucketCount(kESimInstallNonUserErrorSuccessRate,
                                            expected_hermes_status, 0);
    }
    if (expected_hermes_status != HermesResponseStatus::kErrorUnknownResponse) {
      histogram_tester()->ExpectTotalCount(kInstallViaQrCodeDBusResultHistogram,
                                           0);
    }
  }


  void FastForwardProfileRefreshDelay() {
    const base::TimeDelta kProfileRefreshCallbackDelay =
        base::Milliseconds(150);

    // Connect can result in two profile refresh calls before and after
    // enabling profile. Fast forward by delay after refresh.
    task_environment_.FastForwardBy(2 * kProfileRefreshCallbackDelay);
  }

  void FastForwardAutoConnectWaiting() {
    task_environment_.FastForwardBy(
        CellularConnectionHandler::kWaitingForAutoConnectTimeout);
  }

  base::HistogramTester* histogram_tester() { return &histogram_tester_; }

 private:
  base::HistogramTester histogram_tester_;
  base::test::TaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};

  std::unique_ptr<NetworkStateHandler> network_state_handler_;
  std::unique_ptr<NetworkDeviceHandler> network_device_handler_;
  std::unique_ptr<NetworkProfileHandler> network_profile_handler_;
  std::unique_ptr<CellularConnectionHandler> cellular_connection_handler_;
  std::unique_ptr<CellularInhibitor> cellular_inhibitor_;
  std::unique_ptr<TestCellularESimProfileHandler>
      cellular_esim_profile_handler_;
  std::unique_ptr<FakeNetworkConnectionHandler> network_connection_handler_;
  std::unique_ptr<CellularESimInstaller> cellular_esim_installer_;
  std::unique_ptr<FakeStubCellularNetworksProvider>
      stub_cellular_networks_provider_;
};

TEST_F(CellularESimInstallerTest, InstallProfileInvalidActivationCode) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      /*activation_code=*/std::string(), /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/false, /*fail_connect=*/false);
  EXPECT_EQ(HermesResponseStatus::kErrorInvalidActivationCode,
            std::get<0>(result_tuple));
  EXPECT_EQ(std::get<1>(result_tuple), std::nullopt);
  EXPECT_EQ(std::get<2>(result_tuple), std::nullopt);
  CheckESimInstallHistograms(
      /*expected_count=*/1, HermesResponseStatus::kErrorInvalidActivationCode,
      CellularESimInstaller::InstallESimProfileResult::kHermesInstallFailed);

  state.user_install_user_errors_included_all.hermes_failed_count++;
  state.user_install_user_errors_included_via_activation_code_after_smds
      .hermes_failed_count++;
  state.Check(histogram_tester());

  // Verify that install from policy are handled properly.
  result_tuple = InstallProfileFromActivationCode(
      /*activation_code=*/std::string(), /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      GetPolicyShillProperties(),
      /*wait_for_connect=*/false, /*fail_connect=*/false);
  EXPECT_EQ(HermesResponseStatus::kErrorInvalidActivationCode,
            std::get<0>(result_tuple));
  EXPECT_EQ(std::get<1>(result_tuple), std::nullopt);
  EXPECT_EQ(std::get<2>(result_tuple), std::nullopt);
  CheckESimInstallHistograms(
      /*expected_count=*/2, HermesResponseStatus::kErrorInvalidActivationCode,
      CellularESimInstaller::InstallESimProfileResult::kHermesInstallFailed);

  state.policy_install_user_errors_included_all.hermes_failed_count++;
  state.policy_install_user_errors_included_smdp_initial.hermes_failed_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, InstallProfileDBusError) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GetDBusErrorActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/false, /*fail_connect=*/false);

  histogram_tester()->ExpectTotalCount(kInstallViaQrCodeDBusResultHistogram, 1);
  histogram_tester()->ExpectBucketCount(kInstallViaQrCodeDBusResultHistogram,
                                        dbus::DBusResult::kErrorNoMemory, 1);
  histogram_tester()->ExpectBucketCount(
      kInstallViaQrCodeHistogram, HermesResponseStatus::kErrorUnknownResponse,
      1);

  state.user_install_user_errors_filtered_all.hermes_failed_count++;
  state.user_install_user_errors_filtered_via_activation_code_after_smds
      .hermes_failed_count++;
  state.user_install_user_errors_included_all.hermes_failed_count++;
  state.user_install_user_errors_included_via_activation_code_after_smds
      .hermes_failed_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, InstallProfileConnectFailure) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  // Verify that connect failures are handled properly.
  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/true, /*fail_connect=*/true);
  CheckInstallSuccess(result_tuple);
  CheckESimInstallHistograms(
      /*expected_count=*/1, HermesResponseStatus::kSuccess,
      CellularESimInstaller::InstallESimProfileResult::kSuccess);

  state.user_install_user_errors_filtered_all.success_count++;
  state.user_install_user_errors_filtered_via_activation_code_after_smds
      .success_count++;
  state.user_install_user_errors_included_all.success_count++;
  state.user_install_user_errors_included_via_activation_code_after_smds
      .success_count++;
  state.Check(histogram_tester());

  // Verify that install from policy are handled property.
  result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      GetPolicyShillProperties(),
      /*wait_for_connect=*/true, /*fail_connect=*/true);
  CheckInstallSuccess(result_tuple);
  CheckESimInstallHistograms(
      /*expected_count=*/2, HermesResponseStatus::kSuccess,
      CellularESimInstaller::InstallESimProfileResult::kSuccess);

  state.policy_install_user_errors_filtered_all.success_count++;
  state.policy_install_user_errors_filtered_smdp_initial.success_count++;
  state.policy_install_user_errors_included_all.success_count++;
  state.policy_install_user_errors_included_smdp_initial.success_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, InstallProfileSuccess) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  // Verify that install succeeds when valid activation code is passed.
  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/true, /*fail_connect=*/false);
  CheckInstallSuccess(result_tuple);

  histogram_tester()->ExpectTotalCount(kESimProfileDownloadLatencyHistogram, 1);
  CheckESimInstallHistograms(
      /*expected_count=*/1, HermesResponseStatus::kSuccess,
      CellularESimInstaller::InstallESimProfileResult::kSuccess);

  state.user_install_user_errors_filtered_all.success_count++;
  state.user_install_user_errors_filtered_via_activation_code_after_smds
      .success_count++;
  state.user_install_user_errors_included_all.success_count++;
  state.user_install_user_errors_included_via_activation_code_after_smds
      .success_count++;
  state.Check(histogram_tester());

  // Verify install from policy works properly.
  result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      GetPolicyShillProperties(),
      /*wait_for_connect=*/true, /*fail_connect=*/false,
      /*is_initial_install=*/false,
      /*install_method=*/ProfileInstallMethod::kViaSmds);
  CheckInstallSuccess(result_tuple);
  histogram_tester()->ExpectTotalCount(kESimProfileDownloadLatencyHistogram, 2);
  CheckESimInstallHistograms(
      /*expected_count=*/2, HermesResponseStatus::kSuccess,
      CellularESimInstaller::InstallESimProfileResult::kSuccess);

  state.policy_install_user_errors_filtered_all.success_count++;
  state.policy_install_user_errors_filtered_smds_retry.success_count++;
  state.policy_install_user_errors_included_all.success_count++;
  state.policy_install_user_errors_included_smds_retry.success_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, InstallProfileViaQrCodeSuccess) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  // Verify that install succeeds when valid activation code is passed.
  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/true, /*fail_connect=*/false,
      /*is_initial_install=*/true,
      /*install_method=*/ProfileInstallMethod::kViaQrCodeAfterSmds);
  CheckInstallSuccess(result_tuple);

  histogram_tester()->ExpectTotalCount(kESimProfileDownloadLatencyHistogram, 1);
  CheckESimInstallHistograms(
      /*expected_count=*/1, HermesResponseStatus::kSuccess,
      CellularESimInstaller::InstallESimProfileResult::kSuccess);

  state.user_install_user_errors_filtered_all.success_count++;
  state.user_install_user_errors_filtered_via_qr_code_after_smds
      .success_count++;
  state.user_install_user_errors_included_all.success_count++;
  state.user_install_user_errors_included_via_qr_code_after_smds
      .success_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, InstallProfileAutoConnect) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  // Verify that install succeeds when valid activation code is passed.
  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/true, /*fail_connect=*/false,
      /*is_initial_install=*/true,
      /*install_method=*/ProfileInstallMethod::kViaQrCodeSkippedSmds,
      /*auto_connected=*/true);
  CheckInstallSuccess(result_tuple);

  histogram_tester()->ExpectTotalCount(kESimProfileDownloadLatencyHistogram, 1);
  CheckESimInstallHistograms(
      /*expected_count=*/1, HermesResponseStatus::kSuccess,
      CellularESimInstaller::InstallESimProfileResult::kSuccess);

  state.user_install_user_errors_filtered_all.success_count++;
  state.user_install_user_errors_filtered_via_qr_code_skipped_smds
      .success_count++;
  state.user_install_user_errors_included_all.success_count++;
  state.user_install_user_errors_included_via_qr_code_skipped_smds
      .success_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, InstallProfileAlreadyConnected) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  HermesProfileClient::Get()->GetTestInterface()->SetEnableProfileBehavior(
      HermesProfileClient::TestInterface::EnableProfileBehavior::
          kConnectableAndConnected);

  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/false, /*fail_connect=*/false,
      /*is_initial_install=*/true,
      /*install_method=*/ProfileInstallMethod::kViaActivationCodeSkippedSmds);
  CheckInstallSuccess(result_tuple);

  state.user_install_user_errors_filtered_all.success_count++;
  state.user_install_user_errors_filtered_via_activation_code_skipped_smds
      .success_count++;
  state.user_install_user_errors_included_all.success_count++;
  state.user_install_user_errors_included_via_activation_code_skipped_smds
      .success_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, InstallProfileCreateShillConfigFailure) {
  ash::cellular_metrics::ESimInstallHistogramState state;
  state.Check(histogram_tester());

  ShillManagerClient::Get()->GetTestInterface()->SetSimulateConfigurationResult(
      FakeShillSimulatedResult::kFailure);
  // Verify that install succeeds when valid activation code is passed.
  InstallResultTuple result_tuple = InstallProfileFromActivationCode(
      HermesEuiccClient::Get()
          ->GetTestInterface()
          ->GenerateFakeActivationCode(),
      /*confirmation_code=*/std::string(),
      /*euicc_path=*/dbus::ObjectPath(kTestEuiccPath),
      /*new_shill_properties=*/base::Value::Dict(),
      /*wait_for_connect=*/false, /*fail_connect=*/false);
  CheckInstallSuccess(result_tuple);

  state.user_install_user_errors_filtered_all.success_count++;
  state.user_install_user_errors_filtered_via_activation_code_after_smds
      .success_count++;
  state.user_install_user_errors_included_all.success_count++;
  state.user_install_user_errors_included_via_activation_code_after_smds
      .success_count++;
  state.Check(histogram_tester());
}

TEST_F(CellularESimInstallerTest, ConfigureESimService) {
  dbus::ObjectPath profile_path =
      HermesEuiccClient::Get()->GetTestInterface()->AddFakeCarrierProfile(
          dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kInactive,
          /*activation_code=*/"",
          HermesEuiccClient::TestInterface::AddCarrierProfileBehavior::
              kAddProfileWithoutService);

  base::Value::Dict new_shill_properties;
  std::unique_ptr<NetworkUIData> ui_data =
      NetworkUIData::CreateFromONC(::onc::ONCSource::ONC_SOURCE_DEVICE_POLICY);
  new_shill_properties.Set(shill::kUIDataProperty, ui_data->GetAsJson());
  std::optional<dbus::ObjectPath> service_path = ConfigureESimService(
      dbus::ObjectPath(kTestEuiccPath), profile_path, new_shill_properties);
  EXPECT_TRUE(service_path.has_value());

  HermesProfileClient::Properties* profile_properties =
      HermesProfileClient::Get()->GetProperties(profile_path);
  const base::Value::Dict* service_properties =
      ShillServiceClient::Get()->GetTestInterface()->GetServiceProperties(
          service_path->value());
  ASSERT_TRUE(service_properties);
  const std::string* type =
      service_properties->FindString(shill::kTypeProperty);
  EXPECT_EQ(shill::kTypeCellular, *type);
  const std::string* iccid =
      service_properties->FindString(shill::kIccidProperty);
  EXPECT_EQ(profile_properties->iccid().value(), *iccid);
  const std::string* eid = service_properties->FindString(shill::kEidProperty);
  EXPECT_EQ(kTestEid, *eid);
}

TEST_F(CellularESimInstallerTest, ConfigureESimServiceFailure) {
  dbus::ObjectPath profile_path =
      HermesEuiccClient::Get()->GetTestInterface()->AddFakeCarrierProfile(
          dbus::ObjectPath(kTestEuiccPath), hermes::profile::State::kInactive,
          /*activation_code=*/"",
          HermesEuiccClient::TestInterface::AddCarrierProfileBehavior::
              kAddProfileWithoutService);

  ShillManagerClient::Get()->GetTestInterface()->SetSimulateConfigurationResult(
      FakeShillSimulatedResult::kFailure);

  base::Value::Dict new_shill_properties;
  std::optional<dbus::ObjectPath> service_path = ConfigureESimService(
      dbus::ObjectPath(kTestEuiccPath), profile_path, new_shill_properties);
  EXPECT_FALSE(service_path.has_value());
}

}  // namespace ash