1 // Copyright (c) 2012 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.
6 #include "base/message_loop.h"
7 #include "media/base/media_log.h"
8 #include "media/base/mock_data_source_host.h"
9 #include "media/base/mock_filters.h"
10 #include "media/base/test_helpers.h"
11 #include "third_party/WebKit/Source/Platform/chromium/public/WebURLResponse.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
13 #include "webkit/media/buffered_data_source.h"
14 #include "webkit/mocks/mock_webframeclient.h"
15 #include "webkit/mocks/mock_weburlloader.h"
16 #include "webkit/media/test_response_generator.h"
19 using ::testing::Assign
;
20 using ::testing::Invoke
;
21 using ::testing::InSequence
;
22 using ::testing::NiceMock
;
23 using ::testing::StrictMock
;
25 using WebKit::WebFrame
;
26 using WebKit::WebString
;
27 using WebKit::WebURLLoader
;
28 using WebKit::WebURLResponse
;
29 using WebKit::WebView
;
31 using webkit_glue::MockWebFrameClient
;
32 using webkit_glue::MockWebURLLoader
;
34 namespace webkit_media
{
36 // Overrides CreateResourceLoader() to permit injecting a MockWebURLLoader.
37 // Also keeps track of whether said MockWebURLLoader is actively loading.
38 class MockBufferedDataSource
: public BufferedDataSource
{
40 MockBufferedDataSource(
41 const scoped_refptr
<base::MessageLoopProxy
>& message_loop
,
43 : BufferedDataSource(message_loop
, frame
, new media::MediaLog(),
44 base::Bind(&MockBufferedDataSource::set_downloading
,
45 base::Unretained(this))),
49 virtual ~MockBufferedDataSource() {}
51 MOCK_METHOD2(CreateResourceLoader
, BufferedResourceLoader
*(int64
, int64
));
52 BufferedResourceLoader
* CreateMockResourceLoader(int64 first_byte_position
,
53 int64 last_byte_position
) {
54 CHECK(!loading_
) << "Previous resource load wasn't cancelled";
56 BufferedResourceLoader
* loader
=
57 BufferedDataSource::CreateResourceLoader(first_byte_position
,
60 // Keep track of active loading state via loadAsynchronously() and cancel().
61 NiceMock
<MockWebURLLoader
>* url_loader
= new NiceMock
<MockWebURLLoader
>();
62 ON_CALL(*url_loader
, loadAsynchronously(_
, _
))
63 .WillByDefault(Assign(&loading_
, true));
64 ON_CALL(*url_loader
, cancel())
65 .WillByDefault(Assign(&loading_
, false));
67 // |test_loader_| will be used when Start() is called.
68 loader
->test_loader_
= scoped_ptr
<WebURLLoader
>(url_loader
);
72 bool loading() { return loading_
; }
73 void set_loading(bool loading
) { loading_
= loading
; }
74 bool downloading() { return downloading_
; }
75 void set_downloading(bool downloading
) { downloading_
= downloading
; }
78 // Whether the resource is downloading or deferred.
81 // Whether the resource load has starting loading but yet to been cancelled.
84 DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource
);
87 static const int64 kFileSize
= 5000000;
88 static const int64 kFarReadPosition
= 4000000;
89 static const int kDataSize
= 1024;
91 static const char kHttpUrl
[] = "http://localhost/foo.webm";
92 static const char kFileUrl
[] = "file:///tmp/bar.webm";
94 class BufferedDataSourceTest
: public testing::Test
{
96 BufferedDataSourceTest()
97 : view_(WebView::create(NULL
)) {
98 view_
->initializeMainFrame(&client_
);
100 data_source_
.reset(new MockBufferedDataSource(
101 message_loop_
.message_loop_proxy(), view_
->mainFrame()));
102 data_source_
->set_host(&host_
);
105 virtual ~BufferedDataSourceTest() {
109 MOCK_METHOD1(OnInitialize
, void(bool));
111 void Initialize(const char* url
, bool expected
) {
113 response_generator_
.reset(new TestResponseGenerator(gurl
, kFileSize
));
115 ExpectCreateResourceLoader();
116 EXPECT_CALL(*this, OnInitialize(expected
));
117 data_source_
->Initialize(
118 gurl
, BufferedResourceLoader::kUnspecified
, base::Bind(
119 &BufferedDataSourceTest::OnInitialize
, base::Unretained(this)));
120 message_loop_
.RunUntilIdle();
122 bool is_http
= gurl
.SchemeIs(kHttpScheme
) || gurl
.SchemeIs(kHttpsScheme
);
123 EXPECT_EQ(data_source_
->downloading(), is_http
);
126 // Helper to initialize tests with a valid 206 response.
127 void InitializeWith206Response() {
128 Initialize(kHttpUrl
, true);
130 EXPECT_CALL(host_
, SetTotalBytes(response_generator_
->content_length()));
131 Respond(response_generator_
->Generate206(0));
134 // Helper to initialize tests with a valid file:// response.
135 void InitializeWithFileResponse() {
136 Initialize(kFileUrl
, true);
138 EXPECT_CALL(host_
, SetTotalBytes(kFileSize
));
139 EXPECT_CALL(host_
, AddBufferedByteRange(0, kFileSize
));
140 Respond(response_generator_
->GenerateFileResponse(0));
143 // Stops any active loaders and shuts down the data source.
145 // This typically happens when the page is closed and for our purposes is
146 // appropriate to do when tearing down a test.
148 if (data_source_
->loading()) {
149 loader()->didFail(url_loader(), response_generator_
->GenerateError());
150 message_loop_
.RunUntilIdle();
153 data_source_
->Stop(media::NewExpectedClosure());
154 message_loop_
.RunUntilIdle();
157 void ExpectCreateResourceLoader() {
158 EXPECT_CALL(*data_source_
, CreateResourceLoader(_
, _
))
159 .WillOnce(Invoke(data_source_
.get(),
160 &MockBufferedDataSource::CreateMockResourceLoader
));
161 message_loop_
.RunUntilIdle();
164 void Respond(const WebURLResponse
& response
) {
165 loader()->didReceiveResponse(url_loader(), response
);
166 message_loop_
.RunUntilIdle();
169 void ReceiveData(int size
) {
170 scoped_ptr
<char[]> data(new char[size
]);
171 memset(data
.get(), 0xA5, size
); // Arbitrary non-zero value.
173 loader()->didReceiveData(url_loader(), data
.get(), size
, size
);
174 message_loop_
.RunUntilIdle();
177 void FinishLoading() {
178 data_source_
->set_loading(false);
179 loader()->didFinishLoading(url_loader(), 0);
180 message_loop_
.RunUntilIdle();
183 MOCK_METHOD1(ReadCallback
, void(int size
));
185 void ReadAt(int64 position
) {
186 data_source_
->Read(position
, kDataSize
, buffer_
,
187 base::Bind(&BufferedDataSourceTest::ReadCallback
,
188 base::Unretained(this)));
189 message_loop_
.RunUntilIdle();
192 // Accessors for private variables on |data_source_|.
193 BufferedResourceLoader
* loader() {
194 return data_source_
->loader_
.get();
196 WebURLLoader
* url_loader() {
197 return loader()->active_loader_
->loader_
.get();
200 Preload
preload() { return data_source_
->preload_
; }
201 BufferedResourceLoader::DeferStrategy
defer_strategy() {
202 return loader()->defer_strategy_
;
204 int data_source_bitrate() { return data_source_
->bitrate_
; }
205 int data_source_playback_rate() { return data_source_
->playback_rate_
; }
206 int loader_bitrate() { return loader()->bitrate_
; }
207 int loader_playback_rate() { return loader()->playback_rate_
; }
209 scoped_ptr
<MockBufferedDataSource
> data_source_
;
211 scoped_ptr
<TestResponseGenerator
> response_generator_
;
212 MockWebFrameClient client_
;
215 StrictMock
<media::MockDataSourceHost
> host_
;
216 base::MessageLoop message_loop_
;
219 // Used for calling BufferedDataSource::Read().
220 uint8 buffer_
[kDataSize
];
222 DISALLOW_COPY_AND_ASSIGN(BufferedDataSourceTest
);
225 TEST_F(BufferedDataSourceTest
, Range_Supported
) {
226 Initialize(kHttpUrl
, true);
228 EXPECT_CALL(host_
, SetTotalBytes(response_generator_
->content_length()));
229 Respond(response_generator_
->Generate206(0));
231 EXPECT_TRUE(data_source_
->loading());
232 EXPECT_FALSE(data_source_
->IsStreaming());
236 TEST_F(BufferedDataSourceTest
, Range_InstanceSizeUnknown
) {
237 Initialize(kHttpUrl
, true);
239 Respond(response_generator_
->Generate206(
240 0, TestResponseGenerator::kNoContentRangeInstanceSize
));
242 EXPECT_TRUE(data_source_
->loading());
243 EXPECT_TRUE(data_source_
->IsStreaming());
247 TEST_F(BufferedDataSourceTest
, Range_NotFound
) {
248 Initialize(kHttpUrl
, false);
249 Respond(response_generator_
->Generate404());
251 EXPECT_FALSE(data_source_
->loading());
255 TEST_F(BufferedDataSourceTest
, Range_NotSupported
) {
256 Initialize(kHttpUrl
, true);
257 EXPECT_CALL(host_
, SetTotalBytes(response_generator_
->content_length()));
258 Respond(response_generator_
->Generate200());
260 EXPECT_TRUE(data_source_
->loading());
261 EXPECT_TRUE(data_source_
->IsStreaming());
265 // Special carve-out for Apache versions that choose to return a 200 for
266 // Range:0- ("because it's more efficient" than a 206)
267 TEST_F(BufferedDataSourceTest
, Range_SupportedButReturned200
) {
268 Initialize(kHttpUrl
, true);
269 EXPECT_CALL(host_
, SetTotalBytes(response_generator_
->content_length()));
270 WebURLResponse response
= response_generator_
->Generate200();
271 response
.setHTTPHeaderField(WebString::fromUTF8("Accept-Ranges"),
272 WebString::fromUTF8("bytes"));
275 EXPECT_TRUE(data_source_
->loading());
276 EXPECT_FALSE(data_source_
->IsStreaming());
280 TEST_F(BufferedDataSourceTest
, Range_MissingContentRange
) {
281 Initialize(kHttpUrl
, false);
282 Respond(response_generator_
->Generate206(
283 0, TestResponseGenerator::kNoContentRange
));
285 EXPECT_FALSE(data_source_
->loading());
289 TEST_F(BufferedDataSourceTest
, Range_MissingContentLength
) {
290 Initialize(kHttpUrl
, true);
292 // It'll manage without a Content-Length response.
293 EXPECT_CALL(host_
, SetTotalBytes(response_generator_
->content_length()));
294 Respond(response_generator_
->Generate206(
295 0, TestResponseGenerator::kNoContentLength
));
297 EXPECT_TRUE(data_source_
->loading());
298 EXPECT_FALSE(data_source_
->IsStreaming());
302 TEST_F(BufferedDataSourceTest
, Range_WrongContentRange
) {
303 Initialize(kHttpUrl
, false);
305 // Now it's done and will fail.
306 Respond(response_generator_
->Generate206(1337));
308 EXPECT_FALSE(data_source_
->loading());
312 // Test the case where the initial response from the server indicates that
313 // Range requests are supported, but a later request prove otherwise.
314 TEST_F(BufferedDataSourceTest
, Range_ServerLied
) {
315 InitializeWith206Response();
317 // Read causing a new request to be made -- we'll expect it to error.
318 ExpectCreateResourceLoader();
319 ReadAt(kFarReadPosition
);
321 // Return a 200 in response to a range request.
322 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
323 Respond(response_generator_
->Generate200());
325 EXPECT_FALSE(data_source_
->loading());
329 TEST_F(BufferedDataSourceTest
, Http_AbortWhileReading
) {
330 InitializeWith206Response();
332 // Make sure there's a pending read -- we'll expect it to error.
336 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
337 data_source_
->Abort();
338 message_loop_
.RunUntilIdle();
340 EXPECT_FALSE(data_source_
->loading());
344 TEST_F(BufferedDataSourceTest
, File_AbortWhileReading
) {
345 InitializeWithFileResponse();
347 // Make sure there's a pending read -- we'll expect it to error.
351 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
352 data_source_
->Abort();
353 message_loop_
.RunUntilIdle();
355 EXPECT_FALSE(data_source_
->loading());
359 TEST_F(BufferedDataSourceTest
, Http_Retry
) {
360 InitializeWith206Response();
362 // Read to advance our position.
363 EXPECT_CALL(*this, ReadCallback(kDataSize
));
364 EXPECT_CALL(host_
, AddBufferedByteRange(0, kDataSize
- 1));
366 ReceiveData(kDataSize
);
368 // Issue a pending read but terminate the connection to force a retry.
370 ExpectCreateResourceLoader();
372 Respond(response_generator_
->Generate206(kDataSize
));
374 // Complete the read.
375 EXPECT_CALL(*this, ReadCallback(kDataSize
));
376 EXPECT_CALL(host_
, AddBufferedByteRange(kDataSize
, (kDataSize
* 2) - 1));
377 ReceiveData(kDataSize
);
379 EXPECT_TRUE(data_source_
->loading());
383 TEST_F(BufferedDataSourceTest
, File_Retry
) {
384 InitializeWithFileResponse();
386 // Read to advance our position.
387 EXPECT_CALL(*this, ReadCallback(kDataSize
));
389 ReceiveData(kDataSize
);
391 // Issue a pending read but terminate the connection to force a retry.
393 ExpectCreateResourceLoader();
395 Respond(response_generator_
->GenerateFileResponse(kDataSize
));
397 // Complete the read.
398 EXPECT_CALL(*this, ReadCallback(kDataSize
));
399 ReceiveData(kDataSize
);
401 EXPECT_TRUE(data_source_
->loading());
405 TEST_F(BufferedDataSourceTest
, Http_TooManyRetries
) {
406 InitializeWith206Response();
408 // Make sure there's a pending read -- we'll expect it to error.
411 // It'll try three times.
412 ExpectCreateResourceLoader();
414 Respond(response_generator_
->Generate206(0));
416 ExpectCreateResourceLoader();
418 Respond(response_generator_
->Generate206(0));
420 ExpectCreateResourceLoader();
422 Respond(response_generator_
->Generate206(0));
424 // It'll error after this.
425 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
428 EXPECT_FALSE(data_source_
->loading());
432 TEST_F(BufferedDataSourceTest
, File_TooManyRetries
) {
433 InitializeWithFileResponse();
435 // Make sure there's a pending read -- we'll expect it to error.
438 // It'll try three times.
439 ExpectCreateResourceLoader();
441 Respond(response_generator_
->GenerateFileResponse(0));
443 ExpectCreateResourceLoader();
445 Respond(response_generator_
->GenerateFileResponse(0));
447 ExpectCreateResourceLoader();
449 Respond(response_generator_
->GenerateFileResponse(0));
451 // It'll error after this.
452 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
455 EXPECT_FALSE(data_source_
->loading());
459 TEST_F(BufferedDataSourceTest
, File_InstanceSizeUnknown
) {
460 Initialize(kFileUrl
, false);
461 EXPECT_FALSE(data_source_
->downloading());
463 Respond(response_generator_
->GenerateFileResponse(-1));
465 EXPECT_FALSE(data_source_
->loading());
469 TEST_F(BufferedDataSourceTest
, File_Successful
) {
470 InitializeWithFileResponse();
472 EXPECT_TRUE(data_source_
->loading());
473 EXPECT_FALSE(data_source_
->IsStreaming());
477 static void SetTrue(bool* value
) {
481 // This test makes sure that Stop() does not require a task to run on
482 // |message_loop_| before it calls its callback. This prevents accidental
483 // introduction of a pipeline teardown deadlock. The pipeline owner blocks
484 // the render message loop while waiting for Stop() to complete. Since this
485 // object runs on the render message loop, Stop() will not complete if it
486 // requires a task to run on the the message loop that is being blocked.
487 TEST_F(BufferedDataSourceTest
, StopDoesNotUseMessageLoopForCallback
) {
488 InitializeWith206Response();
490 // Stop() the data source, using a callback that lets us verify that it was
491 // called before Stop() returns. This is to make sure that the callback does
492 // not require |message_loop_| to execute tasks before being called.
493 bool stop_done_called
= false;
494 EXPECT_TRUE(data_source_
->loading());
495 data_source_
->Stop(base::Bind(&SetTrue
, &stop_done_called
));
497 // Verify that the callback was called inside the Stop() call.
498 EXPECT_TRUE(stop_done_called
);
499 message_loop_
.RunUntilIdle();
502 TEST_F(BufferedDataSourceTest
, StopDuringRead
) {
503 InitializeWith206Response();
506 data_source_
->Read(0, arraysize(buffer
), buffer
, base::Bind(
507 &BufferedDataSourceTest::ReadCallback
, base::Unretained(this)));
509 // The outstanding read should fail before the stop callback runs.
512 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
513 data_source_
->Stop(media::NewExpectedClosure());
515 message_loop_
.RunUntilIdle();
518 TEST_F(BufferedDataSourceTest
, DefaultValues
) {
519 InitializeWith206Response();
521 // Ensure we have sane values for default loading scenario.
522 EXPECT_EQ(AUTO
, preload());
523 EXPECT_EQ(BufferedResourceLoader::kCapacityDefer
, defer_strategy());
525 EXPECT_EQ(0, data_source_bitrate());
526 EXPECT_EQ(0.0f
, data_source_playback_rate());
527 EXPECT_EQ(0, loader_bitrate());
528 EXPECT_EQ(0.0f
, loader_playback_rate());
530 EXPECT_TRUE(data_source_
->loading());
534 TEST_F(BufferedDataSourceTest
, SetBitrate
) {
535 InitializeWith206Response();
537 data_source_
->SetBitrate(1234);
538 message_loop_
.RunUntilIdle();
539 EXPECT_EQ(1234, data_source_bitrate());
540 EXPECT_EQ(1234, loader_bitrate());
542 // Read so far ahead to cause the loader to get recreated.
543 BufferedResourceLoader
* old_loader
= loader();
544 ExpectCreateResourceLoader();
545 ReadAt(kFarReadPosition
);
546 Respond(response_generator_
->Generate206(kFarReadPosition
));
548 // Verify loader changed but still has same bitrate.
549 EXPECT_NE(old_loader
, loader());
550 EXPECT_EQ(1234, loader_bitrate());
552 EXPECT_TRUE(data_source_
->loading());
553 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
557 TEST_F(BufferedDataSourceTest
, SetPlaybackRate
) {
558 InitializeWith206Response();
560 data_source_
->SetPlaybackRate(2.0f
);
561 message_loop_
.RunUntilIdle();
562 EXPECT_EQ(2.0f
, data_source_playback_rate());
563 EXPECT_EQ(2.0f
, loader_playback_rate());
565 // Read so far ahead to cause the loader to get recreated.
566 BufferedResourceLoader
* old_loader
= loader();
567 ExpectCreateResourceLoader();
568 ReadAt(kFarReadPosition
);
569 Respond(response_generator_
->Generate206(kFarReadPosition
));
571 // Verify loader changed but still has same playback rate.
572 EXPECT_NE(old_loader
, loader());
574 EXPECT_TRUE(data_source_
->loading());
575 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError
));
579 TEST_F(BufferedDataSourceTest
, Http_Read
) {
580 InitializeWith206Response();
584 // Receive first half of the read.
585 EXPECT_CALL(host_
, AddBufferedByteRange(0, (kDataSize
/ 2) - 1));
586 ReceiveData(kDataSize
/ 2);
588 // Receive last half of the read.
589 EXPECT_CALL(*this, ReadCallback(kDataSize
));
590 EXPECT_CALL(host_
, AddBufferedByteRange(0, kDataSize
- 1));
591 ReceiveData(kDataSize
/ 2);
593 EXPECT_TRUE(data_source_
->downloading());
597 TEST_F(BufferedDataSourceTest
, Http_Read_Seek
) {
598 InitializeWith206Response();
600 // Read a bit from the beginning.
602 EXPECT_CALL(*this, ReadCallback(kDataSize
));
603 EXPECT_CALL(host_
, AddBufferedByteRange(0, kDataSize
- 1));
604 ReceiveData(kDataSize
);
606 // Simulate a seek by reading a bit beyond kDataSize.
607 ReadAt(kDataSize
* 2);
609 // We receive data leading up to but not including our read.
610 EXPECT_CALL(host_
, AddBufferedByteRange(0, kDataSize
* 2 - 1));
611 ReceiveData(kDataSize
);
613 // We now receive the rest of the data for our read.
614 EXPECT_CALL(*this, ReadCallback(kDataSize
));
615 EXPECT_CALL(host_
, AddBufferedByteRange(0, kDataSize
* 3 - 1));
616 ReceiveData(kDataSize
);
618 EXPECT_TRUE(data_source_
->downloading());
622 TEST_F(BufferedDataSourceTest
, File_Read
) {
623 InitializeWithFileResponse();
627 // Receive first half of the read but no buffering update.
628 ReceiveData(kDataSize
/ 2);
630 // Receive last half of the read but no buffering update.
631 EXPECT_CALL(*this, ReadCallback(kDataSize
));
632 ReceiveData(kDataSize
/ 2);
637 TEST_F(BufferedDataSourceTest
, Http_FinishLoading
) {
638 InitializeWith206Response();
640 EXPECT_TRUE(data_source_
->downloading());
642 EXPECT_FALSE(data_source_
->downloading());
647 TEST_F(BufferedDataSourceTest
, File_FinishLoading
) {
648 InitializeWithFileResponse();
650 EXPECT_FALSE(data_source_
->downloading());
652 EXPECT_FALSE(data_source_
->downloading());
657 } // namespace webkit_media