Index: chromecast/media/cma/base/balanced_media_task_runner_unittest.cc |
diff --git a/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc b/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e3448f67cace9f3c947a84af3e709f5a25febad2 |
--- /dev/null |
+++ b/chromecast/media/cma/base/balanced_media_task_runner_unittest.cc |
@@ -0,0 +1,263 @@ |
+// Copyright 2014 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 <list> |
+#include <vector> |
+ |
+#include "base/basictypes.h" |
+#include "base/bind.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/threading/thread.h" |
+#include "base/time/time.h" |
+#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h" |
+#include "chromecast/media/cma/base/media_task_runner.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace chromecast { |
+namespace media { |
+ |
+namespace { |
+ |
+struct MediaTaskRunnerTestContext { |
+ MediaTaskRunnerTestContext(); |
+ ~MediaTaskRunnerTestContext(); |
+ |
+ scoped_refptr<MediaTaskRunner> media_task_runner; |
+ |
+ bool is_pending_task; |
+ |
+ std::vector<base::TimeDelta> task_timestamp_list; |
+ |
+ size_t task_index; |
+ base::TimeDelta max_timestamp; |
+}; |
+ |
+MediaTaskRunnerTestContext::MediaTaskRunnerTestContext() { |
+} |
+ |
+MediaTaskRunnerTestContext::~MediaTaskRunnerTestContext() { |
+} |
+ |
+} // namespace |
+ |
+class BalancedMediaTaskRunnerTest : public testing::Test { |
+ public: |
+ BalancedMediaTaskRunnerTest(); |
+ virtual ~BalancedMediaTaskRunnerTest(); |
+ |
+ void SetupTest(base::TimeDelta max_delta, |
+ const std::vector<std::vector<int> >& timestamps_in_ms, |
+ const std::vector<size_t>& pattern, |
+ const std::vector<int>& expected_task_timestamps_ms); |
+ void ProcessAllTasks(); |
+ |
+ protected: |
+ // Expected task order based on their timestamps. |
+ std::list<base::TimeDelta> expected_task_timestamps_; |
+ |
+ private: |
+ void ScheduleTask(); |
+ void Task(size_t task_runner_id, base::TimeDelta timestamp); |
+ |
+ void OnTestTimeout(); |
+ |
+ scoped_refptr<BalancedMediaTaskRunnerFactory> media_task_runner_factory_; |
+ |
+ // Schedule first a task on media task runner #scheduling_pattern[0] |
+ // then a task on media task runner #scheduling_pattern[1] and so on. |
+ // Wrap around when reaching the end of the pattern. |
+ std::vector<size_t> scheduling_pattern_; |
+ size_t pattern_index_; |
+ |
+ // For each media task runner, keep a track of which task has already been |
+ // scheduled. |
+ std::vector<MediaTaskRunnerTestContext> contexts_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BalancedMediaTaskRunnerTest); |
+}; |
+ |
+BalancedMediaTaskRunnerTest::BalancedMediaTaskRunnerTest() { |
+} |
+ |
+BalancedMediaTaskRunnerTest::~BalancedMediaTaskRunnerTest() { |
+} |
+ |
+void BalancedMediaTaskRunnerTest::SetupTest( |
+ base::TimeDelta max_delta, |
+ const std::vector<std::vector<int> >& timestamps_in_ms, |
+ const std::vector<size_t>& pattern, |
+ const std::vector<int>& expected_task_timestamps_ms) { |
+ media_task_runner_factory_ = new BalancedMediaTaskRunnerFactory(max_delta); |
+ |
+ scheduling_pattern_ = pattern; |
+ pattern_index_ = 0; |
+ |
+ // Setup each task runner. |
+ size_t n = timestamps_in_ms.size(); |
+ contexts_.resize(n); |
+ for (size_t k = 0; k < n; k++) { |
+ contexts_[k].media_task_runner = |
+ media_task_runner_factory_->CreateMediaTaskRunner( |
+ base::MessageLoopProxy::current()); |
+ contexts_[k].is_pending_task = false; |
+ contexts_[k].task_index = 0; |
+ contexts_[k].task_timestamp_list.resize( |
+ timestamps_in_ms[k].size()); |
+ for (size_t i = 0; i < timestamps_in_ms[k].size(); i++) { |
+ contexts_[k].task_timestamp_list[i] = |
+ base::TimeDelta::FromMilliseconds(timestamps_in_ms[k][i]); |
+ } |
+ } |
+ |
+ // Expected task order (for tasks that are actually run). |
+ for (size_t k = 0; k < expected_task_timestamps_ms.size(); k++) { |
+ expected_task_timestamps_.push_back( |
+ base::TimeDelta::FromMilliseconds(expected_task_timestamps_ms[k])); |
+ } |
+} |
+ |
+void BalancedMediaTaskRunnerTest::ProcessAllTasks() { |
+ base::MessageLoop::current()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&BalancedMediaTaskRunnerTest::OnTestTimeout, |
+ base::Unretained(this)), |
+ base::TimeDelta::FromSeconds(5)); |
+ ScheduleTask(); |
+} |
+ |
+void BalancedMediaTaskRunnerTest::ScheduleTask() { |
+ bool has_task = false; |
+ for (size_t k = 0; k < contexts_.size(); k++) { |
+ if (contexts_[k].task_index < contexts_[k].task_timestamp_list.size()) |
+ has_task = true; |
+ } |
+ if (!has_task) { |
+ base::MessageLoop::current()->QuitWhenIdle(); |
+ return; |
+ } |
+ |
+ size_t next_pattern_index = |
+ (pattern_index_ + 1) % scheduling_pattern_.size(); |
+ |
+ size_t task_runner_id = scheduling_pattern_[pattern_index_]; |
+ MediaTaskRunnerTestContext& context = contexts_[task_runner_id]; |
+ |
+ // Check whether all tasks have been scheduled for that task runner |
+ // or if there is already one pending task. |
+ if (context.task_index >= context.task_timestamp_list.size() || |
+ context.is_pending_task) { |
+ pattern_index_ = next_pattern_index; |
+ base::MessageLoopProxy::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask, |
+ base::Unretained(this))); |
+ return; |
+ } |
+ |
+ bool expected_may_run = false; |
+ if (context.task_timestamp_list[context.task_index] >= |
+ context.max_timestamp) { |
+ expected_may_run = true; |
+ context.max_timestamp = context.task_timestamp_list[context.task_index]; |
+ } |
+ |
+ bool may_run = context.media_task_runner->PostMediaTask( |
+ FROM_HERE, |
+ base::Bind(&BalancedMediaTaskRunnerTest::Task, |
+ base::Unretained(this), |
+ task_runner_id, |
+ context.task_timestamp_list[context.task_index]), |
+ context.task_timestamp_list[context.task_index]); |
+ EXPECT_EQ(may_run, expected_may_run); |
+ |
+ if (may_run) |
+ context.is_pending_task = true; |
+ |
+ context.task_index++; |
+ pattern_index_ = next_pattern_index; |
+ base::MessageLoopProxy::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask, |
+ base::Unretained(this))); |
+} |
+ |
+void BalancedMediaTaskRunnerTest::Task( |
+ size_t task_runner_id, base::TimeDelta timestamp) { |
+ ASSERT_FALSE(expected_task_timestamps_.empty()); |
+ EXPECT_EQ(timestamp, expected_task_timestamps_.front()); |
+ expected_task_timestamps_.pop_front(); |
+ |
+ contexts_[task_runner_id].is_pending_task = false; |
+} |
+ |
+void BalancedMediaTaskRunnerTest::OnTestTimeout() { |
+ ADD_FAILURE() << "Test timed out"; |
+ if (base::MessageLoop::current()) |
+ base::MessageLoop::current()->QuitWhenIdle(); |
+} |
+ |
+TEST_F(BalancedMediaTaskRunnerTest, OneTaskRunner) { |
+ scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); |
+ |
+ // Timestamps of tasks for the single task runner. |
+ int timestamps0_ms[] = {0, 10, 20, 30, 40, 30, 50, 60, 20, 30, 70}; |
+ std::vector<std::vector<int> > timestamps_ms(1); |
+ timestamps_ms[0] = std::vector<int>( |
+ timestamps0_ms, timestamps0_ms + arraysize(timestamps0_ms)); |
+ |
+ // Scheduling pattern. |
+ std::vector<size_t> scheduling_pattern(1); |
+ scheduling_pattern[0] = 0; |
+ |
+ // Expected results. |
+ int expected_timestamps[] = {0, 10, 20, 30, 40, 50, 60, 70}; |
+ std::vector<int> expected_timestamps_ms(std::vector<int>( |
+ expected_timestamps, |
+ expected_timestamps + arraysize(expected_timestamps))); |
+ |
+ SetupTest(base::TimeDelta::FromMilliseconds(30), |
+ timestamps_ms, |
+ scheduling_pattern, |
+ expected_timestamps_ms); |
+ ProcessAllTasks(); |
+ message_loop->Run(); |
+ EXPECT_TRUE(expected_task_timestamps_.empty()); |
+} |
+ |
+TEST_F(BalancedMediaTaskRunnerTest, TwoTaskRunnerUnbalanced) { |
+ scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); |
+ |
+ // Timestamps of tasks for the 2 task runners. |
+ int timestamps0_ms[] = {0, 10, 20, 30, 40, 30, 50, 60, 20, 30, 70}; |
+ int timestamps1_ms[] = {5, 15, 25, 35, 45, 35, 55, 65, 25, 35, 75}; |
+ std::vector<std::vector<int> > timestamps_ms(2); |
+ timestamps_ms[0] = std::vector<int>( |
+ timestamps0_ms, timestamps0_ms + arraysize(timestamps0_ms)); |
+ timestamps_ms[1] = std::vector<int>( |
+ timestamps1_ms, timestamps1_ms + arraysize(timestamps1_ms)); |
+ |
+ // Scheduling pattern. |
+ size_t pattern[] = {1, 0, 0, 0, 0}; |
+ std::vector<size_t> scheduling_pattern = std::vector<size_t>( |
+ pattern, pattern + arraysize(pattern)); |
+ |
+ // Expected results. |
+ int expected_timestamps[] = { |
+ 5, 0, 10, 20, 30, 15, 40, 25, 50, 35, 60, 45, 70, 55, 65, 75 }; |
+ std::vector<int> expected_timestamps_ms(std::vector<int>( |
+ expected_timestamps, |
+ expected_timestamps + arraysize(expected_timestamps))); |
+ |
+ SetupTest(base::TimeDelta::FromMilliseconds(30), |
+ timestamps_ms, |
+ scheduling_pattern, |
+ expected_timestamps_ms); |
+ ProcessAllTasks(); |
+ message_loop->Run(); |
+ EXPECT_TRUE(expected_task_timestamps_.empty()); |
+} |
+ |
+} // namespace media |
+} // namespace chromecast |