blob: 2bc45946cc643a1e5f41f9cae4463b6d09ba66e3 [file] [log] [blame]
// Copyright (c) 2009 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/sessions/sync_session.h"
#include "chrome/browser/sync/engine/conflict_resolver.h"
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/engine/syncer_util.h"
#include "chrome/browser/sync/syncable/directory_manager.h"
#include "chrome/browser/sync/syncable/syncable.h"
#include "chrome/test/sync/engine/test_directory_setter_upper.h"
#include "testing/gtest/include/gtest/gtest.h"
using syncable::MultiTypeTimeStamp;
using syncable::WriteTransaction;
namespace browser_sync {
namespace sessions {
namespace {
class SyncSessionTest : public testing::Test,
public SyncSession::Delegate,
public ModelSafeWorkerRegistrar {
public:
SyncSessionTest() : controller_invocations_allowed_(false) {
GetModelSafeRoutingInfo(&routes_);
}
virtual void SetUp() {
context_.reset(new SyncSessionContext(NULL, NULL, NULL, this));
session_.reset(new SyncSession(context_.get(), this));
}
virtual void TearDown() {
session_.reset();
context_.reset();
}
virtual void OnSilencedUntil(const base::TimeTicks& silenced_until) {
FailControllerInvocationIfDisabled("OnSilencedUntil");
}
virtual bool IsSyncingCurrentlySilenced() {
FailControllerInvocationIfDisabled("IsSyncingCurrentlySilenced");
return false;
}
virtual void OnReceivedLongPollIntervalUpdate(
const base::TimeDelta& new_interval) {
FailControllerInvocationIfDisabled("OnReceivedLongPollIntervalUpdate");
}
virtual void OnReceivedShortPollIntervalUpdate(
const base::TimeDelta& new_interval) {
FailControllerInvocationIfDisabled("OnReceivedShortPollIntervalUpdate");
}
virtual void OnShouldStopSyncingPermanently() {
FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently");
}
// ModelSafeWorkerRegistrar implementation.
virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) {}
virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) {
(*out)[syncable::BOOKMARKS] = GROUP_UI;
(*out)[syncable::AUTOFILL] = GROUP_UI;
}
StatusController* status() { return session_->status_controller(); }
protected:
void FailControllerInvocationIfDisabled(const std::string& msg) {
if (!controller_invocations_allowed_)
FAIL() << msg;
}
MultiTypeTimeStamp ParamsMeaningAllEnabledTypes() {
MultiTypeTimeStamp request_params;
request_params.timestamp = 2000;
request_params.data_types[syncable::BOOKMARKS] = true;
request_params.data_types[syncable::AUTOFILL] = true;
return request_params;
}
MultiTypeTimeStamp ParamsMeaningJustOneEnabledType() {
MultiTypeTimeStamp request_params;
request_params.timestamp = 5000;
request_params.data_types[syncable::AUTOFILL] = true;
return request_params;
}
bool controller_invocations_allowed_;
scoped_ptr<SyncSession> session_;
scoped_ptr<SyncSessionContext> context_;
ModelSafeRoutingInfo routes_;
};
TEST_F(SyncSessionTest, ScopedContextHelpers) {
ConflictResolver resolver;
SyncerEventChannel* channel = new SyncerEventChannel();
EXPECT_FALSE(context_->resolver());
EXPECT_FALSE(context_->syncer_event_channel());
{
ScopedSessionContextConflictResolver s_resolver(context_.get(), &resolver);
ScopedSessionContextSyncerEventChannel s_channel(context_.get(), channel);
EXPECT_EQ(&resolver, context_->resolver());
EXPECT_EQ(channel, context_->syncer_event_channel());
}
EXPECT_FALSE(context_->resolver());
EXPECT_FALSE(context_->syncer_event_channel());
channel->Notify(SyncerEvent(SyncerEvent::SHUTDOWN_USE_WITH_CARE));
delete channel;
}
TEST_F(SyncSessionTest, SetWriteTransaction) {
TestDirectorySetterUpper db;
db.SetUp();
session_.reset(NULL);
context_.reset(new SyncSessionContext(NULL, NULL, db.manager(), this));
session_.reset(new SyncSession(context_.get(), this));
context_->set_account_name(db.name());
syncable::ScopedDirLookup dir(context_->directory_manager(),
context_->account_name());
ASSERT_TRUE(dir.good());
SyncSession session(context_.get(), this);
EXPECT_TRUE(NULL == session.write_transaction());
{
WriteTransaction trans(dir, syncable::UNITTEST, __FILE__, __LINE__);
sessions::ScopedSetSessionWriteTransaction set_trans(&session, &trans);
EXPECT_TRUE(&trans == session.write_transaction());
}
db.TearDown();
}
TEST_F(SyncSessionTest, MoreToSyncIfUnsyncedGreaterThanCommitted) {
// If any forward progress was made during the session, and the number of
// unsynced handles still exceeds the number of commit ids we added, there is
// more to sync. For example, this occurs if we had more commit ids
// than could fit in a single commit batch.
EXPECT_FALSE(session_->HasMoreToSync());
OrderedCommitSet commit_set(routes_);
commit_set.AddCommitItem(0, syncable::Id(), syncable::BOOKMARKS);
status()->set_commit_set(commit_set);
EXPECT_FALSE(session_->HasMoreToSync());
std::vector<int64> unsynced_handles;
unsynced_handles.push_back(1);
unsynced_handles.push_back(2);
status()->set_unsynced_handles(unsynced_handles);
EXPECT_FALSE(session_->HasMoreToSync());
status()->increment_num_successful_commits();
EXPECT_TRUE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToSyncIfConflictSetsBuilt) {
// If we built conflict sets, then we need to loop back and try
// to get updates & commit again.
status()->update_conflict_sets_built(true);
EXPECT_TRUE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToDownloadIfDownloadFailed) {
status()->set_updates_request_parameters(ParamsMeaningAllEnabledTypes());
// When DownloadUpdatesCommand fails, these should be false.
EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload());
EXPECT_FALSE(status()->download_updates_succeeded());
// Download updates has its own loop in the syncer; it shouldn't factor
// into HasMoreToSync.
EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToDownloadIfGotTimestamp) {
status()->set_updates_request_parameters(ParamsMeaningAllEnabledTypes());
// When the server returns a timestamp, that means there's more to download.
status()->mutable_updates_response()->mutable_get_updates()
->set_new_timestamp(1000000L);
EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload());
EXPECT_TRUE(status()->download_updates_succeeded());
// Download updates has its own loop in the syncer; it shouldn't factor
// into HasMoreToSync.
EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToDownloadIfGotNoTimestamp) {
status()->set_updates_request_parameters(ParamsMeaningAllEnabledTypes());
// When the server returns a timestamp, that means we're up to date.
status()->mutable_updates_response()->mutable_get_updates()
->clear_new_timestamp();
EXPECT_TRUE(status()->ServerSaysNothingMoreToDownload());
EXPECT_TRUE(status()->download_updates_succeeded());
// Download updates has its own loop in the syncer; it shouldn't factor
// into HasMoreToSync.
EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToDownloadIfGotNoTimestampForSubset) {
status()->set_updates_request_parameters(ParamsMeaningJustOneEnabledType());
// When the server returns a timestamp, that means we're up to date for that
// type. But there may still be more to download if there are other
// datatypes that we didn't request on this go-round.
status()->mutable_updates_response()->mutable_get_updates()
->clear_new_timestamp();
EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload());
EXPECT_TRUE(status()->download_updates_succeeded());
// Download updates has its own loop in the syncer; it shouldn't factor
// into HasMoreToSync.
EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToDownloadIfGotTimestampAndEntries) {
status()->set_updates_request_parameters(ParamsMeaningAllEnabledTypes());
// The actual entry count should not factor into the HasMoreToSync
// determination.
status()->mutable_updates_response()->mutable_get_updates()->add_entries();
status()->mutable_updates_response()->mutable_get_updates()
->set_new_timestamp(1000000L);;
EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload());
EXPECT_TRUE(status()->download_updates_succeeded());
// Download updates has its own loop in the syncer; it shouldn't factor
// into HasMoreToSync.
EXPECT_FALSE(session_->HasMoreToSync());
}
TEST_F(SyncSessionTest, MoreToSyncIfConflictsResolved) {
// Conflict resolution happens after get updates and commit,
// so we need to loop back and get updates / commit again now
// that we have made forward progress.
status()->update_conflicts_resolved(true);
EXPECT_TRUE(session_->HasMoreToSync());
}
} // namespace
} // namespace sessions
} // namespace browser_sync