Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chromecast / media / cma / base / balanced_media_task_runner_unittest.cc
blob02e29d4334f7046e59ecee208d825e7f17584e45
1 // Copyright 2014 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.
5 #include <list>
6 #include <vector>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/thread.h"
14 #include "base/time/time.h"
15 #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
16 #include "chromecast/media/cma/base/media_task_runner.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 namespace chromecast {
20 namespace media {
22 namespace {
24 struct MediaTaskRunnerTestContext {
25 MediaTaskRunnerTestContext();
26 ~MediaTaskRunnerTestContext();
28 scoped_refptr<MediaTaskRunner> media_task_runner;
30 bool is_pending_task;
32 std::vector<base::TimeDelta> task_timestamp_list;
34 size_t task_index;
35 base::TimeDelta max_timestamp;
38 MediaTaskRunnerTestContext::MediaTaskRunnerTestContext() {
41 MediaTaskRunnerTestContext::~MediaTaskRunnerTestContext() {
44 } // namespace
46 class BalancedMediaTaskRunnerTest : public testing::Test {
47 public:
48 BalancedMediaTaskRunnerTest();
49 ~BalancedMediaTaskRunnerTest() override;
51 void SetupTest(base::TimeDelta max_delta,
52 const std::vector<std::vector<int> >& timestamps_in_ms,
53 const std::vector<size_t>& pattern,
54 const std::vector<int>& expected_task_timestamps_ms);
55 void ProcessAllTasks();
57 protected:
58 // Expected task order based on their timestamps.
59 std::list<base::TimeDelta> expected_task_timestamps_;
61 private:
62 void ScheduleTask();
63 void Task(size_t task_runner_id, base::TimeDelta timestamp);
65 void OnTestTimeout();
67 scoped_refptr<BalancedMediaTaskRunnerFactory> media_task_runner_factory_;
69 // Schedule first a task on media task runner #scheduling_pattern[0]
70 // then a task on media task runner #scheduling_pattern[1] and so on.
71 // Wrap around when reaching the end of the pattern.
72 std::vector<size_t> scheduling_pattern_;
73 size_t pattern_index_;
75 // For each media task runner, keep a track of which task has already been
76 // scheduled.
77 std::vector<MediaTaskRunnerTestContext> contexts_;
79 DISALLOW_COPY_AND_ASSIGN(BalancedMediaTaskRunnerTest);
82 BalancedMediaTaskRunnerTest::BalancedMediaTaskRunnerTest() {
85 BalancedMediaTaskRunnerTest::~BalancedMediaTaskRunnerTest() {
88 void BalancedMediaTaskRunnerTest::SetupTest(
89 base::TimeDelta max_delta,
90 const std::vector<std::vector<int> >& timestamps_in_ms,
91 const std::vector<size_t>& pattern,
92 const std::vector<int>& expected_task_timestamps_ms) {
93 media_task_runner_factory_ = new BalancedMediaTaskRunnerFactory(max_delta);
95 scheduling_pattern_ = pattern;
96 pattern_index_ = 0;
98 // Setup each task runner.
99 size_t n = timestamps_in_ms.size();
100 contexts_.resize(n);
101 for (size_t k = 0; k < n; k++) {
102 contexts_[k].media_task_runner =
103 media_task_runner_factory_->CreateMediaTaskRunner(
104 base::ThreadTaskRunnerHandle::Get());
105 contexts_[k].is_pending_task = false;
106 contexts_[k].task_index = 0;
107 contexts_[k].task_timestamp_list.resize(
108 timestamps_in_ms[k].size());
109 for (size_t i = 0; i < timestamps_in_ms[k].size(); i++) {
110 contexts_[k].task_timestamp_list[i] =
111 base::TimeDelta::FromMilliseconds(timestamps_in_ms[k][i]);
115 // Expected task order (for tasks that are actually run).
116 for (size_t k = 0; k < expected_task_timestamps_ms.size(); k++) {
117 expected_task_timestamps_.push_back(
118 base::TimeDelta::FromMilliseconds(expected_task_timestamps_ms[k]));
122 void BalancedMediaTaskRunnerTest::ProcessAllTasks() {
123 base::MessageLoop::current()->PostDelayedTask(
124 FROM_HERE,
125 base::Bind(&BalancedMediaTaskRunnerTest::OnTestTimeout,
126 base::Unretained(this)),
127 base::TimeDelta::FromSeconds(5));
128 ScheduleTask();
131 void BalancedMediaTaskRunnerTest::ScheduleTask() {
132 bool has_task = false;
133 for (size_t k = 0; k < contexts_.size(); k++) {
134 if (contexts_[k].task_index < contexts_[k].task_timestamp_list.size())
135 has_task = true;
137 if (!has_task) {
138 base::MessageLoop::current()->QuitWhenIdle();
139 return;
142 size_t next_pattern_index =
143 (pattern_index_ + 1) % scheduling_pattern_.size();
145 size_t task_runner_id = scheduling_pattern_[pattern_index_];
146 MediaTaskRunnerTestContext& context = contexts_[task_runner_id];
148 // Check whether all tasks have been scheduled for that task runner
149 // or if there is already one pending task.
150 if (context.task_index >= context.task_timestamp_list.size() ||
151 context.is_pending_task) {
152 pattern_index_ = next_pattern_index;
153 base::ThreadTaskRunnerHandle::Get()->PostTask(
154 FROM_HERE, base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask,
155 base::Unretained(this)));
156 return;
159 bool expected_may_run = false;
160 if (context.task_timestamp_list[context.task_index] >=
161 context.max_timestamp) {
162 expected_may_run = true;
163 context.max_timestamp = context.task_timestamp_list[context.task_index];
166 bool may_run = context.media_task_runner->PostMediaTask(
167 FROM_HERE,
168 base::Bind(&BalancedMediaTaskRunnerTest::Task,
169 base::Unretained(this),
170 task_runner_id,
171 context.task_timestamp_list[context.task_index]),
172 context.task_timestamp_list[context.task_index]);
173 EXPECT_EQ(may_run, expected_may_run);
175 if (may_run)
176 context.is_pending_task = true;
178 context.task_index++;
179 pattern_index_ = next_pattern_index;
180 base::ThreadTaskRunnerHandle::Get()->PostTask(
181 FROM_HERE, base::Bind(&BalancedMediaTaskRunnerTest::ScheduleTask,
182 base::Unretained(this)));
185 void BalancedMediaTaskRunnerTest::Task(
186 size_t task_runner_id, base::TimeDelta timestamp) {
187 ASSERT_FALSE(expected_task_timestamps_.empty());
188 EXPECT_EQ(timestamp, expected_task_timestamps_.front());
189 expected_task_timestamps_.pop_front();
191 contexts_[task_runner_id].is_pending_task = false;
193 // Release task runner if the task has ended
194 // otherwise, the task runner may may block other streams
195 auto& context = contexts_[task_runner_id];
196 if (context.task_index >= context.task_timestamp_list.size()) {
197 context.media_task_runner = nullptr;
201 void BalancedMediaTaskRunnerTest::OnTestTimeout() {
202 ADD_FAILURE() << "Test timed out";
203 if (base::MessageLoop::current())
204 base::MessageLoop::current()->QuitWhenIdle();
207 TEST_F(BalancedMediaTaskRunnerTest, OneTaskRunner) {
208 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
210 // Timestamps of tasks for the single task runner.
211 int timestamps0_ms[] = {0, 10, 20, 30, 40, 30, 50, 60, 20, 30, 70};
212 std::vector<std::vector<int> > timestamps_ms(1);
213 timestamps_ms[0] = std::vector<int>(
214 timestamps0_ms, timestamps0_ms + arraysize(timestamps0_ms));
216 // Scheduling pattern.
217 std::vector<size_t> scheduling_pattern(1);
218 scheduling_pattern[0] = 0;
220 // Expected results.
221 int expected_timestamps[] = {0, 10, 20, 30, 40, 50, 60, 70};
222 std::vector<int> expected_timestamps_ms(std::vector<int>(
223 expected_timestamps,
224 expected_timestamps + arraysize(expected_timestamps)));
226 SetupTest(base::TimeDelta::FromMilliseconds(30),
227 timestamps_ms,
228 scheduling_pattern,
229 expected_timestamps_ms);
230 ProcessAllTasks();
231 message_loop->Run();
232 EXPECT_TRUE(expected_task_timestamps_.empty());
235 TEST_F(BalancedMediaTaskRunnerTest, TwoTaskRunnerUnbalanced) {
236 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
238 // Timestamps of tasks for the 2 task runners.
239 int timestamps0_ms[] = {0, 10, 20, 30, 40, 30, 50, 60, 20, 30, 70};
240 int timestamps1_ms[] = {5, 15, 25, 35, 45, 35, 55, 65, 25, 35, 75};
241 std::vector<std::vector<int> > timestamps_ms(2);
242 timestamps_ms[0] = std::vector<int>(
243 timestamps0_ms, timestamps0_ms + arraysize(timestamps0_ms));
244 timestamps_ms[1] = std::vector<int>(
245 timestamps1_ms, timestamps1_ms + arraysize(timestamps1_ms));
247 // Scheduling pattern.
248 size_t pattern[] = {1, 0, 0, 0, 0};
249 std::vector<size_t> scheduling_pattern = std::vector<size_t>(
250 pattern, pattern + arraysize(pattern));
252 // Expected results.
253 int expected_timestamps[] = {
254 5, 0, 10, 20, 30, 15, 40, 25, 50, 35, 60, 45, 70, 55, 65, 75 };
255 std::vector<int> expected_timestamps_ms(std::vector<int>(
256 expected_timestamps,
257 expected_timestamps + arraysize(expected_timestamps)));
259 SetupTest(base::TimeDelta::FromMilliseconds(30),
260 timestamps_ms,
261 scheduling_pattern,
262 expected_timestamps_ms);
263 ProcessAllTasks();
264 message_loop->Run();
265 EXPECT_TRUE(expected_task_timestamps_.empty());
268 TEST_F(BalancedMediaTaskRunnerTest, TwoStreamsOfDifferentLength) {
269 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
271 std::vector<std::vector<int>> timestamps = {
272 // One longer stream and one shorter stream.
273 // The longer stream runs first, then the shorter stream begins.
274 // After shorter stream ends, it shouldn't block the longer one.
275 {0, 20, 40, 60, 80, 100, 120, 140, 160},
276 {51, 61, 71, 81},
279 std::vector<int> expected_timestamps = {
280 0, 20, 40, 60, 51, 80, 61, 71, 81, 100, 120, 140, 160};
282 std::vector<size_t> scheduling_pattern = {
283 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0};
285 SetupTest(base::TimeDelta::FromMilliseconds(30), timestamps,
286 scheduling_pattern, expected_timestamps);
287 ProcessAllTasks();
288 message_loop->Run();
289 EXPECT_TRUE(expected_task_timestamps_.empty());
292 } // namespace media
293 } // namespace chromecast