Index: components/scheduler/promises/thread_pool_promise_executor_unittest.cc |
diff --git a/components/scheduler/promises/thread_pool_promise_executor_unittest.cc b/components/scheduler/promises/thread_pool_promise_executor_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f77757c3f006d98c15597489197370b1482be32a |
--- /dev/null |
+++ b/components/scheduler/promises/thread_pool_promise_executor_unittest.cc |
@@ -0,0 +1,437 @@ |
+// Copyright 2016 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/scheduler/promises/thread_pool_promise_executor.h" |
+ |
+#include "base/bind.h" |
+#include "base/synchronization/waitable_event.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using testing::ElementsAre; |
+using testing::WhenSorted; |
+ |
+#if 0 |
+ |
+namespace promise { |
+ |
+class ThreadPoolPromiseExecutorTest : public testing::Test { |
+ public: |
+ ThreadPoolPromiseExecutorTest() {} |
+ ~ThreadPoolPromiseExecutorTest() override {} |
+ |
+ void SetUp() override { |
+ promise_executor_.reset(new internal::ThreadPoolPromiseExecutor()); |
+ } |
+ |
+ scoped_ptr<internal::ThreadPoolPromiseExecutor> promise_executor_; |
+}; |
+ |
+namespace { |
+bool ReturnTrue() { |
+ return true; |
+} |
+ |
+int ReturnOne() { |
+ return 1; |
+} |
+ |
+int ReturnTwo() { |
+ return 2; |
+} |
+ |
+int ReturnTen() { |
+ return 10; |
+} |
+ |
+int AddOne(int i) { |
+ return i + 1; |
+} |
+ |
+int CondTimesThree(int i, bool do_smth) { |
+ if (do_smth) |
+ return i * 3; |
+ return i; |
+} |
+ |
+int ReturnZero() { |
+ return 0; |
+} |
+ |
+scoped_refptr<Promise<int>> Choose(scoped_refptr<Promise<int>> p1, |
+ scoped_refptr<Promise<int>> p2, |
+ int i) { |
+ return i ? p1 : p2; |
+} |
+ |
+void RecordOrder(int value, std::vector<int>* out_result) { |
+ out_result->push_back(value); |
+} |
+ |
+void SignalWaitableEvent(base::WaitableEvent* waitable_event, int) { |
+ waitable_event->Signal(); |
+} |
+ |
+void SignalWaitableEventVoid(base::WaitableEvent* waitable_event) { |
+ waitable_event->Signal(); |
+} |
+ |
+} // namespace |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, NonVoidPromise) { |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<int>> promise(promise::Create(base::Bind(&ReturnOne))); |
+ |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promise.Then(base::Bind(&SignalWaitableEvent, &event))); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ EXPECT_EQ(1, promise->GetResolved()); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, RunAfter_OnePromise_AndThen) { |
+ scoped_refptr<Promise<int>> promise( |
+ promise::Create(base::Bind(&ReturnOne)).Then(base::Bind(&AddOne))); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promise.Then(base::Bind(&SignalWaitableEvent, &event))); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ EXPECT_EQ(2, promise->GetResolved()); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, RunAfter_TwoPromises_AndThen) { |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<int>> promise( |
+ promise::All(promise::Create(base::Bind(&ReturnOne)), |
+ promise::Create(base::Bind(&ReturnTrue))) |
+ .Then(base::Bind(&CondTimesThree))); |
+ |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promise.Then(base::Bind(&SignalWaitableEvent, &event))); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ EXPECT_EQ(3, promise->GetResolved()); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, ChainOfPromises) { |
+ scoped_refptr<Promise<int>> promise(promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&AddOne)) |
+ .Then(base::Bind(&AddOne)) |
+ .Then(base::Bind(&AddOne)) |
+ .Then(base::Bind(&AddOne))); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promise.Then(base::Bind(&SignalWaitableEvent, &event))); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ EXPECT_EQ(5, promise->GetResolved()); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, EagerTasksExecutedFirst) { |
+ std::vector<int> run_order; |
+ |
+ scoped_refptr<Promise<void>> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 4, &run_order))); |
+ |
+ scoped_refptr<Promise<void>> promiseB( |
+ promise::Create(base::Bind(&RecordOrder, 10, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 11, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 12, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 13, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 14, &run_order))); |
+ |
+ promiseB->SetEager(true); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promise::All(promiseA, promiseB) |
+ .Then(base::Bind(&SignalWaitableEventVoid, &event))); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(10, 11, 12, 13, 14, 0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, Cancel) { |
+ /*std::vector<int> run_order; |
+ |
+ scoped_refptr<Promise<void>> promise(promise::Create( |
+ base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promise.Then(base::Bind(&SignalWaitableEventVoid, &event))); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ wait_promise->Cancel(); |
+ event.Wait(); |
+ |
+ EXPECT_TRUE(run_order.empty());*/ |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, CancelChainOfTasks) { |
+ std::vector<int> run_order; |
+ |
+ scoped_refptr<Promise<void>> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 4, &run_order))); |
+ |
+ scoped_refptr<Promise<void>> promiseB( |
+ promise::Create(base::Bind(&RecordOrder, 10, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 11, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 12, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 13, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 14, &run_order))); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promiseA.Then(base::Bind(&SignalWaitableEventVoid, &event))); |
+ |
+ promise_executor_->StartResolve(promiseB.get()); |
+ promiseB->Cancel(); |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, CancelOneBranch) { |
+ std::vector<int> run_order; |
+ |
+ scoped_refptr<Promise<void>> promiseA( |
+ promise::Create(base::Bind(&RecordOrder, 0, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 1, &run_order))); |
+ |
+ scoped_refptr<Promise<void>> promiseB( |
+ promiseA.Then(base::Bind(&RecordOrder, 2, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 3, &run_order))); |
+ |
+ scoped_refptr<Promise<void>> promiseC( |
+ promiseA.Then(base::Bind(&RecordOrder, 4, &run_order)) |
+ .Then(base::Bind(&RecordOrder, 5, &run_order))); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promiseC.Then(base::Bind(&SignalWaitableEventVoid, &event))); |
+ |
+ promise_executor_->StartResolve(promiseB.get()); |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ |
+ promiseB->Cancel(); |
+ |
+ event.Wait(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 4, 5)); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, Choose) { |
+ scoped_refptr<Promise<int>> promise_two( |
+ promise::Create(base::Bind(&ReturnTwo))); |
+ scoped_refptr<Promise<int>> promise_ten( |
+ promise::Create(base::Bind(&ReturnTen))); |
+ scoped_refptr<Promise<int>> promiseA( |
+ promise::Create(base::Bind(&ReturnZero)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten))); |
+ |
+ scoped_refptr<Promise<int>> promiseB( |
+ promise::Create(base::Bind(&ReturnOne)) |
+ .Then(base::Bind(&Choose, promise_two, promise_ten))); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise( |
+ promise::All(promiseA, promiseB) |
+ .Then(base::Bind(&SignalWaitableEventVoid, &event))); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ |
+ EXPECT_EQ(10, promiseA->GetResolved()); |
+ EXPECT_EQ(2, promiseB->GetResolved()); |
+} |
+/* |
+TEST_F(ThreadPoolPromiseExecutorTest, ChooseAndAddOne) { |
+ scoped_refptr<Promise<int>> promise_a( |
+ promise::Create(base::Bind(&ReturnZero))); |
+ scoped_refptr<Promise<int>> promise_b( |
+ promise::Create(base::Bind(&ReturnOne))); |
+ scoped_refptr<Promise<int>> promise_c( |
+ promise::Create(base::Bind(&ReturnTen))); |
+ |
+ scoped_refptr<Promise<int>> promise_d_zero(promise_executor_->RunAfter( |
+ base::Bind(&Choose, promise_b, promise_c), promise_a)); |
+ |
+ scoped_refptr<Promise<int>> promise_d_one(promise_executor_->RunAfter( |
+ base::Bind(&Choose, promise_b, promise_c), promise_b)); |
+ |
+ scoped_refptr<Promise<int>> promise_e( |
+ promise_executor_->RunAfter(base::Bind(&AddOne), promise_d_zero)); |
+ |
+ scoped_refptr<Promise<int>> promise_f( |
+ promise_executor_->RunAfter(base::Bind(&AddOne), promise_d_one)); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise(promise_executor_->RunAfter( |
+ base::Bind(&SignalWaitableEventVoid, &event), promise_e, promise_f)); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ |
+ EXPECT_EQ(11, promise_e->GetResolved()); |
+ EXPECT_EQ(2, promise_f->GetResolved()); |
+} |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, ChooseAndAddOne_ResolvedPromise) { |
+ scoped_refptr<Promise<int>> promise_one( |
+ promise::Create(base::Bind(&ReturnOne))); |
+ |
+ scoped_refptr<Promise<int>> promise_zero( |
+ promise::Create(base::Bind(&ReturnZero))); |
+ |
+ scoped_refptr<Promise<int>> promise_a(promise_executor_->RunAfter( |
+ base::Bind(&Choose, |
+make_scoped_refptr(promise::Create<int>(1)), |
+ make_scoped_refptr(promise::Create<int>(10))), |
+ promise_zero)); |
+ |
+ scoped_refptr<Promise<int>> promise_b(promise_executor_->RunAfter( |
+ base::Bind(&Choose, |
+make_scoped_refptr(promise::Create<int>(1)), |
+ make_scoped_refptr(promise::Create<int>(10))), |
+ promise_one)); |
+ |
+ scoped_refptr<Promise<int>> promise_c( |
+ promise_executor_->RunAfter(base::Bind(&AddOne), promise_a)); |
+ |
+ scoped_refptr<Promise<int>> promise_d( |
+ promise_executor_->RunAfter(base::Bind(&AddOne), promise_b)); |
+ |
+ base::WaitableEvent event(true, false); |
+ scoped_refptr<Promise<void>> wait_promise(promise_executor_->RunAfter( |
+ base::Bind(&SignalWaitableEventVoid, &event), promise_c, promise_d)); |
+ |
+ promise_executor_->StartResolve(wait_promise.get()); |
+ event.Wait(); |
+ |
+ EXPECT_EQ(11, promise_c->GetResolved()); |
+ EXPECT_EQ(2, promise_d->GetResolved()); |
+} |
+*/ |
+ |
+namespace { |
+class BlockingResolveFixture { |
+ public: |
+ void Root() { run_order_.push_back("Root"); } |
+ |
+ void L() { run_order_.push_back("L"); } |
+ |
+ void LL() { run_order_.push_back("LL"); } |
+ |
+ void LR() { run_order_.push_back("LR"); } |
+ |
+ void R() { run_order_.push_back("R"); } |
+ |
+ void RL() { run_order_.push_back("RL"); } |
+ |
+ void RR() { run_order_.push_back("RL"); } |
+ |
+ std::vector<std::string> run_order_; |
+}; |
+} // namespace |
+ |
+/* |
+TEST_F(ThreadPoolPromiseExecutorTest, BlockingResolve) { |
+ BlockingResolveFixture fixture; |
+ |
+ scoped_refptr<Promise<void>> promise_ll(promise::Create( |
+ base::Bind(&BlockingResolveFixture::LL, base::Unretained(&fixture)))); |
+ |
+ scoped_refptr<Promise<void>> promise_lr(promise::Create( |
+ base::Bind(&BlockingResolveFixture::LR, base::Unretained(&fixture)))); |
+ |
+ scoped_refptr<Promise<void>> promise_l(promise_executor_->RunAfter( |
+ base::Bind(&BlockingResolveFixture::L, base::Unretained(&fixture)), |
+ promise_ll, promise_lr)); |
+ |
+ scoped_refptr<Promise<void>> promise_rl(promise::Create( |
+ base::Bind(&BlockingResolveFixture::RL, base::Unretained(&fixture)))); |
+ |
+ scoped_refptr<Promise<void>> promise_rr(promise::Create( |
+ base::Bind(&BlockingResolveFixture::RR, base::Unretained(&fixture)))); |
+ |
+ scoped_refptr<Promise<void>> blocking_promise( |
+ promise::Create<void>()); |
+ |
+ scoped_refptr<Promise<void>> promise_r(promise_executor_->RunAfter( |
+ base::Bind(&BlockingResolveFixture::R, base::Unretained(&fixture)), |
+ promise_rl, promise_rr, scoped_refptr<Promise<void>>(blocking_promise))); |
+ |
+ scoped_refptr<Promise<void>> promise_root(promise_executor_->RunAfter( |
+ base::Bind(&BlockingResolveFixture::Root, base::Unretained(&fixture)), |
+ promise_l, promise_r)); |
+ |
+ promise_executor_->StartResolve(promise_root.get()); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_THAT(fixture.run_order_, |
+ WhenSorted(ElementsAre(std::string("L"), std::string("LL"), |
+ std::string("LR"), std::string("RL"), |
+ std::string("RL")))); |
+ |
+ fixture.run_order_.clear(); |
+ blocking_promise.Resolve(); |
+ mock_task_runner_->RunUntilIdle(); |
+ EXPECT_THAT(fixture.run_order_, |
+ ElementsAre(std::string("R"), std::string("Root"))); |
+} |
+ |
+namespace { |
+scoped_refptr<Promise<void>> GenerateNewTask(PromiseExecutor* executor, |
+ std::vector<int>* out_result) { |
+ out_result->push_back(1); |
+ |
+ scoped_refptr<Promise<void>> promise0( |
+ executor->promise::Create(base::Bind(&RecordOrder, 2, out_result))); |
+ |
+ return executor->RunAfter(base::Bind(&RecordOrder, 3, out_result), promise0); |
+} |
+} // namespace |
+ |
+TEST_F(ThreadPoolPromiseExecutorTest, NewPromiseFromWithinPromise) { |
+ std::vector<int> run_order; |
+ |
+ scoped_refptr<Promise<void>> promise0(promise::Create( |
+ base::Bind(&RecordOrder, 0, &run_order))); |
+ |
+ scoped_refptr<Promise<void>> promise1(promise_executor_->RunAfter( |
+ base::Bind(&GenerateNewTask, base::Unretained(promise_executor_.get()), |
+ &run_order), |
+ promise0)); |
+ |
+ scoped_refptr<Promise<void>> promise4(promise_executor_->RunAfter( |
+ base::Bind(&RecordOrder, 4, &run_order), promise1)); |
+ |
+ promise_executor_->StartResolve(promise4.get()); |
+ |
+ mock_task_runner_->RunUntilIdle(); |
+ |
+ EXPECT_THAT(run_order, ElementsAre(0, 1, 2, 3, 4)); |
+}*/ |
+ |
+} // namespace promise |
+ |
+#endif |