blob: 2c60323fc7b4c2c9b3d0070f7011904f5cab8aac [file] [log] [blame]
toyoshimccb8ff92017-06-13 05:31:46 -07001// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/midi/task_service.h"
6
7#include <memory>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/memory/ptr_util.h"
13#include "base/memory/ref_counted.h"
14#include "base/run_loop.h"
15#include "base/synchronization/lock.h"
16#include "base/test/test_simple_task_runner.h"
17#include "base/threading/thread_task_runner_handle.h"
18#include "base/time/time.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace midi {
22
23namespace {
24
25enum {
26 kDefaultRunner = TaskService::kDefaultRunnerId,
27 kFirstRunner,
28 kSecondRunner
29};
30
31base::WaitableEvent* GetEvent() {
32 static base::WaitableEvent* event =
33 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
34 base::WaitableEvent::InitialState::NOT_SIGNALED);
35 return event;
36}
37
38void SignalEvent() {
39 GetEvent()->Signal();
40}
41
42void WaitEvent() {
43 GetEvent()->Wait();
44}
45
46void ResetEvent() {
47 GetEvent()->Reset();
48}
49
50class TaskServiceClient {
51 public:
52 TaskServiceClient(TaskService* task_service)
53 : task_service_(task_service),
54 wait_task_event_(base::MakeUnique<base::WaitableEvent>(
55 base::WaitableEvent::ResetPolicy::MANUAL,
56 base::WaitableEvent::InitialState::NOT_SIGNALED)),
57 count_(0u) {
58 DCHECK(task_service);
59 }
60
61 bool Bind() { return task_service()->BindInstance(); }
62
63 bool Unbind() { return task_service()->UnbindInstance(); }
64
65 void PostBoundTask(TaskService::RunnerId runner_id) {
66 task_service()->PostBoundTask(
67 runner_id, base::BindOnce(&TaskServiceClient::IncrementCount,
68 base::Unretained(this)));
69 }
70
71 void PostBoundSignalTask(TaskService::RunnerId runner_id) {
72 task_service()->PostBoundTask(
73 runner_id, base::BindOnce(&TaskServiceClient::SignalEvent,
74 base::Unretained(this)));
75 }
76
77 void PostBoundWaitTask(TaskService::RunnerId runner_id) {
78 wait_task_event_->Reset();
79 task_service()->PostBoundTask(
80 runner_id,
81 base::BindOnce(&TaskServiceClient::WaitEvent, base::Unretained(this)));
82 }
83
84 void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) {
85 task_service()->PostBoundDelayedTask(
86 runner_id,
87 base::BindOnce(&TaskServiceClient::SignalEvent, base::Unretained(this)),
88 base::TimeDelta::FromMilliseconds(100));
89 }
90
91 void WaitTask() { wait_task_event_->Wait(); }
92
93 size_t count() {
94 base::AutoLock lock(lock_);
95 return count_;
96 }
97
98 private:
99 TaskService* task_service() { return task_service_; }
100
101 void IncrementCount() {
102 base::AutoLock lock(lock_);
103 count_++;
104 }
105
106 void SignalEvent() {
toyoshimccb8ff92017-06-13 05:31:46 -0700107 IncrementCount();
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000108 midi::SignalEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700109 }
110
111 void WaitEvent() {
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000112 IncrementCount();
toyoshimccb8ff92017-06-13 05:31:46 -0700113 wait_task_event_->Signal();
114 midi::WaitEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700115 }
116
117 base::Lock lock_;
118 TaskService* task_service_;
119 std::unique_ptr<base::WaitableEvent> wait_task_event_;
120 size_t count_;
121
122 DISALLOW_COPY_AND_ASSIGN(TaskServiceClient);
123};
124
125class MidiTaskServiceTest : public ::testing::Test {
126 public:
Chris Watkinsc6cbcf62017-12-01 03:08:01 +0000127 MidiTaskServiceTest() = default;
toyoshimccb8ff92017-06-13 05:31:46 -0700128
129 protected:
130 TaskService* task_service() { return &task_service_; }
131 void RunUntilIdle() { task_runner_->RunUntilIdle(); }
132
133 private:
134 void SetUp() override {
135 ResetEvent();
136 task_runner_ = new base::TestSimpleTaskRunner();
137 thread_task_runner_handle_ =
138 base::MakeUnique<base::ThreadTaskRunnerHandle>(task_runner_);
139 }
140
141 void TearDown() override {
142 thread_task_runner_handle_.reset();
143 task_runner_ = NULL;
144 }
145
146 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
147 std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
148 TaskService task_service_;
149
150 DISALLOW_COPY_AND_ASSIGN(MidiTaskServiceTest);
151};
152
toyoshimccb8ff92017-06-13 05:31:46 -0700153// Tests if posted tasks without calling BindInstance() are ignored.
154TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
155 std::unique_ptr<TaskServiceClient> client =
156 base::MakeUnique<TaskServiceClient>(task_service());
157
158 client->PostBoundTask(kFirstRunner);
159
160 // Destruct |client| immediately, then see if the posted task is just ignored.
161 // If it isn't, another thread will touch the destructed instance and will
162 // cause a crash due to a use-after-free.
163 client = nullptr;
164}
165
166// Tests if invalid BindInstance() calls are correctly rejected, and it does not
167// make the service insanity.
168TEST_F(MidiTaskServiceTest, BindTwice) {
169 std::unique_ptr<TaskServiceClient> client =
170 base::MakeUnique<TaskServiceClient>(task_service());
171
172 EXPECT_TRUE(client->Bind());
173
174 // Should not be able to call BindInstance() twice before unbinding current
175 // bound instance.
176 EXPECT_FALSE(client->Bind());
177
178 // Should be able to unbind only the first instance.
179 EXPECT_TRUE(client->Unbind());
180 EXPECT_FALSE(client->Unbind());
181}
182
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000183// Tests if posted static tasks can be processed correctly.
184TEST_F(MidiTaskServiceTest, RunStaticTask) {
toyoshimccb8ff92017-06-13 05:31:46 -0700185 std::unique_ptr<TaskServiceClient> client =
186 base::MakeUnique<TaskServiceClient>(task_service());
187
188 EXPECT_TRUE(client->Bind());
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000189 // Should be able to post a static task while an instance is bound.
toyoshimccb8ff92017-06-13 05:31:46 -0700190 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
191 WaitEvent();
192 EXPECT_TRUE(client->Unbind());
193
194 ResetEvent();
195
196 EXPECT_TRUE(client->Bind());
Takashi Toyoshimad2bdc592017-09-13 10:02:54 +0000197 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
toyoshimccb8ff92017-06-13 05:31:46 -0700198 // Should be able to unbind the instance to process a static task.
199 EXPECT_TRUE(client->Unbind());
200 WaitEvent();
201}
202
203// Tests functionalities to run bound tasks.
204TEST_F(MidiTaskServiceTest, RunBoundTasks) {
205 std::unique_ptr<TaskServiceClient> client =
206 base::MakeUnique<TaskServiceClient>(task_service());
207
208 EXPECT_TRUE(client->Bind());
209
210 // Tests if a post task run.
211 EXPECT_EQ(0u, client->count());
212 client->PostBoundSignalTask(kFirstRunner);
213 WaitEvent();
214 EXPECT_EQ(1u, client->count());
215
216 // Tests if another posted task is handled correctly even if the instance is
217 // unbound immediately. The posted task should run safely if it starts before
218 // UnboundInstance() is call. Otherwise, it should be ignored. It completely
219 // depends on timing.
220 client->PostBoundTask(kFirstRunner);
221 EXPECT_TRUE(client->Unbind());
222 client = base::MakeUnique<TaskServiceClient>(task_service());
223
224 // Tests if an immediate call of another BindInstance() works correctly.
225 EXPECT_TRUE(client->Bind());
226
227 // Runs two tasks in two runners.
228 ResetEvent();
229 client->PostBoundSignalTask(kFirstRunner);
230 client->PostBoundTask(kSecondRunner);
231
232 // Waits only the first runner completion to see if the second runner handles
233 // the task correctly even if the bound instance is destructed.
234 WaitEvent();
235 EXPECT_TRUE(client->Unbind());
236 client = nullptr;
237}
238
239// Tests if a blocking task does not block other task runners.
240TEST_F(MidiTaskServiceTest, RunBlockingTask) {
241 std::unique_ptr<TaskServiceClient> client =
242 base::MakeUnique<TaskServiceClient>(task_service());
243
244 EXPECT_TRUE(client->Bind());
245
246 // Posts a task that waits until the event is signaled.
247 client->PostBoundWaitTask(kFirstRunner);
248 // Confirms if the posted task starts. Now, the task should block in the task
249 // until the second task is invoked.
250 client->WaitTask();
251
252 // Posts another task to the second runner. The task should be able to run
253 // even though another posted task is blocking inside a critical section that
254 // protects running tasks from an instance unbinding.
255 client->PostBoundSignalTask(kSecondRunner);
256
257 // Wait until the second task runs.
258 WaitEvent();
259
260 // UnbindInstance() should wait until any running task finishes so that the
261 // instance can be destructed safely.
262 EXPECT_TRUE(client->Unbind());
263 EXPECT_EQ(2u, client->count());
264 client = nullptr;
265}
266
267// Tests if a bound delayed task runs correctly.
268TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
269 std::unique_ptr<TaskServiceClient> client =
270 base::MakeUnique<TaskServiceClient>(task_service());
271
272 EXPECT_TRUE(client->Bind());
273
274 // Posts a delayed task that signals after 100msec.
275 client->PostBoundDelayedSignalTask(kFirstRunner);
276
277 // Wait until the delayed task runs.
278 WaitEvent();
279
280 EXPECT_TRUE(client->Unbind());
281 EXPECT_EQ(1u, client->count());
282 client = nullptr;
283}
284
285// Tests if a bound task runs on the thread that bound the instance.
286TEST_F(MidiTaskServiceTest, RunBoundTaskOnDefaultRunner) {
287 std::unique_ptr<TaskServiceClient> client =
288 base::MakeUnique<TaskServiceClient>(task_service());
289
290 EXPECT_TRUE(client->Bind());
291
292 // Posts a task that increments the count on the caller thread.
293 client->PostBoundTask(kDefaultRunner);
294
295 // The posted task should not run until the current message loop is processed.
296 EXPECT_EQ(0u, client->count());
297 RunUntilIdle();
298 EXPECT_EQ(1u, client->count());
299
300 EXPECT_TRUE(client->Unbind());
301}
302
303} // namespace
304
305} // namespace midi