OLD | NEW |
(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 constexpr TaskService::RunnerId kDefaultRunner = 0; |
| 26 constexpr TaskService::RunnerId kSecondRunner = 1; |
| 27 |
| 28 base::WaitableEvent* GetEvent() { |
| 29 static base::WaitableEvent* event = |
| 30 new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL, |
| 31 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 32 return event; |
| 33 } |
| 34 |
| 35 void SignalEvent() { |
| 36 GetEvent()->Signal(); |
| 37 } |
| 38 |
| 39 void WaitEvent() { |
| 40 GetEvent()->Wait(); |
| 41 } |
| 42 |
| 43 void ResetEvent() { |
| 44 GetEvent()->Reset(); |
| 45 } |
| 46 |
| 47 class TaskServiceClient { |
| 48 public: |
| 49 TaskServiceClient(TaskService* task_service) |
| 50 : task_service_(task_service), |
| 51 wait_task_event_(base::MakeUnique<base::WaitableEvent>( |
| 52 base::WaitableEvent::ResetPolicy::MANUAL, |
| 53 base::WaitableEvent::InitialState::NOT_SIGNALED)), |
| 54 count_(0u) { |
| 55 DCHECK(task_service); |
| 56 } |
| 57 |
| 58 bool Bind() { return task_service()->BindInstance(); } |
| 59 |
| 60 bool Unbind() { return task_service()->UnbindInstance(); } |
| 61 |
| 62 void PostBoundTask(TaskService::RunnerId runner_id) { |
| 63 task_service()->PostBoundTask( |
| 64 runner_id, |
| 65 base::Bind(&TaskServiceClient::IncrementCount, base::Unretained(this))); |
| 66 } |
| 67 |
| 68 void PostBoundSignalTask(TaskService::RunnerId runner_id) { |
| 69 task_service()->PostBoundTask( |
| 70 runner_id, |
| 71 base::Bind(&TaskServiceClient::SignalEvent, base::Unretained(this))); |
| 72 } |
| 73 |
| 74 void PostBoundWaitTask(TaskService::RunnerId runner_id) { |
| 75 wait_task_event_->Reset(); |
| 76 task_service()->PostBoundTask( |
| 77 runner_id, |
| 78 base::Bind(&TaskServiceClient::WaitEvent, base::Unretained(this))); |
| 79 } |
| 80 |
| 81 void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) { |
| 82 task_service()->PostBoundDelayedTask( |
| 83 runner_id, |
| 84 base::Bind(&TaskServiceClient::SignalEvent, base::Unretained(this)), |
| 85 base::TimeDelta::FromMilliseconds(100)); |
| 86 } |
| 87 |
| 88 void PostBoundReplyTask() { |
| 89 task_service()->PostBoundReplyTask( |
| 90 base::Bind(&TaskServiceClient::IncrementCount, base::Unretained(this))); |
| 91 } |
| 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() { |
| 109 midi::SignalEvent(); |
| 110 IncrementCount(); |
| 111 } |
| 112 |
| 113 void WaitEvent() { |
| 114 wait_task_event_->Signal(); |
| 115 midi::WaitEvent(); |
| 116 IncrementCount(); |
| 117 } |
| 118 |
| 119 base::Lock lock_; |
| 120 TaskService* task_service_; |
| 121 std::unique_ptr<base::WaitableEvent> wait_task_event_; |
| 122 size_t count_; |
| 123 |
| 124 DISALLOW_COPY_AND_ASSIGN(TaskServiceClient); |
| 125 }; |
| 126 |
| 127 class MidiTaskServiceTest : public ::testing::Test { |
| 128 public: |
| 129 MidiTaskServiceTest() {} |
| 130 |
| 131 protected: |
| 132 TaskService* task_service() { return &task_service_; } |
| 133 void RunUntilIdle() { task_runner_->RunUntilIdle(); } |
| 134 |
| 135 private: |
| 136 void SetUp() override { |
| 137 ResetEvent(); |
| 138 task_runner_ = new base::TestSimpleTaskRunner(); |
| 139 thread_task_runner_handle_ = |
| 140 base::MakeUnique<base::ThreadTaskRunnerHandle>(task_runner_); |
| 141 } |
| 142 |
| 143 void TearDown() override { |
| 144 thread_task_runner_handle_.reset(); |
| 145 task_runner_ = NULL; |
| 146 } |
| 147 |
| 148 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| 149 std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; |
| 150 TaskService task_service_; |
| 151 |
| 152 DISALLOW_COPY_AND_ASSIGN(MidiTaskServiceTest); |
| 153 }; |
| 154 |
| 155 // Tests if posted static tasks can be processed without any bound instance. |
| 156 TEST_F(MidiTaskServiceTest, RunStaticTask) { |
| 157 task_service()->PostStaticTask(kDefaultRunner, base::Bind(&SignalEvent)); |
| 158 WaitEvent(); |
| 159 } |
| 160 |
| 161 // Tests if posted tasks without calling BindInstance() are ignored. |
| 162 TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) { |
| 163 std::unique_ptr<TaskServiceClient> client = |
| 164 base::MakeUnique<TaskServiceClient>(task_service()); |
| 165 |
| 166 client->PostBoundTask(kDefaultRunner); |
| 167 |
| 168 // Destruct |client| immediately, then see if the posted task is just ignored. |
| 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(kDefaultRunner, base::Bind(&SignalEvent)); |
| 197 WaitEvent(); |
| 198 EXPECT_TRUE(client->Unbind()); |
| 199 |
| 200 ResetEvent(); |
| 201 |
| 202 EXPECT_TRUE(client->Bind()); |
| 203 task_service()->PostStaticTask(kDefaultRunner, 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(kDefaultRunner); |
| 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(kDefaultRunner); |
| 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(kDefaultRunner); |
| 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(kDefaultRunner); |
| 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(kDefaultRunner); |
| 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 reply task runs on the thread that bound the instance. |
| 292 TEST_F(MidiTaskServiceTest, RunBoundReplyTask) { |
| 293 std::unique_ptr<TaskServiceClient> client = |
| 294 base::MakeUnique<TaskServiceClient>(task_service()); |
| 295 |
| 296 EXPECT_TRUE(client->Bind()); |
| 297 |
| 298 // Posts a reply task that increments the count on the caller thread. |
| 299 client->PostBoundReplyTask(); |
| 300 |
| 301 // The reply 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 |
OLD | NEW |