diff --git a/Package.swift b/Package.swift index 123aa8ea..cbda579a 100644 --- a/Package.swift +++ b/Package.swift @@ -527,6 +527,7 @@ let package = Package( "internal/platform/byte_array_test.cc", "internal/platform/bluetooth_utils_test.cc", "internal/platform/credential_storage_impl_test.cc", + "internal/platform/implementation/g3/awdl_test.cc", "internal/platform/implementation/g3/ble_v2_test.cc", "internal/platform/input_stream_test.cc", "internal/platform/mac_address_test.cc", diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index e26c2700..9872e1c0 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -120,17 +120,25 @@ cc_library( cc_test( name = "comm_test", - srcs = ["ble_v2_test.cc"], + srcs = [ + "awdl_test.cc", + "ble_v2_test.cc", + ], deps = [ ":comm", ":g3", "//internal/platform:base", + "//internal/platform:cancellation_flag", + "//internal/platform:test_util", "//internal/platform:uuid", "//internal/platform/implementation:comm", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/status", "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", + "@com_google_nisaba//nisaba/port:thread_pool/fiber", ], ) diff --git a/internal/platform/implementation/g3/awdl_test.cc b/internal/platform/implementation/g3/awdl_test.cc new file mode 100644 index 00000000..5e890de9 --- /dev/null +++ b/internal/platform/implementation/g3/awdl_test.cc @@ -0,0 +1,109 @@ +// Copyright 2025 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 "internal/platform/implementation/g3/awdl.h" + +#include + +#include "gtest/gtest.h" +#include "absl/synchronization/notification.h" +#include "absl/time/time.h" +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/implementation/awdl.h" +#include "internal/platform/medium_environment.h" +#include "internal/platform/nsd_service_info.h" +#include "thread/fiber/fiber.h" + +namespace nearby { +namespace g3 { +namespace { + +constexpr char kServiceName[] = "service_name"; +constexpr char kServiceType[] = "_Awdl_test._tcp.local"; + +TEST(AwdlMedium, CanStartStopAdvertising) { + MediumEnvironment::Instance().Start(); + AwdlMedium medium; + NsdServiceInfo nsd_service_info; + nsd_service_info.SetServiceName(kServiceName); + nsd_service_info.SetServiceType(kServiceType); + + EXPECT_TRUE(medium.StartAdvertising(nsd_service_info)); + EXPECT_FALSE(medium.StartAdvertising(nsd_service_info)); + EXPECT_TRUE(medium.StopAdvertising(nsd_service_info)); + EXPECT_FALSE(medium.StopAdvertising(nsd_service_info)); + MediumEnvironment::Instance().Stop(); +} + +TEST(AwdlMedium, CanStartStopDiscovery) { + MediumEnvironment::Instance().Start(); + AwdlMedium medium; + NsdServiceInfo nsd_service_info; + nsd_service_info.SetServiceName(kServiceName); + nsd_service_info.SetServiceType(kServiceType); + + EXPECT_TRUE(medium.StartDiscovery( + nsd_service_info.GetServiceType(), + {.service_discovered_cb = [&](const NsdServiceInfo& service_info) {}})); + EXPECT_FALSE(medium.StartDiscovery( + nsd_service_info.GetServiceType(), + {.service_discovered_cb = [&](const NsdServiceInfo& service_info) {}})); + EXPECT_TRUE(medium.StopDiscovery(nsd_service_info.GetServiceType())); + EXPECT_FALSE(medium.StopDiscovery(nsd_service_info.GetServiceType())); + MediumEnvironment::Instance().Stop(); +} + +TEST(AwdlMedium, CanConnect) { + MediumEnvironment::Instance().Start(); + AwdlMedium medium_a; + AwdlMedium medium_b; + NsdServiceInfo nsd_service_info; + nsd_service_info.SetServiceName(kServiceName); + nsd_service_info.SetServiceType(kServiceType); + + std::unique_ptr server_socket = + medium_a.ListenForService(0); + ASSERT_TRUE(server_socket); + nsd_service_info.SetIPAddress(server_socket->GetIPAddress()); + nsd_service_info.SetPort(server_socket->GetPort()); + medium_a.StartAdvertising(nsd_service_info); + MediumEnvironment::Instance().Sync(); // Ensure advertising is processed + + std::unique_ptr accepted_socket; + absl::Notification accept_notification; + thread::Fiber accept_fiber([&]() { + accepted_socket = server_socket->Accept(); + accept_notification.Notify(); + }); + + CancellationFlag cancellation_flag; + std::unique_ptr client_socket = + medium_b.ConnectToService(nsd_service_info, &cancellation_flag); + + EXPECT_TRUE( + accept_notification.WaitForNotificationWithTimeout(absl::Seconds(1))); + accept_fiber.Join(); + + EXPECT_TRUE(client_socket); + EXPECT_TRUE(accepted_socket); + + if (client_socket) client_socket->Close(); + if (accepted_socket) accepted_socket->Close(); + server_socket->Close(); + MediumEnvironment::Instance().Stop(); +} + +} // namespace +} // namespace g3 +} // namespace nearby