blob: 944d7f6978d325f5a2308f658c2fc1e29ba749ed [file] [log] [blame]
// 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 "components/sync/test/fake_server/fake_server.h"
#include <algorithm>
#include <limits>
#include <set>
#include <utility>
#include "base/guid.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_restrictions.h"
#include "components/sync/engine_impl/net/server_connection_manager.h"
#include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
using syncer::GetModelType;
using syncer::GetModelTypeFromSpecifics;
using syncer::LoopbackServer;
using syncer::LoopbackServerEntity;
using syncer::ModelType;
using syncer::ModelTypeSet;
namespace fake_server {
FakeServer::FakeServer()
: authenticated_(true),
error_type_(sync_pb::SyncEnums::SUCCESS),
alternate_triggered_errors_(false),
request_counter_(0),
network_enabled_(true),
weak_ptr_factory_(this) {
base::ThreadRestrictions::SetIOAllowed(true);
loopback_server_storage_ = std::make_unique<base::ScopedTempDir>();
if (!loopback_server_storage_->CreateUniqueTempDir()) {
NOTREACHED() << "Creating temp dir failed.";
}
loopback_server_ = std::make_unique<syncer::LoopbackServer>(
loopback_server_storage_->GetPath().AppendASCII("profile.pb"));
loopback_server_->set_observer_for_tests(this);
}
FakeServer::~FakeServer() {}
void FakeServer::HandleCommand(const std::string& request,
const base::Closure& completion_closure,
int* error_code,
int* response_code,
std::string* response) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!network_enabled_) {
*error_code = net::ERR_FAILED;
*response_code = net::ERR_FAILED;
*response = std::string();
completion_closure.Run();
return;
}
request_counter_++;
if (!authenticated_) {
*error_code = 0;
*response_code = net::HTTP_UNAUTHORIZED;
*response = std::string();
completion_closure.Run();
return;
}
sync_pb::ClientToServerResponse response_proto;
*response_code = 200;
*error_code = 0;
if (error_type_ != sync_pb::SyncEnums::SUCCESS &&
ShouldSendTriggeredError()) {
response_proto.set_error_code(error_type_);
} else if (triggered_actionable_error_.get() && ShouldSendTriggeredError()) {
sync_pb::ClientToServerResponse_Error* error =
response_proto.mutable_error();
error->CopyFrom(*(triggered_actionable_error_.get()));
} else {
sync_pb::ClientToServerMessage message;
bool parsed = message.ParseFromString(request);
DCHECK(parsed) << "Unable to parse the ClientToServerMessage.";
switch (message.message_contents()) {
case sync_pb::ClientToServerMessage::GET_UPDATES:
last_getupdates_message_ = message;
break;
case sync_pb::ClientToServerMessage::COMMIT:
last_commit_message_ = message;
break;
default:
break;
// Don't care.
}
*response_code = SendToLoopbackServer(request, response);
if (*response_code == net::HTTP_OK) {
InjectClientCommand(response);
}
completion_closure.Run();
return;
}
response_proto.set_store_birthday(loopback_server_->GetStoreBirthday());
*response = response_proto.SerializeAsString();
completion_closure.Run();
}
int FakeServer::SendToLoopbackServer(const std::string& request,
std::string* response) {
int64_t response_code;
syncer::HttpResponse::ServerConnectionCode server_status;
base::ThreadRestrictions::SetIOAllowed(true);
loopback_server_->HandleCommand(request, &server_status, &response_code,
response);
return static_cast<int>(response_code);
}
void FakeServer::InjectClientCommand(std::string* response) {
sync_pb::ClientToServerResponse response_proto;
bool parse_ok = response_proto.ParseFromString(*response);
DCHECK(parse_ok) << "Unable to parse-back the server response";
if (response_proto.error_code() == sync_pb::SyncEnums::SUCCESS) {
*response_proto.mutable_client_command() = client_command_;
*response = response_proto.SerializeAsString();
}
}
bool FakeServer::GetLastCommitMessage(sync_pb::ClientToServerMessage* message) {
if (!last_commit_message_.has_commit())
return false;
message->CopyFrom(last_commit_message_);
return true;
}
bool FakeServer::GetLastGetUpdatesMessage(
sync_pb::ClientToServerMessage* message) {
if (!last_getupdates_message_.has_get_updates())
return false;
message->CopyFrom(last_getupdates_message_);
return true;
}
void FakeServer::OverrideResponseType(
LoopbackServer::ResponseTypeProvider response_type_override) {
loopback_server_->OverrideResponseType(std::move(response_type_override));
}
std::unique_ptr<base::DictionaryValue>
FakeServer::GetEntitiesAsDictionaryValue() {
DCHECK(thread_checker_.CalledOnValidThread());
return loopback_server_->GetEntitiesAsDictionaryValue();
}
std::vector<sync_pb::SyncEntity> FakeServer::GetSyncEntitiesByModelType(
ModelType model_type) {
DCHECK(thread_checker_.CalledOnValidThread());
return loopback_server_->GetSyncEntitiesByModelType(model_type);
}
void FakeServer::InjectEntity(std::unique_ptr<LoopbackServerEntity> entity) {
DCHECK(thread_checker_.CalledOnValidThread());
loopback_server_->SaveEntity(std::move(entity));
}
bool FakeServer::ModifyEntitySpecifics(
const std::string& id,
const sync_pb::EntitySpecifics& updated_specifics) {
return loopback_server_->ModifyEntitySpecifics(id, updated_specifics);
}
bool FakeServer::ModifyBookmarkEntity(
const std::string& id,
const std::string& parent_id,
const sync_pb::EntitySpecifics& updated_specifics) {
return loopback_server_->ModifyBookmarkEntity(id, parent_id,
updated_specifics);
}
void FakeServer::ClearServerData() {
DCHECK(thread_checker_.CalledOnValidThread());
loopback_server_->ClearServerData();
}
void FakeServer::SetAuthenticated() {
DCHECK(thread_checker_.CalledOnValidThread());
authenticated_ = true;
}
void FakeServer::SetUnauthenticated() {
DCHECK(thread_checker_.CalledOnValidThread());
authenticated_ = false;
}
void FakeServer::SetClientCommand(
const sync_pb::ClientCommand& client_command) {
DCHECK(thread_checker_.CalledOnValidThread());
client_command_ = client_command;
}
bool FakeServer::TriggerError(const sync_pb::SyncEnums::ErrorType& error_type) {
DCHECK(thread_checker_.CalledOnValidThread());
if (triggered_actionable_error_) {
DVLOG(1) << "Only one type of error can be triggered at any given time.";
return false;
}
error_type_ = error_type;
return true;
}
bool FakeServer::TriggerActionableError(
const sync_pb::SyncEnums::ErrorType& error_type,
const std::string& description,
const std::string& url,
const sync_pb::SyncEnums::Action& action) {
DCHECK(thread_checker_.CalledOnValidThread());
if (error_type_ != sync_pb::SyncEnums::SUCCESS) {
DVLOG(1) << "Only one type of error can be triggered at any given time.";
return false;
}
sync_pb::ClientToServerResponse_Error* error =
new sync_pb::ClientToServerResponse_Error();
error->set_error_type(error_type);
error->set_error_description(description);
error->set_url(url);
error->set_action(action);
triggered_actionable_error_.reset(error);
return true;
}
bool FakeServer::EnableAlternatingTriggeredErrors() {
DCHECK(thread_checker_.CalledOnValidThread());
if (error_type_ == sync_pb::SyncEnums::SUCCESS &&
!triggered_actionable_error_) {
DVLOG(1) << "No triggered error set. Alternating can't be enabled.";
return false;
}
alternate_triggered_errors_ = true;
// Reset the counter so that the the first request yields a triggered error.
request_counter_ = 0;
return true;
}
bool FakeServer::ShouldSendTriggeredError() const {
if (!alternate_triggered_errors_)
return true;
// Check that the counter is odd so that we trigger an error on the first
// request after alternating is enabled.
return request_counter_ % 2 != 0;
}
void FakeServer::AddObserver(Observer* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
observers_.AddObserver(observer);
}
void FakeServer::RemoveObserver(Observer* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
observers_.RemoveObserver(observer);
}
void FakeServer::OnCommit(const std::string& committer_id,
syncer::ModelTypeSet committed_model_types) {
for (auto& observer : observers_)
observer.OnCommit(committer_id, committed_model_types);
}
void FakeServer::EnableNetwork() {
DCHECK(thread_checker_.CalledOnValidThread());
network_enabled_ = true;
}
void FakeServer::DisableNetwork() {
DCHECK(thread_checker_.CalledOnValidThread());
network_enabled_ = false;
}
base::WeakPtr<FakeServer> FakeServer::AsWeakPtr() {
DCHECK(thread_checker_.CalledOnValidThread());
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace fake_server