sync: Refactor NonBlockingTypeProcessor tests

Moves some test support classes out of the NonBlockingTypeProcessor's
unit test .cc files and into their own files.

Rearranges some responsibilities between the test harness and the mock
classes.  Much of the functionality related to mocking out server
behavior has been moved into the MockNonBlockingTypeProcessor.  This
makes it possible to share that code with other test harnesses.

This is one of several follow-ups to the commits that introduced the
NonBlockingTypeProcessor and NonBlockingTypeProcessorCore.

BUG=351005

Review URL: https://codereview.chromium.org/318193002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276830 0039d316-1c4b-4281-b951-d872f2087c98
parent d9dda412
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
'test/engine/fake_sync_scheduler.h', 'test/engine/fake_sync_scheduler.h',
'test/engine/mock_connection_manager.cc', 'test/engine/mock_connection_manager.cc',
'test/engine/mock_connection_manager.h', 'test/engine/mock_connection_manager.h',
'test/engine/mock_non_blocking_type_processor_core.cc',
'test/engine/mock_non_blocking_type_processor_core.h',
'test/engine/mock_update_handler.cc', 'test/engine/mock_update_handler.cc',
'test/engine/mock_update_handler.h', 'test/engine/mock_update_handler.h',
'test/engine/test_directory_setter_upper.cc', 'test/engine/test_directory_setter_upper.cc',
...@@ -47,6 +49,8 @@ ...@@ -47,6 +49,8 @@
'test/engine/test_id_factory.h', 'test/engine/test_id_factory.h',
'test/engine/test_syncable_utils.cc', 'test/engine/test_syncable_utils.cc',
'test/engine/test_syncable_utils.h', 'test/engine/test_syncable_utils.h',
'test/engine/injectable_sync_core_proxy.cc',
'test/engine/injectable_sync_core_proxy.h',
'test/fake_encryptor.cc', 'test/fake_encryptor.cc',
'test/fake_encryptor.h', 'test/fake_encryptor.h',
'test/fake_sync_encryption_handler.cc', 'test/fake_sync_encryption_handler.cc',
......
// Copyright 2014 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 "sync/test/engine/injectable_sync_core_proxy.h"
#include "sync/engine/non_blocking_type_processor.h"
#include "sync/engine/non_blocking_type_processor_core_interface.h"
namespace syncer {
InjectableSyncCoreProxy::InjectableSyncCoreProxy(
NonBlockingTypeProcessorCoreInterface* core)
: is_core_connected_(false), processor_core_(core) {
}
InjectableSyncCoreProxy::~InjectableSyncCoreProxy() {
}
void InjectableSyncCoreProxy::ConnectTypeToCore(
syncer::ModelType type,
const DataTypeState& data_type_state,
base::WeakPtr<syncer::NonBlockingTypeProcessor> type_processor) {
// This class is allowed to participate in only one connection.
DCHECK(!is_core_connected_);
is_core_connected_ = true;
// Hands off ownership of our member to the type_processor, while keeping
// an unsafe pointer to it. This is why we can only connect once.
scoped_ptr<NonBlockingTypeProcessorCoreInterface> core(processor_core_);
type_processor->OnConnect(core.Pass());
}
void InjectableSyncCoreProxy::Disconnect(syncer::ModelType type) {
// This mock object is not meant for connect and disconnect tests.
NOTREACHED() << "Not implemented";
}
scoped_ptr<SyncCoreProxy> InjectableSyncCoreProxy::Clone() const {
// This confuses ownership. We trust that our callers are well-behaved.
return scoped_ptr<SyncCoreProxy>(
new InjectableSyncCoreProxy(processor_core_));
}
NonBlockingTypeProcessorCoreInterface*
InjectableSyncCoreProxy::GetProcessorCore() {
return processor_core_;
}
} // namespace syncer
// Copyright 2014 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 SYNC_TEST_ENGINE_INJECTABLE_SYNC_CORE_PROXY_H_
#define SYNC_TEST_ENGINE_INJECTABLE_SYNC_CORE_PROXY_H_
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/sync_core_proxy.h"
namespace syncer {
struct DataTypeState;
class NonBlockingTypeProcessor;
class NonBlockingTypeProcessorCoreInterface;
// A SyncCoreProxy implementation that, when a connection request is made,
// initalizes a connection to a previously injected NonBlockingTypeProcessor.
class InjectableSyncCoreProxy : public syncer::SyncCoreProxy {
public:
explicit InjectableSyncCoreProxy(NonBlockingTypeProcessorCoreInterface* core);
virtual ~InjectableSyncCoreProxy();
virtual void ConnectTypeToCore(
syncer::ModelType type,
const DataTypeState& data_type_state,
base::WeakPtr<syncer::NonBlockingTypeProcessor> type_processor) OVERRIDE;
virtual void Disconnect(syncer::ModelType type) OVERRIDE;
virtual scoped_ptr<SyncCoreProxy> Clone() const OVERRIDE;
NonBlockingTypeProcessorCoreInterface* GetProcessorCore();
private:
// A flag to ensure ConnectTypeToCore is called at most once.
bool is_core_connected_;
// The NonBlockingTypeProcessor's contract expects that it gets to own this
// object, so we can retain only a non-owned pointer to it.
//
// This is very unsafe, but we can get away with it since these tests are not
// exercising the processor <-> processor_core connection code.
NonBlockingTypeProcessorCoreInterface* processor_core_;
};
} // namespace syncer
#endif // SYNC_TEST_ENGINE_INJECTABLE_SYNC_CORE_PROXY_H_
// Copyright 2014 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 "sync/test/engine/mock_non_blocking_type_processor_core.h"
#include "base/logging.h"
namespace syncer {
MockNonBlockingTypeProcessorCore::MockNonBlockingTypeProcessorCore() {
}
MockNonBlockingTypeProcessorCore::~MockNonBlockingTypeProcessorCore() {
}
void MockNonBlockingTypeProcessorCore::RequestCommits(
const CommitRequestDataList& list) {
commit_request_lists_.push_back(list);
}
size_t MockNonBlockingTypeProcessorCore::GetNumCommitRequestLists() const {
return commit_request_lists_.size();
}
CommitRequestDataList MockNonBlockingTypeProcessorCore::GetNthCommitRequestList(
size_t n) const {
DCHECK_LT(n, GetNumCommitRequestLists());
return commit_request_lists_[n];
}
bool MockNonBlockingTypeProcessorCore::HasCommitRequestForTagHash(
const std::string& tag_hash) const {
// Iterate backward through the sets of commit requests to find the most
// recent one that applies to the specified tag_hash.
for (std::vector<CommitRequestDataList>::const_reverse_iterator lists_it =
commit_request_lists_.rbegin();
lists_it != commit_request_lists_.rend();
++lists_it) {
for (CommitRequestDataList::const_iterator it = lists_it->begin();
it != lists_it->end();
++it) {
if (it->client_tag_hash == tag_hash) {
return true;
}
}
}
return false;
}
CommitRequestData
MockNonBlockingTypeProcessorCore::GetLatestCommitRequestForTagHash(
const std::string& tag_hash) const {
// Iterate backward through the sets of commit requests to find the most
// recent one that applies to the specified tag_hash.
for (std::vector<CommitRequestDataList>::const_reverse_iterator lists_it =
commit_request_lists_.rbegin();
lists_it != commit_request_lists_.rend();
++lists_it) {
for (CommitRequestDataList::const_iterator it = lists_it->begin();
it != lists_it->end();
++it) {
if (it->client_tag_hash == tag_hash) {
return *it;
}
}
}
NOTREACHED() << "Could not find commit for tag hash " << tag_hash << ".";
return CommitRequestData();
}
UpdateResponseData MockNonBlockingTypeProcessorCore::UpdateFromServer(
int64 version_offset,
const std::string& tag_hash,
const sync_pb::EntitySpecifics& specifics) {
// Overwrite the existing server version if this is the new highest version.
int64 old_version = GetServerVersion(tag_hash);
int64 version = old_version + version_offset;
if (version > old_version) {
SetServerVersion(tag_hash, version);
}
UpdateResponseData data;
data.id = GenerateId(tag_hash);
data.client_tag_hash = tag_hash;
data.response_version = version;
data.deleted = false;
data.specifics = specifics;
// These elements should have no effect on behavior, but we set them anyway
// so we can test they are properly copied around the system if we want to.
data.ctime = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
data.mtime = data.ctime + base::TimeDelta::FromSeconds(version);
data.non_unique_name = specifics.preference().name();
return data;
}
UpdateResponseData MockNonBlockingTypeProcessorCore::TombstoneFromServer(
int64 version_offset,
const std::string& tag_hash) {
int64 old_version = GetServerVersion(tag_hash);
int64 version = old_version + version_offset;
if (version > old_version) {
SetServerVersion(tag_hash, version);
}
UpdateResponseData data;
data.id = GenerateId(tag_hash);
data.client_tag_hash = tag_hash;
data.response_version = version;
data.deleted = true;
// These elements should have no effect on behavior, but we set them anyway
// so we can test they are properly copied around the system if we want to.
data.ctime = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
data.mtime = data.ctime + base::TimeDelta::FromSeconds(version);
data.non_unique_name = "Name Non Unique";
return data;
}
CommitResponseData MockNonBlockingTypeProcessorCore::SuccessfulCommitResponse(
const CommitRequestData& request_data) {
const std::string& client_tag_hash = request_data.client_tag_hash;
CommitResponseData response_data;
if (request_data.base_version == 0) {
// Server assigns new ID to newly committed items.
DCHECK(request_data.id.empty());
response_data.id = request_data.id;
} else {
// Otherwise we reuse the ID from the request.
response_data.id = GenerateId(client_tag_hash);
}
response_data.client_tag_hash = client_tag_hash;
response_data.sequence_number = request_data.sequence_number;
// Increment the server version on successful commit.
int64 version = GetServerVersion(client_tag_hash);
version++;
SetServerVersion(client_tag_hash, version);
response_data.response_version = version;
return response_data;
}
std::string MockNonBlockingTypeProcessorCore::GenerateId(
const std::string& tag_hash) {
return "FakeId:" + tag_hash;
}
int64 MockNonBlockingTypeProcessorCore::GetServerVersion(
const std::string& tag_hash) {
std::map<const std::string, int64>::const_iterator it;
it = server_versions_.find(tag_hash);
if (it == server_versions_.end()) {
return 0;
} else {
return it->second;
}
}
void MockNonBlockingTypeProcessorCore::SetServerVersion(
const std::string& tag_hash,
int64 version) {
server_versions_[tag_hash] = version;
}
} // namespace syncer
// Copyright 2014 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 SYNC_TEST_ENGINE_MOCK_NON_BLOCKING_TYPE_PROCESSOR_CORE_H_
#define SYNC_TEST_ENGINE_MOCK_NON_BLOCKING_TYPE_PROCESSOR_CORE_H_
#include <vector>
#include "base/macros.h"
#include "sync/engine/non_blocking_sync_common.h"
#include "sync/engine/non_blocking_type_processor_core_interface.h"
namespace syncer {
// Receives and records commit requests sent through the
// NonBlockingTypeProcessorCoreInterface.
//
// This class also includes features intended to help mock out server behavior.
// It has some basic functionality to keep track of server state and generate
// plausible UpdateResponseData and CommitResponseData messages.
class MockNonBlockingTypeProcessorCore
: public NonBlockingTypeProcessorCoreInterface {
public:
MockNonBlockingTypeProcessorCore();
virtual ~MockNonBlockingTypeProcessorCore();
// Implementation of NonBlockingTypeProcessorCoreInterface.
virtual void RequestCommits(const CommitRequestDataList& list) OVERRIDE;
// Getters to inspect the requests sent to this object.
size_t GetNumCommitRequestLists() const;
CommitRequestDataList GetNthCommitRequestList(size_t n) const;
bool HasCommitRequestForTagHash(const std::string& tag_hash) const;
CommitRequestData GetLatestCommitRequestForTagHash(
const std::string& tag_hash) const;
// Functions to produce state as though it came from a real server and had
// been filtered through a real NonBlockinTypeProcessorCore.
// Returns an UpdateResponseData representing an update received from
// the server. Updates server state accordingly.
//
// The |version_offset| field can be used to emulate stale data (ie. versions
// going backwards), reflections and redeliveries (ie. several instances of
// the same version) or new updates.
UpdateResponseData UpdateFromServer(
int64 version_offset,
const std::string& tag_hash,
const sync_pb::EntitySpecifics& specifics);
// Returns an UpdateResponseData representing a tombstone update from the
// server. Updates server state accordingly.
UpdateResponseData TombstoneFromServer(int64 version_offset,
const std::string& tag_hash);
// Returns a commit response that indicates a successful commit of the
// given |request_data|. Updates server state accordingly.
CommitResponseData SuccessfulCommitResponse(
const CommitRequestData& request_data);
private:
// Generate an ID string.
static std::string GenerateId(const std::string& tag_hash);
// Retrieve or set the server version.
int64 GetServerVersion(const std::string& tag_hash);
void SetServerVersion(const std::string& tag_hash, int64 version);
// A record of past commits requests.
std::vector<CommitRequestDataList> commit_request_lists_;
// Map of versions by client tag.
// This is an essential part of the mocked server state.
std::map<const std::string, int64> server_versions_;
DISALLOW_COPY_AND_ASSIGN(MockNonBlockingTypeProcessorCore);
};
} // namespace syncer
#endif // SYNC_TEST_ENGINE_MOCK_NON_BLOCKING_TYPE_PROCESSOR_CORE_H_
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