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

Unified Diff: components/sync_driver/non_blocking_data_type_controller_unittest.cc

Issue 272323002: sync: Implement disabling of non blocking types (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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: components/sync_driver/non_blocking_data_type_controller_unittest.cc
diff --git a/components/sync_driver/non_blocking_data_type_controller_unittest.cc b/components/sync_driver/non_blocking_data_type_controller_unittest.cc
index 43c4fa4d25cbe47ab9868db4231e5b817bd13428..d6de39357b09f05f950145b695b0d661ffd13010 100644
--- a/components/sync_driver/non_blocking_data_type_controller_unittest.cc
+++ b/components/sync_driver/non_blocking_data_type_controller_unittest.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <list>
+
+#include "base/bind.h"
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
@@ -14,22 +18,72 @@
namespace {
+// A class that pretends to be the sync backend.
+class MockSyncCore {
+ public:
+ void Connect(syncer::ModelType type,
+ scoped_refptr<base::SingleThreadTaskRunner> model_task_runner,
Nicolas Zea 2014/05/12 19:09:10 nit: passed scoped_refptrs and weakptr's as const
rlarocque 2014/05/12 20:02:13 Done and done.
+ base::WeakPtr<syncer::NonBlockingTypeProcessor> type_processor) {
+ enabled_types_.Put(type);
+ model_task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&syncer::NonBlockingTypeProcessor::OnConnect,
+ type_processor,
+ base::WeakPtr<syncer::NonBlockingTypeProcessorCore>(),
+ scoped_refptr<base::SequencedTaskRunner>()));
+ }
+
+ void Disconnect(syncer::ModelType type) {
+ DCHECK(enabled_types_.Has(type));
+ enabled_types_.Remove(type);
+ }
+
+ private:
+ std::list<base::Closure> tasks_;
+ syncer::ModelTypeSet enabled_types_;
+};
+
+// A proxy to the MockSyncCore that implements SyncCoreProxy.
class MockSyncCoreProxy : public syncer::SyncCoreProxy {
public:
- MockSyncCoreProxy() {}
+ MockSyncCoreProxy(MockSyncCore* sync_core,
+ scoped_refptr<base::TestSimpleTaskRunner> model_task_runner,
+ scoped_refptr<base::TestSimpleTaskRunner> sync_task_runner)
+ : mock_sync_core_(sync_core),
+ model_task_runner_(model_task_runner),
+ sync_task_runner_(sync_task_runner) {}
virtual ~MockSyncCoreProxy() {}
virtual void ConnectTypeToCore(
syncer::ModelType type,
base::WeakPtr<syncer::NonBlockingTypeProcessor> type_processor) OVERRIDE {
- type_processor->OnConnect(
- base::WeakPtr<syncer::NonBlockingTypeProcessorCore>(),
- scoped_refptr<base::SequencedTaskRunner>());
+ // Normally we'd use MessageLoopProxy::current() as the TaskRunner argument
+ // to Connect(). That won't work here in this test, so we use the
+ // model_task_runner_ that was injected for this purpose instead.
+ sync_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&MockSyncCore::Connect,
+ base::Unretained(mock_sync_core_),
+ type,
+ model_task_runner_,
+ type_processor));
+ }
+
+ virtual void Disconnect(syncer::ModelType type) OVERRIDE {
+ sync_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&MockSyncCore::Disconnect,
+ base::Unretained(mock_sync_core_),
+ type));
}
virtual scoped_ptr<SyncCoreProxy> Clone() const OVERRIDE {
- return scoped_ptr<SyncCoreProxy>(new MockSyncCoreProxy());
+ return scoped_ptr<SyncCoreProxy>(new MockSyncCoreProxy(
+ mock_sync_core_, model_task_runner_, sync_task_runner_));
}
+
+ private:
+ MockSyncCore* mock_sync_core_;
+ scoped_refptr<base::TestSimpleTaskRunner> model_task_runner_;
+ scoped_refptr<base::TestSimpleTaskRunner> sync_task_runner_;
};
class NonBlockingDataTypeControllerTest : public testing::Test {
@@ -37,48 +91,75 @@ class NonBlockingDataTypeControllerTest : public testing::Test {
NonBlockingDataTypeControllerTest()
: processor_(syncer::DICTIONARY),
model_thread_(new base::TestSimpleTaskRunner()),
- controller_(syncer::DICTIONARY, true) {}
+ sync_thread_(new base::TestSimpleTaskRunner()),
+ controller_(syncer::DICTIONARY, true),
+ mock_core_proxy_(&mock_sync_core_, model_thread_, sync_thread_),
+ auto_run_tasks_(true) {}
virtual ~NonBlockingDataTypeControllerTest() {}
// Connects the processor to the NonBlockingDataTypeController.
void InitProcessor() {
- controller_.InitializeProcessor(
- model_thread_, processor_.AsWeakPtr());
- RunQueuedTasks();
+ controller_.InitializeProcessor(model_thread_, processor_.AsWeakPtrForUI());
+ if (auto_run_tasks_) {
+ RunAllTasks();
+ }
}
// Connects the sync backend to the NonBlockingDataTypeController.
void InitSync() {
controller_.InitializeSyncCoreProxy(mock_core_proxy_.Clone());
- RunQueuedTasks();
+ if (auto_run_tasks_) {
+ RunAllTasks();
+ }
}
// Disconnects the sync backend from the NonBlockingDataTypeController.
void UninitializeSync() {
controller_.ClearSyncCoreProxy();
- RunQueuedTasks();
+ if (auto_run_tasks_) {
+ RunAllTasks();
+ }
}
// Toggles the user's preference for syncing this type.
void SetIsPreferred(bool preferred) {
controller_.SetIsPreferred(preferred);
- RunQueuedTasks();
+ if (auto_run_tasks_) {
+ RunAllTasks();
+ }
+ }
+
+ // These threads can ping-pong for a bit so we run the model thread twice.
+ void RunAllTasks() {
+ RunQueuedModelThreadTasks();
+ RunQueuedSyncThreadTasks();
+ RunQueuedModelThreadTasks();
}
// The processor pretends to run tasks on a different thread.
// This function runs any posted tasks.
- void RunQueuedTasks() {
- model_thread_->RunUntilIdle();
+ void RunQueuedModelThreadTasks() { model_thread_->RunUntilIdle(); }
+
+ // Processes any pending connect or disconnect requests and sends
+ // responses synchronously.
+ void RunQueuedSyncThreadTasks() { sync_thread_->RunUntilIdle(); }
+
+ void SetAutoRunTasks(bool auto_run_tasks) {
+ auto_run_tasks_ = auto_run_tasks;
}
protected:
- MockSyncCoreProxy mock_core_proxy_;
-
syncer::NonBlockingTypeProcessor processor_;
scoped_refptr<base::TestSimpleTaskRunner> model_thread_;
+ scoped_refptr<base::TestSimpleTaskRunner> sync_thread_;
browser_sync::NonBlockingDataTypeController controller_;
+
+ MockSyncCore mock_sync_core_;
+ MockSyncCoreProxy mock_core_proxy_;
+
+ bool auto_run_tasks_;
};
// Initialization when the user has disabled syncing for this type.
@@ -224,4 +305,103 @@ TEST_F(NonBlockingDataTypeControllerTest, TogglePreferenceWithoutBackend) {
EXPECT_TRUE(processor_.IsPreferred());
}
+// Turns off auto-task-running to test the effects of delaying a connection
+// response.
+//
+// This is mostly a test of the test framework. It's not very interesting on
+// its own, but it provides a useful "control" against some of the more
+// complicated race tests below.
+TEST_F(NonBlockingDataTypeControllerTest, DelayedConnect) {
+ SetAutoRunTasks(false);
+
+ SetIsPreferred(true);
+ InitProcessor();
+ InitSync();
+
+ // Allow the model to emit the request.
+ RunQueuedModelThreadTasks();
+
+ // That should result in a request to connect, but it won't be
+ // executed right away.
+ EXPECT_FALSE(processor_.IsConnected());
+ EXPECT_TRUE(processor_.IsPreferred());
+
+ // Let the sync thread process the request and the model thread handle its
+ // response.
+ RunQueuedSyncThreadTasks();
+ RunQueuedModelThreadTasks();
+
+ EXPECT_TRUE(processor_.IsConnected());
+ EXPECT_TRUE(processor_.IsPreferred());
+}
+
+// Send Disable signal while a connection request is in progress.
+TEST_F(NonBlockingDataTypeControllerTest, DisableRacesWithOnConnect) {
+ SetAutoRunTasks(false);
+
+ SetIsPreferred(true);
+ InitProcessor();
+ InitSync();
+
+ // Allow the model to emit the request.
+ RunQueuedModelThreadTasks();
+
+ // That should result in a request to connect, but it won't be
+ // executed right away.
+ EXPECT_FALSE(processor_.IsConnected());
+ EXPECT_TRUE(processor_.IsPreferred());
+
+ // Send and execute a disable signal before the OnConnect callback returns.
+ SetIsPreferred(false);
+
+ // Now we let sync process the initial request and the disable request,
+ // both of which should be sitting in its queue.
+ RunQueuedSyncThreadTasks();
+
+ // Let the model thread process any responses received from the sync thread.
+ // A plausible error would be that the sync thread returns a "connection OK"
+ // message, and this message overrides the request to disable that arrived
+ // from the UI thread earlier. We need to make sure that doesn't happen.
+ RunQueuedModelThreadTasks();
+
+ EXPECT_FALSE(processor_.IsPreferred());
+ EXPECT_FALSE(processor_.IsConnected());
+}
+
+// Send a request to enable, then disable, then re-enable the data type.
+//
+// To make it more interesting, we stall the sync thread until all three
+// requests have been passed to the model thread.
+TEST_F(NonBlockingDataTypeControllerTest, EnableDisableEnableRace) {
+ SetAutoRunTasks(false);
+
+ SetIsPreferred(true);
+ InitProcessor();
+ InitSync();
+ RunQueuedModelThreadTasks();
+
+ // That was the first enable.
+ EXPECT_FALSE(processor_.IsConnected());
+ EXPECT_TRUE(processor_.IsPreferred());
+
+ // Now disable.
+ SetIsPreferred(false);
+ RunQueuedModelThreadTasks();
+ EXPECT_FALSE(processor_.IsPreferred());
+
+ // And re-enable.
+ SetIsPreferred(true);
+ RunQueuedModelThreadTasks();
+ EXPECT_TRUE(processor_.IsPreferred());
+
+ // The sync thread has three messages related to those enables and
+ // disables sittin in its queue. Let's allow it to process them.
+ RunQueuedSyncThreadTasks();
+
+ // Let the model thread process any messages from the sync thread.
+ RunQueuedModelThreadTasks();
+ EXPECT_TRUE(processor_.IsPreferred());
+ EXPECT_TRUE(processor_.IsConnected());
+}
+
} // namespace

Powered by Google App Engine
This is Rietveld 408576698