diff options
author | pvalenzuela@chromium.org <pvalenzuela@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-16 21:26:11 +0000 |
---|---|---|
committer | pvalenzuela@chromium.org <pvalenzuela@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-16 21:26:11 +0000 |
commit | 6732a39e054cfd28e6518cc34fe542bd56773750 (patch) | |
tree | e86a51a5bb9802840a9ba2b3dee9fe552c1bd298 | |
parent | b32c76fc04ba5e17ae394f026542883cf8037a57 (diff) | |
download | chromium_src-6732a39e054cfd28e6518cc34fe542bd56773750.zip chromium_src-6732a39e054cfd28e6518cc34fe542bd56773750.tar.gz chromium_src-6732a39e054cfd28e6518cc34fe542bd56773750.tar.bz2 |
Basic implementation of the Sync C++ fake server
This CL provides just enough functionality so that
PrototypeFakeServerTest will pass.
BUG=323265
Review URL: https://codereview.chromium.org/115243007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245326 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/sync/test/integration/prototype_fake_server_test.cc | 24 | ||||
-rw-r--r-- | chrome/browser/sync/test/integration/sync_test.cc | 74 | ||||
-rw-r--r-- | chrome/browser/sync/test/integration/sync_test.h | 30 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 10 | ||||
-rw-r--r-- | sync/sync_tests.gypi | 25 | ||||
-rw-r--r-- | sync/test/fake_server/fake_server.cc | 325 | ||||
-rw-r--r-- | sync/test/fake_server/fake_server.h | 79 | ||||
-rw-r--r-- | sync/test/fake_server/fake_server_http_post_provider.cc | 80 | ||||
-rw-r--r-- | sync/test/fake_server/fake_server_http_post_provider.h | 71 | ||||
-rw-r--r-- | sync/test/fake_server/fake_server_network_resources.cc | 30 | ||||
-rw-r--r-- | sync/test/fake_server/fake_server_network_resources.h | 38 |
11 files changed, 753 insertions, 33 deletions
diff --git a/chrome/browser/sync/test/integration/prototype_fake_server_test.cc b/chrome/browser/sync/test/integration/prototype_fake_server_test.cc new file mode 100644 index 0000000..cdb8f85 --- /dev/null +++ b/chrome/browser/sync/test/integration/prototype_fake_server_test.cc @@ -0,0 +1,24 @@ +// 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 "chrome/browser/sync/test/integration/sync_test.h" + +class PrototypeFakeServerTest : public SyncTest { + public: + PrototypeFakeServerTest() : SyncTest(SINGLE_CLIENT) { + UseFakeServer(); + } + + virtual ~PrototypeFakeServerTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(PrototypeFakeServerTest); +}; + +// TODO(pvalenzuela): Remove this test when sync_integration_tests is +// transitioned to use the C++ fake server. This test currently exists to +// ensure fake server functionality during development. See Bug 323265. +IN_PROC_BROWSER_TEST_F(PrototypeFakeServerTest, Setup) { + ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; +} diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index b6297c7..b5b0f3f 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc @@ -60,6 +60,8 @@ #include "sync/engine/sync_scheduler_impl.h" #include "sync/notifier/p2p_invalidator.h" #include "sync/protocol/sync.pb.h" +#include "sync/test/fake_server/fake_server.h" +#include "sync/test/fake_server/fake_server_network_resources.h" #include "url/gurl.h" using content::BrowserThread; @@ -143,30 +145,34 @@ void SyncTest::SetUp() { password_ = "password"; } - if (!cl->HasSwitch(switches::kSyncServiceURL) && - !cl->HasSwitch(switches::kSyncServerCommandLine)) { - // If neither a sync server URL nor a sync server command line is - // provided, start up a local python sync test server and point Chrome - // to its URL. This is the most common configuration, and the only - // one that makes sense for most developers. - server_type_ = LOCAL_PYTHON_SERVER; - } else if (cl->HasSwitch(switches::kSyncServiceURL) && - cl->HasSwitch(switches::kSyncServerCommandLine)) { - // If a sync server URL and a sync server command line are provided, - // start up a local sync server by running the command line. Chrome - // will connect to the server at the URL that was provided. - server_type_ = LOCAL_LIVE_SERVER; - } else if (cl->HasSwitch(switches::kSyncServiceURL) && - !cl->HasSwitch(switches::kSyncServerCommandLine)) { - // If a sync server URL is provided, but not a server command line, - // it is assumed that the server is already running. Chrome will - // automatically connect to it at the URL provided. There is nothing - // to do here. - server_type_ = EXTERNAL_LIVE_SERVER; - } else { - // If a sync server command line is provided, but not a server URL, - // we flag an error. - LOG(FATAL) << "Can't figure out how to run a server."; + // Only set |server_type_| if it hasn't already been set. This allows for + // IN_PROCESS_FAKE_SERVER tests to set this value in each test class. + if (server_type_ == SERVER_TYPE_UNDECIDED) { + if (!cl->HasSwitch(switches::kSyncServiceURL) && + !cl->HasSwitch(switches::kSyncServerCommandLine)) { + // If neither a sync server URL nor a sync server command line is + // provided, start up a local python sync test server and point Chrome + // to its URL. This is the most common configuration, and the only + // one that makes sense for most developers. + server_type_ = LOCAL_PYTHON_SERVER; + } else if (cl->HasSwitch(switches::kSyncServiceURL) && + cl->HasSwitch(switches::kSyncServerCommandLine)) { + // If a sync server URL and a sync server command line are provided, + // start up a local sync server by running the command line. Chrome + // will connect to the server at the URL that was provided. + server_type_ = LOCAL_LIVE_SERVER; + } else if (cl->HasSwitch(switches::kSyncServiceURL) && + !cl->HasSwitch(switches::kSyncServerCommandLine)) { + // If a sync server URL is provided, but not a server command line, + // it is assumed that the server is already running. Chrome will + // automatically connect to it at the URL provided. There is nothing + // to do here. + server_type_ = EXTERNAL_LIVE_SERVER; + } else { + // If a sync server command line is provided, but not a server URL, + // we flag an error. + LOG(FATAL) << "Can't figure out how to run a server."; + } } if (username_.empty() || password_.empty()) @@ -316,7 +322,15 @@ void SyncTest::InitializeInstance(int index) { // Make sure the ProfileSyncService has been created before creating the // ProfileSyncServiceHarness - some tests expect the ProfileSyncService to // already exist. - ProfileSyncServiceFactory::GetForProfile(GetProfile(index)); + ProfileSyncService* profile_sync_service = + ProfileSyncServiceFactory::GetForProfile(GetProfile(index)); + + if (server_type_ == IN_PROCESS_FAKE_SERVER) { + // TODO(pvalenzuela): Run the fake server via EmbeddedTestServer. + profile_sync_service->OverrideNetworkResourcesForTest( + make_scoped_ptr<syncer::NetworkResources>( + new syncer::FakeServerNetworkResources(fake_server_.get()))); + } clients_[index] = ProfileSyncServiceHarness::CreateForIntegrationTest( @@ -509,6 +523,11 @@ void SyncTest::SetUpTestServerIfRequired() { LOG(FATAL) << "Failed to set up local python XMPP server"; if (!SetUpLocalTestServer()) LOG(FATAL) << "Failed to set up local test server"; + } else if (server_type_ == IN_PROCESS_FAKE_SERVER) { + fake_server_.reset(new syncer::FakeServer()); + // Similar to LOCAL_LIVE_SERVER, we must start this for XMPP. + SetUpLocalPythonTestServer(); + SetupMockGaiaResponses(); } else if (server_type_ == EXTERNAL_LIVE_SERVER) { // Nothing to do; we'll just talk to the URL we were given. } else { @@ -862,3 +881,8 @@ void SyncTest::SetProxyConfig(net::URLRequestContextGetter* context_getter, make_scoped_refptr(context_getter), proxy_config)); done.Wait(); } + +void SyncTest::UseFakeServer() { + DCHECK_EQ(SERVER_TYPE_UNDECIDED, server_type_); + server_type_ = IN_PROCESS_FAKE_SERVER; +} diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h index 814f53e..e05fe4a 100644 --- a/chrome/browser/sync/test/integration/sync_test.h +++ b/chrome/browser/sync/test/integration/sync_test.h @@ -18,6 +18,7 @@ #include "net/url_request/url_request_status.h" #include "sync/internal_api/public/base/model_type.h" #include "sync/protocol/sync_protocol_error.h" +#include "sync/test/fake_server/fake_server.h" #include "sync/test/local_sync_test_server.h" @@ -57,14 +58,18 @@ class SyncTest : public InProcessBrowserTest { // The type of server we're running against. enum ServerType { SERVER_TYPE_UNDECIDED, - LOCAL_PYTHON_SERVER, // The mock python server that runs locally and is - // part of the Chromium checkout. - LOCAL_LIVE_SERVER, // Some other server (maybe the real binary used by - // Google's sync service) that can be started on - // a per-test basis by running a command - EXTERNAL_LIVE_SERVER, // A remote server that the test code has no control - // over whatsoever; cross your fingers that the - // account state is initially clean. + LOCAL_PYTHON_SERVER, // The mock python server that runs locally and is + // part of the Chromium checkout. + LOCAL_LIVE_SERVER, // Some other server (maybe the real binary used by + // Google's sync service) that can be started on + // a per-test basis by running a command + EXTERNAL_LIVE_SERVER, // A remote server that the test code has no control + // over whatsoever; cross your fingers that the + // account state is initially clean. + IN_PROCESS_FAKE_SERVER, // The fake Sync server (FakeServer) running + // in-process (bypassing HTTP calls). This + // ServerType will eventually replace + // LOCAL_PYTHON_SERVER. }; // NOTE: IMPORTANT the enum here should match with @@ -251,6 +256,12 @@ class SyncTest : public InProcessBrowserTest { void DisableNotificationsImpl(); void EnableNotificationsImpl(); + // Set up the test to use the in-process fake server. This must be called + // before SetUp(). + // TODO(pvalenzuela): Remove this method when the C++ fake server becomes + // the default server type. + void UseFakeServer(); + // GAIA account used by the test case. std::string username_; @@ -260,6 +271,9 @@ class SyncTest : public InProcessBrowserTest { // Locally available plain text file in which GAIA credentials are stored. base::FilePath password_file_; + // The FakeServer used in tests with server type IN_PROCESS_FAKE_SERVER. + scoped_ptr<syncer::FakeServer> fake_server_; + private: // Helper to ProfileManager::CreateProfile that handles path creation. static Profile* MakeProfile(const base::FilePath::StringType name); diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 67bb60c..15f3c83 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2312,6 +2312,7 @@ '../skia/skia.gyp:skia', '../sync/sync.gyp:sync', '../sync/sync.gyp:test_support_sync_testserver', + '../sync/sync.gyp:test_support_sync_fake_server', '../ui/app_list/app_list.gyp:app_list_test_support', ], 'include_dirs': [ @@ -2434,6 +2435,15 @@ 'browser/sync/test/integration/multiple_client_preferences_sync_test.cc', 'browser/sync/test/integration/multiple_client_sessions_sync_test.cc', 'browser/sync/test/integration/multiple_client_typed_urls_sync_test.cc', + 'browser/sync/test/integration/passwords_helper.cc', + 'browser/sync/test/integration/passwords_helper.h', + 'browser/sync/test/integration/preferences_helper.cc', + 'browser/sync/test/integration/preferences_helper.h', + 'browser/sync/test/integration/prototype_fake_server_test.cc', + 'browser/sync/test/integration/search_engines_helper.cc', + 'browser/sync/test/integration/search_engines_helper.h', + 'browser/sync/test/integration/sessions_helper.cc', + 'browser/sync/test/integration/sessions_helper.h', 'browser/sync/test/integration/single_client_app_list_sync_test.cc', 'browser/sync/test/integration/single_client_apps_sync_test.cc', 'browser/sync/test/integration/single_client_bookmarks_sync_test.cc', diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi index 57e2b47..bfe7e7b 100644 --- a/sync/sync_tests.gypi +++ b/sync/sync_tests.gypi @@ -90,6 +90,31 @@ ], }, + # Test support files for the fake sync server. + { + 'target_name': 'test_support_sync_fake_server', + 'type': 'static_library', + 'variables': { 'enable_wexit_time_destructors': 1, }, + 'include_dirs': [ + '..', + ], + 'dependencies': [ + '../base/base.gyp:base', + 'sync', + ], + 'export_dependent_settings': [ + 'sync', + ], + 'sources': [ + 'test/fake_server/fake_server.h', + 'test/fake_server/fake_server.cc', + 'test/fake_server/fake_server_http_post_provider.h', + 'test/fake_server/fake_server_http_post_provider.cc', + 'test/fake_server/fake_server_network_resources.h', + 'test/fake_server/fake_server_network_resources.cc', + ], + }, + # Test support files for the 'sync_notifier' target. { 'target_name': 'test_support_sync_notifier', diff --git a/sync/test/fake_server/fake_server.cc b/sync/test/fake_server/fake_server.cc new file mode 100644 index 0000000..5f4457d --- /dev/null +++ b/sync/test/fake_server/fake_server.cc @@ -0,0 +1,325 @@ +// 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/fake_server/fake_server.h" + +#include <limits> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "sync/internal_api/public/base/model_type.h" +#include "sync/protocol/sync.pb.h" + +using std::string; + +// The parent tag for childen of the root node. +static const char kRootParentTag[] = "0"; + +namespace syncer { +namespace { + +// A filter used during GetUpdates calls to determine what information to +// send back to the client. There is a 1:1 correspondence between any given +// GetUpdates call and an UpdateSieve instance. +class UpdateSieve { + public: + ~UpdateSieve() { } + + // Factory method for creating an UpdateSieve. + static scoped_ptr<UpdateSieve> Create( + const sync_pb::GetUpdatesMessage& get_updates_message); + + // Sets the progress markers in |get_updates_response| given the progress + // markers from the original GetUpdatesMessage and |new_version| (the latest + // version in the entries sent back). + void UpdateProgressMarkers( + int64 new_version, + sync_pb::GetUpdatesResponse* get_updates_response) const { + ModelTypeToVersionMap::const_iterator it; + for (it = request_from_version_.begin(); it != request_from_version_.end(); + ++it) { + sync_pb::DataTypeProgressMarker* new_marker = + get_updates_response->add_new_progress_marker(); + new_marker->set_data_type_id( + GetSpecificsFieldNumberFromModelType(it->first)); + + int64 version = std::max(new_version, it->second); + new_marker->set_token(base::Int64ToString(version)); + } + } + + // Determines whether the server should send |entity| to the client based + // on its type and version. + bool ClientWantsItem(const sync_pb::SyncEntity& entity) const { + ModelTypeToVersionMap::const_iterator it = + request_from_version_.find(GetModelType(entity)); + + return it == request_from_version_.end() ? + false : it->second < entity.version(); + } + + // Returns the mininum version seen across all types. + int64 GetMinVersion() const { + return min_version_; + } + + // Returns the data type IDs of types being synced for the first time. + std::vector<ModelType> GetFirstTimeTypes() const { + std::vector<ModelType> types; + + ModelTypeToVersionMap::const_iterator it; + for (it = request_from_version_.begin(); it != request_from_version_.end(); + ++it) { + if (it->second == 0) + types.push_back(it->first); + } + + return types; + } + + private: + typedef std::map<ModelType, int64> ModelTypeToVersionMap; + + // Creates an UpdateSieve. + UpdateSieve(const ModelTypeToVersionMap request_from_version, + const int64 min_version) + : request_from_version_(request_from_version), + min_version_(min_version) { } + + // Maps data type IDs to the latest version seen for that type. + const ModelTypeToVersionMap request_from_version_; + + // The minimum version seen among all data types. + const int min_version_; +}; + +scoped_ptr<UpdateSieve> UpdateSieve::Create( + const sync_pb::GetUpdatesMessage& get_updates_message) { + DCHECK_GT(get_updates_message.from_progress_marker_size(), 0); + + UpdateSieve::ModelTypeToVersionMap request_from_version; + int64 min_version = std::numeric_limits<int64>::max(); + for (int i = 0; i < get_updates_message.from_progress_marker_size(); i++) { + sync_pb::DataTypeProgressMarker marker = + get_updates_message.from_progress_marker(i); + + int64 version; + if (!marker.has_token() || marker.token().empty()) { + // Initialize the version on the first request for this type. + version = 0; + } else { + DCHECK(base::StringToInt64(marker.token(), &version)); + } + + ModelType model_type = GetModelTypeFromSpecificsFieldNumber( + marker.data_type_id()); + request_from_version[model_type] = version; + + if (version < min_version) + min_version = version; + } + + return scoped_ptr<UpdateSieve>( + new UpdateSieve(request_from_version, min_version)); +} + +} // namespace + +FakeServer::FakeServer() : version_(0), birthday_("1234567890") { + keystore_keys_.push_back("1111111111111111"); +} + +FakeServer::~FakeServer() { } + +void FakeServer::CreateDefaultPermanentItems( + const std::vector<ModelType>& first_time_types) { + for (std::vector<ModelType>::const_iterator it = first_time_types.begin(); + it != first_time_types.end(); ++it) { + if (!ModelTypeSet::All().Has(*it)) { + NOTREACHED() << "An unexpected ModelType was encountered."; + } + + ModelType model_type = *it; + CreateSyncEntity(model_type, + ModelTypeToRootTag(model_type), + ModelTypeToString(model_type), + kRootParentTag); + + if (model_type == BOOKMARKS) { + CreateSyncEntity(BOOKMARKS, + "bookmark_bar", + "Bookmark Bar", + ModelTypeToRootTag(BOOKMARKS)); + CreateSyncEntity(BOOKMARKS, + "other_bookmarks", + "Other Bookmarks", + ModelTypeToRootTag(BOOKMARKS)); + } + } + + + // TODO(pvalenzuela): Create the mobile bookmarks folder when the fake server + // is used by mobile tests. +} + +void FakeServer::CreateSyncEntity(ModelType model_type, + const std::string& id, + const std::string& name, + const std::string& parent_tag) { + DCHECK(!id.empty()); + DCHECK(!name.empty()); + DCHECK(!parent_tag.empty()); + + sync_pb::SyncEntity entity; + entity.set_id_string(id); + entity.set_non_unique_name(name); + entity.set_name(name); + entity.set_server_defined_unique_tag(id); + entity.set_folder(true); + entity.set_deleted(false); + + entity.set_parent_id_string(parent_tag); + + if (parent_tag != kRootParentTag && model_type == BOOKMARKS) { + // Use a dummy value here. + entity.set_position_in_parent(1337); + } + + sync_pb::EntitySpecifics* specifics = entity.mutable_specifics(); + AddDefaultFieldValue(model_type, specifics); + + SaveEntity(entity); +} + +void FakeServer::SaveEntity(sync_pb::SyncEntity entity) { + version_++; + entity.set_version(version_); + entity.set_sync_timestamp(version_); + + sync_pb::SyncEntity original_entity = entities_[entity.id_string()]; + entity.set_originator_cache_guid(original_entity.originator_cache_guid()); + entity.set_originator_client_item_id( + original_entity.originator_client_item_id()); + + entities_[entity.id_string()] = entity; +} + +int FakeServer::HandleCommand(string request, + int* response_code, + string* response) { + sync_pb::ClientToServerMessage message; + DCHECK(message.ParseFromString(request)); + + sync_pb::ClientToServerResponse response_proto; + switch (message.message_contents()) { + case sync_pb::ClientToServerMessage::GET_UPDATES: + response_proto = HandleGetUpdatesRequest(message); + break; + case sync_pb::ClientToServerMessage::COMMIT: + response_proto = HandleCommitRequest(message); + break; + default: + // Any nonzero int will indicate a failure here. This one happens to + // be net::ERR_NOT_IMPLEMENTED. + return -11; + } + + *response_code = 200; + *response = response_proto.SerializeAsString(); + return 0; +} + +bool SyncEntityVersionComparator(const sync_pb::SyncEntity& first, + const sync_pb::SyncEntity& second) { + return first.version() < second.version(); +} + +sync_pb::ClientToServerResponse FakeServer::HandleGetUpdatesRequest( + const sync_pb::ClientToServerMessage& message) { + sync_pb::ClientToServerResponse response; + response.set_error_code(sync_pb::SyncEnums::SUCCESS); + response.set_store_birthday(birthday_); + + sync_pb::GetUpdatesResponse* get_updates_response = + response.mutable_get_updates(); + // TODO(pvalenzuela): Implement batching instead of sending all information + // at once. + get_updates_response->set_changes_remaining(0); + + scoped_ptr<UpdateSieve> sieve = UpdateSieve::Create(message.get_updates()); + CreateDefaultPermanentItems(sieve->GetFirstTimeTypes()); + + int64 min_version = sieve->GetMinVersion(); + + bool send_encryption_keys_based_on_nigori = false; + int64 max_response_version = 0; + for (EntityMap::iterator it = entities_.begin(); it != entities_.end(); + ++it) { + sync_pb::SyncEntity entity = it->second; + if (entity.version() > min_version && sieve->ClientWantsItem(entity)) { + sync_pb::SyncEntity* response_entity = + get_updates_response->add_entries(); + response_entity->CopyFrom(entity); + max_response_version = std::max(max_response_version, + response_entity->version()); + + if (response_entity->name() == ModelTypeToString(NIGORI)) { + send_encryption_keys_based_on_nigori = + response_entity->specifics().nigori().passphrase_type() == + sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; + } + } + } + + if (send_encryption_keys_based_on_nigori || + message.get_updates().need_encryption_key()) { + for (std::vector<std::string>::iterator it = keystore_keys_.begin(); + it != keystore_keys_.end(); ++it) { + get_updates_response->add_encryption_keys(*it); + } + } + + sieve->UpdateProgressMarkers(max_response_version, get_updates_response); + + return response; +} + +sync_pb::SyncEntity FakeServer::CommitEntity(sync_pb::SyncEntity entity, + string guid) { + // TODO(pvalenzuela): Implement this. Right now this method cheats and + // doesn't actually commit. + return entity; +} + +sync_pb::ClientToServerResponse FakeServer::HandleCommitRequest( + const sync_pb::ClientToServerMessage& message) { + sync_pb::ClientToServerResponse response; + response.set_error_code(sync_pb::SyncEnums::SUCCESS); + response.set_store_birthday(birthday_); + + sync_pb::CommitMessage commit = message.commit(); + string guid = commit.cache_guid(); + + sync_pb::CommitResponse* commit_response = response.mutable_commit(); + + ::google::protobuf::RepeatedPtrField<sync_pb::SyncEntity>::const_iterator it; + for (it = commit.entries().begin(); it != commit.entries().end(); ++it) { + sync_pb::CommitResponse_EntryResponse* entry_response = + commit_response->add_entryresponse(); + + sync_pb::SyncEntity server_entity = CommitEntity(*it, guid); + + entry_response->set_id_string(server_entity.id_string()); + entry_response->set_response_type(sync_pb::CommitResponse::SUCCESS); + entry_response->set_version(it->version() + 1); + } + + return response; +} + +} // namespace syncer diff --git a/sync/test/fake_server/fake_server.h b/sync/test/fake_server/fake_server.h new file mode 100644 index 0000000..bf3affc --- /dev/null +++ b/sync/test/fake_server/fake_server.h @@ -0,0 +1,79 @@ +// 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_FAKE_SERVER_FAKE_SERVER_H_ +#define SYNC_TEST_FAKE_SERVER_FAKE_SERVER_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "sync/internal_api/public/base/model_type.h" +#include "sync/protocol/sync.pb.h" + +namespace syncer { + +// A fake version of the Sync server used for testing. +class FakeServer { + public: + FakeServer(); + virtual ~FakeServer(); + + // Handles a /command POST to the server. If the return value is 0 (success), + // |response_code| and |response| will be set. Otherwise, the return value + // will be a network error code. + int HandleCommand(std::string request, + int* response_code, + std::string* response); + + private: + typedef std::map<std::string, sync_pb::SyncEntity> EntityMap; + + // Processes a GetUpdates call. + sync_pb::ClientToServerResponse HandleGetUpdatesRequest( + const sync_pb::ClientToServerMessage& message); + + // Processes a Commit call. + sync_pb::ClientToServerResponse HandleCommitRequest( + const sync_pb::ClientToServerMessage& message); + + // Inserts the appropriate permanent items in |entities_|. + void CreateDefaultPermanentItems( + const std::vector<ModelType>& first_time_types); + + // Creates and saves a SyncEntity of the given |model_type|. The entity's + // id_string and server_defined_unique_tag fields are set to |id|. The + // non_unique_name and name fields are set to |name|. Since tags are used as + // ids, the parent_id_string field is set to |parent_tag|. + void CreateSyncEntity(ModelType model_type, + const std::string& id, + const std::string& name, + const std::string& parent_tag); + + // Saves a |entity| to |entities_|. + void SaveEntity(sync_pb::SyncEntity entity); + + // Commits a client-side |entity| to |entities_|. + sync_pb::SyncEntity CommitEntity(sync_pb::SyncEntity entity, + std::string guid); + + // This is the last version number assigned to an entity. The next entity will + // have a version number of version_ + 1. + int64 version_; + + // The current birthday value. + std::string birthday_; + + // All SyncEntity objects saved by the server. The key value is the entity's + // id string. + EntityMap entities_; + + // All Keystore keys known to the server. + std::vector<std::string> keystore_keys_; +}; + +} // namespace syncer + +#endif // SYNC_TEST_FAKE_SERVER_FAKE_SERVER_H_ diff --git a/sync/test/fake_server/fake_server_http_post_provider.cc b/sync/test/fake_server/fake_server_http_post_provider.cc new file mode 100644 index 0000000..feb87a4 --- /dev/null +++ b/sync/test/fake_server/fake_server_http_post_provider.cc @@ -0,0 +1,80 @@ +// 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/fake_server/fake_server_http_post_provider.h" + +#include <string> + +#include "sync/test/fake_server/fake_server.h" + +namespace syncer { + +FakeServerHttpPostProviderFactory::FakeServerHttpPostProviderFactory( + FakeServer* fake_server) : fake_server_(fake_server) { } + +FakeServerHttpPostProviderFactory::~FakeServerHttpPostProviderFactory() { } + +void FakeServerHttpPostProviderFactory::Init(const std::string& user_agent) { } + +HttpPostProviderInterface* FakeServerHttpPostProviderFactory::Create() { + FakeServerHttpPostProvider* http = + new FakeServerHttpPostProvider(fake_server_); + http->AddRef(); + return http; +} + +void FakeServerHttpPostProviderFactory::Destroy( + HttpPostProviderInterface* http) { + static_cast<FakeServerHttpPostProvider*>(http)->Release(); +} + +FakeServerHttpPostProvider::FakeServerHttpPostProvider( + FakeServer* fake_server) : fake_server_(fake_server) { } + +FakeServerHttpPostProvider::~FakeServerHttpPostProvider() { } + +void FakeServerHttpPostProvider::SetExtraRequestHeaders(const char* headers) { + // TODO(pvalenzuela): Add assertions on this value. + extra_request_headers_.assign(headers); +} + +void FakeServerHttpPostProvider::SetURL(const char* url, int port) { + // TODO(pvalenzuela): Add assertions on these values. + request_url_.assign(url); + request_port_ = port; +} + +void FakeServerHttpPostProvider::SetPostPayload(const char* content_type, + int content_length, + const char* content) { + request_content_type_.assign(content_type); + request_content_.assign(content, content_length); +} + +bool FakeServerHttpPostProvider::MakeSynchronousPost(int* error_code, + int* response_code) { + // This assumes that a POST is being made to /command. + *error_code = fake_server_->HandleCommand(request_content_, + response_code, + &response_); + return (*error_code == 0); +} + +int FakeServerHttpPostProvider::GetResponseContentLength() const { + return response_.length(); +} + +const char* FakeServerHttpPostProvider::GetResponseContent() const { + return response_.c_str(); +} + +const std::string FakeServerHttpPostProvider::GetResponseHeaderValue( + const std::string& name) const { + return ""; +} + +void FakeServerHttpPostProvider::Abort() { +} + +} // namespace syncer diff --git a/sync/test/fake_server/fake_server_http_post_provider.h b/sync/test/fake_server/fake_server_http_post_provider.h new file mode 100644 index 0000000..dbbbab2 --- /dev/null +++ b/sync/test/fake_server/fake_server_http_post_provider.h @@ -0,0 +1,71 @@ +// 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_FAKE_SERVER_FAKE_SERVER_HTTP_POST_PROVIDER_H_ +#define SYNC_TEST_FAKE_SERVER_FAKE_SERVER_HTTP_POST_PROVIDER_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "sync/internal_api/public/http_post_provider_factory.h" +#include "sync/internal_api/public/http_post_provider_interface.h" + +namespace syncer { + +class FakeServer; + +class FakeServerHttpPostProvider + : public HttpPostProviderInterface, + public base::RefCountedThreadSafe<FakeServerHttpPostProvider> { + public: + FakeServerHttpPostProvider(FakeServer* fake_server); + + // HttpPostProviderInterface implementation. + virtual void SetExtraRequestHeaders(const char* headers) OVERRIDE; + virtual void SetURL(const char* url, int port) OVERRIDE; + virtual void SetPostPayload(const char* content_type, int content_length, + const char* content) OVERRIDE; + virtual bool MakeSynchronousPost(int* error_code, + int* response_code) OVERRIDE; + virtual void Abort() OVERRIDE; + virtual int GetResponseContentLength() const OVERRIDE; + virtual const char* GetResponseContent() const OVERRIDE; + virtual const std::string GetResponseHeaderValue( + const std::string& name) const OVERRIDE; + + protected: + friend class base::RefCountedThreadSafe<FakeServerHttpPostProvider>; + virtual ~FakeServerHttpPostProvider(); + + private: + FakeServer* const fake_server_; + std::string response_; + std::string request_url_; + int request_port_; + std::string request_content_; + std::string request_content_type_; + std::string extra_request_headers_; + + DISALLOW_COPY_AND_ASSIGN(FakeServerHttpPostProvider); +}; + +class FakeServerHttpPostProviderFactory : public HttpPostProviderFactory { + public: + FakeServerHttpPostProviderFactory(FakeServer* fake_server); + virtual ~FakeServerHttpPostProviderFactory(); + + // HttpPostProviderFactory: + virtual void Init(const std::string& user_agent) OVERRIDE; + virtual HttpPostProviderInterface* Create() OVERRIDE; + virtual void Destroy(HttpPostProviderInterface* http) OVERRIDE; + + private: + FakeServer* const fake_server_; + + DISALLOW_COPY_AND_ASSIGN(FakeServerHttpPostProviderFactory); +}; + +} // namespace syncer + +#endif // SYNC_TEST_FAKE_SERVER_FAKE_SERVER_HTTP_POST_PROVIDER_H_ diff --git a/sync/test/fake_server/fake_server_network_resources.cc b/sync/test/fake_server/fake_server_network_resources.cc new file mode 100644 index 0000000..1f5d308 --- /dev/null +++ b/sync/test/fake_server/fake_server_network_resources.cc @@ -0,0 +1,30 @@ +// 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/fake_server/fake_server_network_resources.h" + +#include "base/memory/scoped_ptr.h" +#include "sync/internal_api/public/base/cancelation_signal.h" +#include "sync/internal_api/public/http_post_provider_factory.h" +#include "sync/internal_api/public/network_time_update_callback.h" +#include "sync/test/fake_server/fake_server.h" +#include "sync/test/fake_server/fake_server_http_post_provider.h" + +namespace syncer { + +FakeServerNetworkResources::FakeServerNetworkResources(FakeServer* fake_server) + : fake_server_(fake_server) { } + +FakeServerNetworkResources::~FakeServerNetworkResources() {} + +scoped_ptr<HttpPostProviderFactory> + FakeServerNetworkResources::GetHttpPostProviderFactory( + net::URLRequestContextGetter* baseline_context_getter, + const NetworkTimeUpdateCallback& network_time_update_callback, + CancelationSignal* cancelation_signal) { + return make_scoped_ptr<HttpPostProviderFactory>( + new FakeServerHttpPostProviderFactory(fake_server_)); +} + +} // namespace syncer diff --git a/sync/test/fake_server/fake_server_network_resources.h b/sync/test/fake_server/fake_server_network_resources.h new file mode 100644 index 0000000..eda2fdf --- /dev/null +++ b/sync/test/fake_server/fake_server_network_resources.h @@ -0,0 +1,38 @@ +// 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_FAKE_SERVER_FAKE_SERVER_NETWORK_RESOURCES_H_ +#define SYNC_TEST_FAKE_SERVER_FAKE_SERVER_NETWORK_RESOURCES_H_ + +#include "base/memory/scoped_ptr.h" +#include "sync/internal_api/public/network_resources.h" +#include "sync/internal_api/public/network_time_update_callback.h" + +namespace net { +class URLRequestContextGetter; +} // namespace net + +namespace syncer { + +class FakeServer; +class HttpPostProviderFactory; + +class FakeServerNetworkResources : public NetworkResources { + public: + FakeServerNetworkResources(FakeServer* fake_server); + virtual ~FakeServerNetworkResources(); + + // NetworkResources + virtual scoped_ptr<HttpPostProviderFactory> GetHttpPostProviderFactory( + net::URLRequestContextGetter* baseline_context_getter, + const NetworkTimeUpdateCallback& network_time_update_callback, + CancelationSignal* cancelation_signal) OVERRIDE; + + private: + FakeServer* const fake_server_; +}; + +} // namespace syncer + +#endif // SYNC_TEST_FAKE_SERVER_FAKE_SERVER_NETWORK_RESOURCES_H_ |