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.
8 #include "base/basictypes.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
{
24 struct MediaTaskRunnerTestContext
{
25 MediaTaskRunnerTestContext();
26 ~MediaTaskRunnerTestContext();
28 scoped_refptr
<MediaTaskRunner
> media_task_runner
;
32 std::vector
<base::TimeDelta
> task_timestamp_list
;
35 base::TimeDelta max_timestamp
;
38 MediaTaskRunnerTestContext::MediaTaskRunnerTestContext() {
41 MediaTaskRunnerTestContext::~MediaTaskRunnerTestContext() {
46 class BalancedMediaTaskRunnerTest
: public testing::Test
{
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();
58 // Expected task order based on their timestamps.
59 std::list
<base::TimeDelta
> expected_task_timestamps_
;
63 void Task(size_t task_runner_id
, base::TimeDelta timestamp
);
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
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
;
98 // Setup each task runner.
99 size_t n
= timestamps_in_ms
.size();
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(
125 base::Bind(&BalancedMediaTaskRunnerTest::OnTestTimeout
,
126 base::Unretained(this)),
127 base::TimeDelta::FromSeconds(5));
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())
138 base::MessageLoop::current()->QuitWhenIdle();
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)));
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(
168 base::Bind(&BalancedMediaTaskRunnerTest::Task
,
169 base::Unretained(this),
171 context
.task_timestamp_list
[context
.task_index
]),
172 context
.task_timestamp_list
[context
.task_index
]);
173 EXPECT_EQ(may_run
, expected_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;
221 int expected_timestamps
[] = {0, 10, 20, 30, 40, 50, 60, 70};
222 std::vector
<int> expected_timestamps_ms(std::vector
<int>(
224 expected_timestamps
+ arraysize(expected_timestamps
)));
226 SetupTest(base::TimeDelta::FromMilliseconds(30),
229 expected_timestamps_ms
);
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
));
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>(
257 expected_timestamps
+ arraysize(expected_timestamps
)));
259 SetupTest(base::TimeDelta::FromMilliseconds(30),
262 expected_timestamps_ms
);
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},
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
);
289 EXPECT_TRUE(expected_task_timestamps_
.empty());
293 } // namespace chromecast