[Sync] Add SharingMessageBridge implementation.
Add SharingMessageBridge without wiring it. The bridge does not store any
data on persistent storage.
Bug: 1034930
Change-Id: I0b19a136a2cc8a3e9ec11b7c1bb0f0b629996e52
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2002524
Reviewed-by: Alex Chau <[email protected]>
Reviewed-by: Marc Treib <[email protected]>
Reviewed-by: vitaliii <[email protected]>
Commit-Queue: Rushan Suleymanov <[email protected]>
Cr-Commit-Position: refs/heads/master@{#733594}
diff --git a/chrome/browser/sharing/sharing_message_bridge.h b/chrome/browser/sharing/sharing_message_bridge.h
new file mode 100644
index 0000000..c8f6b6030
--- /dev/null
+++ b/chrome/browser/sharing/sharing_message_bridge.h
@@ -0,0 +1,23 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARING_SHARING_MESSAGE_BRIDGE_H_
+#define CHROME_BROWSER_SHARING_SHARING_MESSAGE_BRIDGE_H_
+
+#include <memory>
+
+#include "components/sync/protocol/sharing_message_specifics.pb.h"
+
+// Class to provide an interface to send sharing messages using Sync.
+class SharingMessageBridge {
+ public:
+ // TODO(crbug.com/1034930): take callbacks once commit error propagation back
+ // to the bridge is implemented.
+ virtual void SendSharingMessage(
+ std::unique_ptr<sync_pb::SharingMessageSpecifics> specifics) = 0;
+
+ virtual ~SharingMessageBridge() = default;
+};
+
+#endif // CHROME_BROWSER_SHARING_SHARING_MESSAGE_BRIDGE_H_
diff --git a/chrome/browser/sharing/sharing_message_bridge_impl.cc b/chrome/browser/sharing/sharing_message_bridge_impl.cc
new file mode 100644
index 0000000..b9cb0371
--- /dev/null
+++ b/chrome/browser/sharing/sharing_message_bridge_impl.cc
@@ -0,0 +1,101 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/sharing_message_bridge_impl.h"
+
+#include "components/sync/model/metadata_batch.h"
+#include "components/sync/model/mutable_data_batch.h"
+#include "components/sync/model_impl/in_memory_metadata_change_list.h"
+
+namespace {
+
+std::unique_ptr<syncer::EntityData> MoveToEntityData(
+ std::unique_ptr<sync_pb::SharingMessageSpecifics> specifics) {
+ auto entity_data = std::make_unique<syncer::EntityData>();
+ entity_data->specifics.set_allocated_sharing_message(specifics.release());
+ return entity_data;
+}
+
+} // namespace
+
+SharingMessageBridgeImpl::SharingMessageBridgeImpl(
+ std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
+ : ModelTypeSyncBridge(std::move(change_processor)) {
+ // Current data type doesn't have persistent storage so it's ready to sync
+ // immediately.
+ this->change_processor()->ModelReadyToSync(
+ std::make_unique<syncer::MetadataBatch>());
+}
+
+SharingMessageBridgeImpl::~SharingMessageBridgeImpl() = default;
+
+void SharingMessageBridgeImpl::SendSharingMessage(
+ std::unique_ptr<sync_pb::SharingMessageSpecifics> specifics) {
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list =
+ CreateMetadataChangeList();
+ std::unique_ptr<syncer::EntityData> entity_data =
+ MoveToEntityData(std::move(specifics));
+ const std::string empty_storage_key;
+ change_processor()->Put(empty_storage_key, std::move(entity_data),
+ metadata_change_list.get());
+}
+
+std::unique_ptr<syncer::MetadataChangeList>
+SharingMessageBridgeImpl::CreateMetadataChangeList() {
+ // The data type intentionally doesn't persist the data on disk, so metadata
+ // is just ignored.
+ // TODO(crbug.com/1034930): this metadata changelist stores data in memory, it
+ // would be better to create DummyMetadataChangeList to ignore any changes at
+ // all.
+ return std::make_unique<syncer::InMemoryMetadataChangeList>();
+}
+
+base::Optional<syncer::ModelError> SharingMessageBridgeImpl::MergeSyncData(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_data) {
+ DCHECK(entity_data.empty());
+ DCHECK(change_processor()->IsTrackingMetadata());
+ return ApplySyncChanges(std::move(metadata_change_list),
+ std::move(entity_data));
+}
+
+base::Optional<syncer::ModelError> SharingMessageBridgeImpl::ApplySyncChanges(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_data) {
+ // This data type is commit only and does not store any data in persistent
+ // storage. We can ignore any data coming from the server.
+ return {};
+}
+
+void SharingMessageBridgeImpl::GetData(StorageKeyList storage_keys,
+ DataCallback callback) {
+ return GetAllDataForDebugging(std::move(callback));
+}
+
+void SharingMessageBridgeImpl::GetAllDataForDebugging(DataCallback callback) {
+ // This data type does not store any data, we can always run the callback
+ // with empty data.
+ std::move(callback).Run(std::make_unique<syncer::MutableDataBatch>());
+}
+
+std::string SharingMessageBridgeImpl::GetClientTag(
+ const syncer::EntityData& entity_data) {
+ return GetStorageKey(entity_data);
+}
+
+std::string SharingMessageBridgeImpl::GetStorageKey(
+ const syncer::EntityData& entity_data) {
+ NOTREACHED();
+ return "";
+}
+
+// This is commit-only data type without storing any data on persistent storage.
+// We do not need keys here.
+bool SharingMessageBridgeImpl::SupportsGetClientTag() const {
+ return false;
+}
+
+bool SharingMessageBridgeImpl::SupportsGetStorageKey() const {
+ return false;
+}
diff --git a/chrome/browser/sharing/sharing_message_bridge_impl.h b/chrome/browser/sharing/sharing_message_bridge_impl.h
new file mode 100644
index 0000000..2ee91a9
--- /dev/null
+++ b/chrome/browser/sharing/sharing_message_bridge_impl.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SHARING_SHARING_MESSAGE_BRIDGE_IMPL_H_
+#define CHROME_BROWSER_SHARING_SHARING_MESSAGE_BRIDGE_IMPL_H_
+
+#include <memory>
+
+#include "chrome/browser/sharing/sharing_message_bridge.h"
+#include "components/sync/model/model_type_change_processor.h"
+#include "components/sync/model/model_type_sync_bridge.h"
+
+// Class that implements sending sharing messages using Sync. This class
+// implements interaction with sync service. Sharing message data type is not
+// stored in any persistent storage.
+class SharingMessageBridgeImpl : public SharingMessageBridge,
+ public syncer::ModelTypeSyncBridge {
+ public:
+ explicit SharingMessageBridgeImpl(
+ std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
+ ~SharingMessageBridgeImpl() override;
+ SharingMessageBridgeImpl(const SharingMessageBridgeImpl&) = delete;
+ SharingMessageBridgeImpl& operator=(const SharingMessageBridgeImpl&) = delete;
+
+ // SharingMessageBridge implementation.
+ void SendSharingMessage(
+ std::unique_ptr<sync_pb::SharingMessageSpecifics> specifics) override;
+
+ // ModelTypeSyncBridge implementation.
+ std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
+ override;
+ base::Optional<syncer::ModelError> MergeSyncData(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_data) override;
+ base::Optional<syncer::ModelError> ApplySyncChanges(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_changes) override;
+ void GetData(StorageKeyList storage_keys, DataCallback callback) override;
+ void GetAllDataForDebugging(DataCallback callback) override;
+ std::string GetClientTag(const syncer::EntityData& entity_data) override;
+ std::string GetStorageKey(const syncer::EntityData& entity_data) override;
+ bool SupportsGetClientTag() const override;
+ bool SupportsGetStorageKey() const override;
+};
+
+#endif // CHROME_BROWSER_SHARING_SHARING_MESSAGE_BRIDGE_IMPL_H_
diff --git a/chrome/browser/sharing/sharing_message_bridge_impl_unittest.cc b/chrome/browser/sharing/sharing_message_bridge_impl_unittest.cc
new file mode 100644
index 0000000..d1bacc2
--- /dev/null
+++ b/chrome/browser/sharing/sharing_message_bridge_impl_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sharing/sharing_message_bridge_impl.h"
+
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "components/sync/model/metadata_batch.h"
+#include "components/sync/model/mock_model_type_change_processor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using testing::_;
+using testing::InvokeWithoutArgs;
+using testing::NotNull;
+using testing::Return;
+using testing::SaveArg;
+
+// Action SaveArgPointeeMove<k>(pointer) saves the value pointed to by the k-th
+// (0-based) argument of the mock function by moving it to *pointer.
+ACTION_TEMPLATE(SaveArgPointeeMove,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(pointer)) {
+ *pointer = std::move(*testing::get<k>(args));
+}
+
+class SharingMessageBridgeTest : public testing::Test {
+ protected:
+ SharingMessageBridgeTest() {
+ EXPECT_CALL(*processor(), ModelReadyToSync(NotNull()));
+ bridge_ = std::make_unique<SharingMessageBridgeImpl>(
+ mock_processor_.CreateForwardingProcessor());
+ ON_CALL(*processor(), IsTrackingMetadata()).WillByDefault(Return(true));
+ }
+
+ SharingMessageBridgeImpl* bridge() { return bridge_.get(); }
+ syncer::MockModelTypeChangeProcessor* processor() { return &mock_processor_; }
+
+ std::unique_ptr<sync_pb::SharingMessageSpecifics> CreateSpecifics(
+ const std::string& payload) const {
+ auto specifics = std::make_unique<sync_pb::SharingMessageSpecifics>();
+ specifics->set_payload(payload);
+ return specifics;
+ }
+
+ private:
+ base::test::TaskEnvironment task_environment_;
+ testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_;
+ std::unique_ptr<SharingMessageBridgeImpl> bridge_;
+};
+
+TEST_F(SharingMessageBridgeTest, ShouldWriteMessagesToProcessor) {
+ syncer::EntityData entity_data;
+ EXPECT_CALL(*processor(), Put(_, _, _))
+ .WillRepeatedly(SaveArgPointeeMove<1>(&entity_data));
+ bridge()->SendSharingMessage(CreateSpecifics("test_payload"));
+
+ EXPECT_TRUE(entity_data.specifics.has_sharing_message());
+ EXPECT_EQ(entity_data.specifics.sharing_message().payload(), "test_payload");
+
+ entity_data.specifics.Clear();
+ bridge()->SendSharingMessage(CreateSpecifics("another_payload"));
+
+ EXPECT_TRUE(entity_data.specifics.has_sharing_message());
+ EXPECT_EQ(entity_data.specifics.sharing_message().payload(),
+ "another_payload");
+}
+
+TEST_F(SharingMessageBridgeTest, ShouldNotGenerateStorageKey) {
+ std::string storage_key;
+ EXPECT_CALL(*processor(), Put(_, _, _)).WillOnce(SaveArg<0>(&storage_key));
+ bridge()->SendSharingMessage(
+ std::make_unique<sync_pb::SharingMessageSpecifics>());
+
+ EXPECT_TRUE(storage_key.empty());
+}
+
+} // namespace