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

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

Issue 9307079: [Sync] Fix thread-ordering-dependent NULL dereference in NewNonFrontendDTC (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sync to head Created 8 years, 10 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/new_non_frontend_data_type_controller_unittest.cc
diff --git a/chrome/browser/sync/glue/new_non_frontend_data_type_controller_unittest.cc b/chrome/browser/sync/glue/new_non_frontend_data_type_controller_unittest.cc
index ab80adac4db8d3fa7ff77e5b990c2f007d79f44a..71983bdab14350832a10cc6d9a363df380eac184 100644
--- a/chrome/browser/sync/glue/new_non_frontend_data_type_controller_unittest.cc
+++ b/chrome/browser/sync/glue/new_non_frontend_data_type_controller_unittest.cc
@@ -24,27 +24,21 @@
#include "content/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace browser_sync {
+
+namespace {
+
using base::WaitableEvent;
-using browser_sync::GenericChangeProcessor;
-using browser_sync::SharedChangeProcessorMock;
-using browser_sync::DataTypeController;
-using browser_sync::GROUP_DB;
-using browser_sync::NewNonFrontendDataTypeController;
-using browser_sync::NewNonFrontendDataTypeControllerMock;
-using browser_sync::StartCallbackMock;
using content::BrowserThread;
using syncable::AUTOFILL_PROFILE;
using testing::_;
using testing::DoAll;
using testing::InvokeWithoutArgs;
+using testing::Mock;
using testing::Return;
using testing::SetArgumentPointee;
using testing::StrictMock;
-namespace browser_sync {
-
-namespace {
-
ACTION_P(WaitOnEvent, event) {
event->Wait();
}
@@ -74,6 +68,7 @@ class NewNonFrontendDataTypeControllerFake
: NewNonFrontendDataTypeController(profile_sync_factory,
profile,
sync_service),
+ blocked_(false),
mock_(mock) {}
virtual syncable::ModelType type() const OVERRIDE {
@@ -83,6 +78,23 @@ class NewNonFrontendDataTypeControllerFake
return GROUP_DB;
}
+ // Prevent tasks from being posted on the backend thread until
+ // UnblockBackendTasks() is called.
+ void BlockBackendTasks() {
+ blocked_ = true;
+ }
+
+ // Post pending tasks on the backend thread and start allowing tasks
+ // to be posted on the backend thread again.
+ void UnblockBackendTasks() {
+ blocked_ = false;
+ for (std::vector<PendingTask>::const_iterator it = pending_tasks_.begin();
+ it != pending_tasks_.end(); ++it) {
+ PostTaskOnBackendThread(it->from_here, it->task);
+ }
+ pending_tasks_.clear();
+ }
+
protected:
virtual base::WeakPtr<SyncableService>
GetWeakPtrToSyncableService() const OVERRIDE {
@@ -92,7 +104,12 @@ class NewNonFrontendDataTypeControllerFake
virtual bool PostTaskOnBackendThread(
const tracked_objects::Location& from_here,
const base::Closure& task) OVERRIDE {
- return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
+ if (blocked_) {
+ pending_tasks_.push_back(PendingTask(from_here, task));
+ return true;
+ } else {
+ return BrowserThread::PostTask(BrowserThread::DB, from_here, task);
+ }
}
// We mock the following methods because their default implementations do
@@ -115,13 +132,27 @@ class NewNonFrontendDataTypeControllerFake
OVERRIDE {
mock_->RecordStartFailure(result);
}
+
private:
+ DISALLOW_COPY_AND_ASSIGN(NewNonFrontendDataTypeControllerFake);
+
+ struct PendingTask {
+ PendingTask(const tracked_objects::Location& from_here,
+ const base::Closure& task)
+ : from_here(from_here), task(task) {}
+
+ tracked_objects::Location from_here;
+ base::Closure task;
+ };
+
+ bool blocked_;
+ std::vector<PendingTask> pending_tasks_;
NewNonFrontendDataTypeControllerMock* mock_;
};
-class NewNonFrontendDataTypeControllerTest : public testing::Test {
+class SyncNewNonFrontendDataTypeControllerTest : public testing::Test {
public:
- NewNonFrontendDataTypeControllerTest()
+ SyncNewNonFrontendDataTypeControllerTest()
: ui_thread_(BrowserThread::UI, &message_loop_),
db_thread_(BrowserThread::DB) {}
@@ -148,7 +179,7 @@ class NewNonFrontendDataTypeControllerTest : public testing::Test {
void WaitForDTC() {
WaitableEvent done(true, false);
BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
- base::Bind(&NewNonFrontendDataTypeControllerTest::SignalDone,
+ base::Bind(&SyncNewNonFrontendDataTypeControllerTest::SignalDone,
&done));
done.TimedWait(base::TimeDelta::FromMilliseconds(
TestTimeouts::action_timeout_ms()));
@@ -173,6 +204,7 @@ class NewNonFrontendDataTypeControllerTest : public testing::Test {
EXPECT_CALL(*change_processor_, Connect(_,_,_,_)).WillOnce(Return(true));
EXPECT_CALL(*change_processor_, CryptoReadyIfNecessary(_)).
WillOnce(Return(true));
+ EXPECT_CALL(*change_processor_, ActivateDataType(_, _, _));
EXPECT_CALL(*change_processor_, SyncModelHasUserCreatedNodes(_,_)).
WillOnce(DoAll(SetArgumentPointee<1>(true), Return(true)));
EXPECT_CALL(*change_processor_, GetSyncDataForType(_,_)).
@@ -184,7 +216,6 @@ class NewNonFrontendDataTypeControllerTest : public testing::Test {
}
void SetActivateExpectations(DataTypeController::StartResult result) {
- EXPECT_CALL(service_, ActivateDataType(_, _, _));
EXPECT_CALL(start_callback_, Run(result,_));
}
@@ -221,7 +252,7 @@ class NewNonFrontendDataTypeControllerTest : public testing::Test {
scoped_ptr<SyncChangeProcessor> saved_change_processor_;
};
-TEST_F(NewNonFrontendDataTypeControllerTest, StartOk) {
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, StartOk) {
SetStartExpectations();
SetAssociateExpectations();
SetActivateExpectations(DataTypeController::OK);
@@ -232,7 +263,7 @@ TEST_F(NewNonFrontendDataTypeControllerTest, StartOk) {
EXPECT_EQ(DataTypeController::RUNNING, new_non_frontend_dtc_->state());
}
-TEST_F(NewNonFrontendDataTypeControllerTest, StartFirstRun) {
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, StartFirstRun) {
SetStartExpectations();
EXPECT_CALL(*change_processor_, Connect(_,_,_,_)).WillOnce(Return(true));
EXPECT_CALL(*change_processor_, CryptoReadyIfNecessary(_)).
@@ -253,7 +284,12 @@ TEST_F(NewNonFrontendDataTypeControllerTest, StartFirstRun) {
EXPECT_EQ(DataTypeController::RUNNING, new_non_frontend_dtc_->state());
}
-TEST_F(NewNonFrontendDataTypeControllerTest, AbortDuringStartModels) {
+// Start the DTC and have StartModels() return false. Then, stop the
+// DTC without finishing model startup. It should stop cleanly.
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, AbortDuringStartModels) {
+ EXPECT_CALL(*profile_sync_factory_,
+ CreateSharedChangeProcessor()).
+ WillOnce(Return(change_processor_.get()));
EXPECT_CALL(*dtc_mock_, StartModels()).WillOnce(Return(false));
EXPECT_CALL(*dtc_mock_, StopModels());
EXPECT_CALL(*dtc_mock_, RecordStartFailure(DataTypeController::ABORTED));
@@ -267,7 +303,7 @@ TEST_F(NewNonFrontendDataTypeControllerTest, AbortDuringStartModels) {
EXPECT_EQ(DataTypeController::NOT_RUNNING, new_non_frontend_dtc_->state());
}
-TEST_F(NewNonFrontendDataTypeControllerTest, StartAssociationFailed) {
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, StartAssociationFailed) {
SetStartExpectations();
EXPECT_CALL(*change_processor_, Connect(_,_,_,_)).WillOnce(Return(true));
EXPECT_CALL(*change_processor_, CryptoReadyIfNecessary(_)).
@@ -289,7 +325,7 @@ TEST_F(NewNonFrontendDataTypeControllerTest, StartAssociationFailed) {
EXPECT_EQ(DataTypeController::DISABLED, new_non_frontend_dtc_->state());
}
-TEST_F(NewNonFrontendDataTypeControllerTest,
+TEST_F(SyncNewNonFrontendDataTypeControllerTest,
StartAssociationTriggersUnrecoverableError) {
SetStartExpectations();
SetStartFailExpectations(DataTypeController::UNRECOVERABLE_ERROR);
@@ -306,7 +342,8 @@ TEST_F(NewNonFrontendDataTypeControllerTest,
EXPECT_EQ(DataTypeController::NOT_RUNNING, new_non_frontend_dtc_->state());
}
-TEST_F(NewNonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) {
+TEST_F(SyncNewNonFrontendDataTypeControllerTest,
+ StartAssociationCryptoNotReady) {
SetStartExpectations();
SetStartFailExpectations(DataTypeController::NEEDS_CRYPTO);
// Set up association to fail with a NEEDS_CRYPTO error.
@@ -322,7 +359,7 @@ TEST_F(NewNonFrontendDataTypeControllerTest, StartAssociationCryptoNotReady) {
// Trigger a Stop() call when we check if the model associator has user created
// nodes.
-TEST_F(NewNonFrontendDataTypeControllerTest, AbortDuringAssociation) {
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, AbortDuringAssociation) {
WaitableEvent wait_for_db_thread_pause(false, false);
WaitableEvent pause_db_thread(false, false);
@@ -351,7 +388,25 @@ TEST_F(NewNonFrontendDataTypeControllerTest, AbortDuringAssociation) {
EXPECT_EQ(DataTypeController::NOT_RUNNING, new_non_frontend_dtc_->state());
}
-TEST_F(NewNonFrontendDataTypeControllerTest, Stop) {
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, Stop) {
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
+ SetStopExpectations();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, new_non_frontend_dtc_->state());
+ new_non_frontend_dtc_->Start(
+ base::Bind(&StartCallbackMock::Run, base::Unretained(&start_callback_)));
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, new_non_frontend_dtc_->state());
+ new_non_frontend_dtc_->Stop();
+ EXPECT_EQ(DataTypeController::NOT_RUNNING, new_non_frontend_dtc_->state());
+}
+
+// Start the DTC then block its backend tasks. While its backend
+// tasks are blocked, stop and start it again, then unblock its
+// backend tasks. The (delayed) running of the backend tasks from the
+// stop after the restart shouldn't cause any problems.
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, StopStart) {
SetStartExpectations();
SetAssociateExpectations();
SetActivateExpectations(DataTypeController::OK);
@@ -361,11 +416,23 @@ TEST_F(NewNonFrontendDataTypeControllerTest, Stop) {
base::Bind(&StartCallbackMock::Run, base::Unretained(&start_callback_)));
WaitForDTC();
EXPECT_EQ(DataTypeController::RUNNING, new_non_frontend_dtc_->state());
+
+ new_non_frontend_dtc_->BlockBackendTasks();
new_non_frontend_dtc_->Stop();
+ Mock::VerifyAndClearExpectations(&profile_sync_factory_);
+ SetStartExpectations();
+ SetAssociateExpectations();
+ SetActivateExpectations(DataTypeController::OK);
EXPECT_EQ(DataTypeController::NOT_RUNNING, new_non_frontend_dtc_->state());
+ new_non_frontend_dtc_->Start(
+ base::Bind(&StartCallbackMock::Run, base::Unretained(&start_callback_)));
+ new_non_frontend_dtc_->UnblockBackendTasks();
+
+ WaitForDTC();
+ EXPECT_EQ(DataTypeController::RUNNING, new_non_frontend_dtc_->state());
}
-TEST_F(NewNonFrontendDataTypeControllerTest, OnUnrecoverableError) {
+TEST_F(SyncNewNonFrontendDataTypeControllerTest, OnUnrecoverableError) {
SetStartExpectations();
SetAssociateExpectations();
SetActivateExpectations(DataTypeController::OK);

Powered by Google App Engine
This is Rietveld 408576698