blob: 7f9d276a76ce4a9df03e4a6432c3331e3ab84878 [file] [log] [blame]
// Copyright 2015 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 "platform/scheduler/child/webthread_impl_for_worker_scheduler.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/synchronization/waitable_event.h"
#include "platform/CrossThreadFunctional.h"
#include "platform/WebTaskRunner.h"
#include "platform/scheduler/child/web_scheduler_impl.h"
#include "platform/scheduler/worker/worker_thread_scheduler.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::AnyOf;
using testing::ElementsAre;
using testing::Invoke;
namespace blink {
namespace scheduler {
namespace webthread_impl_for_worker_scheduler_unittest {
class MockTask {
public:
MOCK_METHOD0(Run, void());
};
class MockIdleTask {
public:
MOCK_METHOD1(Run, void(double deadline));
};
class TestObserver : public blink::WebThread::TaskObserver {
public:
explicit TestObserver(std::string* calls) : calls_(calls) {}
~TestObserver() override = default;
void WillProcessTask() override { calls_->append(" willProcessTask"); }
void DidProcessTask() override { calls_->append(" didProcessTask"); }
private:
std::string* calls_; // NOT OWNED
};
void RunTestTask(std::string* calls) {
calls->append(" run");
}
void AddTaskObserver(WebThreadImplForWorkerScheduler* thread,
TestObserver* observer) {
thread->AddTaskObserver(observer);
}
void RemoveTaskObserver(WebThreadImplForWorkerScheduler* thread,
TestObserver* observer) {
thread->RemoveTaskObserver(observer);
}
void ShutdownOnThread(WebThreadImplForWorkerScheduler* thread) {
WebSchedulerImpl* web_scheduler_impl =
static_cast<WebSchedulerImpl*>(thread->Scheduler());
web_scheduler_impl->Shutdown();
}
class WebThreadImplForWorkerSchedulerTest : public testing::Test {
public:
WebThreadImplForWorkerSchedulerTest() = default;
~WebThreadImplForWorkerSchedulerTest() override = default;
void SetUp() override {
thread_.reset(new WebThreadImplForWorkerScheduler(
WebThreadCreationParams(WebThreadType::kTestThread)));
thread_->Init();
}
void RunOnWorkerThread(const base::Location& from_here,
base::OnceClosure task) {
base::WaitableEvent completion(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
thread_->GetTaskRunner()->PostTask(
from_here,
base::BindOnce(
&WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask,
base::Unretained(this), std::move(task), &completion));
completion.Wait();
}
protected:
void RunOnWorkerThreadTask(base::OnceClosure task,
base::WaitableEvent* completion) {
std::move(task).Run();
completion->Signal();
}
std::unique_ptr<WebThreadImplForWorkerScheduler> thread_;
DISALLOW_COPY_AND_ASSIGN(WebThreadImplForWorkerSchedulerTest);
};
TEST_F(WebThreadImplForWorkerSchedulerTest, TestDefaultTask) {
MockTask task;
base::WaitableEvent completion(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
EXPECT_CALL(task, Run());
ON_CALL(task, Run()).WillByDefault(Invoke([&completion]() {
completion.Signal();
}));
PostCrossThreadTask(
*thread_->GetTaskRunner(), FROM_HERE,
CrossThreadBind(&MockTask::Run, WTF::CrossThreadUnretained(&task)));
completion.Wait();
}
TEST_F(WebThreadImplForWorkerSchedulerTest,
TestTaskExecutedBeforeThreadDeletion) {
MockTask task;
base::WaitableEvent completion(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
EXPECT_CALL(task, Run());
ON_CALL(task, Run()).WillByDefault(Invoke([&completion]() {
completion.Signal();
}));
PostCrossThreadTask(
*thread_->GetTaskRunner(), FROM_HERE,
CrossThreadBind(&MockTask::Run, WTF::CrossThreadUnretained(&task)));
thread_.reset();
}
TEST_F(WebThreadImplForWorkerSchedulerTest, TestIdleTask) {
MockIdleTask task;
base::WaitableEvent completion(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
EXPECT_CALL(task, Run(_));
ON_CALL(task, Run(_)).WillByDefault(Invoke([&completion](double) {
completion.Signal();
}));
thread_->PostIdleTask(
FROM_HERE, base::BindOnce(&MockIdleTask::Run, WTF::Unretained(&task)));
// We need to post a wake-up task or idle work will never happen.
PostDelayedCrossThreadTask(*thread_->GetTaskRunner(), FROM_HERE,
CrossThreadBind([] {}),
TimeDelta::FromMilliseconds(50));
completion.Wait();
}
TEST_F(WebThreadImplForWorkerSchedulerTest, TestTaskObserver) {
std::string calls;
TestObserver observer(&calls);
RunOnWorkerThread(FROM_HERE,
base::BindOnce(&AddTaskObserver, thread_.get(), &observer));
PostCrossThreadTask(
*thread_->GetTaskRunner(), FROM_HERE,
CrossThreadBind(&RunTestTask, WTF::CrossThreadUnretained(&calls)));
RunOnWorkerThread(
FROM_HERE, base::BindOnce(&RemoveTaskObserver, thread_.get(), &observer));
// We need to be careful what we test here. We want to make sure the
// observers are un in the expected order before and after the task.
// Sometimes we get an internal scheduler task running before or after
// TestTask as well. This is not a bug, and we need to make sure the test
// doesn't fail when that happens.
EXPECT_THAT(calls, testing::HasSubstr("willProcessTask run didProcessTask"));
}
TEST_F(WebThreadImplForWorkerSchedulerTest, TestShutdown) {
MockTask task;
MockTask delayed_task;
EXPECT_CALL(task, Run()).Times(0);
EXPECT_CALL(delayed_task, Run()).Times(0);
RunOnWorkerThread(FROM_HERE,
base::BindOnce(&ShutdownOnThread, thread_.get()));
PostCrossThreadTask(
*thread_->GetTaskRunner(), FROM_HERE,
CrossThreadBind(&MockTask::Run, WTF::CrossThreadUnretained(&task)));
PostDelayedCrossThreadTask(
*thread_->GetTaskRunner(), FROM_HERE,
CrossThreadBind(&MockTask::Run,
WTF::CrossThreadUnretained(&delayed_task)),
TimeDelta::FromMilliseconds(50));
thread_.reset();
}
} // namespace webthread_impl_for_worker_scheduler_unittest
} // namespace scheduler
} // namespace blink