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

Unified Diff: components/history/core/browser/history_model_worker_unittest.cc

Issue 2782573002: [Sync] Refactor ModelSafeWorker::DoWorkAndWaitUntilDone() to avoid code duplication. (Closed)
Patch Set: self-review Created 3 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: components/history/core/browser/history_model_worker_unittest.cc
diff --git a/components/history/core/browser/history_model_worker_unittest.cc b/components/history/core/browser/history_model_worker_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1877558782ce247710650728b5a8cf80d137852d
--- /dev/null
+++ b/components/history/core/browser/history_model_worker_unittest.cc
@@ -0,0 +1,227 @@
+// Copyright 2017 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 "components/history/core/browser/history_model_worker.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/atomic_flag.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "components/history/core/browser/history_db_task.h"
+#include "components/history/core/browser/history_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace browser_sync {
+namespace {
+
+class HistoryServiceMock : public history::HistoryService {
+ public:
+ HistoryServiceMock(scoped_refptr<base::SingleThreadTaskRunner> history_thread)
+ : history_thread_(std::move(history_thread)) {}
+
+ base::CancelableTaskTracker::TaskId ScheduleDBTask(
+ std::unique_ptr<history::HistoryDBTask> task,
+ base::CancelableTaskTracker* tracker) override {
+ history::HistoryDBTask* task_raw = task.get();
+ history_thread_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&history::HistoryDBTask::RunOnDBThread),
+ base::Unretained(task_raw), nullptr, nullptr),
+ base::Bind(&history::HistoryDBTask::DoneRunOnMainThread,
+ base::Passed(std::move(task))));
+ return base::CancelableTaskTracker::kBadTaskId; // Unused.
+ }
+
+ private:
+ const scoped_refptr<base::SingleThreadTaskRunner> history_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryServiceMock);
+};
+
+syncer::WorkCallback ClosureToWorkCallback(base::Closure work) {
+ return base::Bind(
+ [](base::Closure work) {
+ work.Run();
+ return syncer::SYNCER_OK;
+ },
+ std::move(work));
+}
+
+class HistoryModelWorkerTest : public testing::Test {
+ public:
+ HistoryModelWorkerTest()
+ : sync_thread_("SyncThreadForTest"),
+ history_service_(history_thread_),
+ history_service_factory_(&history_service_) {
+ sync_thread_.Start();
+ worker_ = new HistoryModelWorker(history_service_factory_.GetWeakPtr(),
+ ui_thread_);
+ }
+
+ ~HistoryModelWorkerTest() override {
+ // HistoryModelWorker posts a cleanup task to the UI thread in its
+ // destructor. Run it to prevent a leak.
+ worker_ = nullptr;
+ ui_thread_->RunUntilIdle();
+ }
+
+ protected:
+ void DoWorkAndWaitUntilDoneOnSyncThread(base::Closure work) {
+ sync_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult(&HistoryModelWorker::DoWorkAndWaitUntilDone),
+ worker_, base::Passed(ClosureToWorkCallback(work))));
+ sync_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&base::AtomicFlag::Set,
+ base::Unretained(&sync_thread_unblocked_)));
+ }
+
+ const scoped_refptr<base::TestSimpleTaskRunner> ui_thread_ =
+ new base::TestSimpleTaskRunner();
+ scoped_refptr<base::TestSimpleTaskRunner> history_thread_ =
+ new base::TestSimpleTaskRunner();
+ base::AtomicFlag sync_thread_unblocked_;
+ base::Thread sync_thread_;
+ HistoryServiceMock history_service_;
+ scoped_refptr<HistoryModelWorker> worker_;
+
+ private:
+ base::WeakPtrFactory<HistoryServiceMock> history_service_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistoryModelWorkerTest);
+};
+
+} // namespace
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDone) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread and run it. Expect this task
+ // to post another task to the history DB thread and run it.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->RunUntilIdle();
+ EXPECT_TRUE(history_thread_->HasPendingTask());
+ history_thread_->RunUntilIdle();
+
+ EXPECT_TRUE(did_work);
+
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDoneRequestStopBeforeRunWork) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread and run it.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->RunUntilIdle();
+
+ // Stop the worker.
+ worker_->RequestStop();
+
+ // The WorkCallback should not run on the history DB thread.
+ EXPECT_TRUE(history_thread_->HasPendingTask());
+ history_thread_->RunUntilIdle();
+ EXPECT_FALSE(did_work);
+
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest,
+ DoWorkAndWaitUntilDoneRequestStopBeforeUITaskRun) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+
+ // Stop the worker.
+ worker_->RequestStop();
+
+ // Stopping the worker should unblock the sync thread.
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDoneDeleteWorkBeforeRun) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](bool* did_work) { *did_work = true; }, base::Unretained(&did_work)));
+
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread. Delete it before it can run.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->ClearPendingTasks();
+
+ EXPECT_FALSE(did_work);
+
+ // Deleting the task should have unblocked the sync thread.
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+TEST_F(HistoryModelWorkerTest, DoWorkAndWaitUntilDoneRequestStopDuringRunWork) {
+ bool did_work = false;
+ DoWorkAndWaitUntilDoneOnSyncThread(base::Bind(
+ [](scoped_refptr<HistoryModelWorker> worker,
+ base::AtomicFlag* sync_thread_unblocked, bool* did_work) {
+ worker->RequestStop();
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+
+ // The sync thread should not be unblocked while a WorkCallback is
+ // running.
+ EXPECT_FALSE(sync_thread_unblocked->IsSet());
+
+ *did_work = true;
+ },
+ worker_, base::Unretained(&sync_thread_unblocked_),
+ base::Unretained(&did_work)));
+ EXPECT_FALSE(did_work);
+ EXPECT_FALSE(sync_thread_unblocked_.IsSet());
+
+ // Wait for a task to be posted to the UI thread and run it.
+ while (!ui_thread_->HasPendingTask())
+ base::PlatformThread::YieldCurrentThread();
+ ui_thread_->RunUntilIdle();
+
+ // Expect a task to be posted to the history DB thread. Run it.
+ EXPECT_TRUE(history_thread_->HasPendingTask());
+ history_thread_->RunUntilIdle();
+ EXPECT_TRUE(did_work);
+
+ sync_thread_.Stop();
+ EXPECT_TRUE(sync_thread_unblocked_.IsSet());
+}
+
+} // namespace browser_sync

Powered by Google App Engine
This is Rietveld 408576698