diff --git a/fastpair/proto/BUILD b/fastpair/proto/BUILD index 3cbcb349..7b749e57 100644 --- a/fastpair/proto/BUILD +++ b/fastpair/proto/BUILD @@ -23,3 +23,22 @@ cc_proto_library( ], deps = [":fastpair_proto"], ) + +cc_library( + name = "util", + srcs = [ + "proto_to_json.cc", + ], + hdrs = [ + "proto_to_json.h", + ], + compatible_with = ["//buildenv/target:non_prod"], + visibility = ["//visibility:public"], + deps = [ + ":fastpair_cc_proto", + "//fastpair/common", + "//internal/platform:logging", + "@com_google_absl//absl/strings", + "@nlohmann_json//:json", + ], +) diff --git a/fastpair/proto/proto_to_json.cc b/fastpair/proto/proto_to_json.cc new file mode 100644 index 00000000..faaae014 --- /dev/null +++ b/fastpair/proto/proto_to_json.cc @@ -0,0 +1,149 @@ +// 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 "fastpair/proto/proto_to_json.h" + +#include +#include + +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/logging.h" + +namespace nearby { +namespace fastpair { +namespace { +using json = ::nlohmann::json; +std::string Encode(absl::string_view str) { + return absl::WebSafeBase64Escape(str); +} + +std::string TruncateString(absl::string_view str) { + if (str.length() <= 10) return std::string(str); + return absl::StrCat(str.substr(0, 5), "...", + str.substr(str.length() - 5, str.length())); +} +} // namespace + +// GetObservedDeviceRequest/Response +json FastPairProtoToJson( + const nearby::fastpair::proto::GetObservedDeviceRequest& request) { + json dict = json::object(); + dict["device_id"] = request.device_id(); + dict["mode"] = request.mode(); + dict["locale"] = request.locale(); + dict["hex_device_id"] = request.hex_device_id(); + dict["max_icon_size_pixels"] = request.max_icon_size_pixels(); + return dict; +} + +json FastPairProtoToJson( + const nearby::fastpair::proto::GetObservedDeviceResponse& response) { + json dict = json::object(); + dict["device"] = FastPairProtoToJson(response.device()); + dict["observed_device_strings "] = FastPairProtoToJson(response.strings()); + return dict; +} + +// UserReadDevicesRequest/Response +json FastPairProtoToJson( + const nearby::fastpair::proto::UserReadDevicesRequest& request) { + json dict = json::object(); + dict["secondary_id"] = request.secondary_id(); + return dict; +} + +json FastPairProtoToJson( + const nearby::fastpair::proto::UserReadDevicesResponse& response) { + json dict = json::object(); + json fast_pair_info_list = json::array(); + for (const auto& fast_pair_info : response.fast_pair_info()) { + fast_pair_info_list.push_back(FastPairProtoToJson(fast_pair_info)); + } + dict["fast_pair_info"] = std::move(fast_pair_info_list); + return dict; +} + +// UserWriteDeviceRequest +json FastPairProtoToJson( + const nearby::fastpair::proto::UserWriteDeviceRequest& request) { + json dict = json::object(); + dict["fast_pair_info"] = FastPairProtoToJson(request.fast_pair_info()); + return dict; +} + +// UserDeleteDeviceRequest/Response +json FastPairProtoToJson( + const nearby::fastpair::proto::UserDeleteDeviceRequest& request) { + json dict = json::object(); + dict["hex_account_key"] = TruncateString(Encode(request.hex_account_key())); + return dict; +} + +json FastPairProtoToJson( + const nearby::fastpair::proto::UserDeleteDeviceResponse& response) { + json dict = json::object(); + dict["success"] = response.success(); + json error_messages = json::array(); + for (const auto& error_message : response.error_messages()) { + error_messages.push_back(error_message); + } + dict["error_messages"] = std::move(error_messages); + return dict; +} + +json FastPairProtoToJson( + const nearby::fastpair::proto::FastPairInfo& fast_pair_info) { + json dict = json::object(); + if (fast_pair_info.has_device()) { + dict["device"] = FastPairProtoToJson(fast_pair_info.device()); + } else if (fast_pair_info.has_opt_in_status()) { + dict["opt_in_status"] = fast_pair_info.opt_in_status(); + } + return dict; +} + +json FastPairProtoToJson( + const nearby::fastpair::proto::FastPairDevice& fast_pair_device) { + json dict = json::object(); + dict["account_key"] = TruncateString(Encode(fast_pair_device.account_key())); + return dict; +} + +json FastPairProtoToJson( + const nearby::fastpair::proto::ObservedDeviceStrings& strings) { + json dict = json::object(); + dict["locale"] = strings.locale(); + return dict; +} + +json FastPairProtoToJson(const nearby::fastpair::proto::Device& device) { + json dict = json::object(); + dict["id"] = device.id(); + dict["project_number"] = device.project_number(); + dict["notification_type"] = device.notification_type(); + dict["image_url"] = device.image_url(); + dict["name"] = device.name(); + dict["intent_uri"] = device.intent_uri(); + dict["ble_tx_power"] = device.ble_tx_power(); + dict["trigger_distance"] = device.trigger_distance(); + dict["device_type"] = device.device_type(); + dict["display_name"] = device.display_name(); + return dict; +} +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/proto/proto_to_json.h b/fastpair/proto/proto_to_json.h new file mode 100644 index 00000000..7aa9b33a --- /dev/null +++ b/fastpair/proto/proto_to_json.h @@ -0,0 +1,62 @@ +// 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_FASTPAIR_PROTO_PROTO_TO_JSON_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_PROTO_PROTO_TO_JSON_H_ + +#include "nlohmann/json_fwd.hpp" +#include "fastpair/proto/data.proto.h" +#include "fastpair/proto/fastpair_rpcs.proto.h" + +namespace nearby { +namespace fastpair { +// Converts Fast Pair protos to readable, JSON-style dictionaries. + +// GetObservedDeviceRequest/Response +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::GetObservedDeviceRequest& request); +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::GetObservedDeviceResponse& response); + +// UserReadDevicesRequest/Response +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::UserReadDevicesRequest& request); +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::UserReadDevicesResponse& response); + +// UserWriteDeviceRequest +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::UserWriteDeviceRequest& request); + +// UserDeleteDeviceRequest/Response +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::UserDeleteDeviceRequest& request); +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::UserDeleteDeviceResponse& response); + +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::FastPairInfo& fast_pair_info); + +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::FastPairDevice& fast_pair_device); + +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::ObservedDeviceStrings& strings); + +nlohmann::json FastPairProtoToJson( + const nearby::fastpair::proto::Device& device); +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_PROTO_PROTO_TO_JSON_H_ diff --git a/fastpair/server_access/BUILD b/fastpair/server_access/BUILD index 1db7fb90..b803c952 100644 --- a/fastpair/server_access/BUILD +++ b/fastpair/server_access/BUILD @@ -17,12 +17,14 @@ licenses(["notice"]) cc_library( name = "server_access", srcs = [ + "fast_pair_http_notifier.cc", "fast_pair_metadata_downloader.cc", "fast_pair_metadata_downloader_impl.cc", "fast_pair_repository.cc", "fast_pair_repository_impl.cc", ], hdrs = [ + "fast_pair_http_notifier.h", "fast_pair_metadata_downloader.h", "fast_pair_metadata_downloader_impl.h", "fast_pair_repository.h", @@ -34,12 +36,15 @@ cc_library( deps = [ "//fastpair/common", "//fastpair/proto:fastpair_cc_proto", + "//fastpair/proto:util", "//fastpair/repository", + "//internal/base", "//internal/network:nearby_http_client", "//internal/network:types", "//internal/platform:logging", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/strings", + "@nlohmann_json//:json", ], ) @@ -100,3 +105,20 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "fast_pair_http_notifier_test", + srcs = [ + "fast_pair_http_notifier_test.cc", + ], + copts = [ + "-Ithird_party", + ], + deps = [ + ":server_access", + "//internal/platform:types", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/server_access/fast_pair_http_notifier.cc b/fastpair/server_access/fast_pair_http_notifier.cc new file mode 100644 index 00000000..24f7acd0 --- /dev/null +++ b/fastpair/server_access/fast_pair_http_notifier.cc @@ -0,0 +1,98 @@ +// Copyright 2022 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 "fastpair/server_access/fast_pair_http_notifier.h" + +#include "nlohmann/json.hpp" +#include "fastpair/proto/proto_to_json.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace fastpair { + +void FastPairHttpNotifier::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void FastPairHttpNotifier::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +// Notifies all observers of GetObservedDeviceRequest/Response +void FastPairHttpNotifier::NotifyOfRequest( + const proto::GetObservedDeviceRequest& request) { + NEARBY_LOGS(VERBOSE) << ": GetObservedDeviceRequest=" + << FastPairProtoToJson(request).dump(); + for (auto& observer : observers_.GetObservers()) + observer->OnGetObservedDeviceRequest(request); +} + +void FastPairHttpNotifier::NotifyOfResponse( + const proto::GetObservedDeviceResponse& response) { + NEARBY_LOGS(VERBOSE) << ": GetObservedDeviceResponse=" + << FastPairProtoToJson(response).dump(); + for (auto& observer : observers_.GetObservers()) + observer->OnGetObservedDeviceResponse(response); +} + +// Notifies all observers of UserReadDevicesRequest/Response +void FastPairHttpNotifier::NotifyOfRequest( + const proto::UserReadDevicesRequest& request) { + NEARBY_LOGS(VERBOSE) << ": UserReadDevicesRequest=" + << FastPairProtoToJson(request).dump(); + for (auto& observer : observers_.GetObservers()) + observer->OnUserReadDevicesRequest(request); +} + +void FastPairHttpNotifier::NotifyOfResponse( + const proto::UserReadDevicesResponse& response) { + NEARBY_LOGS(VERBOSE) << ": UserReadDevicesResponse=" + << FastPairProtoToJson(response).dump(); + for (auto& observer : observers_.GetObservers()) + observer->OnUserReadDevicesResponse(response); +} + +// Notifies all observers of UserWriteDeviceRequest/Response +void FastPairHttpNotifier::NotifyOfRequest( + const proto::UserWriteDeviceRequest& request) { + NEARBY_LOGS(VERBOSE) << ": UserWriteDeviceRequest=" + << FastPairProtoToJson(request).dump(); + for (auto& observer : observers_.GetObservers()) + observer->OnUserWriteDeviceRequest(request); +} + +void FastPairHttpNotifier::NotifyOfResponse( + const proto::UserWriteDeviceResponse& response) { + for (auto& observer : observers_.GetObservers()) + observer->OnUserWriteDeviceResponse(response); +} + +// Notifies all observers of UserDeleteDeviceRequest/Response +void FastPairHttpNotifier::NotifyOfRequest( + const proto::UserDeleteDeviceRequest& request) { + NEARBY_LOGS(VERBOSE) << ": UserDeleteDeviceRequest=" + << FastPairProtoToJson(request).dump(); + for (auto& observer : observers_.GetObservers()) + observer->OnUserDeleteDeviceRequest(request); +} +void FastPairHttpNotifier::NotifyOfResponse( + const proto::UserDeleteDeviceResponse& response) { + NEARBY_LOGS(VERBOSE) << ": UserDeleteDeviceResponse=" + << FastPairProtoToJson(response).dump(); + for (auto& observer : observers_.GetObservers()) + observer->OnUserDeleteDeviceResponse(response); +} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/server_access/fast_pair_http_notifier.h b/fastpair/server_access/fast_pair_http_notifier.h new file mode 100644 index 00000000..7e43292e --- /dev/null +++ b/fastpair/server_access/fast_pair_http_notifier.h @@ -0,0 +1,87 @@ +// Copyright 2022 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_FASTPAIR_SERVER_ACCESS_FAST_PAIR_HTTP_NOTIFIER_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_SERVER_ACCESS_FAST_PAIR_HTTP_NOTIFIER_H_ + +#include "fastpair/proto/fastpair_rpcs.proto.h" +#include "internal/base/observer_list.h" + +namespace nearby { +namespace fastpair { + +// Interface for passing HTTP Responses/Requests to observers, by passing +// instances of this class to each HTTP Client. +class FastPairHttpNotifier { + public: + class Observer { + public: + virtual ~Observer() = default; + + // Called when HTTP RPC is made for GetObservedDeviceRequest/Response + virtual void OnGetObservedDeviceRequest( + const proto::GetObservedDeviceRequest& request) = 0; + virtual void OnGetObservedDeviceResponse( + const proto::GetObservedDeviceResponse& response) = 0; + + // Called when HTTP RPC is made for UserReadDevicesRequest/Response + virtual void OnUserReadDevicesRequest( + const proto::UserReadDevicesRequest& request) = 0; + virtual void OnUserReadDevicesResponse( + const proto::UserReadDevicesResponse& response) = 0; + + // Called when HTTP RPC is made for UserWriteDeviceRequest/Response + virtual void OnUserWriteDeviceRequest( + const proto::UserWriteDeviceRequest& request) = 0; + virtual void OnUserWriteDeviceResponse( + const proto::UserWriteDeviceResponse& response) = 0; + + // Called when HTTP RPC is made for UserDeleteDeviceRequest/Response + virtual void OnUserDeleteDeviceRequest( + const proto::UserDeleteDeviceRequest& request) = 0; + virtual void OnUserDeleteDeviceResponse( + const proto::UserDeleteDeviceResponse& response) = 0; + }; + + FastPairHttpNotifier() = default; + FastPairHttpNotifier(const FastPairHttpNotifier&) = delete; + FastPairHttpNotifier& operator=(const FastPairHttpNotifier&) = delete; + ~FastPairHttpNotifier() = default; + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + // Notifies all observers of GetObservedDeviceRequest/Response + void NotifyOfRequest(const proto::GetObservedDeviceRequest& request); + void NotifyOfResponse(const proto::GetObservedDeviceResponse& response); + + // Notifies all observers of UserReadDevicesRequest/Response + void NotifyOfRequest(const proto::UserReadDevicesRequest& request); + void NotifyOfResponse(const proto::UserReadDevicesResponse& response); + + // Notifies all observers of UserWriteDeviceRequest/Response + void NotifyOfRequest(const proto::UserWriteDeviceRequest& request); + void NotifyOfResponse(const proto::UserWriteDeviceResponse& response); + + // Notifies all observers of UserDeleteDeviceRequest/Response + void NotifyOfRequest(const proto::UserDeleteDeviceRequest& request); + void NotifyOfResponse(const proto::UserDeleteDeviceResponse& response); + + private: + ObserverList observers_; +}; +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_SERVER_ACCESS_FAST_PAIR_HTTP_NOTIFIER_H_ diff --git a/fastpair/server_access/fast_pair_http_notifier_test.cc b/fastpair/server_access/fast_pair_http_notifier_test.cc new file mode 100644 index 00000000..953d17c9 --- /dev/null +++ b/fastpair/server_access/fast_pair_http_notifier_test.cc @@ -0,0 +1,209 @@ +// Copyright 2022 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 "fastpair/server_access/fast_pair_http_notifier.h" + +#include "gtest/gtest.h" +#include "internal/platform/count_down_latch.h" + +namespace nearby { +namespace fastpair { + +namespace { +class FastPairHttpNotifierObserver : public FastPairHttpNotifier::Observer { + public: + explicit FastPairHttpNotifierObserver(CountDownLatch* latch) { + latch_ = latch; + } + + void OnGetObservedDeviceRequest( + const proto::GetObservedDeviceRequest& request) override { + latch_->CountDown(); + get_observer_device_request_ = + &const_cast(request); + } + + void OnGetObservedDeviceResponse( + const proto::GetObservedDeviceResponse& response) override { + latch_->CountDown(); + get_observer_device_response_ = + &const_cast(response); + } + + // Called when HTTP RPC is made for UserReadDevicesRequest/Response + void OnUserReadDevicesRequest( + const proto::UserReadDevicesRequest& request) override { + latch_->CountDown(); + read_devices_request_ = + &const_cast(request); + } + void OnUserReadDevicesResponse( + const proto::UserReadDevicesResponse& response) override { + latch_->CountDown(); + read_devices_response_ = + &const_cast(response); + } + + // Called when HTTP RPC is made for UserWriteDeviceRequest/Response + void OnUserWriteDeviceRequest( + const proto::UserWriteDeviceRequest& request) override { + latch_->CountDown(); + write_device_request_ = + &const_cast(request); + } + void OnUserWriteDeviceResponse( + const proto::UserWriteDeviceResponse& response) override { + latch_->CountDown(); + write_device_response_ = + &const_cast(response); + } + + // Called when HTTP RPC is made for UserDeleteDeviceRequest/Response + void OnUserDeleteDeviceRequest( + const proto::UserDeleteDeviceRequest& request) override { + latch_->CountDown(); + delete_device_request_ = + &const_cast(request); + } + void OnUserDeleteDeviceResponse( + const proto::UserDeleteDeviceResponse& response) override { + latch_->CountDown(); + delete_device_response_ = + &const_cast(response); + } + + CountDownLatch* latch_; + proto::GetObservedDeviceRequest* get_observer_device_request_; + proto::GetObservedDeviceResponse* get_observer_device_response_; + proto::UserReadDevicesRequest* read_devices_request_; + proto::UserReadDevicesResponse* read_devices_response_; + proto::UserWriteDeviceRequest* write_device_request_; + proto::UserWriteDeviceResponse* write_device_response_; + proto::UserDeleteDeviceRequest* delete_device_request_; + proto::UserDeleteDeviceResponse* delete_device_response_; +}; + +TEST(FastPairHttpNotifierTest, TestNotifyGetObservedDeviceRequest) { + proto::GetObservedDeviceRequest request; + int64_t device_id; + CHECK(absl::SimpleHexAtoi("718C17", &device_id)); + request.set_device_id(device_id); + request.set_mode(proto::GetObservedDeviceRequest::MODE_RELEASE); + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfRequest(request); + latch.Await(); + + EXPECT_EQ(observer.get_observer_device_request_, &request); + EXPECT_EQ(observer.get_observer_device_request_->device_id(), device_id); + EXPECT_EQ(observer.get_observer_device_request_->mode(), + proto::GetObservedDeviceRequest::MODE_RELEASE); +} + +TEST(FastPairHttpNotifierTest, TestNotifyGetObservedDeviceResponse) { + proto::GetObservedDeviceResponse response; + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfResponse(response); + latch.Await(); + + EXPECT_EQ(observer.get_observer_device_response_, &response); +} + +TEST(FastPairHttpNotifierTest, TestNotifyUserReadDevicesRequest) { + proto::UserReadDevicesRequest request; + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfRequest(request); + latch.Await(); + + EXPECT_EQ(observer.read_devices_request_, &request); +} + +TEST(FastPairHttpNotifierTest, TestNotifyUserReadDevicesResponse) { + proto::UserReadDevicesResponse response; + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfResponse(response); + latch.Await(); + + EXPECT_EQ(observer.read_devices_response_, &response); +} + +TEST(FastPairHttpNotifierTest, TestNotifyUserWritedeviceRequest) { + proto::UserWriteDeviceRequest request; + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfRequest(request); + latch.Await(); + + EXPECT_EQ(observer.write_device_request_, &request); +} + +TEST(FastPairHttpNotifierTest, TestNotifyUserWriteDeviceResponse) { + proto::UserWriteDeviceResponse response; + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfResponse(response); + latch.Await(); + + EXPECT_EQ(observer.write_device_response_, &response); +} + +TEST(FastPairHttpNotifierTest, TestNotifyUserDeleteDeviceRequest) { + proto::UserDeleteDeviceRequest request; + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfRequest(request); + latch.Await(); + + EXPECT_EQ(observer.delete_device_request_, &request); +} + +TEST(FastPairHttpNotifierTest, TestNotifyUserDeleteDeviceResponse) { + proto::UserDeleteDeviceResponse response; + CountDownLatch latch(1); + FastPairHttpNotifierObserver observer(&latch); + FastPairHttpNotifier notifier; + notifier.AddObserver(&observer); + + notifier.NotifyOfResponse(response); + latch.Await(); + + EXPECT_EQ(observer.delete_device_response_, &response); +} +} // namespace +} // namespace fastpair +} // namespace nearby