blob: f51052f95ec8d92981b9dac9a189b2965f2efaac [file] [log] [blame]
// 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/lww_register.h"
#include <string>
#include "base/bind.h"
#include "base/macros.h"
#include "blimp/helium/helium_test.h"
#include "blimp/helium/revision_generator.h"
#include "blimp/helium/version_vector.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
namespace blimp {
namespace helium {
namespace {
class LwwRegisterTest : public HeliumTest {
public:
LwwRegisterTest() {}
~LwwRegisterTest() override = default;
MOCK_METHOD0(OnEngineCallbackCalled, void());
MOCK_METHOD0(OnClientCallbackCalled, void());
protected:
void Initialize(Peer bias) {
client_ = base::MakeUnique<LwwRegister<int>>(bias, Peer::CLIENT);
engine_ = base::MakeUnique<LwwRegister<int>>(bias, Peer::ENGINE);
client_->SetLocalUpdateCallback(base::Bind(
&LwwRegisterTest::OnClientCallbackCalled, base::Unretained(this)));
engine_->SetLocalUpdateCallback(base::Bind(
&LwwRegisterTest::OnEngineCallbackCalled, base::Unretained(this)));
}
void SyncFromClient() {
Sync(client_.get(), engine_.get(), client_->GetRevision());
}
void SyncFromEngine() {
Sync(engine_.get(), client_.get(), engine_->GetRevision());
}
void Sync(LwwRegister<int>* from_lww_register,
LwwRegister<int>* to_lww_register,
Revision from);
std::unique_ptr<LwwRegister<int>> client_;
std::unique_ptr<LwwRegister<int>> engine_;
private:
DISALLOW_COPY_AND_ASSIGN(LwwRegisterTest);
};
// Takes a changeset from |from_lww_register| and applies it to
// |to_lww_register|.
void LwwRegisterTest::Sync(LwwRegister<int>* from_lww_register,
LwwRegister<int>* to_lww_register,
Revision from) {
// Create a changeset from |from_lww_register|.
std::string changeset;
google::protobuf::io::StringOutputStream raw_output_stream(&changeset);
google::protobuf::io::CodedOutputStream output_stream(&raw_output_stream);
from_lww_register->CreateChangesetToCurrent(from, &output_stream);
// Apply the changeset to |to_lww_register|.
google::protobuf::io::ArrayInputStream raw_input_stream(changeset.data(),
changeset.size());
google::protobuf::io::CodedInputStream input_stream(&raw_input_stream);
to_lww_register->ApplyChangeset(&input_stream);
}
TEST_F(LwwRegisterTest, SetIncrementsLocalVersion) {
Initialize(Peer::CLIENT);
EXPECT_CALL(*this, OnClientCallbackCalled()).Times(1);
EXPECT_CALL(*this, OnEngineCallbackCalled()).Times(0);
Revision earlier_version = client_->GetRevision();
client_->Set(42);
Revision current_version = client_->GetRevision();
EXPECT_EQ(42, client_->Get());
EXPECT_LT(earlier_version, current_version);
}
TEST_F(LwwRegisterTest, ApplyLaterChangeset) {
Initialize(Peer::CLIENT);
EXPECT_CALL(*this, OnClientCallbackCalled()).Times(1);
EXPECT_CALL(*this, OnEngineCallbackCalled()).Times(0);
client_->Set(123);
SyncFromClient();
EXPECT_EQ(123, engine_->Get());
}
TEST_F(LwwRegisterTest, ApplyEarlierChangeset) {
Initialize(Peer::CLIENT);
EXPECT_CALL(*this, OnClientCallbackCalled()).Times(1);
EXPECT_CALL(*this, OnEngineCallbackCalled()).Times(1);
client_->Set(123);
SyncFromClient();
engine_->Set(456);
SyncFromClient();
EXPECT_EQ(456, engine_->Get());
}
TEST_F(LwwRegisterTest, ClientApplyChangesetConflictClientWins) {
Initialize(Peer::CLIENT);
EXPECT_CALL(*this, OnClientCallbackCalled()).Times(1);
EXPECT_CALL(*this, OnEngineCallbackCalled()).Times(1);
client_->Set(123);
engine_->Set(456);
SyncFromEngine();
EXPECT_EQ(123, client_->Get());
}
TEST_F(LwwRegisterTest, EngineApplyChangesetConflictClientWins) {
Initialize(Peer::CLIENT);
EXPECT_CALL(*this, OnClientCallbackCalled()).Times(1);
EXPECT_CALL(*this, OnEngineCallbackCalled()).Times(1);
client_->Set(123);
engine_->Set(456);
SyncFromClient();
EXPECT_EQ(123, engine_->Get());
}
TEST_F(LwwRegisterTest, ClientApplyChangesetConflictEngineWins) {
Initialize(Peer::ENGINE);
EXPECT_CALL(*this, OnClientCallbackCalled()).Times(1);
EXPECT_CALL(*this, OnEngineCallbackCalled()).Times(1);
client_->Set(123);
engine_->Set(456);
SyncFromEngine();
EXPECT_EQ(456, client_->Get());
}
TEST_F(LwwRegisterTest, EngineApplyChangesetConflictEngineWins) {
Initialize(Peer::ENGINE);
EXPECT_CALL(*this, OnClientCallbackCalled()).Times(1);
EXPECT_CALL(*this, OnEngineCallbackCalled()).Times(1);
client_->Set(123);
engine_->Set(456);
SyncFromClient();
EXPECT_EQ(456, engine_->Get());
}
} // namespace
} // namespace helium
} // namespace blimp