Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Side by Side Diff: media/midi/task_service_unittest.cc

Issue 2741713002: Web MIDI: implement TaskService (Closed)
Patch Set: review #35 Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/midi/task_service.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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
21 namespace midi {
22
23 namespace {
24
25 enum {
26 kDefaultRunner = TaskService::kDefaultRunnerId,
27 kFirstRunner,
28 kSecondRunner
29 };
30
31 base::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
38 void SignalEvent() {
39 GetEvent()->Signal();
40 }
41
42 void WaitEvent() {
43 GetEvent()->Wait();
44 }
45
46 void ResetEvent() {
47 GetEvent()->Reset();
48 }
49
50 class 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() {
107 midi::SignalEvent();
108 IncrementCount();
109 }
110
111 void WaitEvent() {
112 wait_task_event_->Signal();
113 midi::WaitEvent();
114 IncrementCount();
115 }
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
125 class MidiTaskServiceTest : public ::testing::Test {
126 public:
127 MidiTaskServiceTest() {}
128
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
153 // Tests if posted static tasks can be processed without any bound instance.
154 TEST_F(MidiTaskServiceTest, RunStaticTask) {
155 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
156 WaitEvent();
157 }
158
159 // Tests if posted tasks without calling BindInstance() are ignored.
160 TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
161 std::unique_ptr<TaskServiceClient> client =
162 base::MakeUnique<TaskServiceClient>(task_service());
163
164 client->PostBoundTask(kFirstRunner);
165
166 // Destruct |client| immediately, then see if the posted task is just ignored.
167 // If it isn't, another thread will touch the destructed instance and will
168 // cause a crash due to a use-after-free.
169 client = nullptr;
170 }
171
172 // Tests if invalid BindInstance() calls are correctly rejected, and it does not
173 // make the service insanity.
174 TEST_F(MidiTaskServiceTest, BindTwice) {
175 std::unique_ptr<TaskServiceClient> client =
176 base::MakeUnique<TaskServiceClient>(task_service());
177
178 EXPECT_TRUE(client->Bind());
179
180 // Should not be able to call BindInstance() twice before unbinding current
181 // bound instance.
182 EXPECT_FALSE(client->Bind());
183
184 // Should be able to unbind only the first instance.
185 EXPECT_TRUE(client->Unbind());
186 EXPECT_FALSE(client->Unbind());
187 }
188
189 // Tests if posted static tasks can be processed even with a bound instance.
190 TEST_F(MidiTaskServiceTest, RunStaticTaskWithBoundInstance) {
191 std::unique_ptr<TaskServiceClient> client =
192 base::MakeUnique<TaskServiceClient>(task_service());
193
194 EXPECT_TRUE(client->Bind());
195 // Should be able to post a static task even with a bound instance.
196 task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
197 WaitEvent();
198 EXPECT_TRUE(client->Unbind());
199
200 ResetEvent();
201
202 EXPECT_TRUE(client->Bind());
203 task_service()->PostStaticTask(kFirstRunner, base::Bind(&SignalEvent));
204 // Should be able to unbind the instance to process a static task.
205 EXPECT_TRUE(client->Unbind());
206 WaitEvent();
207 }
208
209 // Tests functionalities to run bound tasks.
210 TEST_F(MidiTaskServiceTest, RunBoundTasks) {
211 std::unique_ptr<TaskServiceClient> client =
212 base::MakeUnique<TaskServiceClient>(task_service());
213
214 EXPECT_TRUE(client->Bind());
215
216 // Tests if a post task run.
217 EXPECT_EQ(0u, client->count());
218 client->PostBoundSignalTask(kFirstRunner);
219 WaitEvent();
220 EXPECT_EQ(1u, client->count());
221
222 // Tests if another posted task is handled correctly even if the instance is
223 // unbound immediately. The posted task should run safely if it starts before
224 // UnboundInstance() is call. Otherwise, it should be ignored. It completely
225 // depends on timing.
226 client->PostBoundTask(kFirstRunner);
227 EXPECT_TRUE(client->Unbind());
228 client = base::MakeUnique<TaskServiceClient>(task_service());
229
230 // Tests if an immediate call of another BindInstance() works correctly.
231 EXPECT_TRUE(client->Bind());
232
233 // Runs two tasks in two runners.
234 ResetEvent();
235 client->PostBoundSignalTask(kFirstRunner);
236 client->PostBoundTask(kSecondRunner);
237
238 // Waits only the first runner completion to see if the second runner handles
239 // the task correctly even if the bound instance is destructed.
240 WaitEvent();
241 EXPECT_TRUE(client->Unbind());
242 client = nullptr;
243 }
244
245 // Tests if a blocking task does not block other task runners.
246 TEST_F(MidiTaskServiceTest, RunBlockingTask) {
247 std::unique_ptr<TaskServiceClient> client =
248 base::MakeUnique<TaskServiceClient>(task_service());
249
250 EXPECT_TRUE(client->Bind());
251
252 // Posts a task that waits until the event is signaled.
253 client->PostBoundWaitTask(kFirstRunner);
254 // Confirms if the posted task starts. Now, the task should block in the task
255 // until the second task is invoked.
256 client->WaitTask();
257
258 // Posts another task to the second runner. The task should be able to run
259 // even though another posted task is blocking inside a critical section that
260 // protects running tasks from an instance unbinding.
261 client->PostBoundSignalTask(kSecondRunner);
262
263 // Wait until the second task runs.
264 WaitEvent();
265
266 // UnbindInstance() should wait until any running task finishes so that the
267 // instance can be destructed safely.
268 EXPECT_TRUE(client->Unbind());
269 EXPECT_EQ(2u, client->count());
270 client = nullptr;
271 }
272
273 // Tests if a bound delayed task runs correctly.
274 TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
275 std::unique_ptr<TaskServiceClient> client =
276 base::MakeUnique<TaskServiceClient>(task_service());
277
278 EXPECT_TRUE(client->Bind());
279
280 // Posts a delayed task that signals after 100msec.
281 client->PostBoundDelayedSignalTask(kFirstRunner);
282
283 // Wait until the delayed task runs.
284 WaitEvent();
285
286 EXPECT_TRUE(client->Unbind());
287 EXPECT_EQ(1u, client->count());
288 client = nullptr;
289 }
290
291 // Tests if a bound task runs on the thread that bound the instance.
292 TEST_F(MidiTaskServiceTest, RunBoundTaskOnDefaultRunner) {
293 std::unique_ptr<TaskServiceClient> client =
294 base::MakeUnique<TaskServiceClient>(task_service());
295
296 EXPECT_TRUE(client->Bind());
297
298 // Posts a task that increments the count on the caller thread.
299 client->PostBoundTask(kDefaultRunner);
300
301 // The posted task should not run until the current message loop is processed.
302 EXPECT_EQ(0u, client->count());
303 RunUntilIdle();
304 EXPECT_EQ(1u, client->count());
305
306 EXPECT_TRUE(client->Unbind());
307 }
308
309 } // namespace
310
311 } // namespace midi
OLDNEW
« no previous file with comments | « media/midi/task_service.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698