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