blob: bc359fbed547e4ad4464686034ce22b4cdf29453 [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"
toyoshimccb8ff92017-06-13 05:31:46 -070010#include "base/callback.h"
danakj70310852020-11-11 16:01:35 +000011#include "base/callback_helpers.h"
toyoshimccb8ff92017-06-13 05:31:46 -070012#include "base/memory/ref_counted.h"
13#include "base/run_loop.h"
14#include "base/synchronization/lock.h"
15#include "base/test/test_simple_task_runner.h"
16#include "base/threading/thread_task_runner_handle.h"
17#include "base/time/time.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20namespace midi {
21
22namespace {
23
24enum {
25 kDefaultRunner = TaskService::kDefaultRunnerId,
26 kFirstRunner,
27 kSecondRunner
28};
29
30base::WaitableEvent* GetEvent() {
31 static base::WaitableEvent* event =
32 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
33 base::WaitableEvent::InitialState::NOT_SIGNALED);
34 return event;
35}
36
37void SignalEvent() {
38 GetEvent()->Signal();
39}
40
41void WaitEvent() {
42 GetEvent()->Wait();
43}
44
45void ResetEvent() {
46 GetEvent()->Reset();
47}
48
49class TaskServiceClient {
50 public:
51 TaskServiceClient(TaskService* task_service)
52 : task_service_(task_service),
Gyuyoung Kim34e191a2018-01-10 09:48:42 +000053 wait_task_event_(std::make_unique<base::WaitableEvent>(
toyoshimccb8ff92017-06-13 05:31:46 -070054 base::WaitableEvent::ResetPolicy::MANUAL,
55 base::WaitableEvent::InitialState::NOT_SIGNALED)),
56 count_(0u) {
57 DCHECK(task_service);
58 }
59
Peter Boström5e5c4fa2021-10-15 21:43:24 +000060 TaskServiceClient(const TaskServiceClient&) = delete;
61 TaskServiceClient& operator=(const TaskServiceClient&) = delete;
62
toyoshimccb8ff92017-06-13 05:31:46 -070063 bool Bind() { return task_service()->BindInstance(); }
64
65 bool Unbind() { return task_service()->UnbindInstance(); }
66
67 void PostBoundTask(TaskService::RunnerId runner_id) {
68 task_service()->PostBoundTask(
69 runner_id, base::BindOnce(&TaskServiceClient::IncrementCount,
70 base::Unretained(this)));
71 }
72
73 void PostBoundSignalTask(TaskService::RunnerId runner_id) {
74 task_service()->PostBoundTask(
75 runner_id, base::BindOnce(&TaskServiceClient::SignalEvent,
76 base::Unretained(this)));
77 }
78
79 void PostBoundWaitTask(TaskService::RunnerId runner_id) {
80 wait_task_event_->Reset();
81 task_service()->PostBoundTask(
82 runner_id,
83 base::BindOnce(&TaskServiceClient::WaitEvent, base::Unretained(this)));
84 }
85
86 void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) {
87 task_service()->PostBoundDelayedTask(
88 runner_id,
89 base::BindOnce(&TaskServiceClient::SignalEvent, base::Unretained(this)),
Peter Kasting99947e52021-10-02 03:06:35 +000090 base::Milliseconds(100));
toyoshimccb8ff92017-06-13 05:31:46 -070091 }
92
93 void WaitTask() { wait_task_event_->Wait(); }
94
95 size_t count() {
96 base::AutoLock lock(lock_);
97 return count_;
98 }
99
100 private:
101 TaskService* task_service() { return task_service_; }
102
103 void IncrementCount() {
104 base::AutoLock lock(lock_);
105 count_++;
106 }
107
108 void SignalEvent() {
toyoshimccb8ff92017-06-13 05:31:46 -0700109 IncrementCount();
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000110 midi::SignalEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700111 }
112
113 void WaitEvent() {
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000114 IncrementCount();
toyoshimccb8ff92017-06-13 05:31:46 -0700115 wait_task_event_->Signal();
116 midi::WaitEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700117 }
118
119 base::Lock lock_;
120 TaskService* task_service_;
121 std::unique_ptr<base::WaitableEvent> wait_task_event_;
122 size_t count_;
toyoshimccb8ff92017-06-13 05:31:46 -0700123};
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
Peter Boström5e5c4fa2021-10-15 21:43:24 +0000129 MidiTaskServiceTest(const MidiTaskServiceTest&) = delete;
130 MidiTaskServiceTest& operator=(const MidiTaskServiceTest&) = delete;
131
toyoshimccb8ff92017-06-13 05:31:46 -0700132 protected:
133 TaskService* task_service() { return &task_service_; }
134 void RunUntilIdle() { task_runner_->RunUntilIdle(); }
135
136 private:
137 void SetUp() override {
138 ResetEvent();
139 task_runner_ = new base::TestSimpleTaskRunner();
140 thread_task_runner_handle_ =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000141 std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
toyoshimccb8ff92017-06-13 05:31:46 -0700142 }
143
144 void TearDown() override {
145 thread_task_runner_handle_.reset();
kylechar8d191062019-11-14 23:31:59 +0000146 task_runner_.reset();
toyoshimccb8ff92017-06-13 05:31:46 -0700147 }
148
149 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
150 std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
151 TaskService task_service_;
toyoshimccb8ff92017-06-13 05:31:46 -0700152};
153
toyoshimccb8ff92017-06-13 05:31:46 -0700154// Tests if posted tasks without calling BindInstance() are ignored.
155TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
156 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000157 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700158
159 client->PostBoundTask(kFirstRunner);
160
161 // Destruct |client| immediately, then see if the posted task is just ignored.
162 // If it isn't, another thread will touch the destructed instance and will
163 // cause a crash due to a use-after-free.
164 client = nullptr;
165}
166
167// Tests if invalid BindInstance() calls are correctly rejected, and it does not
168// make the service insanity.
169TEST_F(MidiTaskServiceTest, BindTwice) {
170 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000171 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700172
173 EXPECT_TRUE(client->Bind());
174
175 // Should not be able to call BindInstance() twice before unbinding current
176 // bound instance.
177 EXPECT_FALSE(client->Bind());
178
179 // Should be able to unbind only the first instance.
180 EXPECT_TRUE(client->Unbind());
181 EXPECT_FALSE(client->Unbind());
182}
183
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000184// Tests if posted static tasks can be processed correctly.
185TEST_F(MidiTaskServiceTest, RunStaticTask) {
toyoshimccb8ff92017-06-13 05:31:46 -0700186 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000187 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700188
189 EXPECT_TRUE(client->Bind());
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000190 // Should be able to post a static task while an instance is bound.
toyoshimccb8ff92017-06-13 05:31:46 -0700191 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
192 WaitEvent();
193 EXPECT_TRUE(client->Unbind());
194
195 ResetEvent();
196
197 EXPECT_TRUE(client->Bind());
Takashi Toyoshimad2bdc592017-09-13 10:02:54 +0000198 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
toyoshimccb8ff92017-06-13 05:31:46 -0700199 // Should be able to unbind the instance to process a static task.
200 EXPECT_TRUE(client->Unbind());
201 WaitEvent();
Takashi Toyoshima3f0ea8f2018-01-17 09:19:59 +0000202
203 ResetEvent();
204
205 // Should be able to post a static task without a bound instance.
206 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
207 WaitEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700208}
209
210// Tests functionalities to run bound tasks.
211TEST_F(MidiTaskServiceTest, RunBoundTasks) {
212 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000213 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700214
215 EXPECT_TRUE(client->Bind());
216
217 // Tests if a post task run.
218 EXPECT_EQ(0u, client->count());
219 client->PostBoundSignalTask(kFirstRunner);
220 WaitEvent();
221 EXPECT_EQ(1u, client->count());
222
223 // Tests if another posted task is handled correctly even if the instance is
224 // unbound immediately. The posted task should run safely if it starts before
225 // UnboundInstance() is call. Otherwise, it should be ignored. It completely
226 // depends on timing.
227 client->PostBoundTask(kFirstRunner);
228 EXPECT_TRUE(client->Unbind());
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000229 client = std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700230
231 // Tests if an immediate call of another BindInstance() works correctly.
232 EXPECT_TRUE(client->Bind());
233
234 // Runs two tasks in two runners.
235 ResetEvent();
236 client->PostBoundSignalTask(kFirstRunner);
237 client->PostBoundTask(kSecondRunner);
238
239 // Waits only the first runner completion to see if the second runner handles
240 // the task correctly even if the bound instance is destructed.
241 WaitEvent();
242 EXPECT_TRUE(client->Unbind());
243 client = nullptr;
244}
245
246// Tests if a blocking task does not block other task runners.
247TEST_F(MidiTaskServiceTest, RunBlockingTask) {
248 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000249 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700250
251 EXPECT_TRUE(client->Bind());
252
253 // Posts a task that waits until the event is signaled.
254 client->PostBoundWaitTask(kFirstRunner);
255 // Confirms if the posted task starts. Now, the task should block in the task
256 // until the second task is invoked.
257 client->WaitTask();
258
259 // Posts another task to the second runner. The task should be able to run
260 // even though another posted task is blocking inside a critical section that
261 // protects running tasks from an instance unbinding.
262 client->PostBoundSignalTask(kSecondRunner);
263
264 // Wait until the second task runs.
265 WaitEvent();
266
267 // UnbindInstance() should wait until any running task finishes so that the
268 // instance can be destructed safely.
269 EXPECT_TRUE(client->Unbind());
270 EXPECT_EQ(2u, client->count());
271 client = nullptr;
272}
273
274// Tests if a bound delayed task runs correctly.
275TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
276 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000277 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700278
279 EXPECT_TRUE(client->Bind());
280
281 // Posts a delayed task that signals after 100msec.
282 client->PostBoundDelayedSignalTask(kFirstRunner);
283
284 // Wait until the delayed task runs.
285 WaitEvent();
286
287 EXPECT_TRUE(client->Unbind());
288 EXPECT_EQ(1u, client->count());
289 client = nullptr;
290}
291
292// Tests if a bound task runs on the thread that bound the instance.
293TEST_F(MidiTaskServiceTest, RunBoundTaskOnDefaultRunner) {
294 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000295 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700296
297 EXPECT_TRUE(client->Bind());
298
299 // Posts a task that increments the count on the caller thread.
300 client->PostBoundTask(kDefaultRunner);
301
302 // The posted task should not run until the current message loop is processed.
303 EXPECT_EQ(0u, client->count());
304 RunUntilIdle();
305 EXPECT_EQ(1u, client->count());
306
307 EXPECT_TRUE(client->Unbind());
308}
309
310} // namespace
311
312} // namespace midi