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

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

Issue 2741713002: Web MIDI: implement TaskService (Closed)
Patch Set: review #21 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
« media/midi/task_service.cc ('K') | « 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 { kDefaultRunner = TaskService::kDefaultRunnerId, kSecondRunner };
26
27 base::WaitableEvent* GetEvent() {
28 static base::WaitableEvent* event =
29 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
30 base::WaitableEvent::InitialState::NOT_SIGNALED);
31 return event;
32 }
33
34 void SignalEvent() {
35 GetEvent()->Signal();
36 }
37
38 void WaitEvent() {
39 GetEvent()->Wait();
40 }
41
42 void ResetEvent() {
43 GetEvent()->Reset();
44 }
45
46 class TaskServiceClient {
47 public:
48 TaskServiceClient(TaskService* task_service)
49 : task_service_(task_service),
50 wait_task_event_(base::MakeUnique<base::WaitableEvent>(
51 base::WaitableEvent::ResetPolicy::MANUAL,
52 base::WaitableEvent::InitialState::NOT_SIGNALED)),
53 count_(0u) {
54 DCHECK(task_service);
55 }
56
57 bool Bind() { return task_service()->BindInstance(); }
58
59 bool Unbind() { return task_service()->UnbindInstance(); }
60
61 void PostBoundTask(TaskService::RunnerId runner_id) {
62 task_service()->PostBoundTask(
63 runner_id, base::BindOnce(&TaskServiceClient::IncrementCount,
64 base::Unretained(this)));
65 }
66
67 void PostBoundSignalTask(TaskService::RunnerId runner_id) {
68 task_service()->PostBoundTask(
69 runner_id, base::BindOnce(&TaskServiceClient::SignalEvent,
70 base::Unretained(this)));
71 }
72
73 void PostBoundWaitTask(TaskService::RunnerId runner_id) {
74 wait_task_event_->Reset();
75 task_service()->PostBoundTask(
76 runner_id,
77 base::BindOnce(&TaskServiceClient::WaitEvent, base::Unretained(this)));
78 }
79
80 void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) {
81 task_service()->PostBoundDelayedTask(
82 runner_id,
83 base::BindOnce(&TaskServiceClient::SignalEvent, base::Unretained(this)),
84 base::TimeDelta::FromMilliseconds(100));
85 }
86
87 void PostBoundReplyTask() {
88 task_service()->PostBoundReplyTask(base::BindOnce(
89 &TaskServiceClient::IncrementCount, base::Unretained(this)));
90 }
91
92 void WaitTask() { wait_task_event_->Wait(); }
93
94 size_t count() {
95 base::AutoLock lock(lock_);
96 return count_;
97 }
98
99 private:
100 TaskService* task_service() { return task_service_; }
101
102 void IncrementCount() {
103 base::AutoLock lock(lock_);
104 count_++;
105 }
106
107 void SignalEvent() {
108 midi::SignalEvent();
109 IncrementCount();
110 }
111
112 void WaitEvent() {
113 wait_task_event_->Signal();
114 midi::WaitEvent();
115 IncrementCount();
116 }
117
118 base::Lock lock_;
119 TaskService* task_service_;
120 std::unique_ptr<base::WaitableEvent> wait_task_event_;
121 size_t count_;
122
123 DISALLOW_COPY_AND_ASSIGN(TaskServiceClient);
124 };
125
126 class MidiTaskServiceTest : public ::testing::Test {
127 public:
128 MidiTaskServiceTest() {}
129
130 protected:
131 TaskService* task_service() { return &task_service_; }
132 void RunUntilIdle() { task_runner_->RunUntilIdle(); }
133
134 private:
135 void SetUp() override {
136 ResetEvent();
137 task_runner_ = new base::TestSimpleTaskRunner();
138 thread_task_runner_handle_ =
139 base::MakeUnique<base::ThreadTaskRunnerHandle>(task_runner_);
140 }
141
142 void TearDown() override {
143 thread_task_runner_handle_.reset();
144 task_runner_ = NULL;
145 }
146
147 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
148 std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
149 TaskService task_service_;
150
151 DISALLOW_COPY_AND_ASSIGN(MidiTaskServiceTest);
152 };
153
154 // Tests if posted static tasks can be processed without any bound instance.
155 TEST_F(MidiTaskServiceTest, RunStaticTask) {
156 task_service()->PostStaticTask(kDefaultRunner, base::BindOnce(&SignalEvent));
157 WaitEvent();
158 }
159
160 // Tests if posted tasks without calling BindInstance() are ignored.
161 TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
162 std::unique_ptr<TaskServiceClient> client =
163 base::MakeUnique<TaskServiceClient>(task_service());
164
165 client->PostBoundTask(kDefaultRunner);
166
167 // Destruct |client| immediately, then see if the posted task is just ignored.
168 client = nullptr;
169 }
170
171 // Tests if invalid BindInstance() calls are correctly rejected, and it does not
172 // make the service insanity.
173 TEST_F(MidiTaskServiceTest, BindTwice) {
174 std::unique_ptr<TaskServiceClient> client =
175 base::MakeUnique<TaskServiceClient>(task_service());
176
177 EXPECT_TRUE(client->Bind());
178
179 // Should not be able to call BindInstance() twice before unbinding current
180 // bound instance.
181 EXPECT_FALSE(client->Bind());
182
183 // Should be able to unbind only the first instance.
184 EXPECT_TRUE(client->Unbind());
185 EXPECT_FALSE(client->Unbind());
186 }
187
188 // Tests if posted static tasks can be processed even with a bound instance.
189 TEST_F(MidiTaskServiceTest, RunStaticTaskWithBoundInstance) {
190 std::unique_ptr<TaskServiceClient> client =
191 base::MakeUnique<TaskServiceClient>(task_service());
192
193 EXPECT_TRUE(client->Bind());
194 // Should be able to post a static task even with a bound instance.
195 task_service()->PostStaticTask(kDefaultRunner, base::BindOnce(&SignalEvent));
196 WaitEvent();
197 EXPECT_TRUE(client->Unbind());
198
199 ResetEvent();
200
201 EXPECT_TRUE(client->Bind());
202 task_service()->PostStaticTask(kDefaultRunner, base::Bind(&SignalEvent));
203 // Should be able to unbind the instance to process a static task.
204 EXPECT_TRUE(client->Unbind());
205 WaitEvent();
206 }
207
208 // Tests functionalities to run bound tasks.
209 TEST_F(MidiTaskServiceTest, RunBoundTasks) {
210 std::unique_ptr<TaskServiceClient> client =
211 base::MakeUnique<TaskServiceClient>(task_service());
212
213 EXPECT_TRUE(client->Bind());
214
215 // Tests if a post task run.
216 EXPECT_EQ(0u, client->count());
217 client->PostBoundSignalTask(kDefaultRunner);
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(kDefaultRunner);
226 EXPECT_TRUE(client->Unbind());
227 client = base::MakeUnique<TaskServiceClient>(task_service());
228
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(kDefaultRunner);
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.
245 TEST_F(MidiTaskServiceTest, RunBlockingTask) {
246 std::unique_ptr<TaskServiceClient> client =
247 base::MakeUnique<TaskServiceClient>(task_service());
248
249 EXPECT_TRUE(client->Bind());
250
251 // Posts a task that waits until the event is signaled.
252 client->PostBoundWaitTask(kDefaultRunner);
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.
273 TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
274 std::unique_ptr<TaskServiceClient> client =
275 base::MakeUnique<TaskServiceClient>(task_service());
276
277 EXPECT_TRUE(client->Bind());
278
279 // Posts a delayed task that signals after 100msec.
280 client->PostBoundDelayedSignalTask(kDefaultRunner);
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 reply task runs on the thread that bound the instance.
291 TEST_F(MidiTaskServiceTest, RunBoundReplyTask) {
292 std::unique_ptr<TaskServiceClient> client =
293 base::MakeUnique<TaskServiceClient>(task_service());
294
295 EXPECT_TRUE(client->Bind());
296
297 // Posts a reply task that increments the count on the caller thread.
298 client->PostBoundReplyTask();
299
300 // The reply 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
OLDNEW
« media/midi/task_service.cc ('K') | « media/midi/task_service.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698