1 // Copyright 2013 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. 4 5 #include "base/bind.h" 6 #include "base/message_loop/message_loop.h" 7 #include "content/renderer/media/buffered_data_source.h" 8 #include "content/renderer/media/test_response_generator.h" 9 #include "content/test/mock_webframeclient.h" 10 #include "content/test/mock_weburlloader.h" 11 #include "media/base/media_log.h" 12 #include "media/base/mock_data_source_host.h" 13 #include "media/base/mock_filters.h" 14 #include "media/base/test_helpers.h" 15 #include "third_party/WebKit/public/platform/WebURLResponse.h" 16 #include "third_party/WebKit/public/web/WebView.h" 17 18 using ::testing::_; 19 using ::testing::Assign; 20 using ::testing::Invoke; 21 using ::testing::InSequence; 22 using ::testing::NiceMock; 23 using ::testing::StrictMock; 24 25 using blink::WebFrame; 26 using blink::WebString; 27 using blink::WebURLLoader; 28 using blink::WebURLResponse; 29 using blink::WebView; 30 31 namespace content { 32 33 // Overrides CreateResourceLoader() to permit injecting a MockWebURLLoader. 34 // Also keeps track of whether said MockWebURLLoader is actively loading. 35 class MockBufferedDataSource : public BufferedDataSource { 36 public: 37 MockBufferedDataSource( 38 const scoped_refptr<base::MessageLoopProxy>& message_loop, 39 WebFrame* frame) 40 : BufferedDataSource(message_loop, frame, new media::MediaLog(), 41 base::Bind(&MockBufferedDataSource::set_downloading, 42 base::Unretained(this))), 43 downloading_(false), 44 loading_(false) { 45 } 46 virtual ~MockBufferedDataSource() {} 47 48 MOCK_METHOD2(CreateResourceLoader, BufferedResourceLoader*(int64, int64)); 49 BufferedResourceLoader* CreateMockResourceLoader(int64 first_byte_position, 50 int64 last_byte_position) { 51 CHECK(!loading_) << "Previous resource load wasn't cancelled"; 52 53 BufferedResourceLoader* loader = 54 BufferedDataSource::CreateResourceLoader(first_byte_position, 55 last_byte_position); 56 57 // Keep track of active loading state via loadAsynchronously() and cancel(). 58 NiceMock<MockWebURLLoader>* url_loader = new NiceMock<MockWebURLLoader>(); 59 ON_CALL(*url_loader, loadAsynchronously(_, _)) 60 .WillByDefault(Assign(&loading_, true)); 61 ON_CALL(*url_loader, cancel()) 62 .WillByDefault(Assign(&loading_, false)); 63 64 // |test_loader_| will be used when Start() is called. 65 loader->test_loader_ = scoped_ptr<WebURLLoader>(url_loader); 66 return loader; 67 } 68 69 bool loading() { return loading_; } 70 void set_loading(bool loading) { loading_ = loading; } 71 bool downloading() { return downloading_; } 72 void set_downloading(bool downloading) { downloading_ = downloading; } 73 74 private: 75 // Whether the resource is downloading or deferred. 76 bool downloading_; 77 78 // Whether the resource load has starting loading but yet to been cancelled. 79 bool loading_; 80 81 DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource); 82 }; 83 84 static const int64 kFileSize = 5000000; 85 static const int64 kFarReadPosition = 4000000; 86 static const int kDataSize = 1024; 87 88 static const char kHttpUrl[] = "http://localhost/foo.webm"; 89 static const char kFileUrl[] = "file:///tmp/bar.webm"; 90 91 class BufferedDataSourceTest : public testing::Test { 92 public: 93 BufferedDataSourceTest() 94 : view_(WebView::create(NULL)) { 95 view_->initializeMainFrame(&client_); 96 97 data_source_.reset(new MockBufferedDataSource( 98 message_loop_.message_loop_proxy(), view_->mainFrame())); 99 data_source_->set_host(&host_); 100 } 101 102 virtual ~BufferedDataSourceTest() { 103 view_->close(); 104 } 105 106 MOCK_METHOD1(OnInitialize, void(bool)); 107 108 void Initialize(const char* url, bool expected) { 109 GURL gurl(url); 110 response_generator_.reset(new TestResponseGenerator(gurl, kFileSize)); 111 112 ExpectCreateResourceLoader(); 113 EXPECT_CALL(*this, OnInitialize(expected)); 114 data_source_->Initialize( 115 gurl, BufferedResourceLoader::kUnspecified, base::Bind( 116 &BufferedDataSourceTest::OnInitialize, base::Unretained(this))); 117 message_loop_.RunUntilIdle(); 118 119 bool is_http = gurl.SchemeIs(kHttpScheme) || gurl.SchemeIs(kHttpsScheme); 120 EXPECT_EQ(data_source_->downloading(), is_http); 121 } 122 123 // Helper to initialize tests with a valid 206 response. 124 void InitializeWith206Response() { 125 Initialize(kHttpUrl, true); 126 127 EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length())); 128 Respond(response_generator_->Generate206(0)); 129 } 130 131 // Helper to initialize tests with a valid file:// response. 132 void InitializeWithFileResponse() { 133 Initialize(kFileUrl, true); 134 135 EXPECT_CALL(host_, SetTotalBytes(kFileSize)); 136 EXPECT_CALL(host_, AddBufferedByteRange(0, kFileSize)); 137 Respond(response_generator_->GenerateFileResponse(0)); 138 } 139 140 // Stops any active loaders and shuts down the data source. 141 // 142 // This typically happens when the page is closed and for our purposes is 143 // appropriate to do when tearing down a test. 144 void Stop() { 145 if (data_source_->loading()) { 146 loader()->didFail(url_loader(), response_generator_->GenerateError()); 147 message_loop_.RunUntilIdle(); 148 } 149 150 data_source_->Stop(media::NewExpectedClosure()); 151 message_loop_.RunUntilIdle(); 152 } 153 154 void ExpectCreateResourceLoader() { 155 EXPECT_CALL(*data_source_, CreateResourceLoader(_, _)) 156 .WillOnce(Invoke(data_source_.get(), 157 &MockBufferedDataSource::CreateMockResourceLoader)); 158 message_loop_.RunUntilIdle(); 159 } 160 161 void Respond(const WebURLResponse& response) { 162 loader()->didReceiveResponse(url_loader(), response); 163 message_loop_.RunUntilIdle(); 164 } 165 166 void ReceiveData(int size) { 167 scoped_ptr<char[]> data(new char[size]); 168 memset(data.get(), 0xA5, size); // Arbitrary non-zero value. 169 170 loader()->didReceiveData(url_loader(), data.get(), size, size); 171 message_loop_.RunUntilIdle(); 172 } 173 174 void FinishLoading() { 175 data_source_->set_loading(false); 176 loader()->didFinishLoading(url_loader(), 0); 177 message_loop_.RunUntilIdle(); 178 } 179 180 MOCK_METHOD1(ReadCallback, void(int size)); 181 182 void ReadAt(int64 position) { 183 data_source_->Read(position, kDataSize, buffer_, 184 base::Bind(&BufferedDataSourceTest::ReadCallback, 185 base::Unretained(this))); 186 message_loop_.RunUntilIdle(); 187 } 188 189 // Accessors for private variables on |data_source_|. 190 BufferedResourceLoader* loader() { 191 return data_source_->loader_.get(); 192 } 193 WebURLLoader* url_loader() { 194 return loader()->active_loader_->loader_.get(); 195 } 196 197 Preload preload() { return data_source_->preload_; } 198 BufferedResourceLoader::DeferStrategy defer_strategy() { 199 return loader()->defer_strategy_; 200 } 201 int data_source_bitrate() { return data_source_->bitrate_; } 202 int data_source_playback_rate() { return data_source_->playback_rate_; } 203 int loader_bitrate() { return loader()->bitrate_; } 204 int loader_playback_rate() { return loader()->playback_rate_; } 205 206 scoped_ptr<MockBufferedDataSource> data_source_; 207 208 scoped_ptr<TestResponseGenerator> response_generator_; 209 MockWebFrameClient client_; 210 WebView* view_; 211 212 StrictMock<media::MockDataSourceHost> host_; 213 base::MessageLoop message_loop_; 214 215 private: 216 // Used for calling BufferedDataSource::Read(). 217 uint8 buffer_[kDataSize]; 218 219 DISALLOW_COPY_AND_ASSIGN(BufferedDataSourceTest); 220 }; 221 222 TEST_F(BufferedDataSourceTest, Range_Supported) { 223 Initialize(kHttpUrl, true); 224 225 EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length())); 226 Respond(response_generator_->Generate206(0)); 227 228 EXPECT_TRUE(data_source_->loading()); 229 EXPECT_FALSE(data_source_->IsStreaming()); 230 Stop(); 231 } 232 233 TEST_F(BufferedDataSourceTest, Range_InstanceSizeUnknown) { 234 Initialize(kHttpUrl, true); 235 236 Respond(response_generator_->Generate206( 237 0, TestResponseGenerator::kNoContentRangeInstanceSize)); 238 239 EXPECT_TRUE(data_source_->loading()); 240 EXPECT_TRUE(data_source_->IsStreaming()); 241 Stop(); 242 } 243 244 TEST_F(BufferedDataSourceTest, Range_NotFound) { 245 Initialize(kHttpUrl, false); 246 Respond(response_generator_->Generate404()); 247 248 EXPECT_FALSE(data_source_->loading()); 249 Stop(); 250 } 251 252 TEST_F(BufferedDataSourceTest, Range_NotSupported) { 253 Initialize(kHttpUrl, true); 254 EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length())); 255 Respond(response_generator_->Generate200()); 256 257 EXPECT_TRUE(data_source_->loading()); 258 EXPECT_TRUE(data_source_->IsStreaming()); 259 Stop(); 260 } 261 262 // Special carve-out for Apache versions that choose to return a 200 for 263 // Range:0- ("because it's more efficient" than a 206) 264 TEST_F(BufferedDataSourceTest, Range_SupportedButReturned200) { 265 Initialize(kHttpUrl, true); 266 EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length())); 267 WebURLResponse response = response_generator_->Generate200(); 268 response.setHTTPHeaderField(WebString::fromUTF8("Accept-Ranges"), 269 WebString::fromUTF8("bytes")); 270 Respond(response); 271 272 EXPECT_TRUE(data_source_->loading()); 273 EXPECT_FALSE(data_source_->IsStreaming()); 274 Stop(); 275 } 276 277 TEST_F(BufferedDataSourceTest, Range_MissingContentRange) { 278 Initialize(kHttpUrl, false); 279 Respond(response_generator_->Generate206( 280 0, TestResponseGenerator::kNoContentRange)); 281 282 EXPECT_FALSE(data_source_->loading()); 283 Stop(); 284 } 285 286 TEST_F(BufferedDataSourceTest, Range_MissingContentLength) { 287 Initialize(kHttpUrl, true); 288 289 // It'll manage without a Content-Length response. 290 EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length())); 291 Respond(response_generator_->Generate206( 292 0, TestResponseGenerator::kNoContentLength)); 293 294 EXPECT_TRUE(data_source_->loading()); 295 EXPECT_FALSE(data_source_->IsStreaming()); 296 Stop(); 297 } 298 299 TEST_F(BufferedDataSourceTest, Range_WrongContentRange) { 300 Initialize(kHttpUrl, false); 301 302 // Now it's done and will fail. 303 Respond(response_generator_->Generate206(1337)); 304 305 EXPECT_FALSE(data_source_->loading()); 306 Stop(); 307 } 308 309 // Test the case where the initial response from the server indicates that 310 // Range requests are supported, but a later request prove otherwise. 311 TEST_F(BufferedDataSourceTest, Range_ServerLied) { 312 InitializeWith206Response(); 313 314 // Read causing a new request to be made -- we'll expect it to error. 315 ExpectCreateResourceLoader(); 316 ReadAt(kFarReadPosition); 317 318 // Return a 200 in response to a range request. 319 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 320 Respond(response_generator_->Generate200()); 321 322 EXPECT_FALSE(data_source_->loading()); 323 Stop(); 324 } 325 326 TEST_F(BufferedDataSourceTest, Http_AbortWhileReading) { 327 InitializeWith206Response(); 328 329 // Make sure there's a pending read -- we'll expect it to error. 330 ReadAt(0); 331 332 // Abort!!! 333 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 334 data_source_->Abort(); 335 message_loop_.RunUntilIdle(); 336 337 EXPECT_FALSE(data_source_->loading()); 338 Stop(); 339 } 340 341 TEST_F(BufferedDataSourceTest, File_AbortWhileReading) { 342 InitializeWithFileResponse(); 343 344 // Make sure there's a pending read -- we'll expect it to error. 345 ReadAt(0); 346 347 // Abort!!! 348 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 349 data_source_->Abort(); 350 message_loop_.RunUntilIdle(); 351 352 EXPECT_FALSE(data_source_->loading()); 353 Stop(); 354 } 355 356 TEST_F(BufferedDataSourceTest, Http_Retry) { 357 InitializeWith206Response(); 358 359 // Read to advance our position. 360 EXPECT_CALL(*this, ReadCallback(kDataSize)); 361 EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize - 1)); 362 ReadAt(0); 363 ReceiveData(kDataSize); 364 365 // Issue a pending read but terminate the connection to force a retry. 366 ReadAt(kDataSize); 367 ExpectCreateResourceLoader(); 368 FinishLoading(); 369 Respond(response_generator_->Generate206(kDataSize)); 370 371 // Complete the read. 372 EXPECT_CALL(*this, ReadCallback(kDataSize)); 373 EXPECT_CALL(host_, AddBufferedByteRange(kDataSize, (kDataSize * 2) - 1)); 374 ReceiveData(kDataSize); 375 376 EXPECT_TRUE(data_source_->loading()); 377 Stop(); 378 } 379 380 TEST_F(BufferedDataSourceTest, File_Retry) { 381 InitializeWithFileResponse(); 382 383 // Read to advance our position. 384 EXPECT_CALL(*this, ReadCallback(kDataSize)); 385 ReadAt(0); 386 ReceiveData(kDataSize); 387 388 // Issue a pending read but terminate the connection to force a retry. 389 ReadAt(kDataSize); 390 ExpectCreateResourceLoader(); 391 FinishLoading(); 392 Respond(response_generator_->GenerateFileResponse(kDataSize)); 393 394 // Complete the read. 395 EXPECT_CALL(*this, ReadCallback(kDataSize)); 396 ReceiveData(kDataSize); 397 398 EXPECT_TRUE(data_source_->loading()); 399 Stop(); 400 } 401 402 TEST_F(BufferedDataSourceTest, Http_TooManyRetries) { 403 InitializeWith206Response(); 404 405 // Make sure there's a pending read -- we'll expect it to error. 406 ReadAt(0); 407 408 // It'll try three times. 409 ExpectCreateResourceLoader(); 410 FinishLoading(); 411 Respond(response_generator_->Generate206(0)); 412 413 ExpectCreateResourceLoader(); 414 FinishLoading(); 415 Respond(response_generator_->Generate206(0)); 416 417 ExpectCreateResourceLoader(); 418 FinishLoading(); 419 Respond(response_generator_->Generate206(0)); 420 421 // It'll error after this. 422 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 423 FinishLoading(); 424 425 EXPECT_FALSE(data_source_->loading()); 426 Stop(); 427 } 428 429 TEST_F(BufferedDataSourceTest, File_TooManyRetries) { 430 InitializeWithFileResponse(); 431 432 // Make sure there's a pending read -- we'll expect it to error. 433 ReadAt(0); 434 435 // It'll try three times. 436 ExpectCreateResourceLoader(); 437 FinishLoading(); 438 Respond(response_generator_->GenerateFileResponse(0)); 439 440 ExpectCreateResourceLoader(); 441 FinishLoading(); 442 Respond(response_generator_->GenerateFileResponse(0)); 443 444 ExpectCreateResourceLoader(); 445 FinishLoading(); 446 Respond(response_generator_->GenerateFileResponse(0)); 447 448 // It'll error after this. 449 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 450 FinishLoading(); 451 452 EXPECT_FALSE(data_source_->loading()); 453 Stop(); 454 } 455 456 TEST_F(BufferedDataSourceTest, File_InstanceSizeUnknown) { 457 Initialize(kFileUrl, false); 458 EXPECT_FALSE(data_source_->downloading()); 459 460 Respond(response_generator_->GenerateFileResponse(-1)); 461 462 EXPECT_FALSE(data_source_->loading()); 463 Stop(); 464 } 465 466 TEST_F(BufferedDataSourceTest, File_Successful) { 467 InitializeWithFileResponse(); 468 469 EXPECT_TRUE(data_source_->loading()); 470 EXPECT_FALSE(data_source_->IsStreaming()); 471 Stop(); 472 } 473 474 static void SetTrue(bool* value) { 475 *value = true; 476 } 477 478 // This test makes sure that Stop() does not require a task to run on 479 // |message_loop_| before it calls its callback. This prevents accidental 480 // introduction of a pipeline teardown deadlock. The pipeline owner blocks 481 // the render message loop while waiting for Stop() to complete. Since this 482 // object runs on the render message loop, Stop() will not complete if it 483 // requires a task to run on the the message loop that is being blocked. 484 TEST_F(BufferedDataSourceTest, StopDoesNotUseMessageLoopForCallback) { 485 InitializeWith206Response(); 486 487 // Stop() the data source, using a callback that lets us verify that it was 488 // called before Stop() returns. This is to make sure that the callback does 489 // not require |message_loop_| to execute tasks before being called. 490 bool stop_done_called = false; 491 EXPECT_TRUE(data_source_->loading()); 492 data_source_->Stop(base::Bind(&SetTrue, &stop_done_called)); 493 494 // Verify that the callback was called inside the Stop() call. 495 EXPECT_TRUE(stop_done_called); 496 message_loop_.RunUntilIdle(); 497 } 498 499 TEST_F(BufferedDataSourceTest, StopDuringRead) { 500 InitializeWith206Response(); 501 502 uint8 buffer[256]; 503 data_source_->Read(0, arraysize(buffer), buffer, base::Bind( 504 &BufferedDataSourceTest::ReadCallback, base::Unretained(this))); 505 506 // The outstanding read should fail before the stop callback runs. 507 { 508 InSequence s; 509 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 510 data_source_->Stop(media::NewExpectedClosure()); 511 } 512 message_loop_.RunUntilIdle(); 513 } 514 515 TEST_F(BufferedDataSourceTest, DefaultValues) { 516 InitializeWith206Response(); 517 518 // Ensure we have sane values for default loading scenario. 519 EXPECT_EQ(AUTO, preload()); 520 EXPECT_EQ(BufferedResourceLoader::kCapacityDefer, defer_strategy()); 521 522 EXPECT_EQ(0, data_source_bitrate()); 523 EXPECT_EQ(0.0f, data_source_playback_rate()); 524 EXPECT_EQ(0, loader_bitrate()); 525 EXPECT_EQ(0.0f, loader_playback_rate()); 526 527 EXPECT_TRUE(data_source_->loading()); 528 Stop(); 529 } 530 531 TEST_F(BufferedDataSourceTest, SetBitrate) { 532 InitializeWith206Response(); 533 534 data_source_->SetBitrate(1234); 535 message_loop_.RunUntilIdle(); 536 EXPECT_EQ(1234, data_source_bitrate()); 537 EXPECT_EQ(1234, loader_bitrate()); 538 539 // Read so far ahead to cause the loader to get recreated. 540 BufferedResourceLoader* old_loader = loader(); 541 ExpectCreateResourceLoader(); 542 ReadAt(kFarReadPosition); 543 Respond(response_generator_->Generate206(kFarReadPosition)); 544 545 // Verify loader changed but still has same bitrate. 546 EXPECT_NE(old_loader, loader()); 547 EXPECT_EQ(1234, loader_bitrate()); 548 549 EXPECT_TRUE(data_source_->loading()); 550 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 551 Stop(); 552 } 553 554 TEST_F(BufferedDataSourceTest, MediaPlaybackRateChanged) { 555 InitializeWith206Response(); 556 557 data_source_->MediaPlaybackRateChanged(2.0f); 558 message_loop_.RunUntilIdle(); 559 EXPECT_EQ(2.0f, data_source_playback_rate()); 560 EXPECT_EQ(2.0f, loader_playback_rate()); 561 562 // Read so far ahead to cause the loader to get recreated. 563 BufferedResourceLoader* old_loader = loader(); 564 ExpectCreateResourceLoader(); 565 ReadAt(kFarReadPosition); 566 Respond(response_generator_->Generate206(kFarReadPosition)); 567 568 // Verify loader changed but still has same playback rate. 569 EXPECT_NE(old_loader, loader()); 570 571 EXPECT_TRUE(data_source_->loading()); 572 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 573 Stop(); 574 } 575 576 TEST_F(BufferedDataSourceTest, Http_Read) { 577 InitializeWith206Response(); 578 579 ReadAt(0); 580 581 // Receive first half of the read. 582 EXPECT_CALL(host_, AddBufferedByteRange(0, (kDataSize / 2) - 1)); 583 ReceiveData(kDataSize / 2); 584 585 // Receive last half of the read. 586 EXPECT_CALL(*this, ReadCallback(kDataSize)); 587 EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize - 1)); 588 ReceiveData(kDataSize / 2); 589 590 EXPECT_TRUE(data_source_->downloading()); 591 Stop(); 592 } 593 594 TEST_F(BufferedDataSourceTest, Http_Read_Seek) { 595 InitializeWith206Response(); 596 597 // Read a bit from the beginning. 598 ReadAt(0); 599 EXPECT_CALL(*this, ReadCallback(kDataSize)); 600 EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize - 1)); 601 ReceiveData(kDataSize); 602 603 // Simulate a seek by reading a bit beyond kDataSize. 604 ReadAt(kDataSize * 2); 605 606 // We receive data leading up to but not including our read. 607 EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 2 - 1)); 608 ReceiveData(kDataSize); 609 610 // We now receive the rest of the data for our read. 611 EXPECT_CALL(*this, ReadCallback(kDataSize)); 612 EXPECT_CALL(host_, AddBufferedByteRange(0, kDataSize * 3 - 1)); 613 ReceiveData(kDataSize); 614 615 EXPECT_TRUE(data_source_->downloading()); 616 Stop(); 617 } 618 619 TEST_F(BufferedDataSourceTest, File_Read) { 620 InitializeWithFileResponse(); 621 622 ReadAt(0); 623 624 // Receive first half of the read but no buffering update. 625 ReceiveData(kDataSize / 2); 626 627 // Receive last half of the read but no buffering update. 628 EXPECT_CALL(*this, ReadCallback(kDataSize)); 629 ReceiveData(kDataSize / 2); 630 631 Stop(); 632 } 633 634 TEST_F(BufferedDataSourceTest, Http_FinishLoading) { 635 InitializeWith206Response(); 636 637 EXPECT_TRUE(data_source_->downloading()); 638 FinishLoading(); 639 EXPECT_FALSE(data_source_->downloading()); 640 641 Stop(); 642 } 643 644 TEST_F(BufferedDataSourceTest, File_FinishLoading) { 645 InitializeWithFileResponse(); 646 647 EXPECT_FALSE(data_source_->downloading()); 648 FinishLoading(); 649 EXPECT_FALSE(data_source_->downloading()); 650 651 Stop(); 652 } 653 654 } // namespace content 655