| // 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 <sys/socket.h> |
| |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/cancelable_callback.h> |
| #include <base/containers/contains.h> |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_file.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <base/test/mock_callback.h> |
| #include <chromeos/dbus/shill/dbus-constants.h> |
| #include <chromeos/patchpanel/dbus/fake_client.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <net-base/http_url.h> |
| |
| #include "shill/cellular/cellular_service_provider.h" |
| #include "shill/cellular/mock_cellular.h" |
| #include "shill/cellular/mock_cellular_service.h" |
| #include "shill/cellular/mock_cellular_service_provider.h" |
| #include "shill/cellular/mock_modem_info.h" |
| #include "shill/error.h" |
| #include "shill/ethernet/mock_ethernet_provider.h" |
| #include "shill/http_request.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/network/mock_network.h" |
| #include "shill/portal_detector.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_wifi.h" |
| #include "shill/wifi/mock_wifi_phy.h" |
| #include "shill/wifi/mock_wifi_provider.h" |
| |
| using testing::_; |
| using testing::DoAll; |
| using testing::DoDefault; |
| using testing::Eq; |
| using testing::Invoke; |
| using testing::Mock; |
| using testing::NiceMock; |
| using testing::Not; |
| using testing::Return; |
| using testing::StrictMock; |
| using testing::Test; |
| using testing::WithArg; |
| |
| namespace shill { |
| namespace { |
| |
| // Fake profile identities |
| constexpr char kDefaultProfile[] = "default"; |
| constexpr char kUserProfile[] = "~user/profile"; |
| constexpr uint32_t kPhyIndex = 5678; |
| constexpr int kTestInterfaceIndex = 3; |
| constexpr char kTestInterfaceName[] = "wwan0"; |
| constexpr char kTestDownstreamDeviceForTest[] = "wlan5"; |
| constexpr uint32_t kTestDownstreamPhyIndexForTest = 5; |
| |
| // The value below is "testAP-0000" in hex; |
| constexpr char kTestAPHexSSID[] = "7465737441502d30303030"; |
| constexpr char kTestPassword[] = "user_password"; |
| |
| 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); |
| } |
| std::string GetConfigDownstreamDeviceForTest(const KeyValueStore& caps) { |
| return caps.Get<std::string>(kTetheringConfDownstreamDeviceForTestProperty); |
| } |
| uint32_t GetConfigDownstreamPhyIndexForTest(const KeyValueStore& caps) { |
| return caps.Get<uint32_t>(kTetheringConfDownstreamPhyIndexForTestProperty); |
| } |
| 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); |
| } |
| void SetConfigDownstreamDeviceForTest(KeyValueStore& caps, |
| const std::string& value) { |
| caps.Set<std::string>(kTetheringConfDownstreamDeviceForTestProperty, value); |
| } |
| void SetConfigDownstreamPhyIndexForTest(KeyValueStore& caps, uint32_t value) { |
| caps.Set<uint32_t>(kTetheringConfDownstreamPhyIndexForTestProperty, value); |
| } |
| |
| base::ScopedTempDir MakeTempDir() { |
| base::ScopedTempDir temp_dir; |
| EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); |
| return temp_dir; |
| } |
| |
| class MockPatchpanelClient : public patchpanel::FakeClient { |
| public: |
| MockPatchpanelClient() = default; |
| ~MockPatchpanelClient() override = default; |
| |
| MOCK_METHOD(bool, |
| CreateTetheredNetwork, |
| (const std::string&, |
| const std::string&, |
| const std::optional<DHCPOptions>&, |
| const std::optional<UplinkIPv6Configuration>&, |
| const std::optional<int>& mtu, |
| patchpanel::Client::CreateTetheredNetworkCallback), |
| (override)); |
| }; |
| |
| base::ScopedFD MakeFd() { |
| return base::ScopedFD(socket(AF_INET, SOCK_DGRAM, 0)); |
| } |
| |
| } // namespace |
| |
| class TetheringManagerTest : public testing::Test { |
| public: |
| TetheringManagerTest() |
| : temp_dir_(MakeTempDir()), |
| path_(temp_dir_.GetPath().value()), |
| manager_( |
| &control_interface_, &dispatcher_, &metrics_, path_, path_, path_), |
| modem_info_(&control_interface_, &manager_), |
| tethering_manager_(manager_.tethering_manager()), |
| wifi_provider_(new NiceMock<MockWiFiProvider>(&manager_)), |
| ethernet_provider_(new NiceMock<MockEthernetProvider>()), |
| cellular_service_provider_( |
| new NiceMock<MockCellularServiceProvider>(&manager_)), |
| upstart_(new NiceMock<MockUpstart>(&control_interface_)), |
| hotspot_device_(new NiceMock<MockHotspotDevice>( |
| &manager_, "wlan0", "ap0", "", 0, event_cb_.Get())), |
| network_(new MockNetwork( |
| kTestInterfaceIndex, kTestInterfaceName, Technology::kCellular)), |
| service_(new MockService(&manager_)), |
| wifi_phy_(hotspot_device_->phy_index()) { |
| // Replace the Manager's WiFi provider with a mock. |
| manager_.wifi_provider_.reset(wifi_provider_); |
| // Replace the Manager's Ethernet provider with a mock. |
| manager_.ethernet_provider_.reset(ethernet_provider_); |
| // Replace the Manager's Cellular provider with a mock. |
| manager_.cellular_service_provider_.reset(cellular_service_provider_); |
| // Update the Manager's map from technology to provider. |
| manager_.UpdateProviderMapping(); |
| // Replace the Manager's upstart instance with a mock. |
| manager_.upstart_.reset(upstart_); |
| // Replace the Manager's patchpanel DBus client with a mock. |
| auto patchpanel = std::make_unique<MockPatchpanelClient>(); |
| patchpanel_ = patchpanel.get(); |
| manager_.set_patchpanel_client_for_testing(std::move(patchpanel)); |
| |
| ON_CALL(manager_, cellular_service_provider()) |
| .WillByDefault(Return(cellular_service_provider_)); |
| cellular_profile_ = new NiceMock<MockProfile>(&manager_); |
| cellular_service_provider_->set_profile_for_testing(cellular_profile_); |
| ON_CALL(manager_, modem_info()).WillByDefault(Return(&modem_info_)); |
| ON_CALL(*wifi_provider_, CreateHotspotDevice) |
| .WillByDefault(Return(hotspot_device_)); |
| ON_CALL(*hotspot_device_.get(), ConfigureService(_)) |
| .WillByDefault(Return(true)); |
| ON_CALL(*hotspot_device_.get(), DeconfigureService()) |
| .WillByDefault(Return(true)); |
| ON_CALL(*hotspot_device_.get(), IsServiceUp()).WillByDefault(Return(true)); |
| ON_CALL(*cellular_service_provider_, AcquireTetheringNetwork(_, _, _, _)) |
| .WillByDefault(Return()); |
| ON_CALL(*cellular_service_provider_, ReleaseTetheringNetwork(_, _)) |
| .WillByDefault(Return()); |
| ON_CALL(*network_, IsConnected()).WillByDefault(Return(true)); |
| ON_CALL(*wifi_provider_, GetPhyAtIndex(hotspot_device_->phy_index())) |
| .WillByDefault(Return(&wifi_phy_)); |
| wifi_phy_.SetFrequencies( |
| {{0, {{.value = 2412}, {.value = 2432}, {.value = 2437}}}, |
| {1, {{.value = 5220}, {.value = 5240}}}}); |
| } |
| ~TetheringManagerTest() override = default; |
| |
| scoped_refptr<MockCellular> MakeCellular(const std::string& link_name, |
| const std::string& address, |
| int interface_index) { |
| return new NiceMock<MockCellular>(&manager_, link_name, address, |
| interface_index, "", RpcIdentifier("")); |
| } |
| |
| 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_); |
| EXPECT_TRUE(GetStartTimer(tethering_manager_).IsCancelled()); |
| } |
| |
| void SetEnabledVerifyResult( |
| TetheringManager* tethering_manager, |
| bool enabled, |
| TetheringManager::SetEnabledResult expected_result) { |
| SetEnabled(tethering_manager, enabled); |
| if (enabled) { |
| ON_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "wwan0", _, _, _, _)) |
| .WillByDefault(Return(true)); |
| // Send upstream downstream ready events. |
| DownStreamDeviceEvent(tethering_manager, |
| LocalDevice::DeviceEvent::kInterfaceEnabled, |
| hotspot_device_.get()); |
| DownStreamDeviceEvent(tethering_manager, |
| LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| OnDownstreamNetworkReady(tethering_manager_, MakeFd()); |
| } else { |
| // Send upstream tear down event |
| OnUpstreamNetworkReleased(tethering_manager_, true); |
| } |
| 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).has_value(); |
| } |
| |
| KeyValueStore VerifyDefaultTetheringConfig( |
| TetheringManager* tethering_manager) { |
| KeyValueStore caps = GetConfig(tethering_manager); |
| EXPECT_TRUE(GetConfigMAR(caps)); |
| EXPECT_TRUE(tethering_manager->stable_mac_addr_.is_set()); |
| EXPECT_TRUE(GetConfigAutoDisable(caps)); |
| EXPECT_FALSE(tethering_manager_->experimental_tethering_functionality_); |
| 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)); |
| EXPECT_FALSE(caps.Contains<std::string>( |
| kTetheringConfDownstreamDeviceForTestProperty)); |
| EXPECT_FALSE(caps.Contains<uint32_t>( |
| kTetheringConfDownstreamPhyIndexForTestProperty)); |
| return caps; |
| } |
| |
| KeyValueStore GenerateFakeConfig( |
| const std::string& ssid, |
| const std::string passphrase, |
| const std::optional<std::string> downstream_device_for_test = |
| std::nullopt, |
| const std::optional<uint32_t> downstream_phy_index_for_test = |
| std::nullopt) { |
| KeyValueStore config; |
| SetConfigMAR(config, false); |
| SetConfigAutoDisable(config, false); |
| SetConfigSSID(config, ssid); |
| SetConfigPassphrase(config, passphrase); |
| SetConfigSecurity(config, kSecurityWpa3); |
| SetConfigBand(config, kBand2GHz); |
| SetConfigUpstream(config, kTypeCellular); |
| if (downstream_device_for_test) { |
| SetConfigDownstreamDeviceForTest(config, *downstream_device_for_test); |
| EXPECT_NE(downstream_phy_index_for_test, std::nullopt); |
| SetConfigDownstreamPhyIndexForTest(config, |
| *downstream_phy_index_for_test); |
| } |
| 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 DownStreamDeviceEvent(TetheringManager* tethering_manager, |
| LocalDevice::DeviceEvent event, |
| LocalDevice* device) { |
| tethering_manager->OnDownstreamDeviceEvent(event, device); |
| } |
| |
| void OnCellularUpstreamEvent(TetheringManager* tethering_manager, |
| TetheringManager::CellularUpstreamEvent event) { |
| tethering_manager->OnCellularUpstreamEvent(event); |
| } |
| |
| TetheringManager::TetheringState TetheringState( |
| TetheringManager* tethering_manager) { |
| return tethering_manager->state_; |
| } |
| |
| std::string StopReason(TetheringManager* tethering_manager) { |
| return TetheringManager::StopReasonToString( |
| tethering_manager->stop_reason_); |
| } |
| |
| void CheckTetheringStopping(TetheringManager* tethering_manager, |
| const char* reason) { |
| EXPECT_EQ(TetheringState(tethering_manager), |
| TetheringManager::TetheringState::kTetheringStopping); |
| EXPECT_EQ(StopReason(tethering_manager), reason); |
| } |
| |
| void CheckTetheringIdle(TetheringManager* tethering_manager, |
| const char* reason) { |
| EXPECT_EQ(tethering_manager->hotspot_dev_, nullptr); |
| EXPECT_EQ(TetheringState(tethering_manager), |
| TetheringManager::TetheringState::kTetheringIdle); |
| auto status = GetStatus(tethering_manager); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusIdleReasonProperty), |
| reason); |
| EXPECT_TRUE(GetStartTimer(tethering_manager_).IsCancelled()); |
| EXPECT_TRUE(GetStopTimer(tethering_manager_).IsCancelled()); |
| } |
| |
| KeyValueStore GetStatus(TetheringManager* tethering_manager) { |
| return tethering_manager->GetStatus(); |
| } |
| |
| void OnStartingTetheringTimeout(TetheringManager* tethering_manager) { |
| tethering_manager->OnStartingTetheringTimeout(); |
| } |
| |
| void OnStartingTetheringUpdateTimeout(TetheringManager* tethering_manager, |
| base::TimeDelta timeout) { |
| tethering_manager->OnStartingTetheringUpdateTimeout(timeout); |
| } |
| |
| void OnStoppingTetheringTimeout(TetheringManager* tethering_manager) { |
| tethering_manager->OnStoppingTetheringTimeout(); |
| } |
| |
| const base::CancelableOnceClosure& GetStartTimer( |
| TetheringManager* tethering_manager) { |
| return tethering_manager->start_timer_callback_; |
| } |
| |
| const base::CancelableOnceClosure& GetStopTimer( |
| TetheringManager* tethering_manager) { |
| return tethering_manager->stop_timer_callback_; |
| } |
| |
| const base::CancelableOnceClosure& GetInactiveTimer( |
| TetheringManager* tethering_manager) { |
| return tethering_manager->inactive_timer_callback_; |
| } |
| |
| void AddServiceToCellularProvider(CellularServiceRefPtr service) { |
| cellular_service_provider_->AddService(service); |
| } |
| |
| void OnDownstreamNetworkReady(TetheringManager* tethering_manager, |
| base::ScopedFD fd) { |
| tethering_manager->OnDownstreamNetworkReady(std::move(fd)); |
| } |
| |
| void OnUpstreamNetworkAcquired(TetheringManager* tethering_manager, |
| TetheringManager::SetEnabledResult result) { |
| tethering_manager->OnUpstreamNetworkAcquired(result, network_.get(), |
| service_.get()); |
| } |
| |
| void OnUpstreamNetworkReleased(TetheringManager* tethering_manager, |
| bool success) { |
| tethering_manager->OnUpstreamNetworkReleased(success); |
| } |
| |
| void OnUpstreamNetworkStopped(TetheringManager* tethering_manager) { |
| tethering_manager->OnNetworkStopped(kTestInterfaceIndex, false); |
| } |
| |
| void OnUpstreamNetworkDestroyed(TetheringManager* tethering_manager) { |
| tethering_manager->OnNetworkDestroyed(kTestInterfaceIndex); |
| } |
| |
| void OnUpstreamNetworkValidationResult(TetheringManager* tethering_manager, |
| const PortalDetector::Result& result) { |
| tethering_manager->OnNetworkValidationResult(kTestInterfaceIndex, result); |
| } |
| |
| 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_; |
| MockModemInfo modem_info_; |
| MockPatchpanelClient* patchpanel_; |
| TetheringManager* tethering_manager_; |
| MockWiFiProvider* wifi_provider_; |
| MockEthernetProvider* ethernet_provider_; |
| scoped_refptr<NiceMock<MockProfile>> cellular_profile_; |
| MockCellularServiceProvider* cellular_service_provider_; |
| MockUpstart* upstart_; |
| scoped_refptr<MockHotspotDevice> hotspot_device_; |
| std::unique_ptr<MockNetwork> network_; |
| scoped_refptr<MockService> service_; |
| MockWiFiPhy wifi_phy_; |
| }; |
| |
| TEST_F(TetheringManagerTest, GetTetheringCapabilities) { |
| std::unique_ptr<NiceMock<MockWiFiPhy>> phy( |
| new NiceMock<MockWiFiPhy>(kPhyIndex)); |
| const std::vector<const WiFiPhy*> phys = {phy.get()}; |
| ON_CALL(*wifi_provider_, GetPhys()).WillByDefault(Return(phys)); |
| ON_CALL(*phy, SupportAPMode()).WillByDefault(Return(true)); |
| ON_CALL(*phy, SupportAPSTAConcurrency()).WillByDefault(Return(true)); |
| EXPECT_CALL(*cellular_service_provider_, HardwareSupportsTethering(_)) |
| .WillOnce(Return(true)); |
| 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)); |
| EXPECT_CALL(*cellular_service_provider_, HardwareSupportsTethering(_)) |
| .WillOnce(Return(true)); |
| 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, GetTetheringCapabilitiesWithoutCellular) { |
| std::unique_ptr<NiceMock<MockWiFiPhy>> phy( |
| new NiceMock<MockWiFiPhy>(kPhyIndex)); |
| const std::vector<const WiFiPhy*> phys = {phy.get()}; |
| ON_CALL(*wifi_provider_, GetPhys()).WillByDefault(Return(phys)); |
| ON_CALL(*phy, SupportAPMode()).WillByDefault(Return(true)); |
| ON_CALL(*phy, SupportAPSTAConcurrency()).WillByDefault(Return(true)); |
| EXPECT_CALL(*cellular_service_provider_, HardwareSupportsTethering(_)) |
| .WillOnce(Return(false)); |
| 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_FALSE(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, 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. |
| KeyValueStore args = GenerateFakeConfig(kTestAPHexSSID, kTestPassword, |
| kTestDownstreamDeviceForTest, |
| kTestDownstreamPhyIndexForTest); |
| |
| // 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), kTestAPHexSSID); |
| EXPECT_EQ(GetConfigPassphrase(config), kTestPassword); |
| EXPECT_EQ(GetConfigSecurity(config), kSecurityWpa3); |
| EXPECT_EQ(GetConfigBand(config), kBand2GHz); |
| EXPECT_EQ(GetConfigUpstream(config), kTypeCellular); |
| EXPECT_EQ(GetConfigDownstreamDeviceForTest(config), |
| kTestDownstreamDeviceForTest); |
| EXPECT_EQ(GetConfigDownstreamPhyIndexForTest(config), |
| kTestDownstreamPhyIndexForTest); |
| |
| // 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), kTestAPHexSSID); |
| EXPECT_NE(GetConfigPassphrase(default_config), kTestPassword); |
| |
| // 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), kTestAPHexSSID); |
| EXPECT_EQ(GetConfigPassphrase(config), kTestPassword); |
| EXPECT_EQ(GetConfigSecurity(config), kSecurityWpa3); |
| EXPECT_EQ(GetConfigBand(config), kBand2GHz); |
| EXPECT_EQ(GetConfigUpstream(config), kTypeCellular); |
| |
| // These properties are only used for testing, should not be persisted. |
| EXPECT_FALSE( |
| config.ContainsVariant(kTetheringConfDownstreamDeviceForTestProperty)); |
| EXPECT_FALSE( |
| config.ContainsVariant(kTetheringConfDownstreamPhyIndexForTestProperty)); |
| } |
| |
| TEST_F(TetheringManagerTest, DefaultConfigCheck) { |
| SetAllowed(tethering_manager_, true); |
| // SetEnabled proceed to starting state and persist the default config. |
| 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_); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // 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)); |
| EXPECT_FALSE(default_config.ContainsVariant( |
| kTetheringConfDownstreamDeviceForTestProperty)); |
| EXPECT_FALSE(default_config.ContainsVariant( |
| kTetheringConfDownstreamPhyIndexForTestProperty)); |
| |
| // 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)); |
| EXPECT_FALSE(new_config.ContainsVariant( |
| kTetheringConfDownstreamDeviceForTestProperty)); |
| EXPECT_FALSE(new_config.ContainsVariant( |
| kTetheringConfDownstreamPhyIndexForTestProperty)); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringConfigLoadAndUnload) { |
| // 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); |
| MACAddress mac; |
| mac.Randomize(); |
| mac.Save(&store, TetheringManager::kStorageId); |
| store.SetString(TetheringManager::kStorageId, kTetheringConfSSIDProperty, |
| kTestAPHexSSID); |
| store.SetString(TetheringManager::kStorageId, |
| kTetheringConfPassphraseProperty, kTestPassword); |
| store.SetString(TetheringManager::kStorageId, kTetheringConfSecurityProperty, |
| kSecurityWpa3); |
| store.SetString(TetheringManager::kStorageId, kTetheringConfBandProperty, |
| kBand5GHz); |
| store.SetString(TetheringManager::kStorageId, |
| kTetheringConfUpstreamTechProperty, kTypeCellular); |
| store.SetString(TetheringManager::kStorageId, |
| kTetheringConfDownstreamDeviceForTestProperty, "wlan5"); |
| store.SetUint64(TetheringManager::kStorageId, |
| kTetheringConfDownstreamPhyIndexForTestProperty, 5); |
| 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_EQ(tethering_manager_->stable_mac_addr_, mac); |
| EXPECT_TRUE(GetConfigAutoDisable(caps)); |
| EXPECT_EQ(kTestAPHexSSID, GetConfigSSID(caps)); |
| EXPECT_EQ(kTestPassword, GetConfigPassphrase(caps)); |
| EXPECT_EQ(kSecurityWpa3, GetConfigSecurity(caps)); |
| EXPECT_EQ(kBand5GHz, GetConfigBand(caps)); |
| EXPECT_EQ(kTypeCellular, GetConfigUpstream(caps)); |
| |
| // These properties should not be loaded from persisted storage, because they |
| // are only for testing. |
| EXPECT_FALSE( |
| caps.ContainsVariant(kTetheringConfDownstreamDeviceForTestProperty)); |
| EXPECT_FALSE( |
| caps.ContainsVariant(kTetheringConfDownstreamPhyIndexForTestProperty)); |
| |
| // Check the tethering config is reset to default properties when unloading |
| // the profile. |
| tethering_manager_->UnloadConfigFromProfile(); |
| caps = VerifyDefaultTetheringConfig(tethering_manager_); |
| EXPECT_NE(kTestAPHexSSID, caps.Get<std::string>(kTetheringConfSSIDProperty)); |
| EXPECT_NE(kTestPassword, |
| caps.Get<std::string>(kTetheringConfPassphraseProperty)); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringConfigSaveAndLoad) { |
| // Load a fake tethering configuration. |
| KeyValueStore config1 = GenerateFakeConfig(kTestAPHexSSID, kTestPassword, |
| kTestDownstreamDeviceForTest, |
| kTestDownstreamPhyIndexForTest); |
| FromProperties(tethering_manager_, config1); |
| |
| // Save the fake tethering configuration |
| FakeStore store; |
| SaveConfig(tethering_manager_, &store); |
| |
| // These properties should not be saved to persisted storage, because they are |
| // only for testing. |
| EXPECT_FALSE(store.GetString(TetheringManager::kStorageId, |
| kTetheringConfDownstreamDeviceForTestProperty, |
| nullptr)); |
| EXPECT_FALSE(store.GetUint64(TetheringManager::kStorageId, |
| kTetheringConfDownstreamPhyIndexForTestProperty, |
| nullptr)); |
| |
| // 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(kTestAPHexSSID, kTestPassword); |
| |
| // 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); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringInDefaultProfile) { |
| 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); |
| } |
| |
| TEST_F(TetheringManagerTest, CheckReadinessNotAllowed) { |
| base::MockOnceCallback<void(TetheringManager::EntitlementStatus)> cb; |
| KeyValueStore config = GenerateFakeConfig(kTestAPHexSSID, kTestPassword); |
| |
| // Not allowed. |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL(cb, Run(TetheringManager::EntitlementStatus::kNotAllowed)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| } |
| |
| TEST_F(TetheringManagerTest, CheckReadinessCellularUpstream) { |
| base::MockOnceCallback<void(TetheringManager::EntitlementStatus)> cb; |
| KeyValueStore config = |
| GenerateFakeConfig("757365725F73736964", "user_password"); |
| SetConfigUpstream(config, TechnologyName(Technology::kCellular)); |
| SetAllowed(tethering_manager_, true); |
| EXPECT_TRUE(FromProperties(tethering_manager_, config)); |
| |
| // No cellular Device. |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Set one fake ethernet Device. |
| auto eth = |
| new NiceMock<MockDevice>(&manager_, "eth0", "0a:0b:0c:0d:0e:0f", 1); |
| ON_CALL(*eth, technology()).WillByDefault(Return(Technology::kEthernet)); |
| const std::vector<DeviceRefPtr> eth_devices = {eth}; |
| ON_CALL(manager_, FilterByTechnology(Technology::kEthernet)) |
| .WillByDefault(Return(eth_devices)); |
| auto eth_service(new MockService(&manager_)); |
| eth->set_selected_service_for_testing(eth_service); |
| |
| // Set one fake cellular Device. |
| auto cell = MakeCellular("wwan0", "000102030405", 2); |
| const std::vector<DeviceRefPtr> cell_devices = {cell}; |
| ON_CALL(manager_, FilterByTechnology(Technology::kCellular)) |
| .WillByDefault(Return(cell_devices)); |
| scoped_refptr<MockCellularService> cell_service = |
| new MockCellularService(&manager_, cell); |
| AddServiceToCellularProvider(cell_service); |
| cell->set_selected_service_for_testing(cell_service); |
| |
| // Both Ethernet Service and Cellular Service are disconnected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(false)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateIdle)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Ethernet Service is connected, Cellular Service is disconnected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateIdle)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Ethernet Service is disconnected, Cellular Service is connected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(false)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateConnected)); |
| EXPECT_CALL(*cellular_service_provider_, TetheringEntitlementCheck(_, _)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| Mock::VerifyAndClearExpectations(cellular_service_provider_); |
| |
| // Both Ethernet Service and Cellular Service are connected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateConnected)); |
| EXPECT_CALL(*cellular_service_provider_, TetheringEntitlementCheck(_, _)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| DispatchPendingEvents(); |
| } |
| |
| TEST_F(TetheringManagerTest, CheckReadinessEthernetUpstream) { |
| base::MockOnceCallback<void(TetheringManager::EntitlementStatus)> cb; |
| KeyValueStore config = |
| GenerateFakeConfig("757365725F73736964", "user_password"); |
| SetConfigUpstream(config, TechnologyName(Technology::kEthernet)); |
| SetAllowed(tethering_manager_, true); |
| EXPECT_TRUE(FromProperties(tethering_manager_, config)); |
| |
| // No ethernet Device. |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Set one fake ethernet Device. |
| auto eth = |
| new NiceMock<MockDevice>(&manager_, "eth0", "0a:0b:0c:0d:0e:0f", 1); |
| ON_CALL(*eth, technology()).WillByDefault(Return(Technology::kEthernet)); |
| const std::vector<DeviceRefPtr> eth_devices = {eth}; |
| ON_CALL(manager_, FilterByTechnology(Technology::kEthernet)) |
| .WillByDefault(Return(eth_devices)); |
| auto eth_service(new MockService(&manager_)); |
| eth->set_selected_service_for_testing(eth_service); |
| |
| // Set one fake cellular Device. |
| auto cell = MakeCellular("wwan0", "000102030405", 2); |
| const std::vector<DeviceRefPtr> cell_devices = {cell}; |
| ON_CALL(manager_, FilterByTechnology(Technology::kCellular)) |
| .WillByDefault(Return(cell_devices)); |
| scoped_refptr<MockCellularService> cell_service = |
| new MockCellularService(&manager_, cell); |
| AddServiceToCellularProvider(cell_service); |
| cell->set_selected_service_for_testing(cell_service); |
| |
| EXPECT_CALL(*cellular_service_provider_, TetheringEntitlementCheck(_, _)) |
| .Times(0); |
| |
| // Both Ethernet Service and Cellular Service are disconnected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(false)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateIdle)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Ethernet Service is connected, Cellular Service is disconnected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateIdle)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL(cb, Run(TetheringManager::EntitlementStatus::kReady)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Ethernet Service is disconnected, Cellular Service is connected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(false)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateConnected)); |
| tethering_manager_->CheckReadiness(cb.Get()); |
| EXPECT_CALL( |
| cb, |
| Run(TetheringManager::EntitlementStatus::kUpstreamNetworkNotAvailable)); |
| DispatchPendingEvents(); |
| Mock::VerifyAndClearExpectations(&cb); |
| |
| // Both Ethernet Service and Cellular Service are connected. |
| EXPECT_CALL(*eth_service, IsConnected(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*cell_service, state()) |
| .WillRepeatedly(Return(Service::kStateConnected)); |
| 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, StartTetheringSessionSuccessWithCellularUpstream) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| EXPECT_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "wwan0", _, _, _, _)) |
| .WillOnce(Return(true)); |
| |
| // Downstream device event service up. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Upstream network fetched. |
| PortalDetector::Result portal_detector_result; |
| portal_detector_result.http_phase = PortalDetector::Phase::kContent, |
| portal_detector_result.http_status = PortalDetector::Status::kSuccess; |
| portal_detector_result.http_probe_completed = true; |
| portal_detector_result.https_probe_completed = true; |
| network_->set_portal_detector_result_for_testing(portal_detector_result); |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Tethering network created. |
| OnDownstreamNetworkReady(tethering_manager_, MakeFd()); |
| |
| VerifyResult(TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| Mock::VerifyAndClearExpectations(&manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, StartTetheringSessionSuccessWithEthernetUpstream) { |
| MockNetwork eth_network(kTestInterfaceIndex + 1, "eth0", |
| Technology::kEthernet); |
| ON_CALL(eth_network, IsConnected()).WillByDefault(Return(true)); |
| scoped_refptr<MockService> eth_service = new MockService(&manager_); |
| EXPECT_CALL(manager_, GetFirstEthernetService()) |
| .WillOnce(Return(eth_service)); |
| EXPECT_CALL(manager_, FindActiveNetworkFromService(_)) |
| .WillOnce(Return(ð_network)); |
| |
| EXPECT_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "eth0", _, _, _, _)) |
| .WillOnce(Return(true)); |
| |
| // TetheringManager will evaluate the downstream service readiness as soon as |
| // it finds the ethernet upstream network. |
| ON_CALL(*hotspot_device_.get(), IsServiceUp()).WillByDefault(Return(false)); |
| |
| // Change the upstream technology to ethernet. |
| TetheringPrerequisite(tethering_manager_); |
| KeyValueStore config = |
| GenerateFakeConfig("757365725F73736964", "user_password"); |
| SetConfigUpstream(config, TechnologyName(Technology::kEthernet)); |
| EXPECT_TRUE(FromProperties(tethering_manager_, config)); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| Mock::VerifyAndClearExpectations(&manager_); |
| |
| // Downstream device event service up. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| ON_CALL(*hotspot_device_.get(), IsServiceUp()).WillByDefault(Return(true)); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Tethering network created. |
| PortalDetector::Result portal_detector_result; |
| portal_detector_result.http_phase = PortalDetector::Phase::kContent, |
| portal_detector_result.http_status = PortalDetector::Status::kSuccess; |
| portal_detector_result.http_probe_completed = true; |
| portal_detector_result.https_probe_completed = true; |
| eth_network.set_portal_detector_result_for_testing(portal_detector_result); |
| OnDownstreamNetworkReady(tethering_manager_, MakeFd()); |
| |
| Mock::VerifyAndClearExpectations(&manager_); |
| VerifyResult(TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| } |
| |
| TEST_F(TetheringManagerTest, |
| StartTetheringSessionTetheredNetworkImmediateFailure) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| // Tethering network creation request fails. |
| EXPECT_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "wwan0", _, _, _, _)) |
| .WillOnce(Return(false)); |
| |
| // Downstream device event service up. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Upstream network fetched. |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| VerifyResult(TetheringManager::SetEnabledResult::kFailure); |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, |
| StartTetheringSessionTetheredNetworkDelayedFailure) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| EXPECT_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "wwan0", _, _, _, _)) |
| .WillOnce(Return(true)); |
| |
| // Downstream device event service up. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Upstream network fetched. |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Tethering network creation request fails |
| OnDownstreamNetworkReady(tethering_manager_, base::ScopedFD(-1)); |
| |
| VerifyResult(TetheringManager::SetEnabledResult::kFailure); |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, |
| StartTetheringSessionTetheredNetworkAlreadyStarted) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| // Tethering session is started. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| Mock::VerifyAndClearExpectations(&manager_); |
| |
| // Downstream device event service up. |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Upstream network fetched. |
| EXPECT_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "wwan0", _, _, _, _)) |
| .Times(1) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(0); |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| Mock::VerifyAndClearExpectations(&manager_); |
| |
| // Force another LocalDevice::DeviceEvent::kLinkUp event for the |
| // downstream network. |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| VerifyResult(TetheringManager::SetEnabledResult::kFailure); |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, StartTetheringSessionUpstreamNetworkNotConnected) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| Mock::VerifyAndClearExpectations(&manager_); |
| |
| // Upstream Network fetched but the the Network has disconnected. |
| EXPECT_CALL(*network_, IsConnected()).WillRepeatedly(Return(false)); |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| VerifyResult(TetheringManager::SetEnabledResult::kFailure); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, StartTetheringSessionUpstreamNetworkNotReady) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| EXPECT_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "wwan0", _, _, _, _)) |
| .WillOnce(Return(true)); |
| |
| // Downstream device event service up. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Upstream network fetched. Network has no Internet connectivity |
| PortalDetector::Result portal_detector_result; |
| network_->set_portal_detector_result_for_testing(portal_detector_result); |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Tethering network created. |
| OnDownstreamNetworkReady(tethering_manager_, MakeFd()); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| |
| // Feed network validation result event. |
| OnUpstreamNetworkValidationResult(tethering_manager_, portal_detector_result); |
| |
| // TODO(b/291845893): Normally the session is expected to fail. Change the |
| // test expectations once a new tethering session properly fails if |
| // TetheringManager cannot observe the upstream network is ready after a few |
| // network validation retries. |
| VerifyResult(TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| Mock::VerifyAndClearExpectations(&manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, StartTetheringSessionUpstreamNetworkHasPortal) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| EXPECT_CALL(*patchpanel_, CreateTetheredNetwork("ap0", "wwan0", _, _, _, _)) |
| .WillOnce(Return(true)); |
| |
| // Downstream device event service up. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Upstream network fetched. Network is in a portal state. |
| PortalDetector::Result portal_detector_result; |
| portal_detector_result.http_phase = PortalDetector::Phase::kContent, |
| portal_detector_result.http_status = PortalDetector::Status::kRedirect; |
| portal_detector_result.http_probe_completed = true; |
| portal_detector_result.https_probe_completed = true; |
| portal_detector_result.redirect_url = |
| net_base::HttpUrl::CreateFromString("https://portal.com/login"); |
| network_->set_portal_detector_result_for_testing(portal_detector_result); |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Tethering network created. |
| OnDownstreamNetworkReady(tethering_manager_, MakeFd()); |
| |
| VerifyResult(TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| Mock::VerifyAndClearExpectations(&manager_); |
| } |
| |
| 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::kDownstreamWiFiFailure); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| 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::kDownstreamWiFiFailure); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, FailToFetchUpstreamNetwork) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabled(tethering_manager_, true); |
| // Upstream network fetch failed. |
| OnUpstreamNetworkAcquired( |
| tethering_manager_, |
| TetheringManager::SetEnabledResult::kUpstreamNetworkNotAvailable); |
| VerifyResult( |
| TetheringManager::SetEnabledResult::kUpstreamNetworkNotAvailable); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, UserStopTetheringSession) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| SetEnabledVerifyResult(tethering_manager_, false, |
| TetheringManager::SetEnabledResult::kSuccess); |
| CheckTetheringIdle(tethering_manager_, kTetheringIdleReasonClientStop); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringStopWhenUserLogout) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Log out user should also stop active tethering session and put tethering |
| // state to idle. |
| EXPECT_EQ(Error::kSuccess, TestPopProfile(&manager_, kUserProfile)); |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonUserExit); |
| } |
| |
| TEST_F(TetheringManagerTest, DeviceEventInterfaceDisabled) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kInterfaceDisabled, |
| hotspot_device_.get()); |
| DispatchPendingEvents(); |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, DeviceEventServiceDown) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkDown, |
| hotspot_device_.get()); |
| DispatchPendingEvents(); |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, UpstreamNetworkStopped) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| OnUpstreamNetworkStopped(tethering_manager_); |
| CheckTetheringStopping(tethering_manager_, |
| kTetheringIdleReasonUpstreamDisconnect); |
| } |
| |
| TEST_F(TetheringManagerTest, UpstreamNetworkDestroyed) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // State change from active to stopping. |
| EXPECT_CALL(manager_, TetheringStatusChanged()); |
| OnUpstreamNetworkDestroyed(tethering_manager_); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, |
| kTetheringIdleReasonUpstreamDisconnect); |
| } |
| |
| TEST_F(TetheringManagerTest, InterfaceDisabledWhenTetheringIsStarting) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kInterfaceDisabled, |
| hotspot_device_.get()); |
| VerifyResult(TetheringManager::SetEnabledResult::kDownstreamWiFiFailure); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| // TODO(b/273975270) Re-enable this test once Internet connectivity check on the |
| // upstream network has been re-enabled in TetheringManager. |
| TEST_F(TetheringManagerTest, DISABLED_UpstreamNetworkValidationFailed) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Downstream device event service up. |
| EXPECT_CALL(manager_, TetheringStatusChanged()).Times(1); |
| DownStreamDeviceEvent(tethering_manager_, LocalDevice::DeviceEvent::kLinkUp, |
| hotspot_device_.get()); |
| |
| // Upstream network fetched. Network not ready. |
| PortalDetector::Result portal_detector_result; |
| portal_detector_result.http_phase = PortalDetector::Phase::kConnection, |
| portal_detector_result.http_status = PortalDetector::Status::kFailure; |
| portal_detector_result.https_error = HttpRequest::Error::kConnectionFailure; |
| portal_detector_result.http_probe_completed = true; |
| portal_detector_result.https_probe_completed = true; |
| OnUpstreamNetworkAcquired(tethering_manager_, |
| TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Downstream network is fully configured. Upstream network is not yet ready. |
| OnDownstreamNetworkReady(tethering_manager_, MakeFd()); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Feed network validation result event. |
| OnUpstreamNetworkValidationResult(tethering_manager_, portal_detector_result); |
| |
| VerifyResult( |
| TetheringManager::SetEnabledResult::kUpstreamNetworkWithoutInternet); |
| CheckTetheringStopping(tethering_manager_, |
| kTetheringIdleReasonUpstreamDisconnect); |
| } |
| |
| TEST_F(TetheringManagerTest, DeviceEventPeerConnectedDisconnected) { |
| TetheringPrerequisite(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()); |
| Mock::VerifyAndClearExpectations(&manager_); |
| } |
| |
| TEST_F(TetheringManagerTest, GetStatus) { |
| // Check tethering status when idle. |
| auto status = GetStatus(tethering_manager_); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusStateProperty), |
| kTetheringStateIdle); |
| EXPECT_EQ(status.Get<std::string>(kTetheringStatusIdleReasonProperty), |
| kTetheringIdleReasonInitialState); |
| 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_); |
| 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); |
| EXPECT_FALSE( |
| status.Contains<std::string>(kTetheringStatusIdleReasonProperty)); |
| |
| // 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_EQ(status.Get<std::string>(kTetheringStatusIdleReasonProperty), |
| kTetheringIdleReasonClientStop); |
| EXPECT_FALSE( |
| status.Contains<std::string>(kTetheringStatusUpstreamTechProperty)); |
| EXPECT_FALSE( |
| status.Contains<std::string>(kTetheringStatusDownstreamTechProperty)); |
| EXPECT_FALSE(status.Contains<Stringmaps>(kTetheringStatusClientsProperty)); |
| } |
| |
| TEST_F(TetheringManagerTest, InactiveTimer) { |
| // Start tethering. |
| TetheringPrerequisite(tethering_manager_); |
| // Inactive timer is not triggered when tethering is not active. |
| EXPECT_TRUE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| // Inactive timer should be armed when tethering is active and no client is |
| // connected. |
| EXPECT_FALSE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| |
| // Connect client to the hotspot. |
| std::vector<std::vector<uint8_t>> clients; |
| clients.push_back({00, 11, 22, 33, 44, 55}); |
| EXPECT_CALL(*hotspot_device_.get(), GetStations()).WillOnce(Return(clients)); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kPeerConnected, |
| hotspot_device_.get()); |
| DispatchPendingEvents(); |
| // Inactive timer should be canceled if at least one client is connected. |
| EXPECT_TRUE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| |
| clients.clear(); |
| EXPECT_CALL(*hotspot_device_.get(), GetStations()).WillOnce(Return(clients)); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kPeerDisconnected, |
| hotspot_device_.get()); |
| DispatchPendingEvents(); |
| // Inactive timer should be re-armed when tethering is active and the last |
| // client is gone. |
| EXPECT_FALSE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringStartTimer) { |
| // Start tethering. |
| TetheringPrerequisite(tethering_manager_); |
| EXPECT_TRUE(GetStartTimer(tethering_manager_).IsCancelled()); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_FALSE(GetStartTimer(tethering_manager_).IsCancelled()); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Tethering start timeout |
| OnStartingTetheringTimeout(tethering_manager_); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringStartTimerUpdated) { |
| // Start tethering. |
| TetheringPrerequisite(tethering_manager_); |
| EXPECT_TRUE(GetStartTimer(tethering_manager_).IsCancelled()); |
| SetEnabled(tethering_manager_, true); |
| EXPECT_FALSE(GetStartTimer(tethering_manager_).IsCancelled()); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Timeout updated |
| OnStartingTetheringUpdateTimeout(tethering_manager_, base::Seconds(20)); |
| EXPECT_FALSE(GetStartTimer(tethering_manager_).IsCancelled()); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringStarting); |
| |
| // Tethering start timeout |
| OnStartingTetheringTimeout(tethering_manager_); |
| // Expect stopping state: the attempt will be aborted. |
| CheckTetheringStopping(tethering_manager_, kTetheringIdleReasonError); |
| } |
| |
| TEST_F(TetheringManagerTest, TetheringStopTimer) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| // Stop tethering. |
| EXPECT_TRUE(GetStopTimer(tethering_manager_).IsCancelled()); |
| SetEnabled(tethering_manager_, false); |
| EXPECT_FALSE(GetStopTimer(tethering_manager_).IsCancelled()); |
| // Tethering stop timeout |
| OnStoppingTetheringTimeout(tethering_manager_); |
| VerifyResult(TetheringManager::SetEnabledResult::kUpstreamFailure); |
| CheckTetheringIdle(tethering_manager_, kTetheringIdleReasonClientStop); |
| } |
| |
| TEST_F(TetheringManagerTest, MARWithSSIDChange) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| // Upon initialization TetheringManager generates some config. Let's take |
| // a snapshot of the SSID/MAC (to test if MAC changes upon SSID change). |
| std::string ini_ssid = tethering_manager_->hex_ssid_; |
| std::string ini_mac = tethering_manager_->stable_mac_addr_.ToString(); |
| |
| // Change SSID to cause regeneration of MAC address. |
| KeyValueStore args = GenerateFakeConfig(kTestAPHexSSID, kTestPassword); |
| // Turn off randomization. |
| SetConfigMAR(args, false); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, args)); |
| std::string mac = tethering_manager_->stable_mac_addr_.ToString(); |
| ASSERT_NE(ini_ssid, kTestAPHexSSID); |
| EXPECT_NE(ini_mac, mac); |
| |
| // Test 1st argument for CreateHotspotDevice (MAC as a hex-string). |
| EXPECT_CALL(*wifi_provider_, CreateHotspotDevice(Eq(mac), _, _, _)) |
| .WillOnce(Return(hotspot_device_)); |
| SetEnabled(tethering_manager_, true); |
| } |
| |
| MATCHER_P(IsContained, container, "") { |
| return base::Contains(container, arg); |
| } |
| |
| TEST_F(TetheringManagerTest, MARWithTetheringRestart) { |
| TetheringPrerequisite(tethering_manager_); |
| std::set<std::string> known_macs; |
| known_macs.insert(tethering_manager_->stable_mac_addr_.ToString()); |
| |
| auto tether_onoff = [&]() { |
| EXPECT_CALL(*wifi_provider_, |
| CreateHotspotDevice(Not(IsContained(known_macs)), _, _, _)) |
| .WillOnce( |
| DoAll(WithArg<0>(Invoke([&](auto mac) { known_macs.insert(mac); })), |
| Return(hotspot_device_))); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| SetEnabledVerifyResult(tethering_manager_, false, |
| TetheringManager::SetEnabledResult::kSuccess); |
| CheckTetheringIdle(tethering_manager_, kTetheringIdleReasonClientStop); |
| }; |
| |
| for (int i = 0; i < 4; ++i) { |
| tether_onoff(); |
| } |
| } |
| |
| TEST_F(TetheringManagerTest, CheckMACStored) { |
| TetheringPrerequisite(tethering_manager_); |
| |
| // Change SSID to cause regeneration of MAC address. |
| KeyValueStore args; |
| SetConfigSSID(args, kTestAPHexSSID); |
| // Turn off randomization to check the MAC is being used at the end. |
| SetConfigMAR(args, false); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, args)); |
| |
| std::string ini_mac = tethering_manager_->stable_mac_addr_.ToString(); |
| |
| // Now PopProfile and check that MAC is different. |
| EXPECT_EQ(Error::kSuccess, TestPopProfile(&manager_, kUserProfile)); |
| EXPECT_NE(ini_mac, tethering_manager_->stable_mac_addr_.ToString()); |
| |
| // Repush the profile and check that MAC returns to its original value. |
| EXPECT_EQ(Error::kSuccess, TestPushProfile(&manager_, kUserProfile)); |
| EXPECT_EQ(ini_mac, tethering_manager_->stable_mac_addr_.ToString()); |
| |
| // And test that it is actually used. |
| EXPECT_CALL(*wifi_provider_, CreateHotspotDevice(Eq(ini_mac), _, _, _)) |
| .WillOnce(Return(hotspot_device_)); |
| SetEnabled(tethering_manager_, true); |
| } |
| |
| TEST_F(TetheringManagerTest, OnCellularUpstreamEvent) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| OnCellularUpstreamEvent( |
| tethering_manager_, |
| TetheringManager::CellularUpstreamEvent::kUserNoLongerEntitled); |
| CheckTetheringStopping(tethering_manager_, |
| kTetheringIdleReasonUpstreamDisconnect); |
| } |
| |
| TEST_F(TetheringManagerTest, ChangeSSIDWhileIdle) { |
| TetheringPrerequisite(tethering_manager_); |
| CheckTetheringIdle(tethering_manager_, kTetheringIdleReasonInitialState); |
| // Change SSID and set to TetheringConfig. |
| KeyValueStore config = GetConfig(tethering_manager_); |
| SetConfigSSID(config, kTestAPHexSSID); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| DispatchPendingEvents(); |
| CheckTetheringIdle(tethering_manager_, kTetheringIdleReasonInitialState); |
| } |
| |
| TEST_F(TetheringManagerTest, ChangeSSIDWhileActive) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Change SSID and set to TetheringConfig. |
| KeyValueStore config = GetConfig(tethering_manager_); |
| SetConfigSSID(config, kTestAPHexSSID); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| // Changing SSID should not touch the upstream network. |
| EXPECT_CALL(*cellular_service_provider_, ReleaseTetheringNetwork(_, _)) |
| .Times(0); |
| DispatchPendingEvents(); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringRestarting); |
| } |
| |
| TEST_F(TetheringManagerTest, ChangeUpstreamTechWhileActive) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Change upstream tech from cellular to eth and set to TetheringConfig. |
| KeyValueStore config = GetConfig(tethering_manager_); |
| SetConfigUpstream(config, TechnologyName(Technology::kEthernet)); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| // Changing upstream technology should release the upstream network. |
| EXPECT_CALL(*cellular_service_provider_, ReleaseTetheringNetwork(_, _)) |
| .WillOnce(Return()); |
| DispatchPendingEvents(); |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringRestarting); |
| } |
| |
| TEST_F(TetheringManagerTest, ChangeAutoDisableWhileIdle) { |
| TetheringPrerequisite(tethering_manager_); |
| KeyValueStore config = GetConfig(tethering_manager_); |
| SetConfigAutoDisable(config, false); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| EXPECT_TRUE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| CheckTetheringIdle(tethering_manager_, kTetheringIdleReasonInitialState); |
| SetConfigAutoDisable(config, true); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| EXPECT_TRUE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| CheckTetheringIdle(tethering_manager_, kTetheringIdleReasonInitialState); |
| } |
| |
| TEST_F(TetheringManagerTest, ChangeAutoDisableWhileActive) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Change auto disable from true to false and set to TetheringConfig. |
| KeyValueStore config = GetConfig(tethering_manager_); |
| SetConfigAutoDisable(config, false); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| // Set auto disable to false will terminate the inactive timer. |
| EXPECT_TRUE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| // No session restart is triggered. |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| |
| // Change auto disable from false to true and set to TetheringConfig. |
| SetConfigAutoDisable(config, true); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| // Set auto disable to true will restart the inactive timer. |
| EXPECT_FALSE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| // No session restart is triggered. |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| |
| // Connect client to the hotspot. |
| std::vector<std::vector<uint8_t>> clients; |
| clients.push_back({00, 11, 22, 33, 44, 55}); |
| ON_CALL(*hotspot_device_.get(), GetStations()).WillByDefault(Return(clients)); |
| DownStreamDeviceEvent(tethering_manager_, |
| LocalDevice::DeviceEvent::kPeerConnected, |
| hotspot_device_.get()); |
| DispatchPendingEvents(); |
| |
| // Change auto disable from true to false and set to TetheringConfig. |
| SetConfigAutoDisable(config, false); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| // Set auto disable to false will terminate the inactive timer. |
| EXPECT_TRUE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| // No session restart is triggered. |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| |
| // Change auto disable from false to true and set to TetheringConfig. |
| SetConfigAutoDisable(config, true); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| // Set auto disable to true will not restart the inactive timer if there is |
| // client connected to the hotspot. |
| EXPECT_TRUE(GetInactiveTimer(tethering_manager_).IsCancelled()); |
| // No session restart is triggered. |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| } |
| |
| TEST_F(TetheringManagerTest, SetConfigWithNoChangeWhileActive) { |
| TetheringPrerequisite(tethering_manager_); |
| SetEnabledVerifyResult(tethering_manager_, true, |
| TetheringManager::SetEnabledResult::kSuccess); |
| |
| // Change nothing and set to TetheringConfig. |
| KeyValueStore config = GetConfig(tethering_manager_); |
| EXPECT_TRUE(SetAndPersistConfig(tethering_manager_, config)); |
| // No session restart is triggered. |
| EXPECT_EQ(TetheringState(tethering_manager_), |
| TetheringManager::TetheringState::kTetheringActive); |
| } |
| |
| } // namespace shill |