| 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
|
|
|