| Index: media/midi/task_service_unittest.cc
|
| diff --git a/media/midi/task_service_unittest.cc b/media/midi/task_service_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ffb16d514810ff84628ad79aa9a6694a1f5ef654
|
| --- /dev/null
|
| +++ b/media/midi/task_service_unittest.cc
|
| @@ -0,0 +1,311 @@
|
| +// 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 "media/midi/task_service.h"
|
| +
|
| +#include <memory>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/callback.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/synchronization/lock.h"
|
| +#include "base/test/test_simple_task_runner.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| +#include "base/time/time.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace midi {
|
| +
|
| +namespace {
|
| +
|
| +constexpr TaskService::RunnerId kDefaultRunner = 0;
|
| +constexpr TaskService::RunnerId kSecondRunner = 1;
|
| +
|
| +base::WaitableEvent* GetEvent() {
|
| + static base::WaitableEvent* event =
|
| + new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
|
| + base::WaitableEvent::InitialState::NOT_SIGNALED);
|
| + return event;
|
| +}
|
| +
|
| +void SignalEvent() {
|
| + GetEvent()->Signal();
|
| +}
|
| +
|
| +void WaitEvent() {
|
| + GetEvent()->Wait();
|
| +}
|
| +
|
| +void ResetEvent() {
|
| + GetEvent()->Reset();
|
| +}
|
| +
|
| +class TaskServiceClient {
|
| + public:
|
| + TaskServiceClient(TaskService* task_service)
|
| + : task_service_(task_service),
|
| + wait_task_event_(base::MakeUnique<base::WaitableEvent>(
|
| + base::WaitableEvent::ResetPolicy::MANUAL,
|
| + base::WaitableEvent::InitialState::NOT_SIGNALED)),
|
| + count_(0u) {
|
| + DCHECK(task_service);
|
| + }
|
| +
|
| + bool Bind() { return task_service()->BindInstance(); }
|
| +
|
| + bool Unbind() { return task_service()->UnbindInstance(); }
|
| +
|
| + void PostBoundTask(TaskService::RunnerId runner_id) {
|
| + task_service()->PostBoundTask(
|
| + runner_id, base::BindOnce(&TaskServiceClient::IncrementCount,
|
| + base::Unretained(this)));
|
| + }
|
| +
|
| + void PostBoundSignalTask(TaskService::RunnerId runner_id) {
|
| + task_service()->PostBoundTask(
|
| + runner_id, base::BindOnce(&TaskServiceClient::SignalEvent,
|
| + base::Unretained(this)));
|
| + }
|
| +
|
| + void PostBoundWaitTask(TaskService::RunnerId runner_id) {
|
| + wait_task_event_->Reset();
|
| + task_service()->PostBoundTask(
|
| + runner_id,
|
| + base::BindOnce(&TaskServiceClient::WaitEvent, base::Unretained(this)));
|
| + }
|
| +
|
| + void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) {
|
| + task_service()->PostBoundDelayedTask(
|
| + runner_id,
|
| + base::BindOnce(&TaskServiceClient::SignalEvent, base::Unretained(this)),
|
| + base::TimeDelta::FromMilliseconds(100));
|
| + }
|
| +
|
| + void PostBoundReplyTask() {
|
| + task_service()->PostBoundReplyTask(base::BindOnce(
|
| + &TaskServiceClient::IncrementCount, base::Unretained(this)));
|
| + }
|
| +
|
| + void WaitTask() { wait_task_event_->Wait(); }
|
| +
|
| + size_t count() {
|
| + base::AutoLock lock(lock_);
|
| + return count_;
|
| + }
|
| +
|
| + private:
|
| + TaskService* task_service() { return task_service_; }
|
| +
|
| + void IncrementCount() {
|
| + base::AutoLock lock(lock_);
|
| + count_++;
|
| + }
|
| +
|
| + void SignalEvent() {
|
| + midi::SignalEvent();
|
| + IncrementCount();
|
| + }
|
| +
|
| + void WaitEvent() {
|
| + wait_task_event_->Signal();
|
| + midi::WaitEvent();
|
| + IncrementCount();
|
| + }
|
| +
|
| + base::Lock lock_;
|
| + TaskService* task_service_;
|
| + std::unique_ptr<base::WaitableEvent> wait_task_event_;
|
| + size_t count_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TaskServiceClient);
|
| +};
|
| +
|
| +class MidiTaskServiceTest : public ::testing::Test {
|
| + public:
|
| + MidiTaskServiceTest() {}
|
| +
|
| + protected:
|
| + TaskService* task_service() { return &task_service_; }
|
| + void RunUntilIdle() { task_runner_->RunUntilIdle(); }
|
| +
|
| + private:
|
| + void SetUp() override {
|
| + ResetEvent();
|
| + task_runner_ = new base::TestSimpleTaskRunner();
|
| + thread_task_runner_handle_ =
|
| + base::MakeUnique<base::ThreadTaskRunnerHandle>(task_runner_);
|
| + }
|
| +
|
| + void TearDown() override {
|
| + thread_task_runner_handle_.reset();
|
| + task_runner_ = NULL;
|
| + }
|
| +
|
| + scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
|
| + std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
|
| + TaskService task_service_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MidiTaskServiceTest);
|
| +};
|
| +
|
| +// Tests if posted static tasks can be processed without any bound instance.
|
| +TEST_F(MidiTaskServiceTest, RunStaticTask) {
|
| + task_service()->PostStaticTask(kDefaultRunner, base::BindOnce(&SignalEvent));
|
| + WaitEvent();
|
| +}
|
| +
|
| +// Tests if posted tasks without calling BindInstance() are ignored.
|
| +TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
|
| + std::unique_ptr<TaskServiceClient> client =
|
| + base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + client->PostBoundTask(kDefaultRunner);
|
| +
|
| + // Destruct |client| immediately, then see if the posted task is just ignored.
|
| + client = nullptr;
|
| +}
|
| +
|
| +// Tests if invalid BindInstance() calls are correctly rejected, and it does not
|
| +// make the service insanity.
|
| +TEST_F(MidiTaskServiceTest, BindTwice) {
|
| + std::unique_ptr<TaskServiceClient> client =
|
| + base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + EXPECT_TRUE(client->Bind());
|
| +
|
| + // Should not be able to call BindInstance() twice before unbinding current
|
| + // bound instance.
|
| + EXPECT_FALSE(client->Bind());
|
| +
|
| + // Should be able to unbind only the first instance.
|
| + EXPECT_TRUE(client->Unbind());
|
| + EXPECT_FALSE(client->Unbind());
|
| +}
|
| +
|
| +// Tests if posted static tasks can be processed even with a bound instance.
|
| +TEST_F(MidiTaskServiceTest, RunStaticTaskWithBoundInstance) {
|
| + std::unique_ptr<TaskServiceClient> client =
|
| + base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + EXPECT_TRUE(client->Bind());
|
| + // Should be able to post a static task even with a bound instance.
|
| + task_service()->PostStaticTask(kDefaultRunner, base::BindOnce(&SignalEvent));
|
| + WaitEvent();
|
| + EXPECT_TRUE(client->Unbind());
|
| +
|
| + ResetEvent();
|
| +
|
| + EXPECT_TRUE(client->Bind());
|
| + task_service()->PostStaticTask(kDefaultRunner, base::Bind(&SignalEvent));
|
| + // Should be able to unbind the instance to process a static task.
|
| + EXPECT_TRUE(client->Unbind());
|
| + WaitEvent();
|
| +}
|
| +
|
| +// Tests functionalities to run bound tasks.
|
| +TEST_F(MidiTaskServiceTest, RunBoundTasks) {
|
| + std::unique_ptr<TaskServiceClient> client =
|
| + base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + EXPECT_TRUE(client->Bind());
|
| +
|
| + // Tests if a post task run.
|
| + EXPECT_EQ(0u, client->count());
|
| + client->PostBoundSignalTask(kDefaultRunner);
|
| + WaitEvent();
|
| + EXPECT_EQ(1u, client->count());
|
| +
|
| + // Tests if another posted task is handled correctly even if the instance is
|
| + // unbound immediately. The posted task should run safely if it starts before
|
| + // UnboundInstance() is call. Otherwise, it should be ignored. It completely
|
| + // depends on timing.
|
| + client->PostBoundTask(kDefaultRunner);
|
| + EXPECT_TRUE(client->Unbind());
|
| + client = base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + // Tests if an immediate call of another BindInstance() works correctly.
|
| + EXPECT_TRUE(client->Bind());
|
| +
|
| + // Runs two tasks in two runners.
|
| + ResetEvent();
|
| + client->PostBoundSignalTask(kDefaultRunner);
|
| + client->PostBoundTask(kSecondRunner);
|
| +
|
| + // Waits only the first runner completion to see if the second runner handles
|
| + // the task correctly even if the bound instance is destructed.
|
| + WaitEvent();
|
| + EXPECT_TRUE(client->Unbind());
|
| + client = nullptr;
|
| +}
|
| +
|
| +// Tests if a blocking task does not block other task runners.
|
| +TEST_F(MidiTaskServiceTest, RunBlockingTask) {
|
| + std::unique_ptr<TaskServiceClient> client =
|
| + base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + EXPECT_TRUE(client->Bind());
|
| +
|
| + // Posts a task that waits until the event is signaled.
|
| + client->PostBoundWaitTask(kDefaultRunner);
|
| + // Confirms if the posted task starts. Now, the task should block in the task
|
| + // until the second task is invoked.
|
| + client->WaitTask();
|
| +
|
| + // Posts another task to the second runner. The task should be able to run
|
| + // even though another posted task is blocking inside a critical section that
|
| + // protects running tasks from an instance unbinding.
|
| + client->PostBoundSignalTask(kSecondRunner);
|
| +
|
| + // Wait until the second task runs.
|
| + WaitEvent();
|
| +
|
| + // UnbindInstance() should wait until any running task finishes so that the
|
| + // instance can be destructed safely.
|
| + EXPECT_TRUE(client->Unbind());
|
| + EXPECT_EQ(2u, client->count());
|
| + client = nullptr;
|
| +}
|
| +
|
| +// Tests if a bound delayed task runs correctly.
|
| +TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
|
| + std::unique_ptr<TaskServiceClient> client =
|
| + base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + EXPECT_TRUE(client->Bind());
|
| +
|
| + // Posts a delayed task that signals after 100msec.
|
| + client->PostBoundDelayedSignalTask(kDefaultRunner);
|
| +
|
| + // Wait until the delayed task runs.
|
| + WaitEvent();
|
| +
|
| + EXPECT_TRUE(client->Unbind());
|
| + EXPECT_EQ(1u, client->count());
|
| + client = nullptr;
|
| +}
|
| +
|
| +// Tests if a bound reply task runs on the thread that bound the instance.
|
| +TEST_F(MidiTaskServiceTest, RunBoundReplyTask) {
|
| + std::unique_ptr<TaskServiceClient> client =
|
| + base::MakeUnique<TaskServiceClient>(task_service());
|
| +
|
| + EXPECT_TRUE(client->Bind());
|
| +
|
| + // Posts a reply task that increments the count on the caller thread.
|
| + client->PostBoundReplyTask();
|
| +
|
| + // The reply task should not run until the current message loop is processed.
|
| + EXPECT_EQ(0u, client->count());
|
| + RunUntilIdle();
|
| + EXPECT_EQ(1u, client->count());
|
| +
|
| + EXPECT_TRUE(client->Unbind());
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +} // namespace midi
|
|
|