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 |