| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/tethering_manager.h" |
| |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include <base/containers/contains.h> |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/test/mock_callback.h> |
| #include <chromeos/dbus/shill/dbus-constants.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "shill/cellular/cellular_service_provider.h" |
| #include "shill/error.h" |
| #include "shill/ethernet/mock_ethernet_provider.h" |
| #include "shill/manager.h" |
| #include "shill/mock_control.h" |
| #include "shill/mock_device.h" |
| #include "shill/mock_manager.h" |
| #include "shill/mock_metrics.h" |
| #include "shill/mock_profile.h" |
| #include "shill/mock_service.h" |
| #include "shill/store/fake_store.h" |
| #include "shill/store/property_store.h" |
| #include "shill/technology.h" |
| #include "shill/test_event_dispatcher.h" |
| #include "shill/upstart/mock_upstart.h" |
| #include "shill/wifi/local_device.h" |
| #include "shill/wifi/local_service.h" |
| #include "shill/wifi/mock_hotspot_device.h" |
| #include "shill/wifi/mock_wake_on_wifi.h" |
| #include "shill/wifi/mock_wifi.h" |
| #include "shill/wifi/mock_wifi_provider.h" |
| |
| using testing::_; |
| using testing::Mock; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::StrictMock; |
| using testing::Test; |
| |
| namespace shill { |
| namespace { |
| |
| // Fake profile identities |
| constexpr char kDefaultProfile[] = "default"; |
| constexpr char kUserProfile[] = "~user/profile"; |
| |
| bool GetConfigMAR(const KeyValueStore& caps) { |
| return caps.Get<bool>(kTetheringConfMARProperty); |
| } |
| bool GetConfigAutoDisable(const KeyValueStore& caps) { |
| return caps.Get<bool>(kTetheringConfAutoDisableProperty); |
| } |
| std::string GetConfigSSID(const KeyValueStore& caps) { |
| return caps.Get<std::string>(kTetheringConfSSIDProperty); |
| } |
| std::string GetConfigPassphrase(const KeyValueStore& caps) { |
| return caps.Get<std::string>(kTetheringConfPassphraseProperty); |
| } |
| std::string GetConfigSecurity(const KeyValueStore& caps) { |
| return caps.Get<std::string>(kTetheringConfSecurityProperty); |
| } |
| std::string GetConfigBand(const KeyValueStore& caps) { |
| return caps.Get<std::string>(kTetheringConfBandProperty); |
| } |
| std::string GetConfigUpstream(const KeyValueStore& caps) { |
| return caps.Get<std::string>(kTetheringConfUpstreamTechProperty); |
| } |
| void SetConfigMAR(KeyValueStore& caps, bool value) { |
| caps.Set<bool>(kTetheringConfMARProperty, value); |
| } |
| void SetConfigAutoDisable(KeyValueStore& caps, bool value) { |
| caps.Set<bool>(kTetheringConfAutoDisableProperty, value); |
| } |
| void SetConfigSSID(KeyValueStore& caps, const std::string& value) { |
| caps.Set<std::string>(kTetheringConfSSIDProperty, value); |
| } |
| void SetConfigPassphrase(KeyValueStore& caps, const std::string& value) { |
| caps.Set<std::string>(kTetheringConfPassphraseProperty, value); |
| } |
| void SetConfigSecurity(KeyValueStore& caps, const std::string& value) { |
| caps.Set<std::string>(kTetheringConfSecurityProperty, value); |
| } |
| void SetConfigBand(KeyValueStore& caps, const std::string& value) { |
| caps.Set<std::string>(kTetheringConfBandProperty, value); |
| } |
| void SetConfigUpstream(KeyValueStore& caps, const std::string& value) { |
| caps.Set<std::string>(kTetheringConfUpstreamTechProperty, value); |
| } |
| |
| base::ScopedTempDir MakeTempDir() { |
| base::ScopedTempDir temp_dir; |
| EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); |
| return temp_dir; |
| } |
| } // namespace |
| |
| class TetheringManagerTest : public testing::Test { |
| public: |
| TetheringManagerTest() |
| : temp_dir_(MakeTempDir()), |
| path_(temp_dir_.GetPath().value()), |
| manager_( |
| &control_interface_, &dispatcher_, &metrics_, path_, path_, path_), |
| tethering_manager_(manager_.tethering_manager()), |
| wifi_provider_(new NiceMock<MockWiFiProvider>()), |
| ethernet_provider_(new NiceMock<MockEthernetProvider>()), |
| upstart_(new NiceMock<MockUpstart>(&control_interface_)), |
| hotspot_device_(new NiceMock<MockHotspotDevice>( |
| &manager_, "ap0", "", 0, event_cb_.Get())) { |
| // Replace the manager's WiFi provider with our mock. |
| manager_.wifi_provider_.reset(wifi_provider_); |
| // Replace the manager's Ethernet provider with mock. |
| manager_.ethernet_provider_.reset(ethernet_provider_); |
| // Update the manager's map from technology to provider. |
| manager_.UpdateProviderMapping(); |
| // Replace the manager's upstart instance with mock. |
| manager_.upstart_.reset(upstart_); |
| ON_CALL(manager_, cellular_service_provider()) |
| .WillByDefault(Return(&cellular_service_provider_)); |
| } |
| ~TetheringManagerTest() override = default; |
| |
| scoped_refptr<MockWiFi> MakeWiFi(const std::string& ifname, |
| const std::string& mac) { |
| return new NiceMock<MockWiFi>(&manager_, ifname, mac, 1, 1, |
| new MockWakeOnWiFi()); |
| } |
| |
| Error::Type TestCreateProfile(Manager* manager, const std::string& name) { |
| Error error; |
| std::string path; |
| manager->CreateProfile(name, &path, &error); |
| return error.type(); |
| } |
| |
| Error::Type TestPushProfile(Manager* manager, const std::string& name) { |
| Error error; |
| std::string path; |
| manager->PushProfile(name, &path, &error); |
| return error.type(); |
| } |
| |
| Error::Type TestPopProfile(Manager* manager, const std::string& name) { |
| Error error; |
| manager->PopProfile(name, &error); |
| return error.type(); |
| } |
| |
| void SetAllowed(TetheringManager* tethering_manager, bool allowed) { |
| Error error; |
| PropertyStore store; |
| tethering_manager->InitPropertyStore(&store); |
| store.SetBoolProperty(kTetheringAllowedProperty, allowed, &error); |
| EXPECT_TRUE(error.IsSuccess()); |
| } |
| |
| KeyValueStore GetCapabilities(TetheringManager* tethering_manager) { |
| Error error; |
| KeyValueStore caps = tethering_manager->GetCapabilities(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| return caps; |
| } |
| |
| bool SetAndPersistConfig(TetheringManager* tethering_manager, |
| const KeyValueStore& config) { |
| Error error; |
| bool is_success = tethering_manager->SetAndPersistConfig(config, &error); |
| EXPECT_EQ(is_success, error.IsSuccess()); |
| return is_success; |
| } |
| |
| void SetEnabled(TetheringManager* tethering_manager, bool enabled) { |
| tethering_manager->SetEnabled(enabled, result_cb_.Get()); |
| } |
| |
| void VerifyResult(TetheringManager::SetEnabledResult expected_result) { |
| EXPECT_CALL(result_cb_, Run(expected_result)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&result_cb_); |
| } |
| |
| void SetEnabledVerifyResult( |
| TetheringManager* tethering_manager, |
| bool enabled, |
| TetheringManager::SetEnabledResult expected_result) { |
| SetEnabled(tethering_manager, enabled); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kServiceUp, |
| hotspot_device_.get()); |
| VerifyResult(expected_result); |
| } |
| |
| KeyValueStore GetConfig(TetheringManager* tethering_manager) { |
| Error error; |
| KeyValueStore caps = tethering_manager->GetConfig(&error); |
| EXPECT_TRUE(error.IsSuccess()); |
| return caps; |
| } |
| |
| bool SaveConfig(TetheringManager* tethering_manager, |
| StoreInterface* storage) { |
| return tethering_manager->Save(storage); |
| } |
| |
| bool FromProperties(TetheringManager* tethering_manager, |
| const KeyValueStore& config) { |
| return tethering_manager->FromProperties(config); |
| } |
| |
| KeyValueStore VerifyDefaultTetheringConfig( |
| TetheringManager* tethering_manager) { |
| KeyValueStore caps = GetConfig(tethering_manager); |
| EXPECT_TRUE(GetConfigMAR(caps)); |
| EXPECT_TRUE(GetConfigAutoDisable(caps)); |
| std::string ssid = GetConfigSSID(caps); |
| EXPECT_FALSE(ssid.empty()); |
| EXPECT_TRUE(std::all_of(ssid.begin(), ssid.end(), ::isxdigit)); |
| std::string passphrase = GetConfigPassphrase(caps); |
| EXPECT_FALSE(passphrase.empty()); |
| EXPECT_TRUE(std::all_of(passphrase.begin(), passphrase.end(), ::isxdigit)); |
| EXPECT_EQ(kSecurityWpa2, GetConfigSecurity(caps)); |
| EXPECT_EQ(GetConfigBand(caps), kBandAll); |
| EXPECT_TRUE(caps.Contains<std::string>(kTetheringConfUpstreamTechProperty)); |
| return caps; |
| } |
| |
| KeyValueStore GenerateFakeConfig(const std::string& ssid, |
| const std::string passphrase) { |
| KeyValueStore config; |
| SetConfigMAR(config, false); |
| SetConfigAutoDisable(config, false); |
| SetConfigSSID(config, ssid); |
| SetConfigPassphrase(config, passphrase); |
| SetConfigSecurity(config, kSecurityWpa3); |
| SetConfigBand(config, kBand2GHz); |
| SetConfigUpstream(config, kTypeCellular); |
| return config; |
| } |
| |
| void DispatchPendingEvents() { dispatcher_.DispatchPendingEvents(); } |
| |
| void TetheringPrerequisite(TetheringManager* tethering_manager) { |
| SetAllowed(tethering_manager, true); |
| |
| ASSERT_EQ(Error::kSuccess, TestCreateProfile(&manager_, kDefaultProfile)); |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kDefaultProfile)); |
| ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("user"))); |
| ASSERT_EQ(Error::kSuccess, TestCreateProfile(&manager_, kUserProfile)); |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kUserProfile)); |
| } |
| |
| void SetDownstream(TetheringManager* tethering_manager) { |
| ON_CALL(*wifi_provider_, CreateHotspotDevice(_, _, _, _)) |
| .WillByDefault(Return(hotspot_device_)); |
| ON_CALL(*hotspot_device_.get(), ConfigureService(_)) |
| .WillByDefault(Return(true)); |
| ON_CALL(*hotspot_device_.get(), IsServiceUp()).WillByDefault(Return(true)); |
| } |
| |
| void DownStreamDeviceEvent(TetheringManager* tethering_manager, |
| LocalDevice::DeviceEvent event, |
| LocalDevice* device) { |
| tethering_manager->OnDownstreamDeviceEvent(event, device); |
| } |
| |
| TetheringManager::TetheringState TetheringState( |
| TetheringManager* tethering_manager) { |
| return tethering_manager->state_; |
| } |
| |
| void CheckTetheringIdle(TetheringManager* tethering_manager) { |
| EXPECT_EQ(tethering_manager->hotspot_dev_, nullptr); |
| EXPECT_EQ(TetheringState(tethering_manager), |
| TetheringManager::TetheringState::kTetheringIdle); |
| } |
| |
| KeyValueStore GetStatus(TetheringManager* tethering_manager) { |
| return tethering_manager->GetStatus(); |
| } |
| |
| protected: |
| StrictMock<base::MockRepeatingCallback<void(LocalDevice::DeviceEvent, |
| const LocalDevice*)>> |
| event_cb_; |
| StrictMock<base::MockOnceCallback<void(TetheringManager::SetEnabledResult)>> |
| result_cb_; |
| |
| NiceMock<MockControl> control_interface_; |
| EventDispatcherForTest dispatcher_; |
| NiceMock<MockMetrics> metrics_; |
| base::ScopedTempDir temp_dir_; |
| std::string path_; |
| MockManager manager_; |
| TetheringManager* tethering_manager_; |
| MockWiFiProvider* wifi_provider_; |
| MockEthernetProvider* ethernet_provider_; |
| CellularServiceProvider cellular_service_provider_{&manager_}; |
| MockUpstart* upstart_; |
| scoped_refptr<MockHotspotDevice> hotspot_device_; |
| }; |
| |
| TEST_F(TetheringManagerTest, GetTetheringCapabilities) { |
| scoped_refptr<MockWiFi> wifi = MakeWiFi("wlan0", "0a:0b:0c:0d:0e:0f"); |
| ON_CALL(*wifi, SupportAP()).WillByDefault(Return(true)); |
| const std::vector<DeviceRefPtr> devices = {wifi}; |
| ON_CALL(manager_, FilterByTechnology(Technology::kWiFi)) |
| .WillByDefault(Return(devices)); |
| SetAllowed(tethering_manager_, true); |
| KeyValueStore caps = GetCapabilities(tethering_manager_); |
| |
| auto upstream_technologies = |
| caps.Get<std::vector<std::string>>(kTetheringCapUpstreamProperty); |
| EXPECT_FALSE(upstream_technologies.empty()); |
| EXPECT_TRUE(base::Contains(upstream_technologies, kTypeEthernet)); |
| EXPECT_TRUE(base::Contains(upstream_technologies, kTypeCellular)); |
| EXPECT_FALSE(base::Contains(upstream_technologies, kTypeWifi)); |
| |
| auto downstream_technologies = |
| caps.Get<std::vector<std::string>>(kTetheringCapDownstreamProperty); |
| EXPECT_FALSE(downstream_technologies.empty()); |
| EXPECT_FALSE(base::Contains(downstream_technologies, kTypeEthernet)); |
| EXPECT_FALSE(base::Contains(downstream_technologies, kTypeCellular)); |
| EXPECT_TRUE(base::Contains(downstream_technologies, kTypeWifi)); |
| |
| std::vector<std::string> wifi_security = |
| caps.Get<std::vector<std::string>>(kTetheringCapSecurityProperty); |
| EXPECT_FALSE(wifi_security.empty()); |
| } |
| |
| TEST_F(TetheringManagerTest, GetTetheringCapabilitiesWithoutWiFi) { |
| const std::vector<DeviceRefPtr> devices; |
| ON_CALL(manager_, FilterByTechnology(Technology::kWiFi)) |
| .WillByDefault(Return(devices)); |
| SetAllowed(tethering_manager_, true); |
| |
| KeyValueStore caps = GetCapabilities(tethering_manager_); |
| |
| auto upstream_technologies = |
| caps.Get<std::vector<std::string>>(kTetheringCapUpstreamProperty); |
| EXPECT_FALSE(upstream_technologies.empty()); |
| EXPECT_TRUE(base::Contains(upstream_technologies, kTypeEthernet)); |
| EXPECT_TRUE(base::Contains(upstream_technologies, kTypeCellular)); |
| EXPECT_FALSE(base::Contains(upstream_technologies, kTypeWifi)); |
| |
| auto downstream_technologies = |
| caps.Get<std::vector<std::string>>(kTetheringCapDownstreamProperty); |
| EXPECT_TRUE(downstream_technologies.empty()); |
| |
| EXPECT_FALSE( |
| caps.Contains<std::vector<std::string>>(kTetheringCapSecurityProperty)); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringConfig) { |
| SetAllowed(tethering_manager_, true); |
| |
| ASSERT_EQ(Error::kSuccess, TestCreateProfile(&manager_, kDefaultProfile)); |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kDefaultProfile)); |
| |
| // Check default TetheringConfig. |
| VerifyDefaultTetheringConfig(tethering_manager_); |
| |
| // Fake Tethering configuration. |
| std::string ssid = "757365725F73736964"; // "user_ssid" in hex |
| std::string passphrase = "user_password"; |
| KeyValueStore args = GenerateFakeConfig(ssid, passphrase); |
| |
| // Block SetAndPersistConfig when no user has logged in. |
| EXPECT_FALSE(SetAndPersistConfig(tethering_manager_, args)); |
| |
| // SetAndPersistConfig succeeds when a user is logged in. |
| ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("user"))); |
| ASSERT_EQ(Error::kSuccess, TestCreateProfile(&manager_, kUserProfile)); |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kUserProfile)); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, args)); |
| |
| // Read the configuration and check if it matches. |
| KeyValueStore config = GetConfig(tethering_manager_); |
| EXPECT_FALSE(GetConfigMAR(config)); |
| EXPECT_FALSE(GetConfigAutoDisable(config)); |
| EXPECT_EQ(GetConfigSSID(config), ssid); |
| EXPECT_EQ(GetConfigPassphrase(config), passphrase); |
| EXPECT_EQ(GetConfigSecurity(config), kSecurityWpa3); |
| EXPECT_EQ(GetConfigBand(config), kBand2GHz); |
| EXPECT_EQ(GetConfigUpstream(config), kTypeCellular); |
| |
| // Log out user and check user's tethering config is not present. |
| EXPECT_EQ(Error::kSuccess, TestPopProfile(&manager_, kUserProfile)); |
| KeyValueStore default_config = GetConfig(tethering_manager_); |
| EXPECT_NE(GetConfigSSID(default_config), ssid); |
| EXPECT_NE(GetConfigPassphrase(default_config), passphrase); |
| |
| // Log in user and check tethering config again. |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kUserProfile)); |
| config = GetConfig(tethering_manager_); |
| EXPECT_FALSE(GetConfigMAR(config)); |
| EXPECT_FALSE(GetConfigAutoDisable(config)); |
| EXPECT_EQ(GetConfigSSID(config), ssid); |
| EXPECT_EQ(GetConfigPassphrase(config), passphrase); |
| EXPECT_EQ(GetConfigSecurity(config), kSecurityWpa3); |
| EXPECT_EQ(GetConfigBand(config), kBand2GHz); |
| EXPECT_EQ(GetConfigUpstream(config), kTypeCellular); |
| } |
| |
| TEST_F(TetheringManagerTest, DefaultConfigCheck) { |
| SetAllowed(tethering_manager_, true); |
| |
| // SetEnabled fails for the default profile. |
| ASSERT_EQ(Error::kSuccess, TestCreateProfile(&manager_, kDefaultProfile)); |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kDefaultProfile)); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kNotAllowed); |
| |
| // SetEnabled succeeds for a user profile. |
| ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("user"))); |
| ASSERT_EQ(Error::kSuccess, TestCreateProfile(&manager_, kUserProfile)); |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kUserProfile)); |
| KeyValueStore config = GetConfig(tethering_manager_); |
| SetDownstream(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Log out user and check a new SSID and passphrase is generated. |
| EXPECT_EQ(Error::kSuccess, TestPopProfile(&manager_, kUserProfile)); |
| KeyValueStore default_config = GetConfig(tethering_manager_); |
| EXPECT_NE(GetConfigSSID(config), GetConfigSSID(default_config)); |
| EXPECT_NE(GetConfigPassphrase(config), GetConfigPassphrase(default_config)); |
| // Log out user should also stop active tethering session and put tethering |
| // state to idle. |
| CheckTetheringIdle(tethering_manager_); |
| |
| // Log in user and check the tethering config matches. |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kUserProfile)); |
| KeyValueStore new_config = GetConfig(tethering_manager_); |
| EXPECT_EQ(GetConfigMAR(config), GetConfigMAR(new_config)); |
| EXPECT_EQ(GetConfigAutoDisable(config), GetConfigAutoDisable(new_config)); |
| EXPECT_EQ(GetConfigSSID(config), GetConfigSSID(new_config)); |
| EXPECT_EQ(GetConfigPassphrase(config), GetConfigPassphrase(new_config)); |
| EXPECT_EQ(GetConfigBand(config), kBandAll); |
| EXPECT_TRUE( |
| new_config.Contains<std::string>(kTetheringConfUpstreamTechProperty)); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringConfigLoadAndUnload) { |
| std::string ssid = "757365725F73736964"; // "user_ssid" in hex |
| std::string passphrase = "user_password"; |
| |
| // Check properties of the default tethering configuration. |
| VerifyDefaultTetheringConfig(tethering_manager_); |
| |
| // Prepare faked tethering configuration stored for a fake user profile. |
| FakeStore store; |
| store.SetBool(TetheringManager::kStorageId, kTetheringConfAutoDisableProperty, |
| true); |
| store.SetBool(TetheringManager::kStorageId, kTetheringConfMARProperty, true); |
| store.SetString(TetheringManager::kStorageId, kTetheringConfSSIDProperty, |
| ssid); |
| store.SetString(TetheringManager::kStorageId, |
| kTetheringConfPassphraseProperty, passphrase); |
| store.SetString(TetheringManager::kStorageId, kTetheringConfSecurityProperty, |
| kSecurityWpa3); |
| store.SetString(TetheringManager::kStorageId, kTetheringConfBandProperty, |
| kBand5GHz); |
| store.SetString(TetheringManager::kStorageId, |
| kTetheringConfUpstreamTechProperty, kTypeCellular); |
| scoped_refptr<MockProfile> profile = |
| new MockProfile(&manager_, "~user/profile0"); |
| EXPECT_CALL(*profile, GetConstStorage()).WillRepeatedly(Return(&store)); |
| |
| // Check faked properties are loaded. |
| tethering_manager_->LoadConfigFromProfile(profile); |
| KeyValueStore caps = GetConfig(tethering_manager_); |
| EXPECT_TRUE(GetConfigMAR(caps)); |
| EXPECT_TRUE(GetConfigAutoDisable(caps)); |
| EXPECT_EQ(ssid, GetConfigSSID(caps)); |
| EXPECT_EQ(passphrase, GetConfigPassphrase(caps)); |
| EXPECT_EQ(kSecurityWpa3, GetConfigSecurity(caps)); |
| EXPECT_EQ(kBand5GHz, GetConfigBand(caps)); |
| EXPECT_EQ(kTypeCellular, GetConfigUpstream(caps)); |
| |
| // Check the tethering config is reset to default properties when unloading |
| // the profile. |
| tethering_manager_->UnloadConfigFromProfile(); |
| caps = VerifyDefaultTetheringConfig(tethering_manager_); |
| EXPECT_NE(ssid, caps.Get<std::string>(kTetheringConfSSIDProperty)); |
| EXPECT_NE(passphrase, |
| caps.Get<std::string>(kTetheringConfPassphraseProperty)); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringConfigSaveAndLoad) { |
| // Load a fake tethering configuration. |
| KeyValueStore config1 = |
| GenerateFakeConfig("757365725F73736964", "user_password"); |
| FromProperties(tethering_manager_, config1); |
| |
| // Save the fake tethering configuration |
| FakeStore store; |
| SaveConfig(tethering_manager_, &store); |
| |
| // Force the default configuration to change by unloading the profile. |
| tethering_manager_->UnloadConfigFromProfile(); |
| |
| // Reload the configuration |
| scoped_refptr<MockProfile> profile = |
| new MockProfile(&manager_, "~user/profile0"); |
| EXPECT_CALL(*profile, GetConstStorage()).WillRepeatedly(Return(&store)); |
| tethering_manager_->LoadConfigFromProfile(profile); |
| |
| // Check that the configurations are identical |
| KeyValueStore config2 = GetConfig(tethering_manager_); |
| EXPECT_EQ(GetConfigMAR(config1), GetConfigMAR(config2)); |
| EXPECT_EQ(GetConfigAutoDisable(config1), GetConfigAutoDisable(config2)); |
| EXPECT_EQ(GetConfigSSID(config1), GetConfigSSID(config2)); |
| EXPECT_EQ(GetConfigPassphrase(config1), GetConfigPassphrase(config2)); |
| EXPECT_EQ(GetConfigBand(config1), GetConfigBand(config2)); |
| EXPECT_EQ(GetConfigUpstream(config1), GetConfigUpstream(config2)); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringIsNotAllowed) { |
| // Fake Tethering configuration. |
| KeyValueStore config = |
| GenerateFakeConfig("757365725F73736964", "user_password"); |
| |
| // Push a user profile |
| ASSERT_TRUE(base::CreateDirectory(temp_dir_.GetPath().Append("user"))); |
| ASSERT_EQ(Error::kSuccess, TestCreateProfile(&manager_, kUserProfile)); |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kUserProfile)); |
| |
| // Tethering is not allowed. SetAndPersistConfig and SetEnabled should fail |
| // with error code kNotAllowed. |
| SetAllowed(tethering_manager_, false); |
| EXPECT_FALSE(SetAndPersistConfig(tethering_manager_, config)); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kNotAllowed); |
| |
| // Tethering is allowed. SetAndPersistConfig and SetEnabled should success |
| SetAllowed(tethering_manager_, true); |
| SetDownstream(tethering_manager_); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| } |
| |
| TEST_F(TetheringManagerTest, CheckReadiness) { |
| StrictMock<base::MockOnceCallback<void(TetheringManager::EntitlementStatus)>> |
| cb; |
| KeyValueStore config = |
| GenerateFakeConfig("757365725F73736964", "user_password"); |
| |
| // Not allowed. |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL(cb, Run(TetheringManager::EntitlementStatus::kNotAllowed)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| SetAllowed(tethering_manager_, true); |
| |
| // No ethernet Device. |
| SetConfigUpstream(config, TechnologyName(Technology::kEthernet)); |
| EXPECT_TRUE(FromProperties(tethering_manager_, config)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Fake Devices: one Ethernet Device, one Cellular Device. |
| auto eth = |
| new NiceMock<MockDevice>(&manager_, "eth0", "0a:0b:0c:0d:0e:0f", 1); |
| auto cell = |
| new NiceMock<MockDevice>(&manager_, "wwan0", "a0:b0:c0:d0:e0:f0", 2); |
| ON_CALL(*eth, technology()).WillByDefault(Return(Technology::kEthernet)); |
| ON_CALL(*cell, technology()).WillByDefault(Return(Technology::kCellular)); |
| const std::vector<DeviceRefPtr> eth_devices = {eth}; |
| const std::vector<DeviceRefPtr> cell_devices = {cell}; |
| ON_CALL(manager_, FilterByTechnology(Technology::kEthernet)) |
| .WillByDefault(Return(eth_devices)); |
| ON_CALL(manager_, FilterByTechnology(Technology::kCellular)) |
| .WillByDefault(Return(cell_devices)); |
| |
| // No Service connected on Ethernet. |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Ethernet Service is not connected. |
| auto service(new MockService(&manager_)); |
| eth->set_selected_service_for_testing(service); |
| EXPECT_CALL(*service, IsConnected(_)).WillRepeatedly(Return(false)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Service connected on Ethernet |
| EXPECT_CALL(*service, IsConnected(_)).WillRepeatedly(Return(true)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL(cb, Run(TetheringManager::EntitlementStatus::kReady)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Cellular upstream. |
| SetConfigUpstream(config, TechnologyName(Technology::kCellular)); |
| EXPECT_TRUE(FromProperties(tethering_manager_, config)); |
| cell->set_selected_service_for_testing(service); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL(cb, Run(TetheringManager::EntitlementStatus::kReady)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| } |
| |
| TEST_F(TetheringManagerTest, SetEnabledResultName) { |
| EXPECT_EQ("success", TetheringManager::SetEnabledResultName( |
| TetheringManager::SetEnabledResult::kSuccess)); |
| EXPECT_EQ("failure", TetheringManager::SetEnabledResultName( |
| TetheringManager::SetEnabledResult::kFailure)); |
| EXPECT_EQ("not_allowed", |
| TetheringManager::SetEnabledResultName( |
| TetheringManager::SetEnabledResult::kNotAllowed)); |
| EXPECT_EQ("invalid_properties", |
| TetheringManager::SetEnabledResultName( |
| TetheringManager::SetEnabledResult::kInvalidProperties)); |
| EXPECT_EQ( |
| "upstream_not_available", |
| TetheringManager::SetEnabledResultName( |
| TetheringManager::SetEnabledResult::kUpstreamNetworkNotAvailable)); |
| } |
| |
| TEST_F(TetheringManagerTest, StartTetheringSession) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(*wifi_provider_, CreateHotspotDevice(_, _, _, _)) |
| .WillOnce(Return(hotspot_device_)); |
| EXPECT_CALL(*hotspot_device_.get(), ConfigureService(_)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(manager_, TetheringStatusChanged(_)).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // On service up with device event. |
| SetDownstream(tethering_manager_); |
| EXPECT_CALL(manager_, TetheringStatusChanged(_)).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kServiceUp, |
| hotspot_device_.get()); |
| VerifyResult(TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| } |
| |
| TEST_F(TetheringManagerTest, FailToCreateLocalInterface) { |
| TetheringPrerequisite(tethering_manager_); |
| EXPECT_CALL(*wifi_provider_, CreateHotspotDevice(_, _, _, _)) |
| .WillOnce(Return(nullptr)); |
| EXPECT_CALL(*hotspot_device_.get(), ConfigureService(_)).Times(0); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kFailure); |
| CheckTetheringIdle(tethering_manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, FailToConfigureService) { |
| TetheringPrerequisite(tethering_manager_); |
| EXPECT_CALL(*wifi_provider_, CreateHotspotDevice(_, _, _, _)) |
| .WillOnce(Return(hotspot_device_)); |
| EXPECT_CALL(*hotspot_device_.get(), ConfigureService(_)) |
| .WillOnce(Return(false)); |
| EXPECT_CALL(*hotspot_device_.get(), DeconfigureService()) |
| .WillOnce(Return(true)); |
| |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kFailure); |
| CheckTetheringIdle(tethering_manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, StopTetheringSession) { |
| TetheringPrerequisite(tethering_manager_); |
| SetDownstream(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| EXPECT_CALL(*hotspot_device_.get(), DeconfigureService()) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*wifi_provider_, DeleteLocalDevice(_)).Times(1); |
| EXPECT_CALL(manager_, TetheringStatusChanged(_)).Times(1); |
| SetEnabledVerifyResult(tethering_manager_, false, |
| TetheringManager::SetEnabledResult::kSuccess); |
| CheckTetheringIdle(tethering_manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, DeviceEventInterfaceDisabled) { |
| TetheringPrerequisite(tethering_manager_); |
| SetDownstream(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| EXPECT_CALL(*hotspot_device_.get(), DeconfigureService()) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*wifi_provider_, DeleteLocalDevice(_)).Times(1); |
| EXPECT_CALL(manager_, TetheringStatusChanged(_)).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kInterfaceDisabled, |
| hotspot_device_.get()); |
| DispatchPendingEvents(); |
| CheckTetheringIdle(tethering_manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, DeviceEventServiceDown) { |
| TetheringPrerequisite(tethering_manager_); |
| SetDownstream(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| EXPECT_CALL(*hotspot_device_.get(), DeconfigureService()) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*wifi_provider_, DeleteLocalDevice(_)).Times(1); |
| EXPECT_CALL(manager_, TetheringStatusChanged(_)).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kServiceDown, |
| hotspot_device_.get()); |
| DispatchPendingEvents(); |
| CheckTetheringIdle(tethering_manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, InterfaceDisabledWhenTetheringIsStarting) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(*wifi_provider_, CreateHotspotDevice(_, _, _, _)) |
| .WillOnce(Return(hotspot_device_)); |
| EXPECT_CALL(*hotspot_device_.get(), ConfigureService(_)) |
| .WillOnce(Return(true)); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| SetDownstream(tethering_manager_); |
| EXPECT_CALL(*hotspot_device_.get(), DeconfigureService()) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*wifi_provider_, DeleteLocalDevice(_)).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kInterfaceDisabled, |
| hotspot_device_.get()); |
| VerifyResult(TetheringManager::SetEnabledResult::kFailure); |
| CheckTetheringIdle(tethering_manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, DeviceEventPeerConnectedDisconnected) { |
| TetheringPrerequisite(tethering_manager_); |
| SetDownstream(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged(_)).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kPeerConnected, |
| hotspot_device_.get()); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged(_)).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kPeerDisconnected, |
| hotspot_device_.get()); |
| } |
| |
| TEST_F(TetheringManagerTest, GetStatus) { |
| // Check tethering status when idle. |
| auto status = GetStatus(tethering_manager_); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusStateProperty), |
| kTetheringStateIdle); |
| EXPECT_FALSE( |
| status.Contains<std::string>(kTetheringStatusUpstreamTechProperty)); |
| EXPECT_FALSE( |
| status.Contains<std::string>(kTetheringStatusDownstreamTechProperty)); |
| EXPECT_FALSE(status.Contains<Stringmaps>(kTetheringStatusClientsProperty)); |
| |
| // Enabled tethering. |
| TetheringPrerequisite(tethering_manager_); |
| SetDownstream(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| status = GetStatus(tethering_manager_); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusStateProperty), |
| kTetheringStateActive); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusUpstreamTechProperty), |
| kTypeCellular); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusDownstreamTechProperty), |
| kTypeWifi); |
| EXPECT_EQ(status.Get<Stringmaps>(kTetheringStatusClientsProperty).size(), 0); |
| |
| // Connect 2 clients. |
| std::vector<std::vector<uint8_t>> clients; |
| clients.push_back({00, 11, 22, 33, 44, 55}); |
| clients.push_back({00, 11, 22, 33, 44, 66}); |
| EXPECT_CALL(*hotspot_device_.get(), GetStations()).WillOnce(Return(clients)); |
| status = GetStatus(tethering_manager_); |
| EXPECT_EQ(status.Get<Stringmaps>(kTetheringStatusClientsProperty).size(), 2); |
| |
| // Stop tethering. |
| ON_CALL(*hotspot_device_.get(), DeconfigureService()) |
| .WillByDefault(Return(true)); |
| SetEnabledVerifyResult(tethering_manager_, false, |
| TetheringManager::SetEnabledResult::kSuccess); |
| status = GetStatus(tethering_manager_); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusStateProperty), |
| kTetheringStateIdle); |
| EXPECT_FALSE( |
| status.Contains<std::string>(kTetheringStatusUpstreamTechProperty)); |
| EXPECT_FALSE( |
| status.Contains<std::string>(kTetheringStatusDownstreamTechProperty)); |
| EXPECT_FALSE(status.Contains<Stringmaps>(kTetheringStatusClientsProperty)); |
| } |
| |
| } // namespace shill |