// 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/pcp_manager.h" #include #include #include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/time/time.h" #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/mock_device.h" #include "connections/implementation/simulation_user.h" #include "connections/medium_selector.h" #include "connections/out_of_band_connection_metadata.h" #include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" namespace nearby { namespace connections { namespace { using ::testing::Return; constexpr std::array kFakeMacAddress = {'a', 'b', 'c', 'd', 'e', 'f'}; constexpr char kServiceId[] = "service-id"; constexpr char kDeviceA[] = "device-A"; constexpr char kDeviceB[] = "device-B"; constexpr BooleanMediumSelector kTestCases[] = { 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, .wifi_lan = true, }, }; class PcpManagerTest : public ::testing::TestWithParam { protected: MediumEnvironment& env_{MediumEnvironment::Instance()}; }; TEST_P(PcpManagerTest, CanCreateOne) { env_.Start(); SimulationUser user(kDeviceA, GetParam()); env_.Stop(); } TEST_P(PcpManagerTest, CanCreateMany) { env_.Start(); SimulationUser user_a(kDeviceA, GetParam()); SimulationUser user_b(kDeviceB, GetParam()); env_.Stop(); } TEST_P(PcpManagerTest, CanAdvertise) { env_.Start(); SimulationUser user_a(kDeviceA, GetParam()); SimulationUser user_b(kDeviceB, GetParam()); user_a.StartAdvertising(kServiceId, nullptr); env_.Stop(); } TEST_P(PcpManagerTest, CanDiscover) { env_.Start(); SimulationUser user_a("device-a", GetParam()); SimulationUser user_b("device-b", GetParam()); user_a.StartAdvertising(kServiceId, nullptr); CountDownLatch latch(1); user_b.StartDiscovery(kServiceId, &latch); EXPECT_TRUE(latch.Await(absl::Milliseconds(1000)).result()); EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId); EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo()); user_b.StopDiscovery(); env_.Stop(); } TEST_P(PcpManagerTest, CanConnect) { env_.Start(); SimulationUser user_a("device-a", GetParam()); SimulationUser user_b("device-b", GetParam()); CountDownLatch discovery_latch(1); CountDownLatch connection_latch(2); user_a.StartAdvertising(kServiceId, &connection_latch); user_b.StartDiscovery(kServiceId, &discovery_latch); EXPECT_TRUE(discovery_latch.Await(absl::Milliseconds(1000)).result()); EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId); EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo()); user_b.RequestConnection(&connection_latch); EXPECT_TRUE(connection_latch.Await(absl::Milliseconds(1000)).result()); user_a.Stop(); user_b.Stop(); env_.Stop(); } TEST_P(PcpManagerTest, CanAccept) { env_.Start(); SimulationUser user_a("device-a", GetParam()); SimulationUser user_b("device-b", GetParam()); CountDownLatch discovery_latch(1); CountDownLatch connection_latch(2); CountDownLatch accept_latch(2); user_a.StartAdvertising(kServiceId, &connection_latch); user_b.StartDiscovery(kServiceId, &discovery_latch); EXPECT_TRUE(discovery_latch.Await(absl::Milliseconds(1000)).result()); EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId); EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo()); user_b.RequestConnection(&connection_latch); EXPECT_TRUE(connection_latch.Await(absl::Milliseconds(1000)).result()); user_a.AcceptConnection(&accept_latch); user_b.AcceptConnection(&accept_latch); EXPECT_TRUE(accept_latch.Await(absl::Milliseconds(1000)).result()); user_a.Stop(); user_b.Stop(); env_.Stop(); } TEST_P(PcpManagerTest, CanReject) { env_.Start(); SimulationUser user_a("device-a", GetParam()); SimulationUser user_b("device-b", GetParam()); CountDownLatch discovery_latch(1); CountDownLatch connection_latch(2); CountDownLatch reject_latch(1); user_a.StartAdvertising(kServiceId, &connection_latch); user_b.StartDiscovery(kServiceId, &discovery_latch); EXPECT_TRUE(discovery_latch.Await(absl::Milliseconds(1000)).result()); EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId); EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo()); user_b.RequestConnection(&connection_latch); EXPECT_TRUE(connection_latch.Await(absl::Milliseconds(1000)).result()); user_b.ExpectRejectedConnection(reject_latch); user_a.RejectConnection(nullptr); EXPECT_TRUE(reject_latch.Await(absl::Milliseconds(1000)).result()); user_a.Stop(); user_b.Stop(); env_.Stop(); } TEST_P(PcpManagerTest, CanStartListeningForIncomingConnections) { env_.Start(); BooleanMediumSelector selector = GetParam(); SimulationUser user_a(kDeviceA, selector); CountDownLatch start_latch(1); v3::ConnectionListeningOptions options; options.enable_ble_listening = selector.ble; options.enable_bluetooth_listening = selector.bluetooth; options.enable_wlan_listening = selector.wifi_lan; options.listening_mediums = selector.GetMediums(true); options.upgrade_mediums = selector.GetMediums(true); options.strategy = Strategy::kP2pCluster; user_a.StartListeningForIncomingConnections(&start_latch, "service", options, {Status::kSuccess}); user_a.Stop(); env_.Stop(); } TEST_P(PcpManagerTest, StartListeningForIncomingConnectionsFailsNoStrategy) { env_.Start(); BooleanMediumSelector selector = GetParam(); SimulationUser user_a(kDeviceA, selector); CountDownLatch start_latch(1); v3::ConnectionListeningOptions options; options.enable_ble_listening = selector.ble; options.enable_bluetooth_listening = selector.bluetooth; options.enable_wlan_listening = selector.wifi_lan; options.listening_mediums = selector.GetMediums(true); options.upgrade_mediums = selector.GetMediums(true); user_a.StartListeningForIncomingConnections(&start_latch, "service", options, {Status::kError}); user_a.Stop(); env_.Stop(); } TEST_P(PcpManagerTest, CanConnectV3) { env_.Start(); SimulationUser user_a("device-a", GetParam()); SimulationUser user_b("device-b", GetParam()); CountDownLatch discovery_latch(1); CountDownLatch connection_latch(2); user_a.StartAdvertising(kServiceId, &connection_latch); user_b.StartDiscovery(kServiceId, &discovery_latch); EXPECT_TRUE(discovery_latch.Await(absl::Milliseconds(1000)).result()); EXPECT_EQ(user_b.GetDiscovered().service_id, kServiceId); EXPECT_EQ(user_b.GetDiscovered().endpoint_info, user_a.GetInfo()); auto remote_device = MockNearbyDevice(); EXPECT_CALL(remote_device, GetEndpointId) .WillRepeatedly(Return(std::string(user_b.GetDiscovered().endpoint_id))); user_b.RequestConnectionV3(&connection_latch, remote_device); EXPECT_TRUE(connection_latch.Await(absl::Milliseconds(1000)).result()); user_a.Stop(); user_b.Stop(); env_.Stop(); } INSTANTIATE_TEST_SUITE_P(ParametrisedPcpManagerTest, PcpManagerTest, ::testing::ValuesIn(kTestCases)); // Verifies that InjectEndpoint() can be run successfully; does not test the // full connection flow given that normal discovery/advertisement is skipped. // Note: Not parameterized because InjectEndpoint only works over Bluetooth. TEST_F(PcpManagerTest, InjectEndpoint) { env_.Start(); SimulationUser user_a(kDeviceA, BooleanMediumSelector{.bluetooth = true}); user_a.StartDiscovery(kServiceId, /*latch=*/nullptr); user_a.InjectEndpoint(kServiceId, OutOfBandConnectionMetadata{ .medium = Medium::BLUETOOTH, .remote_bluetooth_mac_address = ByteArray(kFakeMacAddress), }); user_a.StopDiscovery(); user_a.Stop(); env_.Stop(); } TEST_F(PcpManagerTest, TestUpdateDiscoveryFailsWithoutPcpHandler) { BooleanMediumSelector selector; selector.SetAll(true); env_.Start(); SimulationUser user_a(kDeviceA, selector); EXPECT_EQ(user_a.UpdateDiscoveryOptions(kServiceId).value, Status::Value::kOutOfOrderApiCall); env_.Stop(); } } // namespace } // namespace connections } // namespace nearby