diff --git a/connections/implementation/bwu_manager_test.cc b/connections/implementation/bwu_manager_test.cc index 64ffb277..62bf809d 100644 --- a/connections/implementation/bwu_manager_test.cc +++ b/connections/implementation/bwu_manager_test.cc @@ -82,6 +82,180 @@ CreateWifiHotspotCredentials() { return credentials; } +class BwuManagerBaseTest : public ::testing::Test { + protected: + void SetUp() override { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature:: + kEnableDynamicRoleSwitch, + true); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableWifiDirect, + true); + } + + void TearDown() override { + NearbyFlags::GetInstance().ResetOverridedValues(); + } +}; + +TEST_F(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) { + ClientProxy client; + EndpointChannelManager ecm; + EndpointManager em(&ecm); + Mediums mediums; + BwuManager::Config config; + config.allow_upgrade_to.SetAll(false); + absl::flat_hash_map> handlers; + auto bwu_manager = std::make_unique(mediums, em, ecm, + std::move(handlers), config); + client.SetLocalOsType(OsInfo::APPLE); + auto channel1 = std::make_unique( + Medium::BLUETOOTH, std::string(kServiceIdA)); + MediumRole medium_role; + medium_role.set_support_wifi_hotspot_host(true); + client.OnConnectionInitiated( + std::string(kEndpointId1), + {.remote_endpoint_info = ByteArray("remote endpoint")}, + {.auto_upgrade_bandwidth = false, + .connection_info = + { + .medium_role = {medium_role}, + }}, + {}, ""); + client.OnConnectionAccepted(std::string(kEndpointId1)); + ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), + std::move(channel1)); + bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), + Medium::WIFI_HOTSPOT); + EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); + + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); + bwu_manager->Shutdown(); +} + +TEST_F(BwuManagerBaseTest, + InitiateBwu_NeedToSwitchRole_WindowsAndroid_Success) { + ClientProxy client; + EndpointChannelManager ecm; + EndpointManager em(&ecm); + Mediums mediums; + BwuManager::Config config; + config.allow_upgrade_to.SetAll(false); + absl::flat_hash_map> handlers; + auto bwu_manager = std::make_unique(mediums, em, ecm, + std::move(handlers), config); + + // Set up local as WINDOWS, remote as ANDROID + client.SetLocalOsType(OsInfo::WINDOWS); + OsInfo remote_os_info; + remote_os_info.set_type(OsInfo::ANDROID); + + auto channel1 = std::make_unique( + Medium::BLUETOOTH, std::string(kServiceIdA)); + auto* channel1_ptr = channel1.get(); + + MediumRole remote_medium_role; + remote_medium_role.set_support_wifi_direct_group_owner(true); + + client.OnConnectionInitiated( + std::string(kEndpointId1), + {.remote_endpoint_info = ByteArray("remote endpoint")}, + {.auto_upgrade_bandwidth = false, + .connection_info = + { + .medium_role = {remote_medium_role}, + }}, + {}, ""); + client.OnConnectionAccepted(std::string(kEndpointId1)); + client.SetRemoteOsInfo(kEndpointId1, remote_os_info); + + ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), + std::move(channel1)); + + // Verify that before upgrade, write_timestamp is infinite past + EXPECT_EQ(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast()); + + // Initiate BWU for WiFi Direct on Windows, which forces + // role switch to Android + bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), + Medium::WIFI_DIRECT); + + // Since role is switched, upgrade is NOT initiated locally, but delegated + EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); + + // Verify that an UPGRADE_PATH_REQUEST frame was actually written to + // the channel + EXPECT_NE(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast()); + + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); + bwu_manager->Shutdown(); +} + +TEST_F(BwuManagerBaseTest, + InitiateBwu_NeedToSwitchRole_WindowsAndroid_NoSwitch_Success) { + ClientProxy client; + EndpointChannelManager ecm; + EndpointManager em(&ecm); + Mediums mediums; + BwuManager::Config config; + config.allow_upgrade_to.SetAll(false); + config.allow_upgrade_to.wifi_direct = true; + absl::flat_hash_map> handlers; + auto fake_wifi_direct = std::make_unique(Medium::WIFI_DIRECT); + auto* fake_wifi_direct_ptr = fake_wifi_direct.get(); + handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct)); + auto bwu_manager = std::make_unique(mediums, em, ecm, + std::move(handlers), config); + + // Set up local as WINDOWS, remote as ANDROID + client.SetLocalOsType(OsInfo::WINDOWS); + OsInfo remote_os_info; + remote_os_info.set_type(OsInfo::ANDROID); + + auto channel1 = std::make_unique( + Medium::BLUETOOTH, std::string(kServiceIdA)); + + MediumRole remote_medium_role; + remote_medium_role.set_support_wifi_direct_group_owner(false); + + client.OnConnectionInitiated( + std::string(kEndpointId1), + {.remote_endpoint_info = ByteArray("remote endpoint")}, + {.auto_upgrade_bandwidth = false, + .connection_info = + { + .medium_role = {remote_medium_role}, + }}, + {}, ""); + client.OnConnectionAccepted(std::string(kEndpointId1)); + client.SetRemoteOsInfo(kEndpointId1, remote_os_info); + + ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), + std::move(channel1)); + + // Verify that before upgrade, upgrade is not ongoing + EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); + + // Initiate BWU for WiFi Direct on Windows. Since remote doesn't support GO, + // we do not switch roles, so we host/upgrade locally. + bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), + Medium::WIFI_DIRECT); + + // Upgrade is ongoing locally + EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); + EXPECT_EQ(fake_wifi_direct_ptr->handle_initialize_calls().size(), 1u); + + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); + bwu_manager->Shutdown(); +} + class BwuManagerTest : public ::testing::Test { protected: static void SetUpTestSuite() { @@ -90,6 +264,10 @@ class BwuManagerTest : public ::testing::Test { true); } + static void TearDownTestSuite() { + NearbyFlags::GetInstance().ResetOverridedValues(); + } + BwuManagerTest() { // Set up fake BWU handlers for WebRTC and WifiLAN. absl::flat_hash_map> handlers; @@ -214,407 +392,55 @@ class BwuManagerTest : public ::testing::Test { std::unique_ptr bwu_manager_; }; -TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableWifiDirect, - true); - ClientProxy client; - EndpointChannelManager ecm; - EndpointManager em(&ecm); - Mediums mediums; - BwuManager::Config config; - config.allow_upgrade_to.SetAll(false); - absl::flat_hash_map> handlers; - auto bwu_manager = std::make_unique(mediums, em, ecm, - std::move(handlers), config); - +TEST_F(BwuManagerTest, AllowToUpgradeMedium) { auto channel1 = std::make_unique( Medium::BLUETOOTH, std::string(kServiceIdA)); - ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), + ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId1), std::move(channel1)); - bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), Medium::WIFI_LAN); - EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); - ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), + EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId1))); + ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, SafeDisconnectionResult::kSafeDisconnection); auto channel2 = std::make_unique( Medium::BLUETOOTH, std::string(kServiceIdA)); - ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId2), + ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId2), std::move(channel2)); - bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId2), + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId2), Medium::WIFI_HOTSPOT); - EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId2))); - ecm.UnregisterChannelForEndpoint(std::string(kEndpointId2), + EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId2))); + ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, SafeDisconnectionResult::kSafeDisconnection); auto channel3 = std::make_unique( Medium::BLUETOOTH, std::string(kServiceIdA)); - ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId3), + ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId3), std::move(channel3)); - bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId3), + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId3), Medium::WIFI_DIRECT); - EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId3))); - ecm.UnregisterChannelForEndpoint(std::string(kEndpointId3), + EXPECT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId3))); + ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId3), DisconnectionReason::LOCAL_DISCONNECTION, SafeDisconnectionResult::kSafeDisconnection); auto channel4 = std::make_unique( Medium::WEB_RTC, std::string(kServiceIdA)); - ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId4), + ecm_.RegisterChannelForEndpoint(&client_, std::string(kEndpointId4), std::move(channel4)); - bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId4), + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId4), Medium::BLUETOOTH); - EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId4))); - ecm.UnregisterChannelForEndpoint(std::string(kEndpointId4), + EXPECT_FALSE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId4))); + ecm_.UnregisterChannelForEndpoint(std::string(kEndpointId4), DisconnectionReason::LOCAL_DISCONNECTION, SafeDisconnectionResult::kSafeDisconnection); - - bwu_manager->Shutdown(); } -TEST(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) { - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableDynamicRoleSwitch, - true); - ClientProxy client; - EndpointChannelManager ecm; - EndpointManager em(&ecm); - Mediums mediums; - BwuManager::Config config; - config.allow_upgrade_to.SetAll(false); - absl::flat_hash_map> handlers; - auto bwu_manager = std::make_unique(mediums, em, ecm, - std::move(handlers), config); - client.SetLocalOsType(OsInfo::APPLE); - auto channel1 = std::make_unique( - Medium::BLUETOOTH, std::string(kServiceIdA)); - MediumRole medium_role; - medium_role.set_support_wifi_hotspot_host(true); - client.OnConnectionInitiated( - std::string(kEndpointId1), - {.remote_endpoint_info = ByteArray("remote endpoint")}, - {.auto_upgrade_bandwidth = false, - .connection_info = - { - .medium_role = {medium_role}, - }}, - {}, ""); - client.OnConnectionAccepted(std::string(kEndpointId1)); - ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), - std::move(channel1)); - bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), - Medium::WIFI_HOTSPOT); - EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); - ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), - DisconnectionReason::LOCAL_DISCONNECTION, - SafeDisconnectionResult::kSafeDisconnection); - bwu_manager->Shutdown(); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableDynamicRoleSwitch, - false); -} -TEST(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_WindowsAndroid_Success) { - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableDynamicRoleSwitch, - true); - ClientProxy client; - EndpointChannelManager ecm; - EndpointManager em(&ecm); - Mediums mediums; - BwuManager::Config config; - config.allow_upgrade_to.SetAll(false); - absl::flat_hash_map> handlers; - auto bwu_manager = std::make_unique(mediums, em, ecm, - std::move(handlers), config); - // Set up local as WINDOWS, remote as ANDROID - client.SetLocalOsType(OsInfo::WINDOWS); - OsInfo remote_os_info; - remote_os_info.set_type(OsInfo::ANDROID); - - auto channel1 = std::make_unique( - Medium::BLUETOOTH, std::string(kServiceIdA)); - auto* channel1_ptr = channel1.get(); - - MediumRole remote_medium_role; - remote_medium_role.set_support_wifi_direct_group_owner(true); - - client.OnConnectionInitiated( - std::string(kEndpointId1), - {.remote_endpoint_info = ByteArray("remote endpoint")}, - {.auto_upgrade_bandwidth = false, - .connection_info = - { - .medium_role = {remote_medium_role}, - }}, - {}, ""); - client.OnConnectionAccepted(std::string(kEndpointId1)); - client.SetRemoteOsInfo(kEndpointId1, remote_os_info); - - ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), - std::move(channel1)); - - // Verify that before upgrade, write_timestamp is infinite past - EXPECT_EQ(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast()); - - // Initiate BWU for WiFi Direct on Windows, which forces - // role switch to Android - bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), - Medium::WIFI_DIRECT); - - // Since role is switched, upgrade is NOT initiated locally, but delegated - EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); - - // Verify that an UPGRADE_PATH_REQUEST frame was actually written to - // the channel - EXPECT_NE(channel1_ptr->GetLastWriteTimestamp(), absl::InfinitePast()); - - ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), - DisconnectionReason::LOCAL_DISCONNECTION, - SafeDisconnectionResult::kSafeDisconnection); - bwu_manager->Shutdown(); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableDynamicRoleSwitch, - false); -} - -TEST(BwuManagerBaseTest, - InitiateBwu_NeedToSwitchRole_WindowsAndroid_NoSwitch_Success) { - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableDynamicRoleSwitch, - true); - ClientProxy client; - EndpointChannelManager ecm; - EndpointManager em(&ecm); - Mediums mediums; - BwuManager::Config config; - config.allow_upgrade_to.SetAll(false); - config.allow_upgrade_to.wifi_direct = true; - absl::flat_hash_map> handlers; - auto fake_wifi_direct = std::make_unique(Medium::WIFI_DIRECT); - auto* fake_wifi_direct_ptr = fake_wifi_direct.get(); - handlers.emplace(Medium::WIFI_DIRECT, std::move(fake_wifi_direct)); - auto bwu_manager = std::make_unique(mediums, em, ecm, - std::move(handlers), config); - - // Set up local as WINDOWS, remote as ANDROID - client.SetLocalOsType(OsInfo::WINDOWS); - OsInfo remote_os_info; - remote_os_info.set_type(OsInfo::ANDROID); - - auto channel1 = std::make_unique( - Medium::BLUETOOTH, std::string(kServiceIdA)); - - MediumRole remote_medium_role; - remote_medium_role.set_support_wifi_direct_group_owner(false); - - client.OnConnectionInitiated( - std::string(kEndpointId1), - {.remote_endpoint_info = ByteArray("remote endpoint")}, - {.auto_upgrade_bandwidth = false, - .connection_info = - { - .medium_role = {remote_medium_role}, - }}, - {}, ""); - client.OnConnectionAccepted(std::string(kEndpointId1)); - client.SetRemoteOsInfo(kEndpointId1, remote_os_info); - - ecm.RegisterChannelForEndpoint(&client, std::string(kEndpointId1), - std::move(channel1)); - - // Verify that before upgrade, upgrade is not ongoing - EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); - - // Initiate BWU for WiFi Direct on Windows. Since remote doesn't support GO, - // we do not switch roles, so we host/upgrade locally. - bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), - Medium::WIFI_DIRECT); - - // Upgrade is ongoing locally - EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); - EXPECT_EQ(fake_wifi_direct_ptr->handle_initialize_calls().size(), 1u); - - ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), - DisconnectionReason::LOCAL_DISCONNECTION, - SafeDisconnectionResult::kSafeDisconnection); - bwu_manager->Shutdown(); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableDynamicRoleSwitch, - false); -} - -class BwuManagerTestParam : public BwuManagerTest, - public ::testing::WithParamInterface { - protected: - BwuManagerTestParam() { - SetSupportMultipleBwuMediums(GetParam()); - } -}; - -TEST_P(BwuManagerTestParam, InitiateBwu_Success) { - // Create the initial device-to-device Bluetooth connection. - FakeEndpointChannel* initial_channel = CreateInitialEndpoint( - &client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); - - // Initiate BWU, and send BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_PATH_AVAILABLE - // to the Responder over the initial Bluetooth channel. - bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), - Medium::WEB_RTC); - - // The appropriate upgrade medium handler is informed of the BWU initiation. - ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); - EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_TRUE( - fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdA), - fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].service_id); - EXPECT_EQ( - kEndpointId1, - fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].endpoint_id); - - // Establish the incoming connection on the new medium. Verify that the - // upgrade channel replaces the initial channel. - std::shared_ptr shared_initial_channel = - ecm_.GetChannelForEndpoint(std::string(kEndpointId1)); - EXPECT_EQ(initial_channel, shared_initial_channel.get()); - FakeEndpointChannel* upgraded_channel = - fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection( - /*initialize_call_index=*/0u, bwu_manager_.get()); - EXPECT_EQ(upgraded_channel, - ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); - - // Confirm that upgrade channel is paused until initial channel is shut down. - EXPECT_TRUE(upgraded_channel->IsPaused()); - EXPECT_FALSE(initial_channel->is_closed()); - - // Receive BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL and then - // BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL from the - // Responder device to trigger the shutdown of the initial Bluetooth channel. - ExceptionOr last_write_frame = - parser::FromBytes(parser::ForBwuLastWrite()); - bwu_manager_->OnIncomingFrame(last_write_frame.result(), - std::string(kEndpointId1), &client_, - Medium::BLUETOOTH); - ExceptionOr safe_to_close_frame = - parser::FromBytes(parser::ForBwuSafeToClose()); - bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(), - std::string(kEndpointId1), &client_, - Medium::BLUETOOTH); - - // Confirm that upgrade channel is resumed after initial channel is shut down. - // Note: If we didn't grab the shared initial channel pointer above, this - // channel would have already been destroyed. - auto old_channel = - dynamic_cast(shared_initial_channel.get()); - EXPECT_FALSE(upgraded_channel->IsPaused()); - EXPECT_TRUE(old_channel->is_closed()); - EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED, - old_channel->disconnection_reason()); - UnRegisterChannelForEndpoint(kEndpointId1); -} - -TEST_P(BwuManagerTestParam, - InitiateBwu_Error_DontUpgradeIfAlreadyConenctedOverTheRequestedMedium) { - CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); - FullyUpgradeEndpoint(kEndpointId1, /*initial_medium=*/Medium::BLUETOOTH, - /*upgrade_medium=*/Medium::WEB_RTC); - EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); - - // Ignore request to upgrade to WebRTC if we're already connected. - bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), - Medium::WEB_RTC); - EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); - UnRegisterChannelForEndpoint(kEndpointId1); -} - -TEST_P(BwuManagerTestParam, - InitiateBwu_Error_DontUpgradeFromWIFI_LANToWIFI_HOTSPOT) { - CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::WIFI_LAN); - - // Ignore request to upgrade to WebRTC if we're already connected. - bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), - Medium::WIFI_HOTSPOT); - EXPECT_TRUE( - fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); - UnRegisterChannelForEndpoint(kEndpointId1); -} - -TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoInitialMedium) { - // Try to upgrade to a Medium without an initial Medium. - bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), - Medium::WIFI_HOTSPOT); - - // Make sure none of the other medium handlers are called. - EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_TRUE( - fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty()); -} - -TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) { - CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); - - bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), - Medium::WEB_RTC); - EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); - - // Try to upgrade an endpoint that already has an ungrade in progress. Should - // just early return with no action. - bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), - Medium::WIFI_LAN); - EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); - EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_TRUE( - fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); - EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty()); - UnRegisterChannelForEndpoint(kEndpointId1); -} - -TEST_P(BwuManagerTestParam, - InitiateBwu_Error_FailedToWriteUpgradePathAvailableFrame) { - // Create the initial device-to-device Bluetooth connection. - FakeEndpointChannel* initial_channel = CreateInitialEndpoint( - &client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); - - // Make the initial endpoint channel fail when writing the - // UPGRADE_PATH_AVAILABLE frame. - initial_channel->set_write_output(Exception{Exception::kIo}); - - bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), - Medium::WEB_RTC); - - // After we notify the WebRTC handler, we try to write the - // UPGRADE_PATH_AVAILABLE frame, but fail by just early returning. - EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); - - // However, we do not record an in-progress attempt. So, if we see an incoming - // connection over WebRTC, we ignore it. In other words, the initial BLUETOOTH - // channel is still used. - EXPECT_EQ(initial_channel, - ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); - FakeEndpointChannel* upgraded_channel = - fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection( - /*initialize_call_index=*/0u, bwu_manager_.get()); - EXPECT_NE(upgraded_channel, - ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); - EXPECT_EQ(initial_channel, - ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); - UnRegisterChannelForEndpoint(kEndpointId1); -} TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_MultipleEndpoints_FlagEnabled) { @@ -1520,6 +1346,167 @@ TEST_F(BwuManagerTest, OnIncomingConnection_EndpointAliasesToLastEndpointId) { false); } +class BwuManagerTestParam : public BwuManagerTest, + public ::testing::WithParamInterface { + protected: + BwuManagerTestParam() { + SetSupportMultipleBwuMediums(GetParam()); + } +}; + +TEST_P(BwuManagerTestParam, InitiateBwu_Success) { + // Create the initial device-to-device Bluetooth connection. + FakeEndpointChannel* initial_channel = CreateInitialEndpoint( + &client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); + + // Initiate BWU, and send BANDWIDTH_UPGRADE_NEGOTIATION.UPGRADE_PATH_AVAILABLE + // to the Responder over the initial Bluetooth channel. + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WEB_RTC); + + // The appropriate upgrade medium handler is informed of the BWU initiation. + ASSERT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); + EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_TRUE( + fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_EQ(WrapInitiatorUpgradeServiceId(kServiceIdA), + fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].service_id); + EXPECT_EQ( + kEndpointId1, + fake_web_rtc_bwu_handler_->handle_initialize_calls()[0].endpoint_id); + + // Establish the incoming connection on the new medium. Verify that the + // upgrade channel replaces the initial channel. + std::shared_ptr shared_initial_channel = + ecm_.GetChannelForEndpoint(std::string(kEndpointId1)); + EXPECT_EQ(initial_channel, shared_initial_channel.get()); + FakeEndpointChannel* upgraded_channel = + fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection( + /*initialize_call_index=*/0u, bwu_manager_.get()); + EXPECT_EQ(upgraded_channel, + ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); + + // Confirm that upgrade channel is paused until initial channel is shut down. + EXPECT_TRUE(upgraded_channel->IsPaused()); + EXPECT_FALSE(initial_channel->is_closed()); + + // Receive BANDWIDTH_UPGRADE_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL and then + // BANDWIDTH_UPGRADE_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL from the + // Responder device to trigger the shutdown of the initial Bluetooth channel. + ExceptionOr last_write_frame = + parser::FromBytes(parser::ForBwuLastWrite()); + bwu_manager_->OnIncomingFrame(last_write_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); + ExceptionOr safe_to_close_frame = + parser::FromBytes(parser::ForBwuSafeToClose()); + bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); + + // Confirm that upgrade channel is resumed after initial channel is shut down. + // Note: If we didn't grab the shared initial channel pointer above, this + // channel would have already been destroyed. + auto old_channel = + dynamic_cast(shared_initial_channel.get()); + EXPECT_FALSE(upgraded_channel->IsPaused()); + EXPECT_TRUE(old_channel->is_closed()); + EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED, + old_channel->disconnection_reason()); + UnRegisterChannelForEndpoint(kEndpointId1); +} + +TEST_P(BwuManagerTestParam, + InitiateBwu_Error_DontUpgradeIfAlreadyConenctedOverTheRequestedMedium) { + CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); + FullyUpgradeEndpoint(kEndpointId1, /*initial_medium=*/Medium::BLUETOOTH, + /*upgrade_medium=*/Medium::WEB_RTC); + EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); + + // Ignore request to upgrade to WebRTC if we're already connected. + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WEB_RTC); + EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); + UnRegisterChannelForEndpoint(kEndpointId1); +} + +TEST_P(BwuManagerTestParam, + InitiateBwu_Error_DontUpgradeFromWIFI_LANToWIFI_HOTSPOT) { + CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::WIFI_LAN); + + // Ignore request to upgrade to WebRTC if we're already connected. + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WIFI_HOTSPOT); + EXPECT_TRUE( + fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); + UnRegisterChannelForEndpoint(kEndpointId1); +} + +TEST_P(BwuManagerTestParam, InitiateBwu_Error_NoInitialMedium) { + // Try to upgrade to a Medium without an initial Medium. + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WIFI_HOTSPOT); + + // Make sure none of the other medium handlers are called. + EXPECT_TRUE(fake_web_rtc_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_TRUE( + fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty()); +} + +TEST_P(BwuManagerTestParam, InitiateBwu_Error_UpgradeAlreadyInProgress) { + CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); + + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WEB_RTC); + EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); + + // Try to upgrade an endpoint that already has an ungrade in progress. Should + // just early return with no action. + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WIFI_LAN); + EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); + EXPECT_TRUE(fake_wifi_lan_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_TRUE( + fake_wifi_hotspot_bwu_handler_->handle_initialize_calls().empty()); + EXPECT_TRUE(fake_wifi_direct_bwu_handler_->handle_initialize_calls().empty()); + UnRegisterChannelForEndpoint(kEndpointId1); +} + +TEST_P(BwuManagerTestParam, + InitiateBwu_Error_FailedToWriteUpgradePathAvailableFrame) { + // Create the initial device-to-device Bluetooth connection. + FakeEndpointChannel* initial_channel = CreateInitialEndpoint( + &client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); + + // Make the initial endpoint channel fail when writing the + // UPGRADE_PATH_AVAILABLE frame. + initial_channel->set_write_output(Exception{Exception::kIo}); + + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WEB_RTC); + + // After we notify the WebRTC handler, we try to write the + // UPGRADE_PATH_AVAILABLE frame, but fail by just early returning. + EXPECT_EQ(1u, fake_web_rtc_bwu_handler_->handle_initialize_calls().size()); + + // However, we do not record an in-progress attempt. So, if we see an incoming + // connection over WebRTC, we ignore it. In other words, the initial BLUETOOTH + // channel is still used. + EXPECT_EQ(initial_channel, + ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); + FakeEndpointChannel* upgraded_channel = + fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection( + /*initialize_call_index=*/0u, bwu_manager_.get()); + EXPECT_NE(upgraded_channel, + ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); + EXPECT_EQ(initial_channel, + ecm_.GetChannelForEndpoint(std::string(kEndpointId1)).get()); + UnRegisterChannelForEndpoint(kEndpointId1); +} + INSTANTIATE_TEST_SUITE_P(BwuManagerTestParam, BwuManagerTestParam, testing::Bool());