| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 <algorithm> | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/test/test_timeouts.h" | |
| 9 #include "media/base/media_log.h" | |
| 10 #include "media/base/mock_callback.h" | |
| 11 #include "media/base/mock_filter_host.h" | |
| 12 #include "media/base/mock_filters.h" | |
| 13 #include "net/base/net_errors.h" | |
| 14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" | |
| 15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h" | |
| 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 17 #include "webkit/glue/media/buffered_data_source.h" | |
| 18 #include "webkit/mocks/mock_webframeclient.h" | |
| 19 #include "webkit/mocks/mock_weburlloader.h" | |
| 20 | |
| 21 using ::testing::_; | |
| 22 using ::testing::Assign; | |
| 23 using ::testing::AtLeast; | |
| 24 using ::testing::DeleteArg; | |
| 25 using ::testing::DoAll; | |
| 26 using ::testing::InSequence; | |
| 27 using ::testing::Invoke; | |
| 28 using ::testing::InvokeWithoutArgs; | |
| 29 using ::testing::NotNull; | |
| 30 using ::testing::Return; | |
| 31 using ::testing::ReturnRef; | |
| 32 using ::testing::SetArgumentPointee; | |
| 33 using ::testing::StrictMock; | |
| 34 using ::testing::NiceMock; | |
| 35 using ::testing::WithArgs; | |
| 36 | |
| 37 using WebKit::WebFrame; | |
| 38 using WebKit::WebString; | |
| 39 using WebKit::WebURLError; | |
| 40 using WebKit::WebURLResponse; | |
| 41 using WebKit::WebView; | |
| 42 | |
| 43 namespace webkit_glue { | |
| 44 | |
| 45 static const char* kHttpUrl = "http://test"; | |
| 46 static const char* kFileUrl = "file://test"; | |
| 47 static const int kDataSize = 1024; | |
| 48 static const int kMaxCacheMissesBeforeFailTest = 20; | |
| 49 | |
| 50 enum NetworkState { | |
| 51 NONE, | |
| 52 LOADED, | |
| 53 LOADING | |
| 54 }; | |
| 55 | |
| 56 // A mock BufferedDataSource to inject mock BufferedResourceLoader through | |
| 57 // CreateResourceLoader() method. | |
| 58 class MockBufferedDataSource : public BufferedDataSource { | |
| 59 public: | |
| 60 MockBufferedDataSource(MessageLoop* message_loop, WebFrame* frame) | |
| 61 : BufferedDataSource(message_loop, frame, new media::MediaLog()) { | |
| 62 } | |
| 63 | |
| 64 virtual base::TimeDelta GetTimeoutMilliseconds() { | |
| 65 return base::TimeDelta::FromMilliseconds( | |
| 66 TestTimeouts::tiny_timeout_ms()); | |
| 67 } | |
| 68 | |
| 69 MOCK_METHOD2(CreateResourceLoader, | |
| 70 BufferedResourceLoader*(int64 first_position, | |
| 71 int64 last_position)); | |
| 72 | |
| 73 private: | |
| 74 DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource); | |
| 75 }; | |
| 76 | |
| 77 class MockBufferedResourceLoader : public BufferedResourceLoader { | |
| 78 public: | |
| 79 MockBufferedResourceLoader() | |
| 80 : BufferedResourceLoader(GURL(), 0, 0, kThresholdDefer, | |
| 81 0, 0, new media::MediaLog()) { | |
| 82 } | |
| 83 | |
| 84 MOCK_METHOD3(Start, void(net::OldCompletionCallback* read_callback, | |
| 85 const base::Closure& network_callback, | |
| 86 WebFrame* frame)); | |
| 87 MOCK_METHOD0(Stop, void()); | |
| 88 MOCK_METHOD4(Read, void(int64 position, int read_size, uint8* buffer, | |
| 89 net::OldCompletionCallback* callback)); | |
| 90 MOCK_METHOD0(content_length, int64()); | |
| 91 MOCK_METHOD0(instance_size, int64()); | |
| 92 MOCK_METHOD0(range_supported, bool()); | |
| 93 MOCK_METHOD0(network_activity, bool()); | |
| 94 MOCK_METHOD0(url, const GURL&()); | |
| 95 MOCK_METHOD0(GetBufferedFirstBytePosition, int64()); | |
| 96 MOCK_METHOD0(GetBufferedLastBytePosition, int64()); | |
| 97 | |
| 98 protected: | |
| 99 ~MockBufferedResourceLoader() {} | |
| 100 | |
| 101 DISALLOW_COPY_AND_ASSIGN(MockBufferedResourceLoader); | |
| 102 }; | |
| 103 | |
| 104 class BufferedDataSourceTest : public testing::Test { | |
| 105 public: | |
| 106 BufferedDataSourceTest() | |
| 107 : view_(WebView::create(NULL)) { | |
| 108 view_->initializeMainFrame(&client_); | |
| 109 message_loop_ = MessageLoop::current(); | |
| 110 | |
| 111 for (size_t i = 0; i < sizeof(data_); ++i) { | |
| 112 data_[i] = i; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 virtual ~BufferedDataSourceTest() { | |
| 117 view_->close(); | |
| 118 } | |
| 119 | |
| 120 void ExpectCreateAndStartResourceLoader(int start_error) { | |
| 121 EXPECT_CALL(*data_source_, CreateResourceLoader(_, _)) | |
| 122 .WillOnce(Return(loader_.get())); | |
| 123 | |
| 124 EXPECT_CALL(*loader_, Start(NotNull(), _, NotNull())) | |
| 125 .WillOnce( | |
| 126 DoAll(Assign(&error_, start_error), | |
| 127 Invoke(this, | |
| 128 &BufferedDataSourceTest::InvokeStartCallback))); | |
| 129 } | |
| 130 | |
| 131 void InitializeDataSource(const char* url, int error, | |
| 132 bool partial_response, int64 instance_size, | |
| 133 NetworkState networkState) { | |
| 134 // Saves the url first. | |
| 135 gurl_ = GURL(url); | |
| 136 | |
| 137 data_source_ = new MockBufferedDataSource(MessageLoop::current(), | |
| 138 view_->mainFrame()); | |
| 139 data_source_->set_host(&host_); | |
| 140 | |
| 141 scoped_refptr<NiceMock<MockBufferedResourceLoader> > first_loader( | |
| 142 new NiceMock<MockBufferedResourceLoader>()); | |
| 143 | |
| 144 // Creates the mock loader to be injected. | |
| 145 loader_ = first_loader; | |
| 146 | |
| 147 bool initialized_ok = (error == net::OK); | |
| 148 bool loaded = networkState == LOADED; | |
| 149 { | |
| 150 InSequence s; | |
| 151 ExpectCreateAndStartResourceLoader(error); | |
| 152 | |
| 153 // In the case of an invalid partial response we expect a second loader | |
| 154 // to be created. | |
| 155 if (partial_response && (error == net::ERR_INVALID_RESPONSE)) { | |
| 156 // Verify that the initial loader is stopped. | |
| 157 EXPECT_CALL(*loader_, url()) | |
| 158 .WillRepeatedly(ReturnRef(gurl_)); | |
| 159 EXPECT_CALL(*loader_, Stop()); | |
| 160 | |
| 161 // Replace loader_ with a new instance. | |
| 162 loader_ = new NiceMock<MockBufferedResourceLoader>(); | |
| 163 | |
| 164 // Create and start. Make sure Start() is called on the new loader. | |
| 165 ExpectCreateAndStartResourceLoader(net::OK); | |
| 166 | |
| 167 // Update initialization variable since we know the second loader will | |
| 168 // return OK. | |
| 169 initialized_ok = true; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 // Attach a static function that deletes the memory referred by the | |
| 174 // "callback" parameter. | |
| 175 ON_CALL(*loader_, Read(_, _, _ , _)) | |
| 176 .WillByDefault(DeleteArg<3>()); | |
| 177 | |
| 178 ON_CALL(*loader_, instance_size()) | |
| 179 .WillByDefault(Return(instance_size)); | |
| 180 | |
| 181 // range_supported() return true if we expect to get a partial response. | |
| 182 ON_CALL(*loader_, range_supported()) | |
| 183 .WillByDefault(Return(partial_response)); | |
| 184 | |
| 185 ON_CALL(*loader_, url()) | |
| 186 .WillByDefault(ReturnRef(gurl_)); | |
| 187 media::PipelineStatus expected_init_status = media::PIPELINE_OK; | |
| 188 if (initialized_ok) { | |
| 189 // Expected loaded or not. | |
| 190 EXPECT_CALL(host_, SetLoaded(loaded)); | |
| 191 | |
| 192 // TODO(hclam): The condition for streaming needs to be adjusted. | |
| 193 if (instance_size != -1 && (loaded || partial_response)) { | |
| 194 EXPECT_CALL(host_, SetTotalBytes(instance_size)); | |
| 195 if (loaded) | |
| 196 EXPECT_CALL(host_, SetBufferedBytes(instance_size)); | |
| 197 else | |
| 198 EXPECT_CALL(host_, SetBufferedBytes(0)); | |
| 199 } else { | |
| 200 EXPECT_CALL(host_, SetStreaming(true)); | |
| 201 } | |
| 202 } else { | |
| 203 expected_init_status = media::PIPELINE_ERROR_NETWORK; | |
| 204 EXPECT_CALL(*loader_, Stop()); | |
| 205 } | |
| 206 | |
| 207 // Actual initialization of the data source. | |
| 208 data_source_->Initialize(url, | |
| 209 media::NewExpectedStatusCB(expected_init_status)); | |
| 210 message_loop_->RunAllPending(); | |
| 211 | |
| 212 if (initialized_ok) { | |
| 213 // Verify the size of the data source. | |
| 214 int64 size; | |
| 215 if (instance_size != -1 && (loaded || partial_response)) { | |
| 216 EXPECT_TRUE(data_source_->GetSize(&size)); | |
| 217 EXPECT_EQ(instance_size, size); | |
| 218 } else { | |
| 219 EXPECT_TRUE(data_source_->IsStreaming()); | |
| 220 } | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 void StopDataSource() { | |
| 225 if (loader_) { | |
| 226 InSequence s; | |
| 227 EXPECT_CALL(*loader_, Stop()); | |
| 228 } | |
| 229 | |
| 230 data_source_->Stop(media::NewExpectedClosure()); | |
| 231 message_loop_->RunAllPending(); | |
| 232 } | |
| 233 | |
| 234 void InvokeStartCallback( | |
| 235 net::OldCompletionCallback* callback, | |
| 236 const base::Closure& network_callback, | |
| 237 WebFrame* frame) { | |
| 238 callback->RunWithParams(Tuple1<int>(error_)); | |
| 239 delete callback; | |
| 240 // TODO(hclam): Save network_callback. | |
| 241 } | |
| 242 | |
| 243 void InvokeReadCallback(int64 position, int size, uint8* buffer, | |
| 244 net::OldCompletionCallback* callback) { | |
| 245 if (error_ > 0) | |
| 246 memcpy(buffer, data_ + static_cast<int>(position), error_); | |
| 247 callback->RunWithParams(Tuple1<int>(error_)); | |
| 248 delete callback; | |
| 249 } | |
| 250 | |
| 251 void ReadDataSourceHit(int64 position, int size, int read_size) { | |
| 252 EXPECT_TRUE(loader_); | |
| 253 | |
| 254 InSequence s; | |
| 255 // Expect the read is delegated to the resource loader. | |
| 256 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull())) | |
| 257 .WillOnce(DoAll(Assign(&error_, read_size), | |
| 258 Invoke(this, | |
| 259 &BufferedDataSourceTest::InvokeReadCallback))); | |
| 260 | |
| 261 // The read has succeeded, so read callback will be called. | |
| 262 EXPECT_CALL(*this, ReadCallback(read_size)); | |
| 263 | |
| 264 data_source_->Read( | |
| 265 position, size, buffer_, | |
| 266 base::Bind(&BufferedDataSourceTest::ReadCallback, | |
| 267 base::Unretained(this))); | |
| 268 message_loop_->RunAllPending(); | |
| 269 | |
| 270 // Make sure data is correct. | |
| 271 EXPECT_EQ(0, | |
| 272 memcmp(buffer_, data_ + static_cast<int>(position), read_size)); | |
| 273 } | |
| 274 | |
| 275 void ReadDataSourceHang(int64 position, int size) { | |
| 276 EXPECT_TRUE(loader_); | |
| 277 | |
| 278 // Expect a call to read, but the call never returns. | |
| 279 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull())); | |
| 280 data_source_->Read( | |
| 281 position, size, buffer_, | |
| 282 base::Bind(&BufferedDataSourceTest::ReadCallback, | |
| 283 base::Unretained(this))); | |
| 284 message_loop_->RunAllPending(); | |
| 285 | |
| 286 // Now expect the read to return after aborting the data source. | |
| 287 EXPECT_CALL(*this, ReadCallback(_)); | |
| 288 EXPECT_CALL(*loader_, Stop()); | |
| 289 data_source_->Abort(); | |
| 290 message_loop_->RunAllPending(); | |
| 291 | |
| 292 // The loader has now been stopped. Set this to null so that when the | |
| 293 // DataSource is stopped, it does not expect a call to stop the loader. | |
| 294 loader_ = NULL; | |
| 295 } | |
| 296 | |
| 297 void ReadDataSourceMiss(int64 position, int size, int start_error) { | |
| 298 EXPECT_TRUE(loader_); | |
| 299 | |
| 300 // 1. Reply with a cache miss for the read. | |
| 301 { | |
| 302 InSequence s; | |
| 303 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull())) | |
| 304 .WillOnce(DoAll(Assign(&error_, net::ERR_CACHE_MISS), | |
| 305 Invoke(this, | |
| 306 &BufferedDataSourceTest::InvokeReadCallback))); | |
| 307 EXPECT_CALL(*loader_, Stop()); | |
| 308 } | |
| 309 | |
| 310 // 2. Then the current loader will be stop and destroyed. | |
| 311 NiceMock<MockBufferedResourceLoader> *new_loader = | |
| 312 new NiceMock<MockBufferedResourceLoader>(); | |
| 313 EXPECT_CALL(*data_source_, CreateResourceLoader(position, -1)) | |
| 314 .WillOnce(Return(new_loader)); | |
| 315 | |
| 316 // 3. Then the new loader will be started. | |
| 317 EXPECT_CALL(*new_loader, Start(NotNull(), _, NotNull())) | |
| 318 .WillOnce(DoAll(Assign(&error_, start_error), | |
| 319 Invoke(this, | |
| 320 &BufferedDataSourceTest::InvokeStartCallback))); | |
| 321 | |
| 322 if (start_error == net::OK) { | |
| 323 EXPECT_CALL(*new_loader, range_supported()) | |
| 324 .WillRepeatedly(Return(loader_->range_supported())); | |
| 325 | |
| 326 // 4a. Then again a read request is made to the new loader. | |
| 327 EXPECT_CALL(*new_loader, Read(position, size, NotNull(), NotNull())) | |
| 328 .WillOnce(DoAll(Assign(&error_, size), | |
| 329 Invoke(this, | |
| 330 &BufferedDataSourceTest::InvokeReadCallback))); | |
| 331 | |
| 332 EXPECT_CALL(*this, ReadCallback(size)); | |
| 333 } else { | |
| 334 // 4b. The read callback is called with an error because Start() on the | |
| 335 // new loader returned an error. | |
| 336 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); | |
| 337 } | |
| 338 | |
| 339 data_source_->Read( | |
| 340 position, size, buffer_, | |
| 341 base::Bind(&BufferedDataSourceTest::ReadCallback, | |
| 342 base::Unretained(this))); | |
| 343 message_loop_->RunAllPending(); | |
| 344 | |
| 345 // Make sure data is correct. | |
| 346 if (start_error == net::OK) | |
| 347 EXPECT_EQ(0, memcmp(buffer_, data_ + static_cast<int>(position), size)); | |
| 348 | |
| 349 loader_ = new_loader; | |
| 350 } | |
| 351 | |
| 352 void ReadDataSourceFailed(int64 position, int size, int error) { | |
| 353 EXPECT_TRUE(loader_); | |
| 354 | |
| 355 // 1. Expect the read is delegated to the resource loader. | |
| 356 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull())) | |
| 357 .WillOnce(DoAll(Assign(&error_, error), | |
| 358 Invoke(this, | |
| 359 &BufferedDataSourceTest::InvokeReadCallback))); | |
| 360 | |
| 361 // 2. Host will then receive an error. | |
| 362 EXPECT_CALL(*loader_, Stop()); | |
| 363 | |
| 364 // 3. The read has failed, so read callback will be called. | |
| 365 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); | |
| 366 | |
| 367 data_source_->Read( | |
| 368 position, size, buffer_, | |
| 369 base::Bind(&BufferedDataSourceTest::ReadCallback, | |
| 370 base::Unretained(this))); | |
| 371 | |
| 372 message_loop_->RunAllPending(); | |
| 373 } | |
| 374 | |
| 375 BufferedResourceLoader* InvokeCacheMissCreateResourceLoader(int64 start, | |
| 376 int64 end) { | |
| 377 NiceMock<MockBufferedResourceLoader>* new_loader = | |
| 378 new NiceMock<MockBufferedResourceLoader>(); | |
| 379 | |
| 380 EXPECT_CALL(*new_loader, Start(NotNull(), _, NotNull())) | |
| 381 .WillOnce(DoAll(Assign(&error_, net::OK), | |
| 382 Invoke(this, | |
| 383 &BufferedDataSourceTest::InvokeStartCallback))); | |
| 384 | |
| 385 EXPECT_CALL(*new_loader, range_supported()) | |
| 386 .WillRepeatedly(Return(loader_->range_supported())); | |
| 387 | |
| 388 int error = net::ERR_FAILED; | |
| 389 if (cache_miss_count_ < kMaxCacheMissesBeforeFailTest) { | |
| 390 cache_miss_count_++; | |
| 391 error = net::ERR_CACHE_MISS; | |
| 392 } | |
| 393 | |
| 394 EXPECT_CALL(*new_loader, Read(start, _, NotNull(), NotNull())) | |
| 395 .WillOnce(DoAll(Assign(&error_, error), | |
| 396 Invoke(this, | |
| 397 &BufferedDataSourceTest::InvokeReadCallback))); | |
| 398 | |
| 399 loader_ = new_loader; | |
| 400 return new_loader; | |
| 401 } | |
| 402 | |
| 403 void ReadDataSourceAlwaysCacheMiss(int64 position, int size) { | |
| 404 cache_miss_count_ = 0; | |
| 405 | |
| 406 EXPECT_CALL(*data_source_, CreateResourceLoader(position, -1)) | |
| 407 .WillRepeatedly(Invoke( | |
| 408 this, | |
| 409 &BufferedDataSourceTest::InvokeCacheMissCreateResourceLoader)); | |
| 410 | |
| 411 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull())) | |
| 412 .WillOnce(DoAll(Assign(&error_, net::ERR_CACHE_MISS), | |
| 413 Invoke(this, | |
| 414 &BufferedDataSourceTest::InvokeReadCallback))); | |
| 415 | |
| 416 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); | |
| 417 | |
| 418 data_source_->Read( | |
| 419 position, size, buffer_, | |
| 420 base::Bind(&BufferedDataSourceTest::ReadCallback, | |
| 421 base::Unretained(this))); | |
| 422 | |
| 423 message_loop_->RunAllPending(); | |
| 424 | |
| 425 EXPECT_LT(cache_miss_count_, kMaxCacheMissesBeforeFailTest); | |
| 426 } | |
| 427 | |
| 428 MOCK_METHOD1(ReadCallback, void(size_t size)); | |
| 429 | |
| 430 scoped_refptr<NiceMock<MockBufferedResourceLoader> > loader_; | |
| 431 scoped_refptr<MockBufferedDataSource> data_source_; | |
| 432 | |
| 433 MockWebFrameClient client_; | |
| 434 WebView* view_; | |
| 435 | |
| 436 StrictMock<media::MockFilterHost> host_; | |
| 437 GURL gurl_; | |
| 438 MessageLoop* message_loop_; | |
| 439 | |
| 440 int error_; | |
| 441 uint8 buffer_[1024]; | |
| 442 uint8 data_[1024]; | |
| 443 | |
| 444 int cache_miss_count_; | |
| 445 | |
| 446 private: | |
| 447 DISALLOW_COPY_AND_ASSIGN(BufferedDataSourceTest); | |
| 448 }; | |
| 449 | |
| 450 TEST_F(BufferedDataSourceTest, InitializationSuccess) { | |
| 451 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); | |
| 452 StopDataSource(); | |
| 453 } | |
| 454 | |
| 455 TEST_F(BufferedDataSourceTest, InitiailizationFailed) { | |
| 456 InitializeDataSource(kHttpUrl, net::ERR_FILE_NOT_FOUND, false, 0, NONE); | |
| 457 StopDataSource(); | |
| 458 } | |
| 459 | |
| 460 TEST_F(BufferedDataSourceTest, MissingContentLength) { | |
| 461 InitializeDataSource(kHttpUrl, net::OK, true, -1, LOADING); | |
| 462 StopDataSource(); | |
| 463 } | |
| 464 | |
| 465 TEST_F(BufferedDataSourceTest, RangeRequestNotSupported) { | |
| 466 InitializeDataSource(kHttpUrl, net::OK, false, 1024, LOADING); | |
| 467 StopDataSource(); | |
| 468 } | |
| 469 | |
| 470 // Test the case where we get a 206 response, but no Content-Range header. | |
| 471 TEST_F(BufferedDataSourceTest, MissingContentRange) { | |
| 472 InitializeDataSource(kHttpUrl, net::ERR_INVALID_RESPONSE, true, 1024, | |
| 473 LOADING); | |
| 474 StopDataSource(); | |
| 475 } | |
| 476 | |
| 477 TEST_F(BufferedDataSourceTest, | |
| 478 MissingContentLengthAndRangeRequestNotSupported) { | |
| 479 InitializeDataSource(kHttpUrl, net::OK, false, -1, LOADING); | |
| 480 StopDataSource(); | |
| 481 } | |
| 482 | |
| 483 TEST_F(BufferedDataSourceTest, ReadCacheHit) { | |
| 484 InitializeDataSource(kHttpUrl, net::OK, true, 25, LOADING); | |
| 485 | |
| 486 // Performs read with cache hit. | |
| 487 ReadDataSourceHit(10, 10, 10); | |
| 488 | |
| 489 // Performs read with cache hit but partially filled. | |
| 490 ReadDataSourceHit(20, 10, 5); | |
| 491 | |
| 492 StopDataSource(); | |
| 493 } | |
| 494 | |
| 495 TEST_F(BufferedDataSourceTest, ReadCacheMiss) { | |
| 496 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); | |
| 497 ReadDataSourceMiss(1000, 10, net::OK); | |
| 498 ReadDataSourceMiss(20, 10, net::OK); | |
| 499 StopDataSource(); | |
| 500 } | |
| 501 | |
| 502 // Test the case where the initial response from the server indicates that | |
| 503 // Range requests are supported, but a later request prove otherwise. | |
| 504 TEST_F(BufferedDataSourceTest, ServerLiesAboutRangeSupport) { | |
| 505 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); | |
| 506 ReadDataSourceHit(10, 10, 10); | |
| 507 ReadDataSourceMiss(1000, 10, net::ERR_INVALID_RESPONSE); | |
| 508 StopDataSource(); | |
| 509 } | |
| 510 | |
| 511 TEST_F(BufferedDataSourceTest, ReadHang) { | |
| 512 InitializeDataSource(kHttpUrl, net::OK, true, 25, LOADING); | |
| 513 ReadDataSourceHang(10, 10); | |
| 514 StopDataSource(); | |
| 515 } | |
| 516 | |
| 517 TEST_F(BufferedDataSourceTest, ReadFailed) { | |
| 518 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); | |
| 519 ReadDataSourceHit(10, 10, 10); | |
| 520 ReadDataSourceFailed(10, 10, net::ERR_CONNECTION_RESET); | |
| 521 StopDataSource(); | |
| 522 } | |
| 523 | |
| 524 // Helper that sets |*value| to true. Useful for binding into a Closure. | |
| 525 static void SetTrue(bool* value) { | |
| 526 *value = true; | |
| 527 } | |
| 528 | |
| 529 // This test makes sure that Stop() does not require a task to run on | |
| 530 // |message_loop_| before it calls its callback. This prevents accidental | |
| 531 // introduction of a pipeline teardown deadlock. The pipeline owner blocks | |
| 532 // the render message loop while waiting for Stop() to complete. Since this | |
| 533 // object runs on the render message loop, Stop() will not complete if it | |
| 534 // requires a task to run on the the message loop that is being blocked. | |
| 535 TEST_F(BufferedDataSourceTest, StopDoesNotUseMessageLoopForCallback) { | |
| 536 InitializeDataSource(kFileUrl, net::OK, true, 1024, LOADED); | |
| 537 | |
| 538 // Stop() the data source, using a callback that lets us verify that it was | |
| 539 // called before Stop() returns. This is to make sure that the callback does | |
| 540 // not require |message_loop_| to execute tasks before being called. | |
| 541 bool stop_done_called = false; | |
| 542 data_source_->Stop(base::Bind(&SetTrue, &stop_done_called)); | |
| 543 | |
| 544 // Verify that the callback was called inside the Stop() call. | |
| 545 EXPECT_TRUE(stop_done_called); | |
| 546 | |
| 547 message_loop_->RunAllPending(); | |
| 548 } | |
| 549 | |
| 550 TEST_F(BufferedDataSourceTest, AbortDuringPendingRead) { | |
| 551 InitializeDataSource(kFileUrl, net::OK, true, 1024, LOADED); | |
| 552 | |
| 553 // Setup a way to verify that Read() is not called on the loader. | |
| 554 // We are doing this to make sure that the ReadTask() is still on | |
| 555 // the message loop queue when Abort() is called. | |
| 556 bool read_called = false; | |
| 557 ON_CALL(*loader_, Read(_, _, _ , _)) | |
| 558 .WillByDefault(DoAll(Assign(&read_called, true), | |
| 559 DeleteArg<3>())); | |
| 560 | |
| 561 // Initiate a Read() on the data source, but don't allow the | |
| 562 // message loop to run. | |
| 563 data_source_->Read( | |
| 564 0, 10, buffer_, | |
| 565 base::Bind(&BufferedDataSourceTest::ReadCallback, | |
| 566 base::Unretained(static_cast<BufferedDataSourceTest*>(this)))); | |
| 567 | |
| 568 // Call Abort() with the read pending. | |
| 569 EXPECT_CALL(*this, ReadCallback(-1)); | |
| 570 EXPECT_CALL(*loader_, Stop()); | |
| 571 data_source_->Abort(); | |
| 572 | |
| 573 // Verify that Read()'s after the Abort() issue callback with an error. | |
| 574 EXPECT_CALL(*this, ReadCallback(-1)); | |
| 575 data_source_->Read( | |
| 576 0, 10, buffer_, | |
| 577 base::Bind(&BufferedDataSourceTest::ReadCallback, | |
| 578 base::Unretained(static_cast<BufferedDataSourceTest*>(this)))); | |
| 579 | |
| 580 // Stop() the data source like normal. | |
| 581 data_source_->Stop(media::NewExpectedClosure()); | |
| 582 | |
| 583 // Allow cleanup task to run. | |
| 584 message_loop_->RunAllPending(); | |
| 585 | |
| 586 // Verify that Read() was not called on the loader. | |
| 587 EXPECT_FALSE(read_called); | |
| 588 } | |
| 589 | |
| 590 // Test that we only allow a limited number of cache misses for a | |
| 591 // single Read() request. | |
| 592 TEST_F(BufferedDataSourceTest, BoundedCacheMisses) { | |
| 593 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); | |
| 594 | |
| 595 ReadDataSourceAlwaysCacheMiss(0, 10); | |
| 596 | |
| 597 StopDataSource(); | |
| 598 } | |
| 599 | |
| 600 // TODO(scherkus): de-dupe from buffered_resource_loader_unittest.cc | |
| 601 ACTION_P(RequestCanceled, loader) { | |
| 602 WebURLError error; | |
| 603 error.reason = net::ERR_ABORTED; | |
| 604 error.domain = WebString::fromUTF8(net::kErrorDomain); | |
| 605 loader->didFail(NULL, error); | |
| 606 } | |
| 607 | |
| 608 // A more realistic BufferedDataSource that uses BufferedResourceLoader instead | |
| 609 // of a mocked version but injects a MockWebURLLoader. | |
| 610 // | |
| 611 // TODO(scherkus): re-write these tests to use this class then drop the "2" | |
| 612 // suffix. | |
| 613 class MockBufferedDataSource2 : public BufferedDataSource { | |
| 614 public: | |
| 615 MockBufferedDataSource2(MessageLoop* message_loop, WebFrame* frame) | |
| 616 : BufferedDataSource(message_loop, frame, new media::MediaLog()), | |
| 617 url_loader_(NULL) { | |
| 618 } | |
| 619 | |
| 620 virtual base::TimeDelta GetTimeoutMilliseconds() { | |
| 621 return base::TimeDelta::FromMilliseconds( | |
| 622 TestTimeouts::tiny_timeout_ms()); | |
| 623 } | |
| 624 | |
| 625 virtual BufferedResourceLoader* CreateResourceLoader(int64 first_position, | |
| 626 int64 last_position) { | |
| 627 loader_ = BufferedDataSource::CreateResourceLoader(first_position, | |
| 628 last_position); | |
| 629 | |
| 630 url_loader_ = new NiceMock<MockWebURLLoader>(); | |
| 631 ON_CALL(*url_loader_, cancel()) | |
| 632 .WillByDefault(RequestCanceled(loader_)); | |
| 633 | |
| 634 loader_->SetURLLoaderForTest(url_loader_); | |
| 635 return loader_; | |
| 636 } | |
| 637 | |
| 638 const scoped_refptr<BufferedResourceLoader>& loader() { return loader_; } | |
| 639 NiceMock<MockWebURLLoader>* url_loader() { return url_loader_; } | |
| 640 | |
| 641 private: | |
| 642 scoped_refptr<BufferedResourceLoader> loader_; | |
| 643 NiceMock<MockWebURLLoader>* url_loader_; | |
| 644 | |
| 645 DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource2); | |
| 646 }; | |
| 647 | |
| 648 class BufferedDataSourceTest2 : public testing::Test { | |
| 649 public: | |
| 650 BufferedDataSourceTest2() | |
| 651 : view_(WebView::create(NULL)), | |
| 652 message_loop_(MessageLoop::current()) { | |
| 653 view_->initializeMainFrame(&client_); | |
| 654 } | |
| 655 | |
| 656 virtual ~BufferedDataSourceTest2() { | |
| 657 view_->close(); | |
| 658 } | |
| 659 | |
| 660 void InitializeDataSource(const char* url) { | |
| 661 gurl_ = GURL(url); | |
| 662 | |
| 663 data_source_ = new MockBufferedDataSource2(message_loop_, | |
| 664 view_->mainFrame()); | |
| 665 data_source_->set_host(&host_); | |
| 666 data_source_->Initialize(url, | |
| 667 media::NewExpectedStatusCB(media::PIPELINE_OK)); | |
| 668 message_loop_->RunAllPending(); | |
| 669 | |
| 670 // Simulate 206 response for a 5,000,000 byte length file. | |
| 671 WebURLResponse response(gurl_); | |
| 672 response.setHTTPHeaderField(WebString::fromUTF8("Accept-Ranges"), | |
| 673 WebString::fromUTF8("bytes")); | |
| 674 response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"), | |
| 675 WebString::fromUTF8("bytes 0-4999999/5000000")); | |
| 676 response.setHTTPHeaderField(WebString::fromUTF8("Content-Length"), | |
| 677 WebString::fromUTF8("5000000")); | |
| 678 response.setExpectedContentLength(5000000); | |
| 679 response.setHTTPStatusCode(206); | |
| 680 | |
| 681 // We should receive corresponding information about the media resource. | |
| 682 EXPECT_CALL(host_, SetLoaded(false)); | |
| 683 EXPECT_CALL(host_, SetTotalBytes(5000000)); | |
| 684 EXPECT_CALL(host_, SetBufferedBytes(0)); | |
| 685 | |
| 686 data_source_->loader()->didReceiveResponse(data_source_->url_loader(), | |
| 687 response); | |
| 688 | |
| 689 message_loop_->RunAllPending(); | |
| 690 } | |
| 691 | |
| 692 void StopDataSource() { | |
| 693 data_source_->Stop(media::NewExpectedClosure()); | |
| 694 message_loop_->RunAllPending(); | |
| 695 } | |
| 696 | |
| 697 MOCK_METHOD1(ReadCallback, void(size_t size)); | |
| 698 media::DataSource::ReadCallback NewReadCallback(size_t size) { | |
| 699 EXPECT_CALL(*this, ReadCallback(size)); | |
| 700 return base::Bind(&BufferedDataSourceTest2::ReadCallback, | |
| 701 base::Unretained(this)); | |
| 702 } | |
| 703 | |
| 704 // Accessors for private variables on |data_source_|. | |
| 705 media::Preload preload() { return data_source_->preload_; } | |
| 706 BufferedResourceLoader::DeferStrategy defer_strategy() { | |
| 707 return data_source_->loader()->defer_strategy_; | |
| 708 } | |
| 709 int data_source_bitrate() { return data_source_->bitrate_; } | |
| 710 int data_source_playback_rate() { return data_source_->playback_rate_; } | |
| 711 int loader_bitrate() { return data_source_->loader()->bitrate_; } | |
| 712 int loader_playback_rate() { return data_source_->loader()->playback_rate_; } | |
| 713 | |
| 714 scoped_refptr<MockBufferedDataSource2> data_source_; | |
| 715 | |
| 716 GURL gurl_; | |
| 717 MockWebFrameClient client_; | |
| 718 WebView* view_; | |
| 719 | |
| 720 StrictMock<media::MockFilterHost> host_; | |
| 721 MessageLoop* message_loop_; | |
| 722 | |
| 723 private: | |
| 724 DISALLOW_COPY_AND_ASSIGN(BufferedDataSourceTest2); | |
| 725 }; | |
| 726 | |
| 727 TEST_F(BufferedDataSourceTest2, Default) { | |
| 728 InitializeDataSource("http://localhost/foo.webm"); | |
| 729 | |
| 730 // Ensure we have sane values for default loading scenario. | |
| 731 EXPECT_EQ(media::AUTO, preload()); | |
| 732 EXPECT_EQ(BufferedResourceLoader::kThresholdDefer, defer_strategy()); | |
| 733 | |
| 734 EXPECT_EQ(0, data_source_bitrate()); | |
| 735 EXPECT_EQ(0.0f, data_source_playback_rate()); | |
| 736 EXPECT_EQ(0, loader_bitrate()); | |
| 737 EXPECT_EQ(0.0f, loader_playback_rate()); | |
| 738 | |
| 739 StopDataSource(); | |
| 740 } | |
| 741 | |
| 742 TEST_F(BufferedDataSourceTest2, SetBitrate) { | |
| 743 InitializeDataSource("http://localhost/foo.webm"); | |
| 744 | |
| 745 data_source_->SetBitrate(1234); | |
| 746 message_loop_->RunAllPending(); | |
| 747 EXPECT_EQ(1234, data_source_bitrate()); | |
| 748 EXPECT_EQ(1234, loader_bitrate()); | |
| 749 | |
| 750 // Read so far ahead to cause the loader to get recreated. | |
| 751 BufferedResourceLoader* old_loader = data_source_->loader(); | |
| 752 | |
| 753 uint8 buffer[1024]; | |
| 754 data_source_->Read(4000000, 1024, buffer, | |
| 755 NewReadCallback(media::DataSource::kReadError)); | |
| 756 message_loop_->RunAllPending(); | |
| 757 | |
| 758 // Verify loader changed but still has same bitrate. | |
| 759 EXPECT_NE(old_loader, data_source_->loader().get()); | |
| 760 EXPECT_EQ(1234, loader_bitrate()); | |
| 761 | |
| 762 StopDataSource(); | |
| 763 } | |
| 764 | |
| 765 TEST_F(BufferedDataSourceTest2, SetPlaybackRate) { | |
| 766 InitializeDataSource("http://localhost/foo.webm"); | |
| 767 | |
| 768 data_source_->SetPlaybackRate(2.0f); | |
| 769 message_loop_->RunAllPending(); | |
| 770 EXPECT_EQ(2.0f, data_source_playback_rate()); | |
| 771 EXPECT_EQ(2.0f, loader_playback_rate()); | |
| 772 | |
| 773 // Read so far ahead to cause the loader to get recreated. | |
| 774 BufferedResourceLoader* old_loader = data_source_->loader(); | |
| 775 | |
| 776 uint8 buffer[1024]; | |
| 777 data_source_->Read(4000000, 1024, buffer, | |
| 778 NewReadCallback(media::DataSource::kReadError)); | |
| 779 message_loop_->RunAllPending(); | |
| 780 | |
| 781 // Verify loader changed but still has same bitrate. | |
| 782 EXPECT_NE(old_loader, data_source_->loader().get()); | |
| 783 EXPECT_EQ(2.0f, loader_playback_rate()); | |
| 784 | |
| 785 StopDataSource(); | |
| 786 } | |
| 787 | |
| 788 } // namespace webkit_glue | |
| OLD | NEW |