Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7506)

Unified Diff: chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc

Issue 6811003: [Sync] Make generic non-frontend thread datatype controller. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Copy paste :( Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
diff --git a/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc b/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8fc2576c3812cd8e69fc0a00eef1a7b261f678f4
--- /dev/null
+++ b/chrome/browser/sync/glue/non_frontend_data_type_controller_unittest.cc
@@ -0,0 +1,397 @@
+// Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h"
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "base/test/test_timeouts.h"
+#include "base/tracked_objects.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/sync/engine/model_safe_worker.h"
+#include "chrome/browser/sync/glue/change_processor_mock.h"
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
+#include "chrome/browser/sync/glue/non_frontend_data_type_controller_mock.h"
+#include "chrome/browser/sync/glue/model_associator_mock.h"
+#include "chrome/browser/sync/profile_sync_factory_mock.h"
+#include "chrome/browser/sync/profile_sync_service_mock.h"
+#include "chrome/test/profile_mock.h"
+#include "content/browser/browser_thread.h"
+
+using base::WaitableEvent;
+using browser_sync::ChangeProcessorMock;
+using browser_sync::DataTypeController;
+using browser_sync::GROUP_DB;
+using browser_sync::NonFrontendDataTypeController;
+using browser_sync::NonFrontendDataTypeControllerMock;
+using browser_sync::ModelAssociatorMock;
+using testing::_;
+using testing::DoAll;
+using testing::InvokeWithoutArgs;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+class StartCallback {
+ public:
+ MOCK_METHOD2(Run, void(DataTypeController::StartResult result,
+ const tracked_objects::Location& from_here));
+};
+
+ACTION_P(WaitOnEvent, event) {
+ event->Wait();
+}
+
+ACTION_P(SignalEvent, event) {
+ event->Signal();
+}
+
+class NonFrontendDataTypeControllerFake : public NonFrontendDataTypeController {
+ public:
+ NonFrontendDataTypeControllerFake(
+ ProfileSyncFactory* profile_sync_factory,
+ Profile* profile,
+ NonFrontendDataTypeControllerMock* mock)
+ : NonFrontendDataTypeController(profile_sync_factory,
+ profile),
+ mock_(mock) {}
+
+ virtual syncable::ModelType type() const { return syncable::BOOKMARKS; }
+ virtual browser_sync::ModelSafeGroup model_safe_group() const {
+ return GROUP_DB;
+ }
+
+ private:
+ virtual void CreateSyncComponents() {
+ ProfileSyncFactory::SyncComponents sync_components =
+ profile_sync_factory()->
+ CreateBookmarkSyncComponents(profile_sync_service(), this);
+ set_model_associator(sync_components.model_associator);
+ set_change_processor(sync_components.change_processor);
+ }
+ virtual bool StartAssociationAsync() {
+ mock_->StartAssociationAsync();
+ return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &NonFrontendDataTypeControllerFake::StartAssociation));
+ }
+ virtual bool StopAssociationAsync() {
+ mock_->StopAssociationAsync();
+ return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &NonFrontendDataTypeControllerFake::StopAssociation));
+ }
+
+ // We mock the following methods because their default implementations do
+ // nothing, but we still want to make sure they're called appropriately.
+ virtual bool StartModels() {
+ return mock_->StartModels();
+ }
+ virtual void StopModels() {
+ mock_->StopModels();
+ }
+ virtual void RecordUnrecoverableError(
+ const tracked_objects::Location& from_here,
+ const std::string& message) {
+ mock_->RecordUnrecoverableError(from_here, message);
+ }
+ virtual void RecordAssociationTime(base::TimeDelta time) {
+ mock_->RecordAssociationTime(time);
+ }
+ virtual void RecordStartFailure(DataTypeController::StartResult result) {
+ mock_->RecordStartFailure(result);
+ }
+ private:
+ NonFrontendDataTypeControllerMock* mock_;
+};
+
+class NonFrontendDataTypeControllerTest : public testing::Test {
+ public:
+ NonFrontendDataTypeControllerTest()
+ : ui_thread_(BrowserThread::UI, &message_loop_),
+ db_thread_(BrowserThread::DB),
+ model_associator_(NULL),
+ change_processor_(NULL),
+ signaled_(false) {}
+
+ virtual void SetUp() {
+ EXPECT_CALL(profile_, GetProfileSyncService()).WillRepeatedly(
+ Return(&service_));
+ db_thread_.Start();
+ profile_sync_factory_.reset(new ProfileSyncFactoryMock());
+
+ // Both of these are refcounted, so don't need to be released.
+ dtc_mock_ = new StrictMock<NonFrontendDataTypeControllerMock>();
+ non_frontend_dtc_ =
+ new NonFrontendDataTypeControllerFake(profile_sync_factory_.get(),
+ &profile_,
+ dtc_mock_.get());
+ }
+
+ virtual void TearDown() {
+ db_thread_.Stop();
+ }
+
+ protected:
+ void SetStartExpectations() {
+ EXPECT_CALL(*dtc_mock_, StartModels()).WillOnce(Return(true));
+ model_associator_ = new ModelAssociatorMock();
+ change_processor_ = new ChangeProcessorMock();
+ EXPECT_CALL(*profile_sync_factory_, CreateBookmarkSyncComponents(_, _)).
+ WillOnce(Return(ProfileSyncFactory::SyncComponents(model_associator_,
+ change_processor_)));
+ }
+
+ void SetAssociateExpectations() {
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ }
+
+ void SetActivateExpectations(DataTypeController::StartResult result) {
+ EXPECT_CALL(service_, ActivateDataType(_, _));
+ EXPECT_CALL(start_callback_, Run(result,_));
+ }
+
+ void SetStopExpectations() {
+ EXPECT_CALL(*dtc_mock_, StopAssociationAsync());
+ EXPECT_CALL(*dtc_mock_, StopModels());
+ EXPECT_CALL(service_, DeactivateDataType(_, _));
+ EXPECT_CALL(*model_associator_, DisassociateModels());
+ }
+
+ void SetStartFailExpectations(DataTypeController::StartResult result) {
+ EXPECT_CALL(*dtc_mock_, StopModels());
+ EXPECT_CALL(*dtc_mock_, RecordStartFailure(result));
+ EXPECT_CALL(start_callback_, Run(result,_));
+ }
+
+ static void SignalDone(WaitableEvent* done, bool* signaled) {
+ done->Signal();
+ *signaled = true;
+ }
+
+ void WaitForDTC() {
+ WaitableEvent done(false, false);
+ signaled_ = false;
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableFunction(&NonFrontendDataTypeControllerTest::SignalDone,
+ &done, &signaled_));
+ done.TimedWait(base::TimeDelta::FromMilliseconds(
+ TestTimeouts::action_timeout_ms()));
+ if (!signaled_) {
+ ADD_FAILURE() << "Timed out waiting for DB thread to finish.";
+ }
+ signaled_ = false;
+ MessageLoop::current()->RunAllPending();
+ }
+
+ MessageLoopForUI message_loop_;
+ BrowserThread ui_thread_;
+ BrowserThread db_thread_;
+ scoped_refptr<NonFrontendDataTypeControllerFake> non_frontend_dtc_;
+ scoped_ptr<ProfileSyncFactoryMock> profile_sync_factory_;
+ scoped_refptr<NonFrontendDataTypeControllerMock> dtc_mock_;
+ ProfileMock profile_;
+ ProfileSyncServiceMock service_;
+ ModelAssociatorMock* model_associator_;
+ ChangeProcessorMock* change_processor_;
+ StartCallback start_callback_;
+ bool signaled_;
+};
+
+TEST_F(NonFrontendDataTypeControllerTest, StartOk) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, StartFirstRun) {
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(SetArgumentPointee<0>(false), Return(true)));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ SetActivateExpectations(DataTypeController::OK_FIRST_RUN);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, AbortDuringStartModels) {
+ EXPECT_CALL(*dtc_mock_, StartModels()).WillOnce(Return(false));
+ SetStartFailExpectations(DataTypeController::ABORTED);
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::MODEL_STARTING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, StartAssociationFailed) {
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(SetArgumentPointee<0>(true), Return(true)));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(false));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ SetStartFailExpectations(DataTypeController::ASSOCIATION_FAILED);
+ // Set up association to fail with an association failed error.
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest,
+ StartAssociationTriggersUnrecoverableError) {
+ SetStartExpectations();
+ SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
+ // Set up association to fail with an unrecoverable error.
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillRepeatedly(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillRepeatedly(DoAll(SetArgumentPointee<0>(false), Return(false)));
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) {
+ SetStartExpectations();
+ SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
+ // Set up association to fail with a NEEDS_CRYPTO error.
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillRepeatedly(Return(false));
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+// Trigger a Stop() call when we check if the model associator has user created
+// nodes.
+TEST_F(NonFrontendDataTypeControllerTest, AbortDuringAssociationInactive) {
+ WaitableEvent wait_for_db_thread_pause(false, false);
+ WaitableEvent pause_db_thread(false, false);
+
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(
+ SignalEvent(&wait_for_db_thread_pause),
+ WaitOnEvent(&pause_db_thread),
+ SetArgumentPointee<0>(true),
+ Return(true)));
+ EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce(
+ SignalEvent(&pause_db_thread));
+ EXPECT_CALL(*model_associator_, AssociateModels()).WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ EXPECT_CALL(service_, ActivateDataType(_, _));
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED,_));
+ EXPECT_CALL(*dtc_mock_, RecordStartFailure(DataTypeController::ABORTED));
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ wait_for_db_thread_pause.Wait();
+ non_frontend_dtc_->Stop();
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+// Same as above but abort during the Activate call.
+TEST_F(NonFrontendDataTypeControllerTest, AbortDuringAssociationActivated) {
+ WaitableEvent wait_for_db_thread_pause(false, false);
+ WaitableEvent pause_db_thread(false, false);
+
+ SetStartExpectations();
+ EXPECT_CALL(*dtc_mock_, StartAssociationAsync());
+ EXPECT_CALL(*model_associator_, CryptoReadyIfNecessary()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*model_associator_, SyncModelHasUserCreatedNodes(_)).
+ WillOnce(DoAll(
+ SetArgumentPointee<0>(true),
+ Return(true)));
+ EXPECT_CALL(*model_associator_, AbortAssociation()).WillOnce(
+ SignalEvent(&pause_db_thread));
+ EXPECT_CALL(*model_associator_, AssociateModels()).
+ WillOnce(Return(true));
+ EXPECT_CALL(*dtc_mock_, RecordAssociationTime(_));
+ EXPECT_CALL(service_, ActivateDataType(_, _)).WillOnce(DoAll(
+ SignalEvent(&wait_for_db_thread_pause),
+ WaitOnEvent(&pause_db_thread)));
+ EXPECT_CALL(start_callback_, Run(DataTypeController::ABORTED,_));
+ EXPECT_CALL(*dtc_mock_, RecordStartFailure(DataTypeController::ABORTED));
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ wait_for_db_thread_pause.Wait();
+ non_frontend_dtc_->Stop();
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, Stop) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}
+
+TEST_F(NonFrontendDataTypeControllerTest, OnUnrecoverableError) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
+ EXPECT_CALL(*dtc_mock_, RecordUnrecoverableError(_, "Test"));
+ EXPECT_CALL(service_, OnUnrecoverableError(_,_)).WillOnce(
+ InvokeWithoutArgs(non_frontend_dtc_.get(),
+ &NonFrontendDataTypeController::Stop));
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+ non_frontend_dtc_->Start(NewCallback(&start_callback_, &StartCallback::Run));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, non_frontend_dtc_->state());
+ // This should cause non_frontend_dtc_->Stop() to be called.
+ BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
+ NewRunnableMethod(
+ non_frontend_dtc_.get(),
+ &NonFrontendDataTypeControllerFake::OnUnrecoverableError,
+ FROM_HERE,
+ std::string("Test")));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, non_frontend_dtc_->state());
+}

Powered by Google App Engine
This is Rietveld 408576698