Commit cfafbc57 authored by steimel's avatar steimel Committed by Commit bot

Add LazySyncableAdapter

The LazySyncableAdapter is used to wrap LazySyncables of any changeset type into a LazySyncable with a string changeset by serializing the changesets into a string and parsing them from strings. That way, ObjectSyncState can just work with LazySyncables of type string.

BUG=663065

Review-Url: https://codereview.chromium.org/2522633004
Cr-Commit-Position: refs/heads/master@{#436137}
parent 792a666e
......@@ -8,6 +8,7 @@ component("helium") {
"compound_syncable.cc",
"compound_syncable.h",
"errors.h",
"lazy_syncable_adapter.h",
"lww_register.h",
"owned_register.h",
"result.cc",
......@@ -56,6 +57,7 @@ source_set("unit_tests") {
sources = [
"compound_syncable_unittest.cc",
"helium_test.h",
"lazy_syncable_adapter_unittest.cc",
"lww_register_unittest.cc",
"owned_register_unittest.cc",
"result_unittest.cc",
......
// Copyright 2016 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 BLIMP_HELIUM_LAZY_SYNCABLE_ADAPTER_H_
#define BLIMP_HELIUM_LAZY_SYNCABLE_ADAPTER_H_
#include <string>
#include "base/memory/ptr_util.h"
#include "blimp/helium/blimp_helium_export.h"
#include "blimp/helium/syncable.h"
#include "third_party/protobuf/src/google/protobuf/io/coded_stream.h"
#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
namespace blimp {
namespace helium {
// The LazySyncableAdapter is used to wrap LazySyncables of any changeset type
// into a LazySyncable with a string changeset by serializing the changesets
// into a string and parsing them from strings. That way, ObjectSyncState can
// just work with LazySyncables of type string.
template <class ChangesetType>
class BLIMP_HELIUM_EXPORT LazySyncableAdapter
: public LazySyncable<std::string> {
public:
explicit LazySyncableAdapter(LazySyncable<ChangesetType>* inner_syncable)
: inner_syncable_(inner_syncable) {}
~LazySyncableAdapter() = default;
// LazySyncable implementation.
std::unique_ptr<std::string> CreateChangeset(Revision from) const override;
void ApplyChangeset(const std::string& changeset) override;
bool ValidateChangeset(const std::string& changeset) const override;
void SetLocalUpdateCallback(
const base::Closure& local_update_callback) override;
void ReleaseBefore(Revision before) override;
Revision GetRevision() const override;
void PrepareToCreateChangeset(Revision from, base::Closure done) override;
private:
static std::unique_ptr<ChangesetType> ParseChangesetFromString(
const std::string& changeset);
LazySyncable<ChangesetType>* inner_syncable_;
DISALLOW_COPY_AND_ASSIGN(LazySyncableAdapter);
};
template <class ChangesetType>
std::unique_ptr<std::string>
LazySyncableAdapter<ChangesetType>::CreateChangeset(Revision from) const {
std::unique_ptr<ChangesetType> changeset =
inner_syncable_->CreateChangeset(from);
std::unique_ptr<std::string> output = base::MakeUnique<std::string>();
google::protobuf::io::StringOutputStream raw_output_stream(output.get());
google::protobuf::io::CodedOutputStream output_stream(&raw_output_stream);
changeset->Serialize(&output_stream);
return output;
}
template <class ChangesetType>
void LazySyncableAdapter<ChangesetType>::ApplyChangeset(
const std::string& changeset) {
std::unique_ptr<ChangesetType> parsed_changeset =
ParseChangesetFromString(changeset);
inner_syncable_->ApplyChangeset(*parsed_changeset);
}
template <class ChangesetType>
bool LazySyncableAdapter<ChangesetType>::ValidateChangeset(
const std::string& changeset) const {
std::unique_ptr<ChangesetType> parsed_changeset =
ParseChangesetFromString(changeset);
return inner_syncable_->ValidateChangeset(*parsed_changeset);
}
template <class ChangesetType>
void LazySyncableAdapter<ChangesetType>::SetLocalUpdateCallback(
const base::Closure& local_update_callback) {
inner_syncable_->SetLocalUpdateCallback(local_update_callback);
}
template <class ChangesetType>
void LazySyncableAdapter<ChangesetType>::ReleaseBefore(Revision before) {
inner_syncable_->ReleaseBefore(before);
}
template <class ChangesetType>
Revision LazySyncableAdapter<ChangesetType>::GetRevision() const {
return inner_syncable_->GetRevision();
}
template <class ChangesetType>
void LazySyncableAdapter<ChangesetType>::PrepareToCreateChangeset(
Revision from,
base::Closure done) {
inner_syncable_->PrepareToCreateChangeset(from, done);
}
template <class ChangesetType>
std::unique_ptr<ChangesetType>
LazySyncableAdapter<ChangesetType>::ParseChangesetFromString(
const std::string& changeset) {
google::protobuf::io::ArrayInputStream raw_input_stream(changeset.data(),
changeset.size());
google::protobuf::io::CodedInputStream input_stream(&raw_input_stream);
std::unique_ptr<ChangesetType> parsed_changeset =
base::MakeUnique<ChangesetType>();
parsed_changeset->Parse(&input_stream);
return parsed_changeset;
}
} // namespace helium
} // namespace blimp
#endif // BLIMP_HELIUM_LAZY_SYNCABLE_ADAPTER_H_
// Copyright 2016 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 "blimp/helium/lazy_syncable_adapter.h"
#include <stdint.h>
#include "base/bind.h"
#include "blimp/helium/helium_test.h"
#include "blimp/helium/serializable_struct.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::DoAll;
using testing::Return;
using testing::SaveArg;
namespace blimp {
namespace helium {
namespace {
constexpr Revision kRevision = 42;
struct TestSyncableChangeset : public SerializableStruct {
TestSyncableChangeset() : value(this) {}
~TestSyncableChangeset() override {}
TestSyncableChangeset& operator=(const TestSyncableChangeset& other) {
value.Set(other.value());
return *this;
}
Field<int32_t> value;
};
class MockSyncable : public LazySyncable<TestSyncableChangeset> {
public:
MockSyncable() {}
~MockSyncable() = default;
// LazySyncable implementation.
MOCK_CONST_METHOD1(CreateChangesetMock, TestSyncableChangeset*(Revision));
MOCK_METHOD1(ApplyChangeset, void(const TestSyncableChangeset&));
MOCK_METHOD1(SetLocalUpdateCallback, void(const base::Closure&));
MOCK_CONST_METHOD1(ValidateChangeset, bool(const TestSyncableChangeset&));
MOCK_METHOD1(ReleaseBefore, void(Revision));
MOCK_CONST_METHOD0(GetRevision, Revision());
MOCK_METHOD2(PrepareToCreateChangeset, void(Revision, base::Closure));
std::unique_ptr<TestSyncableChangeset> CreateChangeset(Revision from) const {
return base::WrapUnique<TestSyncableChangeset>(CreateChangesetMock(from));
}
private:
DISALLOW_COPY_AND_ASSIGN(MockSyncable);
};
class LazySyncableAdapterTest : public HeliumTest {
public:
LazySyncableAdapterTest() : adapter_(&syncable_) {}
~LazySyncableAdapterTest() override = default;
MOCK_METHOD0(CallbackMock, void());
protected:
MockSyncable syncable_;
LazySyncableAdapter<TestSyncableChangeset> adapter_;
private:
DISALLOW_COPY_AND_ASSIGN(LazySyncableAdapterTest);
};
TEST_F(LazySyncableAdapterTest, ForwardsSetLocalCallback) {
base::Closure callback_arg;
EXPECT_CALL(syncable_, SetLocalUpdateCallback(_))
.WillOnce(SaveArg<0>(&callback_arg));
adapter_.SetLocalUpdateCallback(base::Bind(
&LazySyncableAdapterTest::CallbackMock, base::Unretained(this)));
EXPECT_CALL(*this, CallbackMock());
callback_arg.Run();
}
TEST_F(LazySyncableAdapterTest, ForwardsReleaseBefore) {
EXPECT_CALL(syncable_, ReleaseBefore(kRevision));
adapter_.ReleaseBefore(kRevision);
}
TEST_F(LazySyncableAdapterTest, ForwardsGetRevision) {
EXPECT_CALL(syncable_, GetRevision()).WillOnce(Return(kRevision));
EXPECT_EQ(kRevision, adapter_.GetRevision());
}
TEST_F(LazySyncableAdapterTest, ForwardsPrepareToCreateChangeset) {
base::Closure callback_arg;
EXPECT_CALL(syncable_, PrepareToCreateChangeset(kRevision, _))
.WillOnce(SaveArg<1>(&callback_arg));
adapter_.PrepareToCreateChangeset(
kRevision, base::Bind(&LazySyncableAdapterTest::CallbackMock,
base::Unretained(this)));
EXPECT_CALL(*this, CallbackMock());
callback_arg.Run();
}
TEST_F(LazySyncableAdapterTest, SerializesParsesForwardsChangesets) {
std::unique_ptr<TestSyncableChangeset> changeset =
base::MakeUnique<TestSyncableChangeset>();
changeset->value.Set(33);
EXPECT_CALL(syncable_, CreateChangesetMock(kRevision))
.WillOnce(Return(changeset.release()));
std::unique_ptr<std::string> string_changeset =
adapter_.CreateChangeset(kRevision);
TestSyncableChangeset validate_changeset;
EXPECT_CALL(syncable_, ValidateChangeset(_))
.WillOnce(DoAll(SaveArg<0>(&validate_changeset), Return(true)));
EXPECT_EQ(true, adapter_.ValidateChangeset(*string_changeset));
EXPECT_EQ(33, validate_changeset.value());
TestSyncableChangeset apply_changeset;
EXPECT_CALL(syncable_, ApplyChangeset(_))
.WillOnce(SaveArg<0>(&apply_changeset));
adapter_.ApplyChangeset(*string_changeset);
EXPECT_EQ(33, apply_changeset.value());
}
} // namespace
} // namespace helium
} // namespace blimp
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment