// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "connections/implementation/base_pcp_handler.h" #include #include #include #include #include #include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/base/thread_annotations.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" #include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/analytics/mock_analytics_recorder.h" #include "connections/implementation/base_endpoint_channel.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/encryption_runner.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/endpoint_manager.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/mediums/webrtc_peer_id.h" #include "connections/implementation/mock_device.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/pcp.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/implementation/webrtc_state.h" #include "connections/listeners.h" #include "connections/medium_selector.h" #include "connections/out_of_band_connection_metadata.h" #include "connections/params.h" #include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" #include "internal/flags/nearby_flags.h" #include "internal/interop/authentication_status.h" #include "internal/interop/authentication_transport.h" #include "internal/interop/device.h" #include "internal/interop/device_provider.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" #include "internal/platform/feature_flags.h" #include "internal/platform/future.h" #include "internal/platform/input_stream.h" #include "internal/platform/logging.h" #include "internal/platform/mac_address.h" #include "internal/platform/medium_environment.h" #include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" #include "proto/connections_enums.pb.h" #include "proto/connections_enums.proto.h" namespace nearby::connections { namespace { using ::location::nearby::connections::OsInfo; using ::location::nearby::proto::connections::Medium; using ::testing::_; using ::testing::AtLeast; using ::testing::Matcher; using ::testing::MockFunction; using ::testing::NiceMock; using ::testing::Return; using ::testing::StrictMock; constexpr absl::string_view kTestEndpointId = "REMOTETEST"; constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; constexpr BooleanMediumSelector kTestCases[] = { BooleanMediumSelector{}, BooleanMediumSelector{ .ble = true, }, BooleanMediumSelector{ .bluetooth = true, }, BooleanMediumSelector{ .wifi_lan = true, }, BooleanMediumSelector{ .bluetooth = true, .ble = true, }, BooleanMediumSelector{ .bluetooth = true, .wifi_lan = true, }, BooleanMediumSelector{ .ble = true, .wifi_lan = true, }, BooleanMediumSelector{ .bluetooth = true, .ble = true, .web_rtc = true, .wifi_lan = true, }, }; class FakePresenceDevice : public NearbyDevice { public: std::string GetEndpointId() const override { return "LOCALTEST"; } MOCK_METHOD(std::vector, GetConnectionInfos, (), (const, override)); MOCK_METHOD(NearbyDevice::Type, GetType, (), (const, override)); MOCK_METHOD(std::string, ToProtoBytes, (), (const, override)); }; class FakePresenceDeviceProvider : public NearbyDeviceProvider { public: const NearbyDevice* GetLocalDevice() override { return &local_device_; } AuthenticationStatus AuthenticateAsInitiator( const NearbyDevice& remote_device, absl::string_view shared_secret, const AuthenticationTransport& authentication_transport) const override { authenticate_as_initiator_called_ = true; return authentication_status_; } void SetAuthenticationStatus(AuthenticationStatus status) { authentication_status_ = status; } FakePresenceDevice local_device_; mutable bool authenticate_as_initiator_called_ = false; private: AuthenticationStatus authentication_status_ = AuthenticationStatus::kSuccess; }; class MockEndpointChannel : public BaseEndpointChannel { public: explicit MockEndpointChannel(std::unique_ptr reader, std::unique_ptr writer) : BaseEndpointChannel("service_id", "channel", reader.get(), writer.get()), input_stream_(std::move(reader)), output_stream_(std::move(writer)) {} ExceptionOr DoRead() { return BaseEndpointChannel::Read(); } Exception DoWrite(absl::string_view data) { if (broken_write_) { return {Exception::kFailed}; } return BaseEndpointChannel::Write(data); } absl::Time DoGetLastReadTimestamp() { return BaseEndpointChannel::GetLastReadTimestamp(); } MOCK_METHOD(ExceptionOr, Read, (), (override)); MOCK_METHOD(Exception, Write, (absl::string_view data), (override)); MOCK_METHOD(void, CloseImpl, (), (override)); MOCK_METHOD(location::nearby::proto::connections::Medium, GetMedium, (), (const, override)); MOCK_METHOD(std::string, GetType, (), (const, override)); MOCK_METHOD(std::string, GetName, (), (const, override)); MOCK_METHOD(bool, IsPaused, (), (const, override)); MOCK_METHOD(void, Pause, (), (override)); MOCK_METHOD(void, Resume, (), (override)); MOCK_METHOD(absl::Time, GetLastReadTimestamp, (), (const, override)); bool broken_write_{false}; private: std::unique_ptr input_stream_; std::unique_ptr output_stream_; }; class MockPcpHandler : public BasePcpHandler { public: using DiscoveredEndpoint = BasePcpHandler::DiscoveredEndpoint; MockPcpHandler(Mediums* m, EndpointManager* em, EndpointChannelManager* ecm, BwuManager* bwu) : BasePcpHandler(m, em, ecm, bwu, Pcp::kP2pCluster) {} // Expose protected inner types of a base type for mocking. using BasePcpHandler::ConnectImplResult; using BasePcpHandler::DiscoveredEndpoint; using BasePcpHandler::StartOperationResult; MOCK_METHOD(Strategy, GetStrategy, (), (const, override)); MOCK_METHOD(Pcp, GetPcp, (), (const, override)); MOCK_METHOD(bool, CanSendOutgoingConnection, (ClientProxy * client), (const, override)); MOCK_METHOD(bool, CanReceiveIncomingConnection, (ClientProxy * client), (const, override)); MOCK_METHOD(StartOperationResult, StartAdvertisingImpl, (ClientProxy * client, const std::string& service_id, const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, const AdvertisingOptions& advertising_options), (override)); MOCK_METHOD(Status, StopAdvertisingImpl, (ClientProxy * client), (override)); MOCK_METHOD(StartOperationResult, StartDiscoveryImpl, (ClientProxy * client, const std::string& service_id, const DiscoveryOptions& discovery_options), (override)); MOCK_METHOD(Status, StopDiscoveryImpl, (ClientProxy * client), (override)); MOCK_METHOD(StartOperationResult, StartListeningForIncomingConnectionsImpl, (ClientProxy * client_proxy, absl::string_view service_id, absl::string_view local_endpoint_id, v3::ConnectionListeningOptions options), (override)); MOCK_METHOD(void, StopListeningForIncomingConnectionsImpl, (ClientProxy * client_proxy), (override)); MOCK_METHOD(Status, InjectEndpointImpl, (ClientProxy * client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata), (override)); MOCK_METHOD(ConnectImplResult, ConnectImpl, (ClientProxy * client, DiscoveredEndpoint* endpoint), (override)); MOCK_METHOD(location::nearby::proto::connections::Medium, GetDefaultUpgradeMedium, (), (override)); MOCK_METHOD(StartOperationResult, UpdateAdvertisingOptionsImpl, (ClientProxy*, absl::string_view, absl::string_view, absl::string_view, const AdvertisingOptions&), (override)); MOCK_METHOD(StartOperationResult, UpdateDiscoveryOptionsImpl, (ClientProxy*, absl::string_view, absl::string_view, absl::string_view, const DiscoveryOptions&), (override)); std::vector GetConnectionMediumsByPriority() override { return std::vector{ location::nearby::proto::connections::WIFI_LAN, location::nearby::proto::connections::WEB_RTC, location::nearby::proto::connections::BLUETOOTH, location::nearby::proto::connections::BLE}; } // Mock adapters for protected non-virtual methods of a base class. void OnEndpointFound(ClientProxy* client, std::shared_ptr endpoint) ABSL_NO_THREAD_SAFETY_ANALYSIS { BasePcpHandler::OnEndpointFound(client, std::move(endpoint)); } void OnEndpointLost(ClientProxy* client, const DiscoveredEndpoint& endpoint) ABSL_NO_THREAD_SAFETY_ANALYSIS { BasePcpHandler::OnEndpointLost(client, endpoint); } void OnInstantLost(ClientProxy* client, std::shared_ptr endpoint) ABSL_NO_THREAD_SAFETY_ANALYSIS { BasePcpHandler::OnInstantLost(client, endpoint->endpoint_id, endpoint->endpoint_info); } BasePcpHandler::DiscoveredEndpoint* GetDiscoveredEndpoint( const std::string& endpoint_id) { return BasePcpHandler::GetDiscoveredEndpoint(endpoint_id); } std::vector GetDiscoveredEndpoints( const std::string& endpoint_id) { return BasePcpHandler::GetDiscoveredEndpoints(endpoint_id); } std::vector GetDiscoveredEndpoints( location::nearby::proto::connections::Medium medium) { return BasePcpHandler::GetDiscoveredEndpoints(medium); } int GetEndpointLostByMediumAlarmsCount() { Future alarms_count; RunOnPcpHandlerThread( "GetEndpointLostByMediumAlarmsCount", [this, alarms_count]() RUN_ON_PCP_HANDLER_THREAD() mutable { alarms_count.Set( BasePcpHandler::GetEndpointLostByMediumAlarmsCount()); }); return alarms_count.Get().result(); } void StartEndpointLostByMediumAlarms( ClientProxy* client, location::nearby::proto::connections::Medium medium) { RunOnPcpHandlerThread("StartEndpointLostByMediumAlarms", [this, client, medium]() RUN_ON_PCP_HANDLER_THREAD() { BasePcpHandler::StartEndpointLostByMediumAlarms( client, medium); }); } void StopEndpointLostByMediumAlarm( absl::string_view endpoint_id, location::nearby::proto::connections::Medium medium) { RunOnPcpHandlerThread("StopEndpointLostByMediumAlarm", [this, endpoint_id = std::string(endpoint_id), medium]() RUN_ON_PCP_HANDLER_THREAD() { BasePcpHandler::StopEndpointLostByMediumAlarm( endpoint_id, medium); }); } std::vector GetDiscoveryMediums( ClientProxy* client) { auto allowed = client->GetDiscoveryOptions().CompatibleOptions().allowed; return GetMediumsFromSelector(allowed); } std::vector GetMediumsFromSelector(BooleanMediumSelector allowed) { return allowed.GetMediums(true); } std::vector GetConnectionInfoFromResult( absl::string_view service_id, BasePcpHandler::StartOperationResult result) { return BasePcpHandler::GetConnectionInfoFromResult(service_id, result); } Exception OnIncomingConnection( ClientProxy* client, const ByteArray& remote_endpoint_info, std::unique_ptr endpoint_channel, location::nearby::proto::connections::Medium medium, NearbyDevice::Type listening_device_type) { return BasePcpHandler::OnIncomingConnection(client, remote_endpoint_info, std::move(endpoint_channel), medium, listening_device_type); } bool NeedsToTurnOffAdvertisingMedium( location::nearby::proto::connections::Medium medium, const AdvertisingOptions& old_options, const AdvertisingOptions& new_options) { return BasePcpHandler::NeedsToTurnOffAdvertisingMedium(medium, old_options, new_options); } bool NeedsToTurnOffDiscoveryMedium( location::nearby::proto::connections::Medium medium, const DiscoveryOptions& old_options, const DiscoveryOptions& new_options) { return BasePcpHandler::NeedsToTurnOffDiscoveryMedium(medium, old_options, new_options); } void StripOutWifiHotspotMedium(ConnectionInfo& connection_info) { BasePcpHandler::StripOutWifiHotspotMedium(connection_info); } mediums::WebrtcPeerId CreatePeerIdFromAdvertisement( const std::string& service_id, const std::string& endpoint_id, const ByteArray& endpoint_info) { return BasePcpHandler::CreatePeerIdFromAdvertisement( service_id, endpoint_id, endpoint_info); } bool HasOutgoingConnections(ClientProxy* client) const override { return BasePcpHandler::HasOutgoingConnections(client); } bool HasIncomingConnections(ClientProxy* client) const override { return BasePcpHandler::HasIncomingConnections(client); } }; class MockContext { public: explicit MockContext(std::atomic_int* destroyed = nullptr) : destroyed_{destroyed} {} MockContext(MockContext&& other) { *this = std::move(other); } MockContext& operator=(MockContext&& other) { destroyed_ = other.destroyed_; other.destroyed_ = nullptr; return *this; } ~MockContext() { if (destroyed_) (*destroyed_)++; } private: std::atomic_int* destroyed_; }; struct MockDiscoveredEndpoint : public MockPcpHandler::DiscoveredEndpoint { MockDiscoveredEndpoint(DiscoveredEndpoint endpoint, MockContext context) : DiscoveredEndpoint(std::move(endpoint)), context(std::move(context)) {} MockContext context; }; class SetSafeToDisconnect { public: explicit SetSafeToDisconnect(bool safe_to_disconnect) { NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: kEnableSafeToDisconnect, safe_to_disconnect); } }; class BasePcpHandlerTest : public ::testing::TestWithParam { protected: struct MockConnectionListener { StrictMock> initiated_cb; StrictMock> accepted_cb; StrictMock> rejected_cb; StrictMock> disconnected_cb; StrictMock< MockFunction> bandwidth_changed_cb; }; struct MockDiscoveryListener { StrictMock> endpoint_found_cb; StrictMock> endpoint_lost_cb; StrictMock< MockFunction> endpoint_distance_changed_cb; }; BasePcpHandlerTest() { client_ = std::make_unique(CreateAnalyticsRecorder()); } void SetUp() override { MacAddress::FromString("12:34:56:78:9a:bc", remote_mac_address_); } void TearDown() override { env_.Stop(); } std::unique_ptr CreateAnalyticsRecorder() { auto recorder = std::make_unique(); mock_analytics_recorder_ptr_ = recorder.get(); return recorder; } void StartAdvertising(ClientProxy* client, MockPcpHandler* pcp_handler, BooleanMediumSelector allowed = GetParam()) { AdvertisingOptions advertising_options{ { Strategy::kP2pCluster, allowed, }, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints }; StartAdvertisingWithOptions(client, pcp_handler, advertising_options); } void StartAdvertisingWithOptions(ClientProxy* client, MockPcpHandler* pcp_handler, AdvertisingOptions advertising_options) { std::string service_id{"service"}; ConnectionRequestInfo info{ .endpoint_info = ByteArray{"remote_endpoint_name"}, .listener = connection_listener_, }; EXPECT_CALL(*pcp_handler, StartAdvertisingImpl(client, service_id, _, info.endpoint_info, _)) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = pcp_handler->GetMediumsFromSelector( advertising_options.allowed), })); EXPECT_EQ(pcp_handler->StartAdvertising(client, service_id, advertising_options, info), Status{Status::kSuccess}); EXPECT_TRUE(client->IsAdvertising()); EXPECT_EQ(client->GetLocalEndpointInfo(), info.endpoint_info.string_data()); } void UpdateAdvertisingOptions(ClientProxy* client, MockPcpHandler* pcp_handler, AdvertisingOptions new_options, Status expected_status) { EXPECT_CALL(*pcp_handler, UpdateAdvertisingOptionsImpl) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = expected_status, .mediums = pcp_handler->GetMediumsFromSelector(new_options.allowed), })); pcp_handler->UpdateAdvertisingOptions(client, "service", new_options); } void StartDiscovery(ClientProxy* client, MockPcpHandler* pcp_handler, BooleanMediumSelector allowed = GetParam()) { DiscoveryOptions discovery_options{ { Strategy::kP2pCluster, allowed, }, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints }; StartDiscoveryWithOptions(client, pcp_handler, discovery_options); } void StartDiscoveryWithOptions(ClientProxy* client, MockPcpHandler* pcp_handler, const DiscoveryOptions& discovery_options) { std::string service_id("service"); EXPECT_CALL(*pcp_handler, StartDiscoveryImpl(client, service_id, _)) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = pcp_handler->GetMediumsFromSelector(discovery_options.allowed), })); EXPECT_EQ(pcp_handler->StartDiscovery(client, service_id, discovery_options, GetDiscoveryListener()), Status{Status::kSuccess}); EXPECT_TRUE(client->IsDiscovering()); for (const auto& discovered_medium : pcp_handler->GetDiscoveryMediums(client)) { EXPECT_TRUE( pcp_handler->GetDiscoveredEndpoints(discovered_medium).empty()); } } void UpdateDiscoveryOptions(ClientProxy* client, MockPcpHandler* pcp_handler, DiscoveryOptions new_options, Status expected_status) { EXPECT_CALL(*pcp_handler, UpdateDiscoveryOptionsImpl) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = expected_status, .mediums = pcp_handler->GetMediumsFromSelector(new_options.allowed), })); pcp_handler->UpdateDiscoveryOptions(client, "service", new_options); } std::pair, std::unique_ptr> SetupConnection( location::nearby::proto::connections::Medium medium) { // NOLINT auto [input_a, output_a] = CreatePipe(); auto [input_b, output_b] = CreatePipe(); auto channel_a = std::make_unique(std::move(input_a), std::move(output_b)); auto channel_b = std::make_unique(std::move(input_b), std::move(output_a)); ON_CALL(mock_device_, GetType) .WillByDefault(Return(NearbyDevice::Type::kUnknownDevice)); ON_CALL(mock_device_, GetEndpointId) .WillByDefault(Return(std::string(kTestEndpointId))); // On initiator (A) side, we drop the first write, since this is a // connection establishment packet, and we don't have the peer entity, just // the peer channel. The rest of the exchange must happen for the benefit of // DH key exchange. EXPECT_CALL(*channel_a, Read()) .WillRepeatedly( [channel = channel_a.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_a, Write(_)) .WillOnce(Return(Exception{Exception::kSuccess})) .WillRepeatedly( [channel = channel_a.get()](absl::string_view data) { return channel->DoWrite(data); }); EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_a, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false)); EXPECT_CALL(*channel_b, Read()) .WillRepeatedly( [channel = channel_b.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_b, Write(_)) .WillRepeatedly( [channel = channel_b.get()](absl::string_view data) { return channel->DoWrite(data); }); EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_b, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); EXPECT_CALL(*channel_b, IsPaused).WillRepeatedly(Return(false)); return std::make_pair(std::move(channel_a), std::move(channel_b)); } std::pair, std::unique_ptr> SetupConnectionForConnectFailure( location::nearby::proto::connections::Medium medium) { // NOLINT auto [input_a, output_a] = CreatePipe(); auto [input_b, output_b] = CreatePipe(); auto channel_a = std::make_unique(std::move(input_a), std::move(output_b)); auto channel_b = std::make_unique(std::move(input_b), std::move(output_a)); ON_CALL(mock_device_, GetType) .WillByDefault(Return(NearbyDevice::Type::kUnknownDevice)); ON_CALL(mock_device_, GetEndpointId) .WillByDefault(Return(std::string(kTestEndpointId))); // On initiator (A) side, we drop the first write, since this is a // connection establishment packet, and we don't have the peer entity, just // the peer channel. The rest of the exchange must happen for the benefit of // DH key exchange. EXPECT_CALL(*channel_a, Read()) .WillRepeatedly( [channel = channel_a.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_a, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false)); EXPECT_CALL(*channel_b, Read()) .WillRepeatedly( [channel = channel_b.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_b, Write(_)) .WillRepeatedly( [channel = channel_b.get()](absl::string_view data) { return channel->DoWrite(data); }); EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_b, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); EXPECT_CALL(*channel_b, IsPaused).WillRepeatedly(Return(false)); return std::make_pair(std::move(channel_a), std::move(channel_b)); } void RequestConnection( const std::string& endpoint_id, std::unique_ptr channel_a, std::shared_ptr channel_b, ClientProxy* client, MockPcpHandler* pcp_handler, location::nearby::proto::connections::Medium connect_medium, std::atomic_int* flag = nullptr, Status expected_result = {Status::kSuccess}) { ConnectionRequestInfo info{ .endpoint_info = ByteArray{"ABCD"}, .listener = connection_listener_, }; ConnectionOptions connection_options{ .remote_bluetooth_mac_address = remote_mac_address_, .keep_alive_interval_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis, .keep_alive_timeout_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis, }; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); EXPECT_CALL(*pcp_handler, CanSendOutgoingConnection) .WillRepeatedly(Return(true)); EXPECT_CALL(*pcp_handler, GetStrategy) .WillRepeatedly(Return(Strategy::kP2pCluster)); if (expected_result == Status{Status::kSuccess}) { EXPECT_CALL(mock_connection_listener_.initiated_cb, Call).Times(1); } // Simulate successful discovery. auto encryption_runner = std::make_unique(); auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client); EXPECT_CALL(*pcp_handler, ConnectImpl) .WillOnce([&channel_a, connect_medium]( ClientProxy* client, MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ .medium = connect_medium, .status = {Status::kSuccess}, .endpoint_channel = std::move(channel_a), }; }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler->OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, info.endpoint_info, "service", discovered_medium, WebRtcState::kUndefined, }, MockContext{flag}, })); } auto other_client = std::make_unique(); // Run peer crypto in advance, if channel_b is provided. // Otherwise stay in not-encrypted state. if (channel_b != nullptr) { encryption_runner->StartServer(other_client.get(), endpoint_id, channel_b, {}); } EXPECT_EQ(pcp_handler->RequestConnection(client, endpoint_id, info, connection_options), expected_result); LOG(INFO) << "Stopping Encryption Runner"; } void RequestConnectionV3( const NearbyDevice& remote_device, std::unique_ptr channel_a, std::shared_ptr channel_b, ClientProxy* client, MockPcpHandler* pcp_handler, location::nearby::proto::connections::Medium connect_medium, FakePresenceDeviceProvider* fake_presence_device_provider, std::atomic_int* flag = nullptr, Status expected_result = {Status::kSuccess}, AuthenticationStatus expected_authentication_status = AuthenticationStatus::kSuccess) { ConnectionRequestInfo info{ .endpoint_info = ByteArray{"ABCD"}, .listener = connection_listener_, }; ConnectionOptions connection_options{ .remote_bluetooth_mac_address = remote_mac_address_, .keep_alive_interval_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis, .keep_alive_timeout_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis, }; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); EXPECT_CALL(*pcp_handler, CanSendOutgoingConnection) .WillRepeatedly(Return(true)); EXPECT_CALL(*pcp_handler, GetStrategy) .WillRepeatedly(Return(Strategy::kP2pCluster)); if (expected_result == Status{Status::kSuccess}) { EXPECT_CALL(mock_connection_listener_.initiated_cb, Call) .WillOnce([&](const std::string& endpoint_id, const ConnectionResponseInfo& info) { EXPECT_EQ(info.authentication_status, expected_authentication_status); EXPECT_TRUE(fake_presence_device_provider ->authenticate_as_initiator_called_); }); } // Simulate successful discovery. auto encryption_runner = std::make_unique(); auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client); EXPECT_CALL(*pcp_handler, ConnectImpl) .WillRepeatedly( [&channel_a, connect_medium]( ClientProxy* client, MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ .medium = connect_medium, .status = {Status::kSuccess}, .endpoint_channel = std::move(channel_a), }; }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler->OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { remote_device.GetEndpointId(), info.endpoint_info, "service", discovered_medium, WebRtcState::kUndefined, }, MockContext{flag}, })); } auto other_client = std::make_unique(); // Run peer crypto in advance, if channel_b is provided. // Otherwise stay in not-encrypted state. if (channel_b != nullptr) { encryption_runner->StartServer( other_client.get(), remote_device.GetEndpointId(), channel_b, {}); } EXPECT_EQ(pcp_handler->RequestConnectionV3(client, remote_device, info, connection_options), expected_result); } void RequestConnectionWifiLanFail( const std::string& endpoint_id, std::unique_ptr channel_a, std::shared_ptr channel_b, ClientProxy* client, MockPcpHandler* pcp_handler, std::atomic_int* flag = nullptr, Status expected_result = {Status::kSuccess}) { ConnectionRequestInfo info{ .endpoint_info = ByteArray{"ABCD"}, .listener = connection_listener_, }; ConnectionOptions connection_options{ .remote_bluetooth_mac_address = remote_mac_address_, .keep_alive_interval_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis, .keep_alive_timeout_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis, }; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); EXPECT_CALL(*pcp_handler, CanSendOutgoingConnection) .WillRepeatedly(Return(true)); EXPECT_CALL(*pcp_handler, GetStrategy) .WillRepeatedly(Return(Strategy::kP2pCluster)); if (expected_result == Status{Status::kSuccess}) { EXPECT_CALL(mock_connection_listener_.initiated_cb, Call).Times(1); } // Simulate successful discovery. auto encryption_runner = std::make_unique(); auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client); EXPECT_CALL(*pcp_handler, ConnectImpl) .WillRepeatedly( [&channel_a](ClientProxy* client, MockPcpHandler::DiscoveredEndpoint* endpoint) { if (endpoint->medium == location::nearby::proto::connections::WIFI_LAN) { LOG(INFO) << "Connect with Medium WIFI_LAN failed."; return MockPcpHandler::ConnectImplResult{ .medium = endpoint->medium, .status = {Status::kError}, .endpoint_channel = nullptr, }; } else { LOG(INFO) << "Connect with Medium: " << location::nearby::proto::connections::Medium_Name( endpoint->medium); return MockPcpHandler::ConnectImplResult{ .medium = endpoint->medium, .status = {Status::kSuccess}, .endpoint_channel = std::move(channel_a), }; } }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler->OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, info.endpoint_info, "service", discovered_medium, WebRtcState::kUndefined, }, MockContext{flag}, })); } auto other_client = std::make_unique(); // Run peer crypto in advance, if channel_b is provided. // Otherwise stay in not-encrypted state. if (channel_b != nullptr) { encryption_runner->StartServer(other_client.get(), endpoint_id, channel_b, {}); } EXPECT_EQ(pcp_handler->RequestConnection(client, endpoint_id, info, connection_options), expected_result); LOG(INFO) << "Stopping Encryption Runner"; } MockConnectionListener mock_connection_listener_; MockDiscoveryListener mock_discovery_listener_; ConnectionListener connection_listener_{ .initiated_cb = mock_connection_listener_.initiated_cb.AsStdFunction(), .accepted_cb = mock_connection_listener_.accepted_cb.AsStdFunction(), .rejected_cb = mock_connection_listener_.rejected_cb.AsStdFunction(), .disconnected_cb = mock_connection_listener_.disconnected_cb.AsStdFunction(), .bandwidth_changed_cb = mock_connection_listener_.bandwidth_changed_cb.AsStdFunction(), }; DiscoveryListener GetDiscoveryListener() { return DiscoveryListener{ .endpoint_found_cb = mock_discovery_listener_.endpoint_found_cb.AsStdFunction(), .endpoint_lost_cb = mock_discovery_listener_.endpoint_lost_cb.AsStdFunction(), .endpoint_distance_changed_cb = mock_discovery_listener_.endpoint_distance_changed_cb .AsStdFunction(), }; } SetSafeToDisconnect set_safe_to_disconnect_{true}; MediumEnvironment& env_ = MediumEnvironment::Instance(); NiceMock mock_device_; MacAddress remote_mac_address_; nearby::analytics::MockAnalyticsRecorder* mock_analytics_recorder_ptr_; std::unique_ptr client_; }; TEST_P(BasePcpHandlerTest, ConstructorDestructorWorks) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); SUCCEED(); bwu.Shutdown(); env_.Stop(); } TEST_P(BasePcpHandlerTest, StartAdvertisingChangesState) { NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature::kEnableDct, true); env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartAdvertising(client_.get(), &pcp_handler); bwu.Shutdown(); env_.Stop(); } TEST_P(BasePcpHandlerTest, StopAdvertisingChangesState) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartAdvertising(client_.get(), &pcp_handler); EXPECT_CALL(pcp_handler, StopAdvertisingImpl(client_.get())).Times(1); EXPECT_TRUE(client_->IsAdvertising()); pcp_handler.StopAdvertising(client_.get()); EXPECT_FALSE(client_->IsAdvertising()); bwu.Shutdown(); env_.Stop(); } TEST_P(BasePcpHandlerTest, StartDiscoveryChangesState) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); bwu.Shutdown(); env_.Stop(); } TEST_P(BasePcpHandlerTest, StartDiscoveryFails) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); DiscoveryOptions discovery_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints false, // is_out_of_band_connection, "", // fast_advertisement_service_uuid true, // low_power }; EXPECT_CALL(pcp_handler, StartDiscoveryImpl) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kError}, .mediums = {}, })); EXPECT_EQ( pcp_handler.StartDiscovery(client_.get(), "service", discovery_options, GetDiscoveryListener()), Status{Status::kError}); bwu.Shutdown(); env_.Stop(); } TEST_P(BasePcpHandlerTest, StopDiscoveryChangesState) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); EXPECT_CALL(pcp_handler, StopDiscoveryImpl(client_.get())).Times(1); EXPECT_TRUE(client_->IsDiscovering()); pcp_handler.StopDiscovery(client_.get()); EXPECT_FALSE(client_->IsDiscovering()); bwu.Shutdown(); env_.Stop(); } TEST_P(BasePcpHandlerTest, StartStopStartDiscoveryClearsEndpoints) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); pcp_handler.OnEndpointFound( client_.get(), std::make_shared(MockDiscoveredEndpoint{ { "DEFG", ByteArray("1"), "service", connect_medium, WebRtcState::kUndefined, }, MockContext{nullptr}, })); EXPECT_CALL(pcp_handler, StopDiscoveryImpl(client_.get())).Times(1); pcp_handler.StopDiscovery(client_.get()); EXPECT_FALSE(client_->IsDiscovering()); StartDiscovery(client_.get(), &pcp_handler); bwu.Shutdown(); env_.Stop(); } TEST_F(BasePcpHandlerTest, ShouldLostEndpointWhenReportInstantLost) { env_.Start({.use_simulated_clock = true}); BooleanMediumSelector allowed{ .bluetooth = true, .ble = true, .wifi_lan = true, }; auto endpoint = std::make_shared( MockDiscoveredEndpoint{{"ABCD", ByteArray("1234"), "service", Medium::BLE, WebRtcState::kUndefined}, MockContext{nullptr}}); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler, allowed); EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); pcp_handler.OnEndpointFound(client_.get(), endpoint); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints("ABCD").size(), 1); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call); pcp_handler.OnInstantLost(client_.get(), endpoint); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints("ABCD").size(), 0); EXPECT_CALL(pcp_handler, StopDiscoveryImpl(client_.get())).Times(1); pcp_handler.StopDiscovery(client_.get()); bwu.Shutdown(); env_.Stop(); } TEST_F(BasePcpHandlerTest, ShouldLostAllEndpointsWhenReportInstantLost) { env_.Start({.use_simulated_clock = true}); BooleanMediumSelector allowed{ .bluetooth = true, .ble = true, .wifi_lan = true, }; auto endpoint = std::make_shared( MockDiscoveredEndpoint{{"ABCD", ByteArray("1234"), "service", Medium::BLE, WebRtcState::kUndefined}, MockContext{nullptr}}); auto endpoint_bluetooth = std::make_shared( MockDiscoveredEndpoint{{"ABCD", ByteArray("1234"), "service", Medium::BLUETOOTH, WebRtcState::kUndefined}, MockContext{nullptr}}); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler, allowed); EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); pcp_handler.OnEndpointFound(client_.get(), endpoint); pcp_handler.OnEndpointFound(client_.get(), endpoint_bluetooth); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints("ABCD").size(), 2); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call); pcp_handler.OnInstantLost(client_.get(), endpoint); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints("ABCD").size(), 0); EXPECT_CALL(pcp_handler, StopDiscoveryImpl(client_.get())).Times(1); pcp_handler.StopDiscovery(client_.get()); bwu.Shutdown(); env_.Stop(); } TEST_F(BasePcpHandlerTest, WifiMediumFailFallBackToBT) { env_.Start(); std::string service_id{"service"}; std::string endpoint_id{"ABCD"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector allowed{ .bluetooth = true, .wifi_lan = true, }; DiscoveryOptions discovery_options{ { Strategy::kP2pCluster, allowed, }, false, // auto_upgrade_bandwidth; false, // enforce_topology_constraints; }; EXPECT_CALL(pcp_handler, StartDiscoveryImpl(client_.get(), service_id, _)) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); EXPECT_EQ( pcp_handler.StartDiscovery(client_.get(), service_id, discovery_options, GetDiscoveryListener()), Status{Status::kSuccess}); EXPECT_TRUE(client_->IsDiscovering()); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnectionWifiLanFail(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, RequestConnectionChangesState) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnection("1234", std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium); LOG(INFO) << "RequestConnection complete"; EXPECT_TRUE(pcp_handler.HasOutgoingConnections(client_.get())); EXPECT_FALSE(pcp_handler.HasIncomingConnections(client_.get())); channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, CanRequestConnectionPresence) { env_.Start(); FakePresenceDeviceProvider provider; EXPECT_CALL(provider.local_device_, GetType) .WillRepeatedly(Return(NearbyDevice::Type::kPresenceDevice)); EXPECT_CALL(provider.local_device_, ToProtoBytes).WillRepeatedly([]() { location::nearby::connections::PresenceDevice presence_device; presence_device.set_endpoint_id("TEST"); presence_device.set_device_id(2468); presence_device.add_identity_type(1); presence_device.add_actions(1); presence_device.add_actions(2); presence_device.add_actions(3); presence_device.add_actions(4); presence_device.add_discovery_medium( location::nearby::connections::ConnectionRequestFrame::BLUETOOTH); std::string serialized = presence_device.SerializeAsString(); EXPECT_FALSE(serialized.empty()); return serialized; }); client_->RegisterDeviceProvider(&provider); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnection("1234", std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); } TEST_P(BasePcpHandlerTest, CanRequestConnectionLegacy) { env_.Start(); FakePresenceDeviceProvider provider; EXPECT_CALL(provider.local_device_, GetType) .WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice)); EXPECT_CALL(provider.local_device_, ToProtoBytes); client_->RegisterDeviceProvider(&provider); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnection("1234", std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, RequestConnectionV3) { env_.Start(); FakePresenceDeviceProvider provider; EXPECT_CALL(provider.local_device_, GetType) .WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice)); EXPECT_CALL(provider.local_device_, ToProtoBytes); client_->RegisterDeviceProvider(&provider); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnectionV3(mock_device_, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &provider); LOG(INFO) << "RequestConnectionV3 complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, RequestConnectionV3_AuthenticationFailure) { env_.Start(); FakePresenceDeviceProvider provider; provider.SetAuthenticationStatus(AuthenticationStatus::kFailure); EXPECT_CALL(provider.local_device_, GetType) .WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice)); EXPECT_CALL(provider.local_device_, ToProtoBytes); client_->RegisterDeviceProvider(&provider); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnectionV3( mock_device_, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &provider, /*flag=*/nullptr, /*expected_result=*/{Status::kSuccess}, /*expected_authentication_status=*/AuthenticationStatus::kFailure); LOG(INFO) << "RequestConnectionV3 complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) { env_.Start(); FakePresenceDeviceProvider provider; EXPECT_CALL(provider.local_device_, GetType) .WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice)); client_->RegisterDeviceProvider(&provider); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnectionForConnectFailure(connect_medium); std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); ConnectionRequestInfo info{ .endpoint_info = ByteArray{"ABCD"}, .listener = connection_listener_, }; ConnectionOptions connection_options{ .remote_bluetooth_mac_address = remote_mac_address_, .keep_alive_interval_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis, .keep_alive_timeout_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis, }; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); EXPECT_CALL(pcp_handler, CanSendOutgoingConnection) .WillRepeatedly(Return(true)); EXPECT_CALL(pcp_handler, GetStrategy) .WillRepeatedly(Return(Strategy::kP2pCluster)); // Simulate successful discovery. auto encryption_runner = std::make_unique(); auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get()); EXPECT_CALL(pcp_handler, ConnectImpl) .WillRepeatedly( [connect_medium](ClientProxy* client, MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ .medium = connect_medium, .status = {Status::kError}, .endpoint_channel = nullptr, }; }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler.OnEndpointFound( client_.get(), std::make_shared(MockDiscoveredEndpoint{ { mock_device_.GetEndpointId(), info.endpoint_info, "service", discovered_medium, WebRtcState::kUndefined, }, MockContext{nullptr}, })); } Status expected_result = {Status::kError}; EXPECT_EQ(pcp_handler.RequestConnectionV3(client_.get(), mock_device_, info, connection_options), expected_result); LOG(INFO) << "RequestConnectionV3 complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) { env_.Start(); FakePresenceDeviceProvider provider; EXPECT_CALL(provider.local_device_, GetType) .WillRepeatedly(Return(NearbyDevice::Type::kUnknownDevice)); client_->RegisterDeviceProvider(&provider); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnectionForConnectFailure(connect_medium); std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); ConnectionRequestInfo info{ .endpoint_info = ByteArray{"ABCD"}, .listener = connection_listener_, }; ConnectionOptions connection_options{ .remote_bluetooth_mac_address = remote_mac_address_, .keep_alive_interval_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_interval_millis, .keep_alive_timeout_millis = FeatureFlags::GetInstance().GetFlags().keep_alive_timeout_millis, }; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); EXPECT_CALL(pcp_handler, CanSendOutgoingConnection) .WillRepeatedly(Return(true)); EXPECT_CALL(pcp_handler, GetStrategy) .WillRepeatedly(Return(Strategy::kP2pCluster)); // Simulate successful discovery. auto encryption_runner = std::make_unique(); auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get()); EXPECT_CALL(pcp_handler, ConnectImpl) .WillRepeatedly( [connect_medium](ClientProxy* client, MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ .medium = connect_medium, .status = {Status::kError}, .endpoint_channel = nullptr, }; }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler.OnEndpointFound( client_.get(), std::make_shared(MockDiscoveredEndpoint{ { std::string(kTestEndpointId), info.endpoint_info, "service", discovered_medium, WebRtcState::kUndefined, }, MockContext{nullptr}, })); } Status expected_result = {Status::kError}; EXPECT_EQ( pcp_handler.RequestConnection(client_.get(), std::string(kTestEndpointId), info, connection_options), expected_result); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, IoError_RequestConnectionV3Fails) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1)); EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1)); channel_b->broken_write_ = true; EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnectionV3(mock_device_, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, nullptr, nullptr, {Status::kEndpointIoError}); LOG(INFO) << "RequestConnectionV3 complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, IoError_RequestConnectionFails) { env_.Start(); std::string endpoint_id{"1234"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1)); EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1)); channel_b->broken_write_ = true; EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, nullptr, {Status::kEndpointIoError}); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, AcceptConnectionChangesState) { env_.Start(); std::string endpoint_id{"1234"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium); LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id; EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}), Status{Status::kSuccess}); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); LOG(INFO) << "Closing connection: id=" << endpoint_id; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, RejectConnectionChangesState) { env_.Start(); std::string endpoint_id{"1234"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(1); RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b, client_.get(), &pcp_handler, connect_medium); LOG(INFO) << "Attempting to reject connection: id=" << endpoint_id; EXPECT_EQ(pcp_handler.RejectConnection(client_.get(), endpoint_id), Status{Status::kSuccess}); LOG(INFO) << "Closing connection: id=" << endpoint_id; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) { env_.Start(); std::string endpoint_id{"1234"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium); LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id; EXPECT_CALL(mock_connection_listener_.accepted_cb, Call).Times(1); EXPECT_CALL(mock_connection_listener_.disconnected_cb, Call) .Times(AtLeast(0)); EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}), Status{Status::kSuccess}); LOG(INFO) << "Simulating remote accept: id=" << endpoint_id; OsInfo os_info; auto frame = parser::FromBytes( parser::ForConnectionResponse(Status::kSuccess, os_info)); EXPECT_CALL(mock_connection_listener_.bandwidth_changed_cb, Call).Times(1); pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(), connect_medium); LOG(INFO) << "Closing connection: id=" << endpoint_id; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); env_.Stop(); } TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) { env_.Start(); std::atomic_int destroyed_flag = 0; int mediums_count = 0; { std::string endpoint_id{"1234"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &destroyed_flag); mediums_count = mediums.size(); LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id; EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}), Status{Status::kSuccess}); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); LOG(INFO) << "Closing connection: id=" << endpoint_id; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); } EXPECT_EQ(destroyed_flag.load(), mediums_count); env_.Stop(); } TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) { env_.Start(); BooleanMediumSelector allowed = GetParam(); if (allowed.Count(true) < 2) { // Ignore single-medium test cases, and implicit "all mediums" case. SUCCEED(); return; } std::atomic_int destroyed_flag = 0; int mediums_count = 0; { std::string endpoint_id{"1234"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; std::shared_ptr channel_b = std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call).Times(1); RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &destroyed_flag); auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get()); mediums_count = allowed_mediums.size(); LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id; EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}), Status{Status::kSuccess}); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); auto endpoint_disc = pcp_handler.GetDiscoveredEndpoint(endpoint_id); pcp_handler.OnEndpointLost(client_.get(), *endpoint_disc); EXPECT_NE(pcp_handler.GetDiscoveredEndpoint(endpoint_id), nullptr); for (const auto* endpoint : pcp_handler.GetDiscoveredEndpoints(endpoint_id)) { pcp_handler.OnEndpointLost(client_.get(), *endpoint); } EXPECT_EQ(pcp_handler.GetDiscoveredEndpoint(endpoint_id), nullptr); EXPECT_FALSE(client_->IsConnectedToEndpoint(endpoint_id)); LOG(INFO) << "Closing connection: id=" << endpoint_id; channel_b->Close(); bwu.Shutdown(); pcp_handler.DisconnectFromEndpointManager(); } EXPECT_EQ(destroyed_flag.load(), mediums_count); env_.Stop(); } INSTANTIATE_TEST_SUITE_P(ParameterizedBasePcpHandlerTest, BasePcpHandlerTest, ::testing::ValuesIn(kTestCases)); TEST_F(BasePcpHandlerTest, StripOutWifiHotspotMedium) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); ConnectionInfo connection_info; connection_info.supported_mediums = {Medium::WIFI_LAN, Medium::WIFI_HOTSPOT, Medium::BLUETOOTH}; pcp_handler.StripOutWifiHotspotMedium(connection_info); EXPECT_THAT( connection_info.supported_mediums, ::testing::UnorderedElementsAre(Medium::WIFI_LAN, Medium::BLUETOOTH)); ConnectionInfo connection_info2; connection_info2.supported_mediums = {Medium::WIFI_HOTSPOT, Medium::BLUETOOTH}; pcp_handler.StripOutWifiHotspotMedium(connection_info2); EXPECT_THAT( connection_info2.supported_mediums, ::testing::UnorderedElementsAre(Medium::WIFI_HOTSPOT, Medium::BLUETOOTH)); bwu.Shutdown(); env_.Stop(); } TEST_F(BasePcpHandlerTest, CreatePeerIdFromAdvertisement) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); std::string service_id = "service"; std::string endpoint_id = "endpoint"; ByteArray endpoint_info("info"); mediums::WebrtcPeerId peer_id = pcp_handler.CreatePeerIdFromAdvertisement( service_id, endpoint_id, endpoint_info); std::string seed = absl::StrCat(service_id, endpoint_id, std::string(endpoint_info)); mediums::WebrtcPeerId expected_peer_id = mediums::WebrtcPeerId::FromSeed(ByteArray(std::move(seed))); EXPECT_EQ(peer_id.GetId(), expected_peer_id.GetId()); bwu.Shutdown(); env_.Stop(); } TEST_F(BasePcpHandlerTest, InjectEndpoint) { env_.Start(); std::string service_id{"service"}; std::string endpoint_id{"ABCD"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector allowed{ .bluetooth = true, }; DiscoveryOptions discovery_options{ { Strategy::kP2pPointToPoint, allowed, }, false, // auto_upgrade_bandwidth; false, // enforce_topology_constraints; }; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call); EXPECT_CALL(pcp_handler, StartDiscoveryImpl(client_.get(), service_id, _)) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); EXPECT_EQ( pcp_handler.StartDiscovery(client_.get(), service_id, discovery_options, GetDiscoveryListener()), Status{Status::kSuccess}); EXPECT_TRUE(client_->IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl(client_.get(), service_id, _)) .WillOnce([&pcp_handler, &endpoint_id]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { pcp_handler.OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, /*endpoint_info=*/ByteArray{"ABCD"}, service_id, Medium::BLUETOOTH, WebRtcState::kUndefined, }, MockContext{nullptr}, })); return Status{Status::kSuccess}; }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); bwu.Shutdown(); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestEndpointInfoChangedWhenEndpointDiscoveredOnMultipleMediums) { env_.Start(); std::string service_id{"service"}; std::string endpoint_id{"ABCD"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector allowed{ .bluetooth = true, .ble = true, }; DiscoveryOptions discovery_options{ { Strategy::kP2pPointToPoint, allowed, }, false, // auto_upgrade_bandwidth; false, // enforce_topology_constraints; }; EXPECT_CALL(pcp_handler, StartDiscoveryImpl) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); EXPECT_EQ( pcp_handler.StartDiscovery(client_.get(), service_id, discovery_options, GetDiscoveryListener()), Status{Status::kSuccess}); EXPECT_TRUE(client_->IsDiscovering()); ::testing::InSequence seq; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call) .WillOnce([id = endpoint_id](const std::string& endpoint_id, const ByteArray& endpoint_info, const std::string& service_id) { EXPECT_EQ(endpoint_id, id); EXPECT_EQ(endpoint_info, ByteArray{"ABCD"}); }); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call) .WillOnce([id = endpoint_id](const std::string& endpoint_id) { EXPECT_EQ(endpoint_id, id); }); EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call) .WillOnce([id = endpoint_id](const std::string& endpoint_id, const ByteArray& endpoint_info, const std::string& service_id) { EXPECT_EQ(endpoint_id, id); EXPECT_EQ(endpoint_info, ByteArray{"ABCDEF"}); }); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call) .WillOnce([id = endpoint_id](const std::string& endpoint_id) { EXPECT_EQ(endpoint_id, id); }); // Found endpoint on Bluetooth pcp_handler.OnEndpointFound( client_.get(), std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, /*endpoint_info=*/ByteArray{"ABCD"}, service_id, Medium::BLUETOOTH, WebRtcState::kUndefined, }, MockContext{nullptr}, })); // Found endpoint on BLE pcp_handler.OnEndpointFound( client_.get(), std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, /*endpoint_info=*/ByteArray{"ABCD"}, service_id, Medium::BLE, WebRtcState::kUndefined, }, MockContext{nullptr}, })); // Endpoint info changed on BLE pcp_handler.OnEndpointFound( client_.get(), std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, /*endpoint_info=*/ByteArray{"ABCDEF"}, service_id, Medium::BLE, WebRtcState::kUndefined, }, MockContext{nullptr}, })); pcp_handler.OnEndpointLost(client_.get(), MockDiscoveredEndpoint{ { endpoint_id, /*endpoint_info=*/ByteArray{"ABCDEF"}, service_id, Medium::BLE, WebRtcState::kUndefined, }, MockContext{nullptr}, }); env_.Sync(false); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) { env_.Start(); std::string service_id{"service"}; std::string endpoint_id{"ABCD"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector allowed{ .bluetooth = true, }; DiscoveryOptions discovery_options{ { Strategy::kP2pPointToPoint, allowed, }, false, // auto_upgrade_bandwidth; false, // enforce_topology_constraints; }; EXPECT_CALL(pcp_handler, StartDiscoveryImpl) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); EXPECT_EQ(pcp_handler.StartDiscovery(client_.get(), service_id, discovery_options, {}), Status{Status::kSuccess}); EXPECT_TRUE(client_->IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl) .WillOnce([&pcp_handler, &endpoint_id]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { pcp_handler.OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, /*endpoint_info=*/ByteArray{"ABCD"}, service_id, Medium::BLUETOOTH, WebRtcState::kUndefined, }, MockContext{nullptr}, })); return Status{Status::kSuccess}; }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); pcp_handler.StartEndpointLostByMediumAlarms(client_.get(), Medium::BLUETOOTH); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 1); pcp_handler.StopEndpointLostByMediumAlarm(endpoint_id, Medium::BLUETOOTH); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) { env_.Start(); std::string service_id{"service"}; std::string endpoint_id{"ABCD"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector allowed{ .bluetooth = true, }; DiscoveryOptions discovery_options{ { Strategy::kP2pPointToPoint, allowed, }, false, // auto_upgrade_bandwidth; false, // enforce_topology_constraints; }; EXPECT_CALL(pcp_handler, StartDiscoveryImpl) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); EXPECT_EQ(pcp_handler.StartDiscovery(client_.get(), service_id, discovery_options, {}), Status{Status::kSuccess}); EXPECT_TRUE(client_->IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl) .WillOnce([&pcp_handler, &endpoint_id]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { pcp_handler.OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, /*endpoint_info=*/ByteArray{"ABCD"}, service_id, Medium::BLUETOOTH, WebRtcState::kUndefined, }, MockContext{nullptr}, })); return Status{Status::kSuccess}; }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); pcp_handler.StartEndpointLostByMediumAlarms(client_.get(), Medium::BLUETOOTH); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 1); absl::SleepFor(absl::Seconds(11)); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 0); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) { env_.Start(); std::string service_id{"service"}; std::string endpoint_id{"ABCD"}; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector allowed{ .bluetooth = true, }; DiscoveryOptions discovery_options{ { Strategy::kP2pPointToPoint, allowed, }, false, // auto_upgrade_bandwidth; false, // enforce_topology_constraints; }; EXPECT_CALL(pcp_handler, StartDiscoveryImpl) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kSuccess}, .mediums = allowed.GetMediums(true), })); EXPECT_EQ(pcp_handler.StartDiscovery(client_.get(), service_id, discovery_options, {}), Status{Status::kSuccess}); EXPECT_TRUE(client_->IsDiscovering()); bool first_call = true; EXPECT_CALL(pcp_handler, InjectEndpointImpl) .Times(2) .WillRepeatedly( [&pcp_handler, &endpoint_id, &first_call]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { ByteArray endpoint_info; if (first_call) { endpoint_info = ByteArray("ABCD"); } else { endpoint_info = ByteArray("ABCDE"); } first_call = false; pcp_handler.OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { endpoint_id, endpoint_info, service_id, Medium::BLUETOOTH, WebRtcState::kUndefined, }, MockContext{nullptr}, })); return Status{Status::kSuccess}; }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); EXPECT_EQ(pcp_handler.GetDiscoveredEndpoints(Medium::BLUETOOTH).size(), 1); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); pcp_handler.StartEndpointLostByMediumAlarms(client_.get(), Medium::BLUETOOTH); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 1); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); EXPECT_EQ(pcp_handler.GetEndpointLostByMediumAlarmsCount(), 0); env_.Stop(); } TEST_P(BasePcpHandlerTest, TestGetConnectionInfosFromMediums) { env_.Start(); Mediums mediums; EndpointChannelManager endpoint_channel_manager; EndpointManager endpoint_manager(&endpoint_channel_manager); BwuManager bwu_manager(mediums, endpoint_manager, endpoint_channel_manager, {}, {}); MockPcpHandler pcp_handler(&mediums, &endpoint_manager, &endpoint_channel_manager, &bwu_manager); BooleanMediumSelector selector = GetParam(); // Flip on a medium we should not get info for. selector.web_rtc = true; std::vector infos = pcp_handler.GetConnectionInfoFromResult( "service", {.mediums = selector.GetMediums(true)}); // Make sure we don't count webrtc. EXPECT_EQ(infos.size(), selector.Count(true) - 1); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestCanStartListeningForIncomingConnections) { env_.Start(); Mediums mediums; EndpointChannelManager endpoint_channel_manager; EndpointManager endpoint_manager(&endpoint_channel_manager); BwuManager bwu_manager(mediums, endpoint_manager, endpoint_channel_manager, {}, {}); MockPcpHandler pcp_handler(&mediums, &endpoint_manager, &endpoint_channel_manager, &bwu_manager); EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .Times(1) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); v3::ConnectionListeningOptions options = {.strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true}; pcp_handler.StartListeningForIncomingConnections(client_.get(), "service", options, {}); EXPECT_TRUE(client_->IsListeningForIncomingConnections()); } TEST_F(BasePcpHandlerTest, TestStartListeningForIncomingConnectionsBadStatus) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .Times(1) .WillOnce(Return(MockPcpHandler::StartOperationResult{ .status = {Status::kAlreadyListening}})); v3::ConnectionListeningOptions options = {.strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true}; pcp_handler.StartListeningForIncomingConnections(client_.get(), "service", options, {}); EXPECT_FALSE(client_->IsListeningForIncomingConnections()); } TEST_F(BasePcpHandlerTest, TestCanStopListeningForIncomingConnections) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .Times(1) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, StopListeningForIncomingConnectionsImpl).Times(1); v3::ConnectionListeningOptions options = {.strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true}; pcp_handler.StartListeningForIncomingConnections(client_.get(), "service", options, {}); pcp_handler.StopListeningForIncomingConnections(client_.get()); EXPECT_FALSE(client_->IsListeningForIncomingConnections()); } TEST_F(BasePcpHandlerTest, TestWifiLanStopListeningForIncomingConnectionsSuccessWhenStopped) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .Times(1) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, StopListeningForIncomingConnectionsImpl).Times(1); v3::ConnectionListeningOptions options = {.strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true}; pcp_handler.StartListeningForIncomingConnections(client_.get(), "service", options, {}); m.GetWifiLan().StopAcceptingConnections("service"); pcp_handler.StopListeningForIncomingConnections(client_.get()); EXPECT_FALSE(client_->IsListeningForIncomingConnections()); } TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithUnknown) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kConnectionsDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; frame.ParseFromString(serialized_frame); frame.mutable_v1()->mutable_connection_request()->clear_connections_device(); frame.mutable_v1()->mutable_connection_request()->clear_presence_device(); ASSERT_FALSE(frame.v1().connection_request().has_connections_device()); ASSERT_FALSE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. channel_pair.first->Write(""); channel_pair.first->Write(frame.SerializeAsString()); EXPECT_TRUE(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), std::move(channel_pair.second), Medium::BLUETOOTH, NearbyDevice::Type::kConnectionsDevice) .Ok()); EXPECT_TRUE(pcp_handler.HasIncomingConnections(client_.get())); EXPECT_FALSE(pcp_handler.HasOutgoingConnections(client_.get())); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithUnknown) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kPresenceDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; frame.ParseFromString(serialized_frame); frame.mutable_v1()->mutable_connection_request()->clear_connections_device(); frame.mutable_v1()->mutable_connection_request()->clear_presence_device(); ASSERT_FALSE(frame.v1().connection_request().has_connections_device()); ASSERT_FALSE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. channel_pair.first->Write(""); channel_pair.first->Write(frame.SerializeAsString()); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), std::move(channel_pair.second), Medium::BLUETOOTH, NearbyDevice::Type::kPresenceDevice) .value, Exception::Value::kIo); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithConnections) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kPresenceDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_connections_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_connections_device()); // do a dummy write to get to the actual write. channel_pair.first->Write(""); channel_pair.first->Write(frame.SerializeAsString()); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), std::move(channel_pair.second), Medium::BLUETOOTH, NearbyDevice::Type::kPresenceDevice) .value, Exception::Value::kIo); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithPresence) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kPresenceDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_presence_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. channel_pair.first->Write(""); channel_pair.first->Write(frame.SerializeAsString()); EXPECT_TRUE(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), std::move(channel_pair.second), Medium::BLUETOOTH, NearbyDevice::Type::kPresenceDevice) .Ok()); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithConnections) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kConnectionsDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_connections_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_connections_device()); // do a dummy write to get to the actual write. channel_pair.first->Write(""); channel_pair.first->Write(frame.SerializeAsString()); EXPECT_TRUE(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), std::move(channel_pair.second), Medium::BLUETOOTH, NearbyDevice::Type::kConnectionsDevice) .Ok()); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithPresence) { env_.Start(); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kConnectionsDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_presence_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. channel_pair.first->Write(""); channel_pair.first->Write(frame.SerializeAsString()); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), std::move(channel_pair.second), Medium::BLUETOOTH, NearbyDevice::Type::kConnectionsDevice) .value, Exception::Value::kIo); env_.Stop(); } TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) { env_.Start({.use_simulated_clock = true}); client_ = std::make_unique(CreateAnalyticsRecorder()); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kConnectionsDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_CALL(*mock_analytics_recorder_ptr_, OnStartedIncomingConnectionListening(_)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "", .local_endpoint_info = ByteArray("local endpoint"), }); // At this point the connection request doesn't have an endpoint ID field // set, so we do that here. location::nearby::connections::OfflineFrame frame; frame.ParseFromString(serialized_frame); frame.mutable_v1()->mutable_connection_request()->set_endpoint_id(""); ASSERT_TRUE(frame.v1().connection_request().has_endpoint_id()); // do a dummy write to get to the actual write. channel_pair.first->Write(""); channel_pair.first->Write(frame.SerializeAsString()); EXPECT_CALL(*mock_analytics_recorder_ptr_, LogSession()).Times(3); EXPECT_CALL(*mock_analytics_recorder_ptr_, LogStartSession()).Times(3); EXPECT_CALL( *mock_analytics_recorder_ptr_, OnIncomingConnectionAttempt( location::nearby::proto::connections::INITIAL, Medium::BLUETOOTH, location::nearby::proto::connections::RESULT_ERROR, _, _, _)); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), std::move(channel_pair.second), Medium::BLUETOOTH, NearbyDevice::Type::kConnectionsDevice) .value, Exception::Value::kIo); env_.Stop(); } TEST_F(BasePcpHandlerTest, IncomingConnectionWithNoDataFailsWithoutLogging) { env_.Start({.use_simulated_clock = true}); // Recreate ClientProxy so that AnalyticRecorder uses simulated clock. client_ = std::make_unique(CreateAnalyticsRecorder()); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); v3::ConnectionListeningOptions options = { .strategy = Strategy::kP2pCluster, .enable_ble_listening = true, .enable_bluetooth_listening = true, .enable_wlan_listening = true, .listening_endpoint_type = NearbyDevice::Type::kConnectionsDevice}; EXPECT_CALL(pcp_handler, StartListeningForIncomingConnectionsImpl) .WillOnce(Return( MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); EXPECT_CALL(*mock_analytics_recorder_ptr_, OnStartedIncomingConnectionListening(_)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) .first.Ok()); ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto [input_a, output_a] = CreatePipe(); auto input_channel = std::make_unique( std::move(input_a), std::move(output_a)); EXPECT_CALL(*input_channel, Read()) .WillRepeatedly(Return(ExceptionOr(Exception::kNoData))); EXPECT_CALL(*mock_analytics_recorder_ptr_, LogSession()).Times(3); EXPECT_CALL(*mock_analytics_recorder_ptr_, LogStartSession()).Times(3); EXPECT_EQ( pcp_handler .OnIncomingConnection(client_.get(), ByteArray("remote endpoint"), std::move(input_channel), Medium::BLUETOOTH, NearbyDevice::Type::kConnectionsDevice) .value, Exception::Value::kNoData); client_.reset(); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestNeedsToTurnOffAdvertisingMedium) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector old_meds{ .bluetooth = true, .ble = true, .wifi_lan = false, }; AdvertisingOptions old_opts, new_opts; old_opts.allowed = old_meds; BooleanMediumSelector new_meds{ .bluetooth = false, .ble = true, .wifi_lan = false, }; new_opts.allowed = new_meds; EXPECT_TRUE(pcp_handler.NeedsToTurnOffAdvertisingMedium(Medium::BLUETOOTH, old_opts, new_opts)); EXPECT_FALSE(pcp_handler.NeedsToTurnOffAdvertisingMedium(Medium::BLE, old_opts, new_opts)); EXPECT_FALSE(pcp_handler.NeedsToTurnOffAdvertisingMedium(Medium::WIFI_LAN, old_opts, new_opts)); } TEST_F(BasePcpHandlerTest, TestUpdateAdvertisingOptionsWorks) { env_.Start(); AdvertisingOptions old_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints true, // low_power false, // enable_bluetooth_listening }; AdvertisingOptions new_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints false, // low_power true, // enable_bluetooth_listening }; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartAdvertisingWithOptions(client_.get(), &pcp_handler, old_options); EXPECT_TRUE(client_->IsAdvertising()); auto current_client_opts = client_->GetAdvertisingOptions(); // check custom option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, old_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, old_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, old_options.low_power); EXPECT_EQ(current_client_opts.enable_bluetooth_listening, old_options.enable_bluetooth_listening); UpdateAdvertisingOptions(client_.get(), &pcp_handler, new_options, {Status::kSuccess}); EXPECT_TRUE(client_->IsAdvertising()); current_client_opts = client_->GetAdvertisingOptions(); // check new option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, new_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, new_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, new_options.low_power); EXPECT_EQ(current_client_opts.enable_bluetooth_listening, new_options.enable_bluetooth_listening); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestUpdateAdvertisingOptionsFailsWithBadStatus) { env_.Start(); AdvertisingOptions old_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints true, // low_power false, // enable_bluetooth_listening }; AdvertisingOptions new_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints false, // low_power true, // enable_bluetooth_listening }; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartAdvertisingWithOptions(client_.get(), &pcp_handler, old_options); EXPECT_TRUE(client_->IsAdvertising()); auto current_client_opts = client_->GetAdvertisingOptions(); // check custom option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, old_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, old_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, old_options.low_power); EXPECT_EQ(current_client_opts.enable_bluetooth_listening, old_options.enable_bluetooth_listening); UpdateAdvertisingOptions(client_.get(), &pcp_handler, new_options, {Status::kBleError}); EXPECT_TRUE(client_->IsAdvertising()); current_client_opts = client_->GetAdvertisingOptions(); // check new option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, old_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, old_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, old_options.low_power); EXPECT_EQ(current_client_opts.enable_bluetooth_listening, old_options.enable_bluetooth_listening); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestNeedsToTurnOffDiscoveryMedium) { Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); BooleanMediumSelector old_meds{ .bluetooth = true, .ble = true, .wifi_lan = false, }; DiscoveryOptions old_opts, new_opts; old_opts.allowed = old_meds; BooleanMediumSelector new_meds{ .bluetooth = false, .ble = true, .wifi_lan = false, }; new_opts.allowed = new_meds; EXPECT_TRUE(pcp_handler.NeedsToTurnOffDiscoveryMedium(Medium::BLUETOOTH, old_opts, new_opts)); EXPECT_FALSE(pcp_handler.NeedsToTurnOffDiscoveryMedium(Medium::BLE, old_opts, new_opts)); EXPECT_FALSE(pcp_handler.NeedsToTurnOffDiscoveryMedium(Medium::WIFI_LAN, old_opts, new_opts)); } TEST_F(BasePcpHandlerTest, TestUpdateDiscoveryOptionsWorks) { env_.Start(); DiscoveryOptions old_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints false, // is_out_of_band_connection, "", // fast_advertisement_service_uuid false, // low_power }; DiscoveryOptions new_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints false, // is_out_of_band_connection, "", // fast_advertisement_service_uuid true, // low_power }; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscoveryWithOptions(client_.get(), &pcp_handler, old_options); EXPECT_TRUE(client_->IsDiscovering()); auto current_client_opts = client_->GetDiscoveryOptions(); // check custom option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, old_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, old_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, old_options.low_power); EXPECT_EQ(current_client_opts.is_out_of_band_connection, old_options.is_out_of_band_connection); EXPECT_EQ(current_client_opts.fast_advertisement_service_uuid, old_options.fast_advertisement_service_uuid); UpdateDiscoveryOptions(client_.get(), &pcp_handler, new_options, {Status::kSuccess}); EXPECT_TRUE(client_->IsDiscovering()); current_client_opts = client_->GetDiscoveryOptions(); // check new option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, new_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, new_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, new_options.low_power); EXPECT_EQ(current_client_opts.is_out_of_band_connection, new_options.is_out_of_band_connection); EXPECT_EQ(current_client_opts.fast_advertisement_service_uuid, new_options.fast_advertisement_service_uuid); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestUpdateDiscoveryOptionsFailsWithBadStatus) { env_.Start(); DiscoveryOptions old_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints false, // is_out_of_band_connection, "", // fast_advertisement_service_uuid false, // low_power }; DiscoveryOptions new_options{ {}, true, // auto_upgrade_bandwidth true, // enforce_topology_constraints false, // is_out_of_band_connection, "", // fast_advertisement_service_uuid true, // low_power }; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartDiscoveryWithOptions(client_.get(), &pcp_handler, old_options); EXPECT_TRUE(client_->IsDiscovering()); auto current_client_opts = client_->GetDiscoveryOptions(); // check custom option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, old_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, old_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, old_options.low_power); EXPECT_EQ(current_client_opts.is_out_of_band_connection, old_options.is_out_of_band_connection); EXPECT_EQ(current_client_opts.fast_advertisement_service_uuid, old_options.fast_advertisement_service_uuid); UpdateDiscoveryOptions(client_.get(), &pcp_handler, new_options, {Status::kBleError}); EXPECT_TRUE(client_->IsDiscovering()); current_client_opts = client_->GetDiscoveryOptions(); // check new option parameters EXPECT_EQ(current_client_opts.auto_upgrade_bandwidth, old_options.auto_upgrade_bandwidth); EXPECT_EQ(current_client_opts.enforce_topology_constraints, old_options.enforce_topology_constraints); EXPECT_EQ(current_client_opts.low_power, old_options.low_power); EXPECT_EQ(current_client_opts.is_out_of_band_connection, old_options.is_out_of_band_connection); EXPECT_EQ(current_client_opts.fast_advertisement_service_uuid, old_options.fast_advertisement_service_uuid); env_.Stop(); } TEST_F(BasePcpHandlerTest, TestForceUpdateEndpointIdAdvertisingOption) { env_.Start(); AdvertisingOptions use_old_endpoint_id_options{ .auto_upgrade_bandwidth = true, .enforce_topology_constraints = true, .low_power = true, .enable_bluetooth_listening = false, .force_new_endpoint_id = false, }; AdvertisingOptions use_new_endpoint_id_options{ .auto_upgrade_bandwidth = true, .enforce_topology_constraints = true, .low_power = true, .enable_bluetooth_listening = false, .force_new_endpoint_id = true, }; Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); std::string old_endpoint_id = client_->GetLocalEndpointId(); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); StartAdvertisingWithOptions(client_.get(), &pcp_handler, use_old_endpoint_id_options); EXPECT_TRUE(client_->IsAdvertising()); EXPECT_EQ(client_->GetLocalEndpointId(), old_endpoint_id); pcp_handler.StopAdvertising(client_.get()); EXPECT_FALSE(client_->IsAdvertising()); StartAdvertisingWithOptions(client_.get(), &pcp_handler, use_new_endpoint_id_options); EXPECT_TRUE(client_->IsAdvertising()); EXPECT_NE(client_->GetLocalEndpointId(), old_endpoint_id); env_.Stop(); } } // namespace } // namespace nearby::connections