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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/midi/task_service.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/midi/task_service_unittest.cc
diff --git a/media/midi/task_service_unittest.cc b/media/midi/task_service_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..614e950f392517ed124b9ee18c5075a0ba9deb55
--- /dev/null
+++ b/media/midi/task_service_unittest.cc
@@ -0,0 +1,311 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/midi/task_service.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/synchronization/lock.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace midi {
+
+namespace {
+
+enum {
+ kDefaultRunner = TaskService::kDefaultRunnerId,
+ kFirstRunner,
+ kSecondRunner
+};
+
+base::WaitableEvent* GetEvent() {
+ static base::WaitableEvent* event =
+ new base::WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ return event;
+}
+
+void SignalEvent() {
+ GetEvent()->Signal();
+}
+
+void WaitEvent() {
+ GetEvent()->Wait();
+}
+
+void ResetEvent() {
+ GetEvent()->Reset();
+}
+
+class TaskServiceClient {
+ public:
+ TaskServiceClient(TaskService* task_service)
+ : task_service_(task_service),
+ wait_task_event_(base::MakeUnique<base::WaitableEvent>(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED)),
+ count_(0u) {
+ DCHECK(task_service);
+ }
+
+ bool Bind() { return task_service()->BindInstance(); }
+
+ bool Unbind() { return task_service()->UnbindInstance(); }
+
+ void PostBoundTask(TaskService::RunnerId runner_id) {
+ task_service()->PostBoundTask(
+ runner_id, base::BindOnce(&TaskServiceClient::IncrementCount,
+ base::Unretained(this)));
+ }
+
+ void PostBoundSignalTask(TaskService::RunnerId runner_id) {
+ task_service()->PostBoundTask(
+ runner_id, base::BindOnce(&TaskServiceClient::SignalEvent,
+ base::Unretained(this)));
+ }
+
+ void PostBoundWaitTask(TaskService::RunnerId runner_id) {
+ wait_task_event_->Reset();
+ task_service()->PostBoundTask(
+ runner_id,
+ base::BindOnce(&TaskServiceClient::WaitEvent, base::Unretained(this)));
+ }
+
+ void PostBoundDelayedSignalTask(TaskService::RunnerId runner_id) {
+ task_service()->PostBoundDelayedTask(
+ runner_id,
+ base::BindOnce(&TaskServiceClient::SignalEvent, base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(100));
+ }
+
+ void WaitTask() { wait_task_event_->Wait(); }
+
+ size_t count() {
+ base::AutoLock lock(lock_);
+ return count_;
+ }
+
+ private:
+ TaskService* task_service() { return task_service_; }
+
+ void IncrementCount() {
+ base::AutoLock lock(lock_);
+ count_++;
+ }
+
+ void SignalEvent() {
+ midi::SignalEvent();
+ IncrementCount();
+ }
+
+ void WaitEvent() {
+ wait_task_event_->Signal();
+ midi::WaitEvent();
+ IncrementCount();
+ }
+
+ base::Lock lock_;
+ TaskService* task_service_;
+ std::unique_ptr<base::WaitableEvent> wait_task_event_;
+ size_t count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskServiceClient);
+};
+
+class MidiTaskServiceTest : public ::testing::Test {
+ public:
+ MidiTaskServiceTest() {}
+
+ protected:
+ TaskService* task_service() { return &task_service_; }
+ void RunUntilIdle() { task_runner_->RunUntilIdle(); }
+
+ private:
+ void SetUp() override {
+ ResetEvent();
+ task_runner_ = new base::TestSimpleTaskRunner();
+ thread_task_runner_handle_ =
+ base::MakeUnique<base::ThreadTaskRunnerHandle>(task_runner_);
+ }
+
+ void TearDown() override {
+ thread_task_runner_handle_.reset();
+ task_runner_ = NULL;
+ }
+
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+ std::unique_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_;
+ TaskService task_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(MidiTaskServiceTest);
+};
+
+// Tests if posted static tasks can be processed without any bound instance.
+TEST_F(MidiTaskServiceTest, RunStaticTask) {
+ task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
+ WaitEvent();
+}
+
+// Tests if posted tasks without calling BindInstance() are ignored.
+TEST_F(MidiTaskServiceTest, RunUnauthorizedBoundTask) {
+ std::unique_ptr<TaskServiceClient> client =
+ base::MakeUnique<TaskServiceClient>(task_service());
+
+ client->PostBoundTask(kFirstRunner);
+
+ // Destruct |client| immediately, then see if the posted task is just ignored.
+ // If it isn't, another thread will touch the destructed instance and will
+ // cause a crash due to a use-after-free.
+ client = nullptr;
+}
+
+// Tests if invalid BindInstance() calls are correctly rejected, and it does not
+// make the service insanity.
+TEST_F(MidiTaskServiceTest, BindTwice) {
+ std::unique_ptr<TaskServiceClient> client =
+ base::MakeUnique<TaskServiceClient>(task_service());
+
+ EXPECT_TRUE(client->Bind());
+
+ // Should not be able to call BindInstance() twice before unbinding current
+ // bound instance.
+ EXPECT_FALSE(client->Bind());
+
+ // Should be able to unbind only the first instance.
+ EXPECT_TRUE(client->Unbind());
+ EXPECT_FALSE(client->Unbind());
+}
+
+// Tests if posted static tasks can be processed even with a bound instance.
+TEST_F(MidiTaskServiceTest, RunStaticTaskWithBoundInstance) {
+ std::unique_ptr<TaskServiceClient> client =
+ base::MakeUnique<TaskServiceClient>(task_service());
+
+ EXPECT_TRUE(client->Bind());
+ // Should be able to post a static task even with a bound instance.
+ task_service()->PostStaticTask(kFirstRunner, base::BindOnce(&SignalEvent));
+ WaitEvent();
+ EXPECT_TRUE(client->Unbind());
+
+ ResetEvent();
+
+ EXPECT_TRUE(client->Bind());
+ task_service()->PostStaticTask(kFirstRunner, base::Bind(&SignalEvent));
+ // Should be able to unbind the instance to process a static task.
+ EXPECT_TRUE(client->Unbind());
+ WaitEvent();
+}
+
+// Tests functionalities to run bound tasks.
+TEST_F(MidiTaskServiceTest, RunBoundTasks) {
+ std::unique_ptr<TaskServiceClient> client =
+ base::MakeUnique<TaskServiceClient>(task_service());
+
+ EXPECT_TRUE(client->Bind());
+
+ // Tests if a post task run.
+ EXPECT_EQ(0u, client->count());
+ client->PostBoundSignalTask(kFirstRunner);
+ WaitEvent();
+ EXPECT_EQ(1u, client->count());
+
+ // Tests if another posted task is handled correctly even if the instance is
+ // unbound immediately. The posted task should run safely if it starts before
+ // UnboundInstance() is call. Otherwise, it should be ignored. It completely
+ // depends on timing.
+ client->PostBoundTask(kFirstRunner);
+ EXPECT_TRUE(client->Unbind());
+ client = base::MakeUnique<TaskServiceClient>(task_service());
+
+ // Tests if an immediate call of another BindInstance() works correctly.
+ EXPECT_TRUE(client->Bind());
+
+ // Runs two tasks in two runners.
+ ResetEvent();
+ client->PostBoundSignalTask(kFirstRunner);
+ client->PostBoundTask(kSecondRunner);
+
+ // Waits only the first runner completion to see if the second runner handles
+ // the task correctly even if the bound instance is destructed.
+ WaitEvent();
+ EXPECT_TRUE(client->Unbind());
+ client = nullptr;
+}
+
+// Tests if a blocking task does not block other task runners.
+TEST_F(MidiTaskServiceTest, RunBlockingTask) {
+ std::unique_ptr<TaskServiceClient> client =
+ base::MakeUnique<TaskServiceClient>(task_service());
+
+ EXPECT_TRUE(client->Bind());
+
+ // Posts a task that waits until the event is signaled.
+ client->PostBoundWaitTask(kFirstRunner);
+ // Confirms if the posted task starts. Now, the task should block in the task
+ // until the second task is invoked.
+ client->WaitTask();
+
+ // Posts another task to the second runner. The task should be able to run
+ // even though another posted task is blocking inside a critical section that
+ // protects running tasks from an instance unbinding.
+ client->PostBoundSignalTask(kSecondRunner);
+
+ // Wait until the second task runs.
+ WaitEvent();
+
+ // UnbindInstance() should wait until any running task finishes so that the
+ // instance can be destructed safely.
+ EXPECT_TRUE(client->Unbind());
+ EXPECT_EQ(2u, client->count());
+ client = nullptr;
+}
+
+// Tests if a bound delayed task runs correctly.
+TEST_F(MidiTaskServiceTest, RunBoundDelayedTask) {
+ std::unique_ptr<TaskServiceClient> client =
+ base::MakeUnique<TaskServiceClient>(task_service());
+
+ EXPECT_TRUE(client->Bind());
+
+ // Posts a delayed task that signals after 100msec.
+ client->PostBoundDelayedSignalTask(kFirstRunner);
+
+ // Wait until the delayed task runs.
+ WaitEvent();
+
+ EXPECT_TRUE(client->Unbind());
+ EXPECT_EQ(1u, client->count());
+ client = nullptr;
+}
+
+// Tests if a bound task runs on the thread that bound the instance.
+TEST_F(MidiTaskServiceTest, RunBoundTaskOnDefaultRunner) {
+ std::unique_ptr<TaskServiceClient> client =
+ base::MakeUnique<TaskServiceClient>(task_service());
+
+ EXPECT_TRUE(client->Bind());
+
+ // Posts a task that increments the count on the caller thread.
+ client->PostBoundTask(kDefaultRunner);
+
+ // The posted task should not run until the current message loop is processed.
+ EXPECT_EQ(0u, client->count());
+ RunUntilIdle();
+ EXPECT_EQ(1u, client->count());
+
+ EXPECT_TRUE(client->Unbind());
+}
+
+} // namespace
+
+} // namespace midi
« 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