// Copyright 2022 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/managed_cellular_pref_handler.h"
#include <string>
#include "ash/constants/ash_pref_names.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chromeos/ash/components/network/network_state_test_helper.h"
#include "chromeos/ash/components/network/policy_util.h"
#include "components/onc/onc_constants.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
constexpr char kName0[] = "cellular0";
constexpr char kName1[] = "cellular1";
constexpr char kIccid0[] = "0000000000000000000";
constexpr char kIccid1[] = "1111111111111111111";
constexpr char kActivationCode0[] = "LPA:1$ActivationCode0$MatchingId";
class FakeObserver : public ManagedCellularPrefHandler::Observer {
public:
FakeObserver() = default;
~FakeObserver() override = default;
int change_count() const { return change_count_; }
// ManagedCellularPref::Observer:
void OnManagedCellularPrefChanged() override { ++change_count_; }
private:
int change_count_ = 0u;
};
} // namespace
class ManagedCellularPrefHandlerTest : public testing::Test {
protected:
ManagedCellularPrefHandlerTest() = default;
~ManagedCellularPrefHandlerTest() override = default;
// testing::Test:
void SetUp() override {
ManagedCellularPrefHandler::RegisterLocalStatePrefs(
device_prefs_.registry());
}
void TearDown() override {
managed_cellular_pref_handler_->RemoveObserver(&observer_);
managed_cellular_pref_handler_.reset();
}
void Init() {
if (managed_cellular_pref_handler_ &&
managed_cellular_pref_handler_->HasObserver(&observer_)) {
managed_cellular_pref_handler_->RemoveObserver(&observer_);
}
managed_cellular_pref_handler_ =
std::make_unique<ManagedCellularPrefHandler>();
managed_cellular_pref_handler_->AddObserver(&observer_);
managed_cellular_pref_handler_->Init(helper_.network_state_handler());
}
void SetDevicePrefs(bool set_to_null = false) {
managed_cellular_pref_handler_->SetDevicePrefs(
set_to_null ? nullptr : &device_prefs_);
}
void AddApnMigratedIccid(const std::string& iccid) {
managed_cellular_pref_handler_->AddApnMigratedIccid(iccid);
}
bool ContainsApnMigratedIccid(const std::string& iccid) {
return managed_cellular_pref_handler_->ContainsApnMigratedIccid(iccid);
}
void ExpectESimMetadata(
const char* expected_iccid,
const char* expected_name,
const policy_util::SmdxActivationCode& expected_activation_code) {
const base::Value::Dict* esim_metadata =
managed_cellular_pref_handler_->GetESimMetadata(expected_iccid);
ASSERT_TRUE(esim_metadata);
const std::string* name =
esim_metadata->FindString(::onc::network_config::kName);
ASSERT_TRUE(name);
EXPECT_EQ(expected_name, *name);
const std::string* activation_code = esim_metadata->FindString(
expected_activation_code.type() ==
policy_util::SmdxActivationCode::Type::SMDP
? ::onc::cellular::kSMDPAddress
: ::onc::cellular::kSMDSAddress);
ASSERT_TRUE(activation_code);
EXPECT_EQ(expected_activation_code.value(), *activation_code);
}
int NumObserverEvents() { return observer_.change_count(); }
ManagedCellularPrefHandler* managed_cellular_pref_handler() {
return managed_cellular_pref_handler_.get();
}
TestingPrefServiceSimple* device_prefs() { return &device_prefs_; }
private:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
NetworkStateTestHelper helper_{/*use_default_devices_and_services=*/false};
TestingPrefServiceSimple device_prefs_;
FakeObserver observer_;
std::unique_ptr<ManagedCellularPrefHandler> managed_cellular_pref_handler_;
};
TEST_F(ManagedCellularPrefHandlerTest, AddAndRemoveESimMetadata) {
Init();
SetDevicePrefs();
const policy_util::SmdxActivationCode smdp_activation_code(
policy_util::SmdxActivationCode::Type::SMDP,
HermesEuiccClient::Get()
->GetTestInterface()
->GenerateFakeActivationCode());
const policy_util::SmdxActivationCode smds_activation_code(
policy_util::SmdxActivationCode::Type::SMDS,
HermesEuiccClient::Get()
->GetTestInterface()
->GenerateFakeActivationCode());
EXPECT_EQ(0, NumObserverEvents());
EXPECT_FALSE(managed_cellular_pref_handler()->GetESimMetadata(kIccid0));
managed_cellular_pref_handler()->AddESimMetadata(kIccid0, kName0,
smdp_activation_code);
EXPECT_EQ(1, NumObserverEvents());
ExpectESimMetadata(kIccid0, kName0, smdp_activation_code);
// When there are not any differences between the existing metadata and the
// metadata we are trying to add we don't notify observers.
managed_cellular_pref_handler()->AddESimMetadata(kIccid0, kName0,
smdp_activation_code);
EXPECT_EQ(1, NumObserverEvents());
managed_cellular_pref_handler()->AddESimMetadata(kIccid0, kName1,
smdp_activation_code);
EXPECT_EQ(2, NumObserverEvents());
ExpectESimMetadata(kIccid0, kName1, smdp_activation_code);
managed_cellular_pref_handler()->AddESimMetadata(kIccid0, kName1,
smds_activation_code);
EXPECT_EQ(3, NumObserverEvents());
ExpectESimMetadata(kIccid0, kName1, smds_activation_code);
managed_cellular_pref_handler()->RemoveESimMetadata(kIccid0);
EXPECT_EQ(4, NumObserverEvents());
// When the metadata does not exist we should not notify observers.
managed_cellular_pref_handler()->RemoveESimMetadata(kIccid0);
EXPECT_EQ(4, NumObserverEvents());
}
TEST_F(ManagedCellularPrefHandlerTest, AddApnMigratedIccid) {
Init();
SetDevicePrefs();
EXPECT_FALSE(ContainsApnMigratedIccid(kIccid0));
// Add APN migrated ICCIDs to pref and verify that the prefs store these
// values.
AddApnMigratedIccid(kIccid0);
EXPECT_EQ(0, NumObserverEvents());
EXPECT_TRUE(ContainsApnMigratedIccid(kIccid0));
EXPECT_FALSE(ContainsApnMigratedIccid(kIccid1));
AddApnMigratedIccid(kIccid1);
EXPECT_EQ(0, NumObserverEvents());
EXPECT_TRUE(ContainsApnMigratedIccid(kIccid0));
EXPECT_TRUE(ContainsApnMigratedIccid(kIccid1));
}
TEST_F(ManagedCellularPrefHandlerTest, NoDevicePrefSet) {
Init();
SetDevicePrefs(/*set_to_null=*/true);
// Verify that metadata cannot be added, removed, or accessed when there are
// no device prefs.
const policy_util::SmdxActivationCode activation_code(
policy_util::SmdxActivationCode::Type::SMDP,
HermesEuiccClient::Get()
->GetTestInterface()
->GenerateFakeActivationCode());
EXPECT_EQ(0, NumObserverEvents());
managed_cellular_pref_handler()->AddESimMetadata(kIccid0, kName0,
activation_code);
managed_cellular_pref_handler()->RemoveESimMetadata(kIccid0);
EXPECT_EQ(0, NumObserverEvents());
EXPECT_FALSE(managed_cellular_pref_handler()->GetESimMetadata(kIccid0));
// Verify that APN migration information can be added or accessed when there
// are no device prefs.
EXPECT_FALSE(ContainsApnMigratedIccid(kIccid0));
AddApnMigratedIccid(kIccid0);
EXPECT_EQ(0, NumObserverEvents());
EXPECT_FALSE(ContainsApnMigratedIccid(kIccid0));
}
TEST_F(ManagedCellularPrefHandlerTest,
IccidSmdpPairMigration_MigrationHappensOnce) {
Init();
// The value that we will set the existing/pre-migration prefs to.
auto existing_prefs = base::Value::Dict().Set(kIccid0, kActivationCode0);
device_prefs()->Set(prefs::kManagedCellularIccidSmdpPair,
base::Value(existing_prefs.Clone()));
// Set the pref to some arbitrary value since we just want to confirm that if
// the pref has a value we will assume that we have already performed the
// migration and will not attempt another migration.
base::Value::Dict new_prefs;
device_prefs()->Set(prefs::kManagedCellularESimMetadata,
base::Value(new_prefs.Clone()));
EXPECT_TRUE(device_prefs()->HasPrefPath(prefs::kManagedCellularESimMetadata));
SetDevicePrefs();
const base::Value::Dict& migrated_prefs =
device_prefs()->GetDict(prefs::kManagedCellularESimMetadata);
EXPECT_EQ(new_prefs, migrated_prefs);
}
TEST_F(ManagedCellularPrefHandlerTest, IccidSmdpPairMigration_Migration) {
Init();
auto generate_esim_metadata = [](const std::string& smdp_activation_code) {
return base::Value::Dict().Set(::onc::cellular::kSMDPAddress,
smdp_activation_code);
};
// The value that we will set the existing/pre-migration prefs to.
base::Value::Dict existing_prefs;
// The value that we expect the new/post-migration prefs to be.
base::Value::Dict new_prefs;
// Nothing missing
existing_prefs.Set(kIccid0, kActivationCode0);
base::Value::Dict esim_metadata0 = generate_esim_metadata(kActivationCode0);
new_prefs.Set(kIccid0, esim_metadata0.Clone());
// Activation code empty
existing_prefs.Set(kIccid1, "");
device_prefs()->Set(prefs::kManagedCellularIccidSmdpPair,
base::Value(existing_prefs.Clone()));
SetDevicePrefs();
// The existing prefs should not have changed.
EXPECT_EQ(device_prefs()->GetDict(prefs::kManagedCellularIccidSmdpPair),
existing_prefs);
const base::Value::Dict& migrated_prefs =
device_prefs()->GetDict(prefs::kManagedCellularESimMetadata);
const base::Value::Dict* actual_pref = migrated_prefs.FindDict(kIccid0);
ASSERT_TRUE(actual_pref);
EXPECT_EQ(esim_metadata0, *actual_pref);
EXPECT_FALSE(migrated_prefs.FindDict(kIccid1));
}
} // namespace ash