// 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 "chrome/browser/ash/net/apn_migrator.h"
#include "ash/constants/ash_features.h"
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/components/login/login_state/login_state.h"
#include "chromeos/ash/components/network/device_state.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/mock_managed_cellular_pref_handler.h"
#include "chromeos/ash/components/network/mock_managed_network_configuration_handler.h"
#include "chromeos/ash/components/network/mock_network_metadata_store.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/ash/components/network/network_profile_handler.h"
#include "chromeos/ash/components/network/network_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/network_state_test_helper.h"
#include "chromeos/ash/components/network/network_type_pattern.h"
#include "chromeos/ash/services/network_config/in_process_instance.h"
#include "chromeos/services/network_config/public/cpp/cros_network_config_util.h"
#include "chromeos/services/network_config/public/cpp/fake_cros_network_config.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "components/onc/onc_constants.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
namespace ash {
namespace {
using ::chromeos::network_config::FakeCrosNetworkConfig;
using ::chromeos::network_config::mojom::ApnPropertiesPtr;
using ::chromeos::network_config::mojom::ApnState;
using ::chromeos::network_config::mojom::ApnType;
using network_config::OverrideInProcessInstanceForTesting;
using ::testing::_;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::Truly;
using ::testing::WithArg;
using ::testing::WithArgs;
constexpr char kCellularName1[] = "cellular_device_1";
constexpr char kTestCellularPath1[] = "/device/cellular_device_1";
constexpr char kTestCellularIccid1[] = "test_iccid_1";
constexpr char kTestCellularGuid1[] = "test_guid_1";
constexpr char kCellularName2[] = "cellular_device_2";
constexpr char kTestCellularPath2[] = "/device/cellular_device_2";
constexpr char kTestCellularIccid2[] = "test_iccid_2";
constexpr char kTestCellularGuid2[] = "test_guid_2";
constexpr char kCellularName3[] = "cellular_device_3";
constexpr char kTestCellularPath3[] = "/device/cellular_device_3";
constexpr char kTestCellularIccid3[] = "test_iccid_3";
constexpr char kTestCellularGuid3[] = "test_guid_3";
constexpr char kCellularServicePattern[] =
R"({"GUID": "%s", "Type": "cellular", "State": "idle",
"Strength": 0, "Cellular.NetworkTechnology": "LTE",
"Cellular.ActivationState": "activated", "Cellular.ICCID": "%s",
"Profile": "%s"%s})";
constexpr char kUiData[] =
R"(, "UIData": "{\"onc_source\": \"device_policy\"}")";
constexpr char kAttachAccessPointName[] = "apn_attach_access_point_name";
constexpr char kDefaultAccessPointName[] = "apn_default_access_point_name";
} // namespace
class ApnMigratorTest : public testing::Test {
protected:
ApnMigratorTest() = default;
ApnMigratorTest(const ApnMigratorTest&) = delete;
ApnMigratorTest& operator=(const ApnMigratorTest&) = delete;
~ApnMigratorTest() override = default;
// testing::Test
void SetUp() override {
// TODO(b/278643115) Remove LoginState dependency.
LoginState::Initialize();
const AccountId account_id = AccountId::FromUserEmail("test@test");
auto fake_user_manager = std::make_unique<user_manager::FakeUserManager>();
fake_user_manager->AddUser(account_id);
fake_user_manager->UserLoggedIn(
account_id,
user_manager::FakeUserManager::GetFakeUsernameHash(account_id),
/*browser_restart=*/false,
/*is_child=*/false);
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
std::move(fake_user_manager));
managed_cellular_pref_handler_ =
base::WrapUnique(new testing::NiceMock<MockManagedCellularPrefHandler>);
managed_network_configuration_handler_ = base::WrapUnique(
new testing::NiceMock<MockManagedNetworkConfigurationHandler>);
network_metadata_store_ =
base::WrapUnique(new testing::NiceMock<MockNetworkMetadataStore>());
cros_network_config_ = std::make_unique<FakeCrosNetworkConfig>();
OverrideInProcessInstanceForTesting(cros_network_config_.get());
apn_migrator_ = std::make_unique<ApnMigrator>(
managed_cellular_pref_handler_.get(),
managed_network_configuration_handler_.get(),
network_state_helper_.network_state_handler());
apn_migrator_->set_network_metadata_store_for_testing(
network_metadata_store_.get());
network_state_helper_.manager_test()->AddTechnology(shill::kTypeCellular,
/*enabled=*/true);
network_state_helper_.network_state_handler()
->set_stub_cellular_networks_provider(
&stub_cellular_networks_provider_);
}
void TearDown() override {
apn_migrator_.reset();
managed_network_configuration_handler_.reset();
managed_cellular_pref_handler_.reset();
scoped_user_manager_.reset();
LoginState::Shutdown();
}
void TriggerNetworkListChanged() {
static_cast<NetworkStateHandlerObserver*>(apn_migrator_.get())
->NetworkListChanged();
}
void AddStub(const std::string& stub_iccid, const std::string& eid) {
stub_cellular_networks_provider_.AddStub(stub_iccid, eid);
network_state_helper_.network_state_handler()->SyncStubCellularNetworks();
}
// Creates a fake cellular device and a fake cellular service. The path of
// the fake cellular service is returned.
std::string AddTestCellularDeviceAndService(const std::string& device_name,
const std::string& device_path,
const std::string& device_iccid,
const std::string& device_guid,
bool is_managed = false) {
network_state_helper_.device_test()->AddDevice(
device_path, shill::kTypeCellular, device_name);
network_state_helper_.device_test()->SetDeviceProperty(
device_path, shill::kIccidProperty, base::Value(device_iccid),
/*notify_changed=*/false);
std::string ui_data = is_managed ? kUiData : "";
return network_state_helper_.ConfigureService(base::StringPrintf(
kCellularServicePattern, device_guid.c_str(), device_iccid.c_str(),
NetworkProfileHandler::GetSharedProfilePath().c_str(),
ui_data.c_str()));
}
void ClearCellularServices() { return network_state_helper_.ClearServices(); }
const std::vector<ApnPropertiesPtr>& GetCustomApns() {
return cros_network_config_->custom_apns();
}
void InvokePendingCreateCustomApnCallback(bool success) {
cros_network_config_->InvokePendingCreateCustomApnCallback(success);
}
MockManagedCellularPrefHandler* managed_cellular_pref_handler() const {
return managed_cellular_pref_handler_.get();
}
MockManagedNetworkConfigurationHandler*
managed_network_configuration_handler() const {
return managed_network_configuration_handler_.get();
}
MockNetworkMetadataStore* network_metadata_store() const {
return network_metadata_store_.get();
}
base::HistogramTester& histogram_tester() { return histogram_tester_; }
private:
base::test::SingleThreadTaskEnvironment task_environment_;
NetworkStateTestHelper network_state_helper_{
/*use_default_devices_and_services=*/true};
NetworkHandlerTestHelper handler_test_helper_;
FakeStubCellularNetworksProvider stub_cellular_networks_provider_;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
std::unique_ptr<MockManagedCellularPrefHandler>
managed_cellular_pref_handler_;
std::unique_ptr<MockManagedNetworkConfigurationHandler>
managed_network_configuration_handler_;
std::unique_ptr<MockNetworkMetadataStore> network_metadata_store_;
std::unique_ptr<FakeCrosNetworkConfig> cros_network_config_;
base::HistogramTester histogram_tester_;
// Class under test
std::unique_ptr<ApnMigrator> apn_migrator_;
};
TEST_F(ApnMigratorTest, ApnRevampFlagDisabled) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 =
AddTestCellularDeviceAndService(kCellularName1, kTestCellularPath1,
kTestCellularIccid1, kTestCellularGuid1);
const std::string cellular_service_path_2 =
AddTestCellularDeviceAndService(kCellularName2, kTestCellularPath2,
kTestCellularIccid2, kTestCellularGuid2);
// Every network should be evaluated, simulate the first one as migrated, and
// the second one as not.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(2)
.WillRepeatedly(Return(true));
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid2)))
.Times(3)
.WillRepeatedly(Return(false));
// For the migrated network, the routine should not check for the current
// custom APN list, but rather just resets the CustomApnList.
EXPECT_CALL(*network_metadata_store(), GetCustomApnList(kTestCellularGuid1))
.Times(0);
base::OnceClosure success_cb;
network_handler::ErrorCallback failure_cb;
std::vector<std::string> expected_names;
expected_names.push_back(shill::kCellularCustomApnListProperty);
EXPECT_CALL(
*managed_network_configuration_handler(),
ClearShillProperties(
cellular_service_path_1,
Truly([&expected_names](const std::vector<std::string>& names) {
return expected_names == names;
}),
_, _))
.Times(2)
.WillRepeatedly(WithArgs<2, 3>(
Invoke([&success_cb, &failure_cb](
base::OnceClosure callback,
network_handler::ErrorCallback error_callback) {
success_cb = std::move(callback);
failure_cb = std::move(error_callback);
})));
// Ensure that the function does not modify the non-migrated network.
EXPECT_CALL(*network_metadata_store(), GetCustomApnList(kTestCellularGuid2))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
ClearShillProperties(cellular_service_path_2, _, _, _))
.Times(0);
// Function under test
TriggerNetworkListChanged();
// Simulate the ClearShillProperties() call failing.
std::move(failure_cb).Run("error");
base::RunLoop().RunUntilIdle();
// Invoke the function again. |cellular_service_path_1|'s property should be
// attempted to be cleared again.
TriggerNetworkListChanged();
// Simulate the ClearShillProperties() call succeeding.
std::move(success_cb).Run();
base::RunLoop().RunUntilIdle();
// Invoke the function again. |cellular_service_path_1|'s property shouldn't
// be attempted to be cleared again.
TriggerNetworkListChanged();
}
TEST_F(ApnMigratorTest, AlreadyMigratedNetworks) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 =
AddTestCellularDeviceAndService(kCellularName1, kTestCellularPath1,
kTestCellularIccid1, kTestCellularGuid1);
const std::string cellular_service_path_2 =
AddTestCellularDeviceAndService(kCellularName2, kTestCellularPath2,
kTestCellularIccid2, kTestCellularGuid2);
const std::string cellular_service_path_3 =
AddTestCellularDeviceAndService(kCellularName3, kTestCellularPath3,
kTestCellularIccid3, kTestCellularGuid3);
const char kTestStubIccid[] = "test_stub_iccid";
const char kTestStubEid[] = "test_stub_eid";
AddStub(kTestStubIccid, kTestStubEid);
// The migrator routine will iterate through cellular networks. Stub networks
// must be ignored. For this test, pretend that all non-stub cellular network
// have been migrated.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid2)))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid3)))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestStubIccid)))
.Times(0);
// Return nullptr and empty list for the first two networks.
EXPECT_CALL(*network_metadata_store(), GetCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(nullptr));
base::Value::List empty_apn_list;
EXPECT_CALL(*network_metadata_store(), GetCustomApnList(kTestCellularGuid2))
.Times(1)
.WillOnce(Return(&empty_apn_list));
// For the third network, simulate a populated custom APN list.
auto populated_apn_list =
base::Value::List()
.Append(base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
"apn_1"))
.Append(base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
"apn_2"));
EXPECT_CALL(*network_metadata_store(), GetCustomApnList(kTestCellularGuid3))
.Times(1)
.WillOnce(Return(&populated_apn_list));
// For the first and second networks, the function should update Shill with
// empty custom APN lists.
base::Value::Dict expected_onc_1 =
chromeos::network_config::CustomApnListToOnc(kTestCellularGuid1,
&empty_apn_list);
base::OnceClosure onc_success_callback_1;
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1,
Truly([&expected_onc_1](const base::Value::Dict& value) {
return expected_onc_1 == value;
}),
_, _))
.Times(1)
.WillOnce(WithArg<2>(
Invoke([&onc_success_callback_1](base::OnceClosure callback) {
onc_success_callback_1 = std::move(callback);
})));
base::Value::Dict expected_onc_2 =
chromeos::network_config::CustomApnListToOnc(kTestCellularGuid2,
&empty_apn_list);
base::OnceClosure onc_success_callback_2;
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_2,
Truly([&expected_onc_2](const base::Value::Dict& value) {
return expected_onc_2 == value;
}),
_, _))
.Times(1)
.WillOnce(WithArg<2>(
Invoke([&onc_success_callback_2](base::OnceClosure callback) {
onc_success_callback_2 = std::move(callback);
})));
// Verify that Shill receives the custom APNs for the third list.
base::Value::Dict expected_onc_3 =
chromeos::network_config::CustomApnListToOnc(kTestCellularGuid3,
&populated_apn_list);
base::OnceClosure onc_success_callback_3;
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_3,
Truly([&expected_onc_3](const base::Value::Dict& value) {
return expected_onc_3 == value;
}),
_, _))
.Times(1)
.WillOnce(WithArg<2>(
Invoke([&onc_success_callback_3](base::OnceClosure callback) {
onc_success_callback_3 = std::move(callback);
})));
// Function under test.
TriggerNetworkListChanged();
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid2)))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid3)))
.Times(0);
// Run successfully sent to shill callbacks for first and second network.
std::move(onc_success_callback_1).Run();
std::move(onc_success_callback_2).Run();
base::RunLoop().RunUntilIdle();
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid2)))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid3)))
#if DCHECK_IS_ON()
.Times(2)
#else
.Times(1)
#endif // DCHECK_IS_ON()
.WillRepeatedly(Return(false));
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_2, _, _, _))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_3, _, _, _))
.Times(1);
// The revamp APN lists will not be sent to shill for first and second network
// as they have already successfully been done so. It will still be sent to
// the third network as the list was not sent.
TriggerNetworkListChanged();
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid3)))
.Times(1);
// Run successfully sent to shill callbacks for third network.
std::move(onc_success_callback_3).Run();
base::RunLoop().RunUntilIdle();
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid3)))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_2, _, _, _))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_3, _, _, _))
.Times(0);
// The revamp APN lists will not be sent to any of the networks in shill as
// they have all been successfully sent now.
TriggerNetworkListChanged();
}
TEST_F(ApnMigratorTest, MigrateNetworksWithoutCustomApns) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 =
AddTestCellularDeviceAndService(kCellularName1, kTestCellularPath1,
kTestCellularIccid1, kTestCellularGuid1);
const std::string cellular_service_path_2 =
AddTestCellularDeviceAndService(kCellularName2, kTestCellularPath2,
kTestCellularIccid2, kTestCellularGuid2);
// Every network should be evaluated, pretend that all network need to be
// migrated.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid2)))
.WillRepeatedly(Return(false));
// Simulate that all networks do not have custom APNs
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(nullptr));
base::Value::List empty_apn_list;
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid2))
.Times(1)
.WillOnce(Return(&empty_apn_list));
// The function should only update Shill with empty custom APN lists.
base::Value::Dict expected_onc_1 =
chromeos::network_config::CustomApnListToOnc(kTestCellularGuid1,
&empty_apn_list);
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1,
Truly([&expected_onc_1](const base::Value::Dict& value) {
return expected_onc_1 == value;
}),
_, _))
.Times(1)
.WillOnce(WithArg<2>(Invoke(
[&](base::OnceClosure callback) { std::move(callback).Run(); })));
base::Value::Dict expected_onc_2 =
chromeos::network_config::CustomApnListToOnc(kTestCellularGuid2,
&empty_apn_list);
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_2,
Truly([&expected_onc_2](const base::Value::Dict& value) {
return expected_onc_2 == value;
}),
_, _))
.Times(1)
.WillOnce(WithArg<2>(Invoke(
[&](base::OnceClosure callback) { std::move(callback).Run(); })));
// All network should be marked as migrated
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid2)))
.Times(1);
// Function under test.
TriggerNetworkListChanged();
}
TEST_F(ApnMigratorTest, MigrateNetworkEmptyIccid) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1,
/*device_iccid=*/std::string(), kTestCellularGuid1);
// A call to the migrator should exit early and not start the migration
// process for |cellular_service_path_1|.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(0);
// Function under test.
TriggerNetworkListChanged();
}
TEST_F(ApnMigratorTest, MigrateNetworkAlreadyMigrating) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 =
AddTestCellularDeviceAndService(kCellularName1, kTestCellularPath1,
kTestCellularIccid1, kTestCellularGuid1);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// The first call to the migrator should start the migration process for
// |cellular_service_path_1|. This will trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
auto populated_apn_list =
base::Value::List()
.Append(base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
"apn_1"))
.Append(base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
"apn_2"));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&get_managed_properties_callback](
network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// A second call should not trigger a GetManagedProperties, as the network is
// already waiting for the async callback response.
{
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1)
.WillOnce(Return(false));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(0);
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(0);
// Function under test.
TriggerNetworkListChanged();
}
// Execute the GetManagedProperties callback with a failure, expect that the
// migration service does not mark the network as migrated.
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, base::Value::Dict(),
/*error=*/"error");
base::RunLoop().RunUntilIdle();
get_managed_properties_callback.Reset();
// A third call should trigger GetManagedProperties, as the network is no
// longer migrating.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&get_managed_properties_callback](
network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
}
TEST_F(ApnMigratorTest, MigrateNetworkNoPropertiesOrNotFound) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 =
AddTestCellularDeviceAndService(kCellularName1, kTestCellularPath1,
kTestCellularIccid1, kTestCellularGuid1);
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
auto populated_apn_list = base::Value::List().Append(
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName, "apn_1"));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&get_managed_properties_callback](
network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with no properties, expect that
// the migration service does not mark the network as migrated.
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, /*properties=*/std::nullopt,
/*error=*/std::nullopt);
get_managed_properties_callback.Reset();
// Start the migration process for |cellular_service_path_1| again.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Remove the network.
ClearCellularServices();
// Execute the GetManagedProperties callback, expect that the migration
// service does not mark the network as migrated as the network is no longer
// found.
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, /*properties=*/base::Value::Dict(),
/*error=*/std::nullopt);
}
TEST_F(ApnMigratorTest, MigrateNetworkCustomApnRemovedDuringMigration) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 =
AddTestCellularDeviceAndService(kCellularName1, kTestCellularPath1,
kTestCellularIccid1, kTestCellularGuid1);
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
auto populated_apn_list = base::Value::List().Append(
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName, "apn_1"));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&get_managed_properties_callback](
network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test with failure to send APN list to shill.
TriggerNetworkListChanged();
// During the GetManagedProperties call, set the custom APN list to be empty.
base::Value::List empty_apn_list;
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&empty_apn_list));
// Execute the GetManagedProperties callback, and an attempt to update shill
// with an empty APN list should be made. Intentionally fail the update to
// shill.
base::Value::Dict expected_onc_1 =
chromeos::network_config::CustomApnListToOnc(kTestCellularGuid1,
&empty_apn_list);
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1,
Truly([&expected_onc_1](const base::Value::Dict& value) {
return expected_onc_1 == value;
}),
_, _))
.Times(1)
.WillOnce(WithArg<3>(Invoke([&](network_handler::ErrorCallback callback) {
std::move(callback).Run("error");
})));
// ICCID should not have been migrated.
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, /*properties=*/base::Value::Dict(),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&get_managed_properties_callback](
network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test with successful APN list to shill.
TriggerNetworkListChanged();
// During the GetManagedProperties call, set the custom APN list to be empty.
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(1)
.WillOnce(Return(&empty_apn_list));
// Execute the GetManagedProperties callback, Shill should be updated with an
// empty APN list. The network should be marked as migrated.
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1,
Truly([&expected_onc_1](const base::Value::Dict& value) {
return expected_onc_1 == value;
}),
_, _))
.Times(1)
.WillOnce(WithArg<2>(Invoke(
[&](base::OnceClosure callback) { std::move(callback).Run(); })));
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, /*properties=*/base::Value::Dict(),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GetCustomApns().empty());
}
TEST_F(ApnMigratorTest,
MigrateManagedNetwork_NoLastConnectedDefaultApn_NonMatchingSelectedApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/true);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// The first call to the migrator should start the migration process for
// |cellular_service_path_1|. This will trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
auto populated_apn_list = base::Value::List().Append(
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName, "apn_1"));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with no selected_apn. Simulate
// failure to update shill. The network should not be marked as migrated.
base::Value::List empty_apn_list;
base::Value::Dict expected_onc = chromeos::network_config::CustomApnListToOnc(
kTestCellularGuid1, &empty_apn_list);
base::OnceClosure onc_success_callback;
network_handler::ErrorCallback onc_failure_callback;
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1,
Truly([&expected_onc](const base::Value::Dict& value) {
return expected_onc == value;
}),
_, _))
.Times(1)
.WillRepeatedly(WithArgs<2, 3>(
Invoke([&onc_success_callback, &onc_failure_callback](
base::OnceClosure callback,
network_handler::ErrorCallback error_callback) {
onc_success_callback = std::move(callback);
onc_failure_callback = std::move(error_callback);
})));
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular, base::Value::Dict());
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
std::move(onc_failure_callback).Run("error");
base::RunLoop().RunUntilIdle();
get_managed_properties_callback.Reset();
onc_success_callback.Reset();
onc_failure_callback.Reset();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GetCustomApns().empty());
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::ManagedApnMigrationType::
kDoesNotMatchSelectedApn,
1);
// Attempt to migrate |cellular_service_path_1| again.
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&get_managed_properties_callback](
network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with a non-matching selected_apn.
// Simulate Shill successfully updating with an empty APN list. The network
// should be marked as migrated.
EXPECT_CALL(
*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1,
Truly([&expected_onc](const base::Value::Dict& value) {
return expected_onc == value;
}),
_, _))
.Times(1)
.WillRepeatedly(WithArgs<2, 3>(
Invoke([&onc_success_callback, &onc_failure_callback](
base::OnceClosure callback,
network_handler::ErrorCallback error_callback) {
onc_success_callback = std::move(callback);
onc_failure_callback = std::move(error_callback);
})));
properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict().Set(
::onc::cellular::kAPN,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
"apn_2")));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
std::move(onc_success_callback).Run();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GetCustomApns().empty());
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
2);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::ManagedApnMigrationType::
kDoesNotMatchSelectedApn,
2);
}
TEST_F(ApnMigratorTest,
MigrateManagedNetwork_NoLastConnectedDefaultApn_MatchingSelectedApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/true);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, access_point_name));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with a selected_apn that matches
// the persisted APN. This should trigger a call to CreateCustomApns().
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict().Set(
::onc::cellular::kAPN,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
access_point_name)));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsManagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::ManagedApnMigrationType::
kMatchesSelectedApn,
1);
}
TEST_F(ApnMigratorTest,
MigrateManagedNetwork_MatchingLastConnectedAttachApnAndDefaultApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/true);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
base::Value::Dict custom_apn;
custom_apn.Set(::onc::cellular_apn::kAccessPointName, access_point_name);
base::Value::List populated_apn_list;
populated_apn_list.Append(std::move(custom_apn));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with a last connected attach
// APN and a last connected default APN that match the persisted APN.
// This should trigger a call to CreateCustomApns() with the APN in the
// enabled state with APN types of kAttach and kDefault.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict();
base::Value::Dict last_connected_attach_apn_dict;
last_connected_attach_apn_dict.Set(::onc::cellular_apn::kAccessPointName,
access_point_name);
base::Value::Dict last_connected_default_apn_dict;
last_connected_default_apn_dict.Set(::onc::cellular_apn::kAccessPointName,
access_point_name);
// Set the last_connected_attach_apn and last_connected_default_apn. This will
// cause the APN to be migrated the same as the non-managed case.
base::Value::Dict cellular;
cellular.Set(::onc::cellular::kLastConnectedAttachApnProperty,
std::move(last_connected_attach_apn_dict));
cellular.Set(::onc::cellular::kLastConnectedDefaultApnProperty,
std::move(last_connected_default_apn_dict));
properties->Set(::onc::network_config::kCellular, std::move(cellular));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kMatchesLastConnectedAttachAndDefault,
1);
}
TEST_F(
ApnMigratorTest,
MigrateNonManagedNetwork_NoLastConnectedAttachApnAndDefaultApn_MatchingLastGoodApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, access_point_name));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with no last connected attach
// APN, no last connected default APN, and a last good APN that matches the
// persisted APN. This should trigger a call to CreateCustomApns() with the
// APN in the enabled state.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict().Set(
::onc::cellular::kLastGoodAPN,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
access_point_name)));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kMatchesLastGoodApn,
1);
}
TEST_F(
ApnMigratorTest,
MigrateNonManagedNetwork_NoLastConnectedAttachApnAndDefaultApn_NonMatchingLastGoodApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, access_point_name));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with no last connected attach
// APN, no last connected default APN, and a last good APN that does NOT match
// the persisted APN. This should trigger a call to CreateCustomApns() with
// the APN in the disabled state.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict().Set(
::onc::cellular::kLastGoodAPN,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
"apn_2")));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kDisabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kDoesNotMatchLastGoodApn,
1);
}
TEST_F(ApnMigratorTest,
MigrateNonManagedNetwork_MatchingLastConnectedAttachApnAndDefaultApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, access_point_name));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with a last connected attach
// APN and a last connected default APN that match the persisted APN.
// This should trigger a call to CreateCustomApns() with the APN in the
// enabled state with APN types of kAttach and kDefault.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict()
.Set(::onc::cellular::kLastConnectedAttachApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
access_point_name))
.Set(::onc::cellular::kLastConnectedDefaultApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
access_point_name)));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kMatchesLastConnectedAttachAndDefault,
1);
}
TEST_F(
ApnMigratorTest,
MigrateNonManagedNetwork_NoLastConnectedAttachApn_MatchingLastConnectedDefaultApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, access_point_name));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with no last connected attach
// APN, and a last connected default APN that matches the persisted APN.
// This should trigger a call to CreateCustomApns() with the APN in the
// enabled state with APN types of kDefault.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict().Set(
::onc::cellular::kLastConnectedDefaultApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
access_point_name)));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_FALSE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kMatchesLastConnectedDefaultNoLastConnectedAttach,
1);
}
TEST_F(
ApnMigratorTest,
MigrateNonManagedNetwork_EmptyLastConnectedAttachApn_MatchingLastConnectedDefaultApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, access_point_name));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with no last connected attach
// APN, and a last connected default APN that matches the persisted APN.
// This should trigger a call to CreateCustomApns() with the APN in the
// enabled state with APN types of kDefault.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict()
.Set(::onc::cellular::kLastConnectedDefaultApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
access_point_name))
.Set(::onc::cellular::kLastConnectedAttachApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
std::string())));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_FALSE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kMatchesLastConnectedDefaultNoLastConnectedAttach,
1);
}
TEST_F(
ApnMigratorTest,
MigrateNonManagedNetwork_MatchesLastConnectedAttachOnlyAndDefaultExists) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, kAttachAccessPointName));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with a last connected attach
// APN and a last connected default APN that match the persisted APN.
// This should trigger CreateCustomApns() for a default APN, then for an
// attach APN.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict()
.Set(::onc::cellular::kLastConnectedAttachApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
kAttachAccessPointName))
.Set(::onc::cellular::kLastConnectedDefaultApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
kDefaultAccessPointName))
.Set(::onc::cellular::kAPNList,
base::Value::List().Append(
base::Value::Dict()
.Set(::onc::cellular_apn::kAccessPointName,
kDefaultAccessPointName)
.Set(::onc::cellular_apn::kApnTypes,
base::Value::List().Append(
::onc::cellular_apn::kApnTypeDefault)))));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(2u, custom_apns.size());
// Last connected default APN is saved first.
EXPECT_EQ(kDefaultAccessPointName, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
// Last connected attach APN is saved second.
EXPECT_EQ(kAttachAccessPointName, custom_apns[1]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[1]->state);
EXPECT_TRUE(base::Contains(custom_apns[1]->apn_types, ApnType::kAttach));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kMatchesLastConnectedAttachOnlyAndDefaultExists,
1);
}
TEST_F(
ApnMigratorTest,
MigrateNonManagedNetwork_MatchesLastConnectedDefaultOnlyAndAttachExists) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, kDefaultAccessPointName));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with a last connected attach
// APN and a last connected default APN that match the persisted APN.
// This should trigger CreateCustomApns() for a default APN, then for an
// attach APN.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict()
.Set(::onc::cellular::kLastConnectedAttachApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
kAttachAccessPointName))
.Set(::onc::cellular::kLastConnectedDefaultApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
kDefaultAccessPointName))
.Set(::onc::cellular::kAPNList,
base::Value::List().Append(
base::Value::Dict()
.Set(::onc::cellular_apn::kAccessPointName,
kDefaultAccessPointName)
.Set(::onc::cellular_apn::kApnTypes,
base::Value::List().Append(
::onc::cellular_apn::kApnTypeDefault)))));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(2u, custom_apns.size());
// Last connected default APN is saved first.
EXPECT_EQ(kDefaultAccessPointName, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kAttach));
// Last connected attach APN is saved second.
EXPECT_EQ(kAttachAccessPointName, custom_apns[1]->access_point_name);
EXPECT_EQ(ApnState::kEnabled, custom_apns[1]->state);
EXPECT_TRUE(base::Contains(custom_apns[1]->apn_types, ApnType::kAttach));
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kMatchesLastConnectedDefaultOnlyAndAttachExists,
1);
}
TEST_F(
ApnMigratorTest,
MigrateNonManagedNetwork_CreatedEnabledDefaultApnBeforeEnabledAttachApn) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, kAttachAccessPointName));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with a last connected attach
// APN and a last connected default APN that match the persisted APN.
// This should trigger CreateCustomApns() for a default APN, then for an
// attach APN.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(0);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict()
.Set(::onc::cellular::kLastConnectedAttachApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
kAttachAccessPointName))
.Set(::onc::cellular::kLastConnectedDefaultApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
kDefaultAccessPointName))
.Set(::onc::cellular::kAPNList,
base::Value::List().Append(
base::Value::Dict()
.Set(::onc::cellular_apn::kAccessPointName,
kDefaultAccessPointName)
.Set(::onc::cellular_apn::kApnTypes,
base::Value::List().Append(
::onc::cellular_apn::kApnTypeDefault)))));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
// Simulate failure to create default custom APN.
InvokePendingCreateCustomApnCallback(/*success=*/false);
base::RunLoop().RunUntilIdle();
// The attach APN should not be created, since the default custom APN was not
// created.
EXPECT_TRUE(GetCustomApns().empty());
}
TEST_F(ApnMigratorTest, MigrateNonManagedNetwork_Default) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(features::kApnRevamp);
const std::string cellular_service_path_1 = AddTestCellularDeviceAndService(
kCellularName1, kTestCellularPath1, kTestCellularIccid1,
kTestCellularGuid1, /*is_managed=*/false);
// We will use this delegate to simulate a late async reply.
network_handler::PropertiesCallback get_managed_properties_callback;
// Start the migration process for |cellular_service_path_1|. This will
// trigger a GetManagedProperties call.
EXPECT_CALL(*managed_cellular_pref_handler(),
ContainsApnMigratedIccid(Eq(kTestCellularIccid1)))
.WillRepeatedly(Return(false));
const std::string access_point_name = "apn_1";
auto populated_apn_list = base::Value::List().Append(base::Value::Dict().Set(
::onc::cellular_apn::kAccessPointName, access_point_name));
EXPECT_CALL(*network_metadata_store(),
GetPreRevampCustomApnList(kTestCellularGuid1))
.Times(2)
.WillRepeatedly(Return(&populated_apn_list));
EXPECT_CALL(*managed_network_configuration_handler(),
GetManagedProperties(LoginState::Get()->primary_user_hash(),
cellular_service_path_1, _))
.Times(1)
.WillOnce(
WithArg<2>(Invoke([&](network_handler::PropertiesCallback callback) {
ASSERT_TRUE(get_managed_properties_callback.is_null());
get_managed_properties_callback = std::move(callback);
ASSERT_FALSE(get_managed_properties_callback.is_null());
})));
// Function under test.
TriggerNetworkListChanged();
// Execute the GetManagedProperties callback with no last connected attach
// APN, and a last connected default APN that does not match the persisted
// APN. This should trigger a call to CreateCustomApns() with the APN in the
// disabled state.
EXPECT_CALL(*managed_network_configuration_handler(),
SetProperties(cellular_service_path_1, _, _, _))
.Times(0);
EXPECT_CALL(*managed_cellular_pref_handler(),
AddApnMigratedIccid(Eq(kTestCellularIccid1)))
.Times(1);
EXPECT_TRUE(GetCustomApns().empty());
std::optional<base::Value::Dict> properties = base::Value::Dict().Set(
::onc::network_config::kCellular,
base::Value::Dict().Set(
::onc::cellular::kLastConnectedDefaultApnProperty,
base::Value::Dict().Set(::onc::cellular_apn::kAccessPointName,
"apn_2")));
std::move(get_managed_properties_callback)
.Run(cellular_service_path_1, std::move(properties),
/*error=*/std::nullopt);
base::RunLoop().RunUntilIdle();
InvokePendingCreateCustomApnCallback(/*success=*/true);
base::RunLoop().RunUntilIdle();
const std::vector<ApnPropertiesPtr>& custom_apns = GetCustomApns();
ASSERT_EQ(1u, custom_apns.size());
EXPECT_EQ(access_point_name, custom_apns[0]->access_point_name);
EXPECT_EQ(ApnState::kDisabled, custom_apns[0]->state);
EXPECT_TRUE(base::Contains(custom_apns[0]->apn_types, ApnType::kDefault));
EXPECT_EQ(1u, custom_apns[0]->apn_types.size());
histogram_tester().ExpectTotalCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
1);
histogram_tester().ExpectBucketCount(
CellularNetworkMetricsLogger::kCustomApnsUnmanagedMigrationTypeHistogram,
CellularNetworkMetricsLogger::UnmanagedApnMigrationType::
kNoMatchingConnectedApn,
1);
}
} // namespace ash