blob: e76eeba47183bc597c24a88873393c990b2fc682 [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
60 bool Bind() { return task_service()->BindInstance(); }
61
62 bool Unbind() { return task_service()->UnbindInstance(); }
63
64 void PostBoundTask(TaskService::RunnerId runner_id) {
65 task_service()->PostBoundTask(
66 runner_id, base::BindOnce(&TaskServiceClient::IncrementCount,
67 base::Unretained(this)));
68 }
69
70 void PostBoundSignalTask(TaskService::RunnerId runner_id) {
71 task_service()->PostBoundTask(
72 runner_id, base::BindOnce(&TaskServiceClient::SignalEvent,
73 base::Unretained(this)));
74 }
75
76 void PostBoundWaitTask(TaskService::RunnerId runner_id) {
77 wait_task_event_->Reset();
78 task_service()->PostBoundTask(
79 runner_id,
80 base::BindOnce(&TaskServiceClient::WaitEvent, base::Unretained(this)));
81 }
82
83 void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) {
84 task_service()->PostBoundDelayedTask(
85 runner_id,
86 base::BindOnce(&TaskServiceClient::SignalEvent, base::Unretained(this)),
Peter Kasting99947e52021-10-02 03:06:35 +000087 base::Milliseconds(100));
toyoshimccb8ff92017-06-13 05:31:46 -070088 }
89
90 void WaitTask() { wait_task_event_->Wait(); }
91
92 size_t count() {
93 base::AutoLock lock(lock_);
94 return count_;
95 }
96
97 private:
98 TaskService* task_service() { return task_service_; }
99
100 void IncrementCount() {
101 base::AutoLock lock(lock_);
102 count_++;
103 }
104
105 void SignalEvent() {
toyoshimccb8ff92017-06-13 05:31:46 -0700106 IncrementCount();
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000107 midi::SignalEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700108 }
109
110 void WaitEvent() {
Takashi Toyoshima4f4ef5e2017-07-20 12:19:20 +0000111 IncrementCount();
toyoshimccb8ff92017-06-13 05:31:46 -0700112 wait_task_event_->Signal();
113 midi::WaitEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700114 }
115
116 base::Lock lock_;
117 TaskService* task_service_;
118 std::unique_ptr<base::WaitableEvent> wait_task_event_;
119 size_t count_;
120
121 DISALLOW_COPY_AND_ASSIGN(TaskServiceClient);
122};
123
124class MidiTaskServiceTest : public ::testing::Test {
125 public:
Chris Watkinsc6cbcf62017-12-01 03:08:01 +0000126 MidiTaskServiceTest() = default;
toyoshimccb8ff92017-06-13 05:31:46 -0700127
128 protected:
129 TaskService* task_service() { return &task_service_; }
130 void RunUntilIdle() { task_runner_->RunUntilIdle(); }
131
132 private:
133 void SetUp() override {
134 ResetEvent();
135 task_runner_ = new base::TestSimpleTaskRunner();
136 thread_task_runner_handle_ =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000137 std::make_unique<base::ThreadTaskRunnerHandle>(task_runner_);
toyoshimccb8ff92017-06-13 05:31:46 -0700138 }
139
140 void TearDown() override {
141 thread_task_runner_handle_.reset();
kylechar8d191062019-11-14 23:31:59 +0000142 task_runner_.reset();
toyoshimccb8ff92017-06-13 05:31:46 -0700143 }
144
145 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
146 std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
147 TaskService task_service_;
148
149 DISALLOW_COPY_AND_ASSIGN(MidiTaskServiceTest);
150};
151
toyoshimccb8ff92017-06-13 05:31:46 -0700152// Tests if posted tasks without calling BindInstance() are ignored.
153TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
154 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000155 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700156
157 client->PostBoundTask(kFirstRunner);
158
159 // Destruct |client| immediately, then see if the posted task is just ignored.
160 // If it isn't, another thread will touch the destructed instance and will
161 // cause a crash due to a use-after-free.
162 client = nullptr;
163}
164
165// Tests if invalid BindInstance() calls are correctly rejected, and it does not
166// make the service insanity.
167TEST_F(MidiTaskServiceTest, BindTwice) {
168 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000169 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700170
171 EXPECT_TRUE(client->Bind());
172
173 // Should not be able to call BindInstance() twice before unbinding current
174 // bound instance.
175 EXPECT_FALSE(client->Bind());
176
177 // Should be able to unbind only the first instance.
178 EXPECT_TRUE(client->Unbind());
179 EXPECT_FALSE(client->Unbind());
180}
181
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000182// Tests if posted static tasks can be processed correctly.
183TEST_F(MidiTaskServiceTest, RunStaticTask) {
toyoshimccb8ff92017-06-13 05:31:46 -0700184 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000185 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700186
187 EXPECT_TRUE(client->Bind());
Takashi Toyoshima5bbd0f82017-07-04 17:05:09 +0000188 // Should be able to post a static task while an instance is bound.
toyoshimccb8ff92017-06-13 05:31:46 -0700189 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
190 WaitEvent();
191 EXPECT_TRUE(client->Unbind());
192
193 ResetEvent();
194
195 EXPECT_TRUE(client->Bind());
Takashi Toyoshimad2bdc592017-09-13 10:02:54 +0000196 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
toyoshimccb8ff92017-06-13 05:31:46 -0700197 // Should be able to unbind the instance to process a static task.
198 EXPECT_TRUE(client->Unbind());
199 WaitEvent();
Takashi Toyoshima3f0ea8f2018-01-17 09:19:59 +0000200
201 ResetEvent();
202
203 // Should be able to post a static task without a bound instance.
204 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
205 WaitEvent();
toyoshimccb8ff92017-06-13 05:31:46 -0700206}
207
208// Tests functionalities to run bound tasks.
209TEST_F(MidiTaskServiceTest, RunBoundTasks) {
210 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000211 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700212
213 EXPECT_TRUE(client->Bind());
214
215 // Tests if a post task run.
216 EXPECT_EQ(0u, client->count());
217 client->PostBoundSignalTask(kFirstRunner);
218 WaitEvent();
219 EXPECT_EQ(1u, client->count());
220
221 // Tests if another posted task is handled correctly even if the instance is
222 // unbound immediately. The posted task should run safely if it starts before
223 // UnboundInstance() is call. Otherwise, it should be ignored. It completely
224 // depends on timing.
225 client->PostBoundTask(kFirstRunner);
226 EXPECT_TRUE(client->Unbind());
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000227 client = std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700228
229 // Tests if an immediate call of another BindInstance() works correctly.
230 EXPECT_TRUE(client->Bind());
231
232 // Runs two tasks in two runners.
233 ResetEvent();
234 client->PostBoundSignalTask(kFirstRunner);
235 client->PostBoundTask(kSecondRunner);
236
237 // Waits only the first runner completion to see if the second runner handles
238 // the task correctly even if the bound instance is destructed.
239 WaitEvent();
240 EXPECT_TRUE(client->Unbind());
241 client = nullptr;
242}
243
244// Tests if a blocking task does not block other task runners.
245TEST_F(MidiTaskServiceTest, RunBlockingTask) {
246 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000247 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700248
249 EXPECT_TRUE(client->Bind());
250
251 // Posts a task that waits until the event is signaled.
252 client->PostBoundWaitTask(kFirstRunner);
253 // Confirms if the posted task starts. Now, the task should block in the task
254 // until the second task is invoked.
255 client->WaitTask();
256
257 // Posts another task to the second runner. The task should be able to run
258 // even though another posted task is blocking inside a critical section that
259 // protects running tasks from an instance unbinding.
260 client->PostBoundSignalTask(kSecondRunner);
261
262 // Wait until the second task runs.
263 WaitEvent();
264
265 // UnbindInstance() should wait until any running task finishes so that the
266 // instance can be destructed safely.
267 EXPECT_TRUE(client->Unbind());
268 EXPECT_EQ(2u, client->count());
269 client = nullptr;
270}
271
272// Tests if a bound delayed task runs correctly.
273TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
274 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000275 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700276
277 EXPECT_TRUE(client->Bind());
278
279 // Posts a delayed task that signals after 100msec.
280 client->PostBoundDelayedSignalTask(kFirstRunner);
281
282 // Wait until the delayed task runs.
283 WaitEvent();
284
285 EXPECT_TRUE(client->Unbind());
286 EXPECT_EQ(1u, client->count());
287 client = nullptr;
288}
289
290// Tests if a bound task runs on the thread that bound the instance.
291TEST_F(MidiTaskServiceTest, RunBoundTaskOnDefaultRunner) {
292 std::unique_ptr<TaskServiceClient> client =
Gyuyoung Kim34e191a2018-01-10 09:48:42 +0000293 std::make_unique<TaskServiceClient>(task_service());
toyoshimccb8ff92017-06-13 05:31:46 -0700294
295 EXPECT_TRUE(client->Bind());
296
297 // Posts a task that increments the count on the caller thread.
298 client->PostBoundTask(kDefaultRunner);
299
300 // The posted task should not run until the current message loop is processed.
301 EXPECT_EQ(0u, client->count());
302 RunUntilIdle();
303 EXPECT_EQ(1u, client->count());
304
305 EXPECT_TRUE(client->Unbind());
306}
307
308} // namespace
309
310} // namespace midi