blob: 46854467795b8968f2673df7c8bd897f8d655d19 [file] [log] [blame]
// Copyright (c) 2012 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 "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/tracked_objects.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/search_engines/template_url_service_test_util.h"
#include "chrome/browser/sync/glue/data_type_controller_mock.h"
#include "chrome/browser/sync/glue/fake_generic_change_processor.h"
#include "chrome/browser/sync/glue/search_engine_data_type_controller.h"
#include "chrome/browser/sync/profile_sync_components_factory_mock.h"
#include "chrome/browser/sync/profile_sync_service_mock.h"
#include "chrome/test/base/profile_mock.h"
#include "sync/api/fake_syncable_service.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::DoAll;
using testing::InvokeWithoutArgs;
using testing::Return;
using testing::SetArgumentPointee;
namespace browser_sync {
namespace {
ACTION(MakeSharedChangeProcessor) {
return new SharedChangeProcessor();
}
ACTION_P(ReturnAndRelease, change_processor) {
return change_processor->release();
}
class SyncSearchEngineDataTypeControllerTest : public testing::Test {
public:
SyncSearchEngineDataTypeControllerTest()
: change_processor_(new FakeGenericChangeProcessor()) {}
virtual void SetUp() {
test_util_.SetUp();
profile_sync_factory_.reset(new ProfileSyncComponentsFactoryMock());
// Feed the DTC test_util_'s profile so it is reused later.
// This allows us to control the associated TemplateURLService.
search_engine_dtc_ =
new SearchEngineDataTypeController(profile_sync_factory_.get(),
test_util_.profile(),
&service_);
}
virtual void TearDown() {
// Must be done before we pump the loop.
syncable_service_.StopSyncing(syncer::SEARCH_ENGINES);
search_engine_dtc_ = NULL;
test_util_.TearDown();
}
protected:
// Pre-emptively get the TURL Service and make sure it is loaded.
void PreloadTemplateURLService() {
test_util_.VerifyLoad();
}
void SetStartExpectations() {
// Ownership gets passed to caller of CreateGenericChangeProcessor.
EXPECT_CALL(model_load_callback_, Run(_, _));
EXPECT_CALL(*profile_sync_factory_,
GetSyncableServiceForType(syncer::SEARCH_ENGINES)).
WillOnce(Return(syncable_service_.AsWeakPtr()));
EXPECT_CALL(*profile_sync_factory_, CreateSharedChangeProcessor()).
WillOnce(MakeSharedChangeProcessor());
EXPECT_CALL(*profile_sync_factory_,
CreateGenericChangeProcessor(_, _, _, _)).
WillOnce(ReturnAndRelease(&change_processor_));
}
void SetActivateExpectations() {
EXPECT_CALL(service_, ActivateDataType(syncer::SEARCH_ENGINES, _, _));
}
void SetStopExpectations() {
EXPECT_CALL(service_, DeactivateDataType(syncer::SEARCH_ENGINES));
}
void Start() {
search_engine_dtc_->LoadModels(
base::Bind(&ModelLoadCallbackMock::Run,
base::Unretained(&model_load_callback_)));
search_engine_dtc_->StartAssociating(
base::Bind(&StartCallbackMock::Run,
base::Unretained(&start_callback_)));
}
// This also manages a BrowserThread and MessageLoop for us. Note that this
// must be declared here as the destruction order of the BrowserThread
// matters - we could leak if this is declared below.
TemplateURLServiceTestUtil test_util_;
scoped_refptr<SearchEngineDataTypeController> search_engine_dtc_;
scoped_ptr<ProfileSyncComponentsFactoryMock> profile_sync_factory_;
ProfileSyncServiceMock service_;
scoped_ptr<FakeGenericChangeProcessor> change_processor_;
syncer::FakeSyncableService syncable_service_;
StartCallbackMock start_callback_;
ModelLoadCallbackMock model_load_callback_;
};
TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceReady) {
SetStartExpectations();
// We want to start ready.
PreloadTemplateURLService();
SetActivateExpectations();
EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
Start();
EXPECT_EQ(DataTypeController::RUNNING, search_engine_dtc_->state());
EXPECT_TRUE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceNotReady) {
EXPECT_CALL(*profile_sync_factory_, CreateSharedChangeProcessor()).
WillOnce(MakeSharedChangeProcessor());
EXPECT_CALL(model_load_callback_, Run(_, _));
EXPECT_FALSE(syncable_service_.syncing());
search_engine_dtc_->LoadModels(
base::Bind(&ModelLoadCallbackMock::Run,
base::Unretained(&model_load_callback_)));
EXPECT_EQ(DataTypeController::MODEL_STARTING, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
// Send the notification that the TemplateURLService has started.
PreloadTemplateURLService();
EXPECT_EQ(DataTypeController::MODEL_LOADED, search_engine_dtc_->state());
// Wait until WebDB is loaded before we shut it down.
base::RunLoop().RunUntilIdle();
}
TEST_F(SyncSearchEngineDataTypeControllerTest, StartFirstRun) {
SetStartExpectations();
PreloadTemplateURLService();
SetActivateExpectations();
change_processor_->set_sync_model_has_user_created_nodes(false);
EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _));
Start();
EXPECT_TRUE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest, StartAssociationFailed) {
SetStartExpectations();
PreloadTemplateURLService();
SetStopExpectations();
EXPECT_CALL(start_callback_,
Run(DataTypeController::ASSOCIATION_FAILED, _, _));
syncable_service_.set_merge_data_and_start_syncing_error(
syncer::SyncError(FROM_HERE,
syncer::SyncError::DATATYPE_ERROR,
"Error",
syncer::SEARCH_ENGINES));
Start();
EXPECT_EQ(DataTypeController::DISABLED, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
search_engine_dtc_->Stop();
EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest,
StartAssociationTriggersUnrecoverableError) {
SetStartExpectations();
PreloadTemplateURLService();
EXPECT_CALL(start_callback_,
Run(DataTypeController::UNRECOVERABLE_ERROR, _, _));
// Set up association to fail with an unrecoverable error.
change_processor_->set_sync_model_has_user_created_nodes_success(false);
Start();
EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest, Stop) {
SetStartExpectations();
PreloadTemplateURLService();
SetActivateExpectations();
SetStopExpectations();
EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
Start();
EXPECT_EQ(DataTypeController::RUNNING, search_engine_dtc_->state());
EXPECT_TRUE(syncable_service_.syncing());
search_engine_dtc_->Stop();
EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
}
TEST_F(SyncSearchEngineDataTypeControllerTest,
OnSingleDatatypeUnrecoverableError) {
SetStartExpectations();
PreloadTemplateURLService();
SetActivateExpectations();
EXPECT_CALL(service_, DisableBrokenDatatype(_, _, _)).
WillOnce(InvokeWithoutArgs(search_engine_dtc_.get(),
&SearchEngineDataTypeController::Stop));
SetStopExpectations();
EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
Start();
// This should cause search_engine_dtc_->Stop() to be called.
search_engine_dtc_->OnSingleDatatypeUnrecoverableError(FROM_HERE, "Test");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(DataTypeController::NOT_RUNNING, search_engine_dtc_->state());
EXPECT_FALSE(syncable_service_.syncing());
}
} // namespace
} // namespace browser_sync