blob: 60f852be8de53209c9949859d75e65a112c1cc53 [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"
Keishi Hattori5b8de612021-11-27 09:25:52 +000012#include "base/memory/raw_ptr.h"
toyoshimccb8ff92017-06-13 05:31:46 -070013#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),
Gyuyoung Kim34e191a2018-01-10 09:48:42 +000054 wait_task_event_(std::make_unique<base::WaitableEvent>(
toyoshimccb8ff92017-06-13 05:31:46 -070055 base::WaitableEvent::ResetPolicy::MANUAL,
56 base::WaitableEvent::InitialState::NOT_SIGNALED)),
57 count_(0u) {
58 DCHECK(task_service);
59 }
60
Peter Boström5e5c4fa2021-10-15 21:43:24 +000061 TaskServiceClient(const TaskServiceClient&) = delete;
62 TaskServiceClient& operator=(const TaskServiceClient&) = delete;
63
toyoshimccb8ff92017-06-13 05:31:46 -070064 bool Bind() { return task_service()->BindInstance(); }
65
66 bool Unbind() { return task_service()->UnbindInstance(); }
67
68 void PostBoundTask(TaskService::RunnerId runner_id) {
69 task_service()->PostBoundTask(
70 runner_id, base::BindOnce(&TaskServiceClient::IncrementCount,
71 base::Unretained(this)));
72 }
73
74 void PostBoundSignalTask(TaskService::RunnerId runner_id) {
75 task_service()->PostBoundTask(
76 runner_id, base::BindOnce(&TaskServiceClient::SignalEvent,
77 base::Unretained(this)));
78 }
79
80 void PostBoundWaitTask(TaskService::RunnerId runner_id) {
81 wait_task_event_->Reset();
82 task_service()->PostBoundTask(
83 runner_id,
84 base::BindOnce(&TaskServiceClient::WaitEvent, base::Unretained(this)));
85 }
86
87 void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) {
88 task_service()->PostBoundDelayedTask(
89 runner_id,
90 base::BindOnce(&TaskServiceClient::SignalEvent, base::Unretained(this)),
Peter Kasting99947e52021-10-02 03:06:35 +000091 base::Milliseconds(100));
toyoshimccb8ff92017-06-13 05:31:46 -070092 }
93
94 void WaitTask() { wait_task_event_->Wait(); }
95
96 size_t count() {
97 base::AutoLock lock(lock_);
98 return count_;
99 }
100
101 private:
102 TaskService* task_service() { return task_service_; }
103
104 void IncrementCount() {
105 base::AutoLock lock(lock_);
106 count_++;
107 }
108
109 void SignalEvent() {
toyoshimccb8ff92017-06-13 05:31:46 -0700110 IncrementCount();
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000111 midi::SignalEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700112 }
113
114 void WaitEvent() {
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000115 IncrementCount();
toyoshimccb8ff92017-06-13 05:31:46 -0700116 wait_task_event_->Signal();
117 midi::WaitEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700118 }
119
120 base::Lock lock_;
Keishi Hattori5b8de612021-11-27 09:25:52 +0000121 raw_ptr<TaskService> task_service_;
toyoshimccb8ff92017-06-13 05:31:46 -0700122 std::unique_ptr<base::WaitableEvent> wait_task_event_;
123 size_t count_;
toyoshimccb8ff92017-06-13 05:31:46 -0700124};
125
126class MidiTaskServiceTest : public ::testing::Test {
127 public:
Chris Watkinsc6cbcf62017-12-01 03:08:01 +0000128 MidiTaskServiceTest() = default;
toyoshimccb8ff92017-06-13 05:31:46 -0700129
Peter Boström5e5c4fa2021-10-15 21:43:24 +0000130 MidiTaskServiceTest(const MidiTaskServiceTest&) = delete;
131 MidiTaskServiceTest& operator=(const MidiTaskServiceTest&) = delete;
132
toyoshimccb8ff92017-06-13 05:31:46 -0700133 protected:
134 TaskService* task_service() { return &task_service_; }
135 void RunUntilIdle() { task_runner_->RunUntilIdle(); }
136
137 private:
138 void SetUp() override {
139 ResetEvent();
140 task_runner_ = new base::TestSimpleTaskRunner();
141 thread_task_runner_handle_ =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000142 std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
toyoshimccb8ff92017-06-13 05:31:46 -0700143 }
144
145 void TearDown() override {
146 thread_task_runner_handle_.reset();
kylechar8d191062019-11-14 23:31:59 +0000147 task_runner_.reset();
toyoshimccb8ff92017-06-13 05:31:46 -0700148 }
149
150 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
151 std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
152 TaskService task_service_;
toyoshimccb8ff92017-06-13 05:31:46 -0700153};
154
toyoshimccb8ff92017-06-13 05:31:46 -0700155// Tests if posted tasks without calling BindInstance() are ignored.
156TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
157 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000158 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700159
160 client->PostBoundTask(kFirstRunner);
161
162 // Destruct |client| immediately, then see if the posted task is just ignored.
163 // If it isn't, another thread will touch the destructed instance and will
164 // cause a crash due to a use-after-free.
165 client = nullptr;
166}
167
168// Tests if invalid BindInstance() calls are correctly rejected, and it does not
169// make the service insanity.
170TEST_F(MidiTaskServiceTest, BindTwice) {
171 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000172 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700173
174 EXPECT_TRUE(client->Bind());
175
176 // Should not be able to call BindInstance() twice before unbinding current
177 // bound instance.
178 EXPECT_FALSE(client->Bind());
179
180 // Should be able to unbind only the first instance.
181 EXPECT_TRUE(client->Unbind());
182 EXPECT_FALSE(client->Unbind());
183}
184
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000185// Tests if posted static tasks can be processed correctly.
186TEST_F(MidiTaskServiceTest, RunStaticTask) {
toyoshimccb8ff92017-06-13 05:31:46 -0700187 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000188 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700189
190 EXPECT_TRUE(client->Bind());
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000191 // Should be able to post a static task while an instance is bound.
toyoshimccb8ff92017-06-13 05:31:46 -0700192 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
193 WaitEvent();
194 EXPECT_TRUE(client->Unbind());
195
196 ResetEvent();
197
198 EXPECT_TRUE(client->Bind());
Takashi Toyoshimad2bdc592017-09-13 10:02:54 +0000199 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
toyoshimccb8ff92017-06-13 05:31:46 -0700200 // Should be able to unbind the instance to process a static task.
201 EXPECT_TRUE(client->Unbind());
202 WaitEvent();
Takashi Toyoshima3f0ea8f2018-01-17 09:19:59 +0000203
204 ResetEvent();
205
206 // Should be able to post a static task without a bound instance.
207 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
208 WaitEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700209}
210
211// Tests functionalities to run bound tasks.
212TEST_F(MidiTaskServiceTest, RunBoundTasks) {
213 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000214 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700215
216 EXPECT_TRUE(client->Bind());
217
218 // Tests if a post task run.
219 EXPECT_EQ(0u, client->count());
220 client->PostBoundSignalTask(kFirstRunner);
221 WaitEvent();
222 EXPECT_EQ(1u, client->count());
223
224 // Tests if another posted task is handled correctly even if the instance is
225 // unbound immediately. The posted task should run safely if it starts before
226 // UnboundInstance() is call. Otherwise, it should be ignored. It completely
227 // depends on timing.
228 client->PostBoundTask(kFirstRunner);
229 EXPECT_TRUE(client->Unbind());
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000230 client = std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700231
232 // Tests if an immediate call of another BindInstance() works correctly.
233 EXPECT_TRUE(client->Bind());
234
235 // Runs two tasks in two runners.
236 ResetEvent();
237 client->PostBoundSignalTask(kFirstRunner);
238 client->PostBoundTask(kSecondRunner);
239
240 // Waits only the first runner completion to see if the second runner handles
241 // the task correctly even if the bound instance is destructed.
242 WaitEvent();
243 EXPECT_TRUE(client->Unbind());
244 client = nullptr;
245}
246
247// Tests if a blocking task does not block other task runners.
248TEST_F(MidiTaskServiceTest, RunBlockingTask) {
249 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000250 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700251
252 EXPECT_TRUE(client->Bind());
253
254 // Posts a task that waits until the event is signaled.
255 client->PostBoundWaitTask(kFirstRunner);
256 // Confirms if the posted task starts. Now, the task should block in the task
257 // until the second task is invoked.
258 client->WaitTask();
259
260 // Posts another task to the second runner. The task should be able to run
261 // even though another posted task is blocking inside a critical section that
262 // protects running tasks from an instance unbinding.
263 client->PostBoundSignalTask(kSecondRunner);
264
265 // Wait until the second task runs.
266 WaitEvent();
267
268 // UnbindInstance() should wait until any running task finishes so that the
269 // instance can be destructed safely.
270 EXPECT_TRUE(client->Unbind());
271 EXPECT_EQ(2u, client->count());
272 client = nullptr;
273}
274
275// Tests if a bound delayed task runs correctly.
276TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
277 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000278 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700279
280 EXPECT_TRUE(client->Bind());
281
282 // Posts a delayed task that signals after 100msec.
283 client->PostBoundDelayedSignalTask(kFirstRunner);
284
285 // Wait until the delayed task runs.
286 WaitEvent();
287
288 EXPECT_TRUE(client->Unbind());
289 EXPECT_EQ(1u, client->count());
290 client = nullptr;
291}
292
293// Tests if a bound task runs on the thread that bound the instance.
294TEST_F(MidiTaskServiceTest, RunBoundTaskOnDefaultRunner) {
295 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000296 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700297
298 EXPECT_TRUE(client->Bind());
299
300 // Posts a task that increments the count on the caller thread.
301 client->PostBoundTask(kDefaultRunner);
302
303 // The posted task should not run until the current message loop is processed.
304 EXPECT_EQ(0u, client->count());
305 RunUntilIdle();
306 EXPECT_EQ(1u, client->count());
307
308 EXPECT_TRUE(client->Unbind());
309}
310
311} // namespace
312
313} // namespace midi