diff --git a/presence/BUILD b/presence/BUILD index 6d48be7f..2607462e 100644 --- a/presence/BUILD +++ b/presence/BUILD @@ -18,11 +18,12 @@ package(default_visibility = ["//:__subpackages__"]) cc_library( name = "presence", srcs = [ - "presence_client.cc", + "presence_client_impl.cc", "presence_service.cc", ], hdrs = [ "presence_client.h", + "presence_client_impl.h", "presence_device_provider.h", "presence_service.h", ], @@ -37,6 +38,24 @@ cc_library( ], ) +cc_library( + name = "test_support", + testonly = 1, + srcs = [ + "fake_presence_client.cc", + ], + hdrs = [ + "fake_presence_client.h", + ], + compatible_with = ["//buildenv/target:non_prod"], + deps = [ + ":presence", + ":types", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + ], +) + cc_library( name = "types", srcs = [ diff --git a/presence/fake_presence_client.cc b/presence/fake_presence_client.cc new file mode 100644 index 00000000..a6fbe881 --- /dev/null +++ b/presence/fake_presence_client.cc @@ -0,0 +1,81 @@ +// Copyright 2023 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 "presence/fake_presence_client.h" + + +#include +#include +#include + +#include "presence/data_types.h" +#include "presence/presence_device.h" +#include "presence/scan_request.h" + +namespace { + +::nearby::internal::Metadata BuildTestMetadata() { + ::nearby::internal::Metadata metadata; + metadata.set_bluetooth_mac_address("01234567"); + metadata.set_device_name("Pepper's device"); + return metadata; +} + +} // namespace + +namespace nearby { +namespace presence { + +absl::StatusOr FakePresenceClient::StartScan( + ScanRequest scan_request, ScanCallback callback) { + current_scan_session_id_++; + active_scan_sessions_.push_back(current_scan_session_id_); + absl::StatusOr scan_session_id(current_scan_session_id_); + callback_ = std::move(callback); + return scan_session_id; +} + +void FakePresenceClient::StopScan(ScanSessionId id) { + auto position = + std::find(active_scan_sessions_.begin(), active_scan_sessions_.end(), id); + if (position != active_scan_sessions_.end()) { + active_scan_sessions_.erase(position); + } +} + +std::vector FakePresenceClient::GetActiveScanSessions() { + return active_scan_sessions_; +} + +void FakePresenceClient::CallStartScanCallback(absl::Status status) { + callback_.start_scan_cb(status); +} + +void FakePresenceClient::CallOnDiscovered() { + PresenceDevice device{BuildTestMetadata()}; + callback_.on_discovered_cb(std::move(device)); +} + +void FakePresenceClient::CallOnUpdated() { + PresenceDevice device{BuildTestMetadata()}; + callback_.on_updated_cb(std::move(device)); +} + +void FakePresenceClient::CallOnLost() { + PresenceDevice device{BuildTestMetadata()}; + callback_.on_lost_cb(std::move(device)); +} + +} // namespace presence +} // namespace nearby diff --git a/presence/fake_presence_client.h b/presence/fake_presence_client.h new file mode 100644 index 00000000..7bb8fffe --- /dev/null +++ b/presence/fake_presence_client.h @@ -0,0 +1,78 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_CLIENT_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_CLIENT_H_ + + +#include +#include + +#include "absl/status/statusor.h" +#include "presence/broadcast_request.h" +#include "presence/presence_client.h" +#include "presence/presence_device.h" +#include "presence/scan_request.h" + +namespace nearby { +namespace presence { + +class FakePresenceClient : public PresenceClient { + public: + FakePresenceClient() = default; + FakePresenceClient(const FakePresenceClient&) = delete; + FakePresenceClient(FakePresenceClient&&) = default; + FakePresenceClient& operator=(const FakePresenceClient&) = delete; + ~FakePresenceClient() = default; + + absl::StatusOr StartScan(ScanRequest scan_request, + ScanCallback callback) override; + + void StopScan(ScanSessionId session_id) override; + + // Not Implemented. + absl::StatusOr StartBroadcast( + BroadcastRequest broadcast_request, BroadcastCallback callback) override { + return 0; + } + + // Not Implemented. + void StopBroadcast(BroadcastSessionId session_id) override {} + + // Not Implemented. + std::optional GetLocalDevice() override { + return std::nullopt; + } + + void SetNextScanSessionSuccess(bool success) { + next_scan_should_succeed_ = success; + } + + std::vector GetActiveScanSessions(); + void CallStartScanCallback(absl::Status status); + void CallOnDiscovered(); + void CallOnUpdated(); + void CallOnLost(); + + private: + uint64_t current_scan_session_id_; + ScanCallback callback_; + std::vector active_scan_sessions_; + bool next_scan_should_succeed_ = true; +}; + +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_CLIENT_H_ diff --git a/presence/presence_client.h b/presence/presence_client.h index f27c3932..92807d95 100644 --- a/presence/presence_client.h +++ b/presence/presence_client.h @@ -36,11 +36,7 @@ class PresenceClient { public: using BorrowablePresenceService = ::nearby::Borrowable; - explicit PresenceClient(BorrowablePresenceService service) - : service_(service) {} - PresenceClient(const PresenceClient&) = delete; - PresenceClient(PresenceClient&&) = default; - PresenceClient& operator=(const PresenceClient&) = delete; + virtual ~PresenceClient() = default; // Starts a Nearby Presence scan and registers `ScanCallback` // which will be invoked when a matching `PresenceDevice` is detected, @@ -53,12 +49,12 @@ class PresenceClient { // `ScanRequest` contains the options like scan power mode // and type; the filters including credentials, actions and extended // properties. - absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback); + virtual absl::StatusOr StartScan(ScanRequest scan_request, + ScanCallback callback) = 0; // Terminates the scan session. Does nothing if the session is already // terminated. - void StopScan(ScanSessionId session_id); + virtual void StopScan(ScanSessionId session_id) = 0; // Starts a Nearby Presence broadcast and registers `BroadcastCallback` // which will be invoked after broadcast is started. @@ -70,20 +66,17 @@ class PresenceClient { // `BroadcastRequest` contains the options like tx_power, // the credential info like salt and private credential, the actions and // extended properties. - absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback); + virtual absl::StatusOr StartBroadcast( + BroadcastRequest broadcast_request, BroadcastCallback callback) = 0; // Terminates a broadcast session. Does nothing if the session is already // terminated. - void StopBroadcast(BroadcastSessionId session_id); + virtual void StopBroadcast(BroadcastSessionId session_id) = 0; // Returns the local PresenceDevice describing the current device's actions, // connectivity info and unique identifier for use in Connections and // Presence. - std::optional GetLocalDevice(); - - private: - BorrowablePresenceService service_; + virtual std::optional GetLocalDevice() = 0; }; } // namespace presence diff --git a/presence/presence_client.cc b/presence/presence_client_impl.cc similarity index 69% rename from presence/presence_client.cc rename to presence/presence_client_impl.cc index d96249e0..a136f86d 100644 --- a/presence/presence_client.cc +++ b/presence/presence_client_impl.cc @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "presence/presence_client.h" +#include "presence/presence_client_impl.h" +#include #include #include @@ -26,7 +27,28 @@ namespace nearby { namespace presence { -absl::StatusOr PresenceClient::StartScan( +// static +PresenceClientImpl::Factory* PresenceClientImpl::Factory::g_test_factory_ = + nullptr; + +// static +std::unique_ptr PresenceClientImpl::Factory::Create( + BorrowablePresenceService service) { + if (g_test_factory_) { + return g_test_factory_->CreateInstance(service); + } + return absl::WrapUnique(new PresenceClientImpl(service)); +} + +// static +void PresenceClientImpl::Factory::SetFactoryForTesting( + Factory* g_test_factory) { + g_test_factory_ = g_test_factory; +} + +PresenceClientImpl::Factory::~Factory() = default; + +absl::StatusOr PresenceClientImpl::StartScan( ScanRequest scan_request, ScanCallback callback) { ::nearby::Borrowed borrowed = service_.Borrow(); if (!borrowed) { @@ -36,14 +58,14 @@ absl::StatusOr PresenceClient::StartScan( return (*borrowed)->StartScan(scan_request, std::move(callback)); } -void PresenceClient::StopScan(ScanSessionId id) { +void PresenceClientImpl::StopScan(ScanSessionId id) { ::nearby::Borrowed borrowed = service_.Borrow(); if (borrowed) { (*borrowed)->StopScan(id); } } -absl::StatusOr PresenceClient::StartBroadcast( +absl::StatusOr PresenceClientImpl::StartBroadcast( BroadcastRequest broadcast_request, BroadcastCallback callback) { ::nearby::Borrowed borrowed = service_.Borrow(); if (!borrowed) { @@ -53,7 +75,7 @@ absl::StatusOr PresenceClient::StartBroadcast( return (*borrowed)->StartBroadcast(broadcast_request, std::move(callback)); } -void PresenceClient::StopBroadcast(BroadcastSessionId session_id) { +void PresenceClientImpl::StopBroadcast(BroadcastSessionId session_id) { ::nearby::Borrowed borrowed = service_.Borrow(); if (borrowed) { (*borrowed)->StopBroadcast(session_id); @@ -62,7 +84,7 @@ void PresenceClient::StopBroadcast(BroadcastSessionId session_id) { } } -std::optional PresenceClient::GetLocalDevice() { +std::optional PresenceClientImpl::GetLocalDevice() { ::nearby::Borrowed borrowed = service_.Borrow(); if (borrowed) { const PresenceDevice* device = static_cast( diff --git a/presence/presence_client_impl.h b/presence/presence_client_impl.h new file mode 100644 index 00000000..e7f376c8 --- /dev/null +++ b/presence/presence_client_impl.h @@ -0,0 +1,75 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_IMPL_H_ +#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_IMPL_H_ + +#include +#include + +#include "absl/status/statusor.h" +#include "internal/platform/borrowable.h" +#include "presence/broadcast_request.h" +#include "presence/data_types.h" +#include "presence/presence_client.h" +#include "presence/presence_device.h" +#include "presence/scan_request.h" + +namespace nearby { +namespace presence { + +class PresenceClientImpl : public PresenceClient{ + public: + using BorrowablePresenceService = ::nearby::Borrowable; + + class Factory { + public: + static std::unique_ptr Create( + BorrowablePresenceService service); + static void SetFactoryForTesting(Factory* test_factory); + + protected: + virtual ~Factory(); + virtual std::unique_ptr CreateInstance( + BorrowablePresenceService service) = 0; + + private: + static Factory* g_test_factory_; + }; + + PresenceClientImpl(const PresenceClientImpl&) = delete; + PresenceClientImpl(PresenceClientImpl&&) = default; + PresenceClientImpl& operator=(const PresenceClientImpl&) = delete; + ~PresenceClientImpl() override = default; + + // PresenceClient: + absl::StatusOr StartScan(ScanRequest scan_request, + ScanCallback callback) override; + void StopScan(ScanSessionId session_id) override; + absl::StatusOr StartBroadcast( + BroadcastRequest broadcast_request, BroadcastCallback callback) override; + void StopBroadcast(BroadcastSessionId session_id) override; + std::optional GetLocalDevice() override; + + private: + explicit PresenceClientImpl(BorrowablePresenceService service) + : service_(service) {} + + BorrowablePresenceService service_; +}; + +} // namespace presence +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_IMPL_H_ diff --git a/presence/presence_client_test.cc b/presence/presence_client_test.cc index 0d9ba146..9103f0ce 100644 --- a/presence/presence_client_test.cc +++ b/presence/presence_client_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "presence/presence_client.h" +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" @@ -34,7 +34,7 @@ constexpr absl::string_view kMacAddr = "\x4C\x8B\x1D\xCE\xBA\xD1"; // Creates a PresenceClient and destroys PresenceService that was used to create // it. -PresenceClient CreateDefunctPresenceClient() { +std::unique_ptr CreateDefunctPresenceClient() { PresenceService presence_service; return presence_service.CreatePresenceClient(); } @@ -60,8 +60,9 @@ TEST_F(PresenceClientTest, StartBroadcastWithDefaultConstructor) { absl::Status broadcast_result; PresenceService presence_service; - PresenceClient presence_client = presence_service.CreatePresenceClient(); - auto unused = presence_client.StartBroadcast( + std::unique_ptr presence_client = + presence_service.CreatePresenceClient(); + auto unused = presence_client->StartBroadcast( {}, { .start_broadcast_cb = [&](absl::Status status) { broadcast_result = status; }, @@ -76,7 +77,7 @@ TEST_F(PresenceClientTest, StartBroadcastFailsWhenPresenceServiceIsGone) { absl::Status broadcast_result = absl::UnknownError(""); absl::StatusOr session_id = - CreateDefunctPresenceClient().StartBroadcast( + CreateDefunctPresenceClient()->StartBroadcast( {}, { .start_broadcast_cb = [&](absl::Status status) { broadcast_result = status; }, @@ -95,8 +96,9 @@ TEST_F(PresenceClientTest, StartScanWithDefaultConstructor) { }; PresenceService presence_service; - PresenceClient presence_client = presence_service.CreatePresenceClient(); - EXPECT_OK(presence_client.StartScan({}, std::move(scan_callback))); + std::unique_ptr presence_client = + presence_service.CreatePresenceClient(); + EXPECT_OK(presence_client->StartScan({}, std::move(scan_callback))); EXPECT_TRUE(scan_result.Get().ok()); EXPECT_OK(scan_result.Get().GetResult()); @@ -108,7 +110,7 @@ TEST_F(PresenceClientTest, StartScanFailsWhenPresenceServiceIsGone) { absl::Status scan_result = absl::UnknownError(""); absl::StatusOr session_id = - CreateDefunctPresenceClient().StartScan( + CreateDefunctPresenceClient()->StartScan( {}, { .start_scan_cb = [&](absl::Status status) { scan_result = status; }, @@ -121,19 +123,21 @@ TEST_F(PresenceClientTest, StartScanFailsWhenPresenceServiceIsGone) { TEST_F(PresenceClientTest, GettingDeviceWorks) { PresenceService presence_service; - PresenceClient presence_client = presence_service.CreatePresenceClient(); + std::unique_ptr presence_client = + presence_service.CreatePresenceClient(); presence_service.UpdateLocalDeviceMetadata(CreateTestMetadata(), false, "", {}, 0, 0, {}); - auto device = presence_client.GetLocalDevice(); + auto device = presence_client->GetLocalDevice(); ASSERT_NE(device, std::nullopt); - EXPECT_EQ((*device).GetEndpointId().length(), kEndpointIdLength); - EXPECT_EQ((*device).GetMetadata().SerializeAsString(), + EXPECT_EQ(device->GetEndpointId().length(), kEndpointIdLength); + EXPECT_EQ(device->GetMetadata().SerializeAsString(), CreateTestMetadata().SerializeAsString()); } TEST_F(PresenceClientTest, TestGettingDeviceDefunct) { - PresenceClient presence_client = CreateDefunctPresenceClient(); - auto device = presence_client.GetLocalDevice(); + std::unique_ptr presence_client = + CreateDefunctPresenceClient(); + auto device = presence_client->GetLocalDevice(); EXPECT_EQ(device, std::nullopt); } } // namespace diff --git a/presence/presence_service.cc b/presence/presence_service.cc index f4a1868c..9ed07bb5 100644 --- a/presence/presence_service.cc +++ b/presence/presence_service.cc @@ -21,6 +21,7 @@ #include "internal/platform/borrowable.h" #include "presence/data_types.h" #include "presence/implementation/service_controller_impl.h" +#include "presence/presence_client_impl.h" namespace nearby { namespace presence { @@ -30,8 +31,8 @@ PresenceService::PresenceService() { service_controller_->GetLocalDeviceMetadata()); } -PresenceClient PresenceService::CreatePresenceClient() { - return PresenceClient(lender_.GetBorrowable()); +std::unique_ptr PresenceService::CreatePresenceClient() { + return PresenceClientImpl::Factory::Create(lender_.GetBorrowable()); } absl::StatusOr PresenceService::StartScan( diff --git a/presence/presence_service.h b/presence/presence_service.h index be221ab5..85d90814 100644 --- a/presence/presence_service.h +++ b/presence/presence_service.h @@ -39,7 +39,7 @@ class PresenceService { PresenceService(); ~PresenceService() { lender_.Release(); } - PresenceClient CreatePresenceClient(); + std::unique_ptr CreatePresenceClient(); absl::StatusOr StartScan(ScanRequest scan_request, ScanCallback callback); diff --git a/presence/presence_service_test.cc b/presence/presence_service_test.cc index 2c33aac3..fb8717e6 100644 --- a/presence/presence_service_test.cc +++ b/presence/presence_service_test.cc @@ -14,6 +14,7 @@ #include "presence/presence_service.h" +#include #include #include #include @@ -67,22 +68,23 @@ TEST_F(PresenceServiceTest, StartThenStopScan) { .start_scan_cb = [&](absl::Status status) { scan_result = status; }, }; PresenceService presence_service; - PresenceClient client = presence_service.CreatePresenceClient(); + std::unique_ptr client = + presence_service.CreatePresenceClient(); - absl::StatusOr scan_session = client.StartScan( + absl::StatusOr scan_session = client->StartScan( {}, { .start_scan_cb = [&](absl::Status status) { scan_result = status; }, }); absl::StatusOr scan_session_with_default_params = - client.StartScan(ScanRequest(), ScanCallback()); + client->StartScan(ScanRequest(), ScanCallback()); ASSERT_OK(scan_session); ASSERT_OK(scan_session_with_default_params); EXPECT_NE(*scan_session, *scan_session_with_default_params); - client.StopScan(*scan_session); - client.StopScan(*scan_session_with_default_params); + client->StopScan(*scan_session); + client->StopScan(*scan_session_with_default_params); env_.Stop(); }