Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / buffered_data_source_unittest.cc
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/WebFrame.h"
17 #include "third_party/WebKit/public/web/WebView.h"
18
19 using ::testing::_;
20 using ::testing::Assign;
21 using ::testing::Invoke;
22 using ::testing::InSequence;
23 using ::testing::NiceMock;
24 using ::testing::StrictMock;
25
26 using blink::WebFrame;
27 using blink::WebString;
28 using blink::WebURLLoader;
29 using blink::WebURLResponse;
30 using blink::WebView;
31
32 namespace content {
33
34 // Overrides CreateResourceLoader() to permit injecting a MockWebURLLoader.
35 // Also keeps track of whether said MockWebURLLoader is actively loading.
36 class MockBufferedDataSource : public BufferedDataSource {
37  public:
38   MockBufferedDataSource(
39       const scoped_refptr<base::MessageLoopProxy>& message_loop,
40       WebFrame* frame)
41       : BufferedDataSource(message_loop, frame, new media::MediaLog(),
42                            base::Bind(&MockBufferedDataSource::set_downloading,
43                                       base::Unretained(this))),
44         downloading_(false),
45         loading_(false) {
46   }
47   virtual ~MockBufferedDataSource() {}
48
49   MOCK_METHOD2(CreateResourceLoader, BufferedResourceLoader*(int64, int64));
50   BufferedResourceLoader* CreateMockResourceLoader(int64 first_byte_position,
51                                                    int64 last_byte_position) {
52     CHECK(!loading_) << "Previous resource load wasn't cancelled";
53
54     BufferedResourceLoader* loader =
55         BufferedDataSource::CreateResourceLoader(first_byte_position,
56                                                  last_byte_position);
57
58     // Keep track of active loading state via loadAsynchronously() and cancel().
59     NiceMock<MockWebURLLoader>* url_loader = new NiceMock<MockWebURLLoader>();
60     ON_CALL(*url_loader, loadAsynchronously(_, _))
61         .WillByDefault(Assign(&loading_, true));
62     ON_CALL(*url_loader, cancel())
63         .WillByDefault(Assign(&loading_, false));
64
65     // |test_loader_| will be used when Start() is called.
66     loader->test_loader_ = scoped_ptr<WebURLLoader>(url_loader);
67     return loader;
68   }
69
70   bool loading() { return loading_; }
71   void set_loading(bool loading) { loading_ = loading; }
72   bool downloading() { return downloading_; }
73   void set_downloading(bool downloading) { downloading_ = downloading; }
74
75  private:
76   // Whether the resource is downloading or deferred.
77   bool downloading_;
78
79   // Whether the resource load has starting loading but yet to been cancelled.
80   bool loading_;
81
82   DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource);
83 };
84
85 static const int64 kFileSize = 5000000;
86 static const int64 kFarReadPosition = 4000000;
87 static const int kDataSize = 1024;
88
89 static const char kHttpUrl[] = "http://localhost/foo.webm";
90 static const char kFileUrl[] = "file:///tmp/bar.webm";
91
92 class BufferedDataSourceTest : public testing::Test {
93  public:
94   BufferedDataSourceTest()
95       : view_(WebView::create(NULL)), frame_(WebFrame::create(&client_)) {
96     view_->setMainFrame(frame_);
97
98     data_source_.reset(new MockBufferedDataSource(
99         message_loop_.message_loop_proxy(), view_->mainFrame()));
100     data_source_->set_host(&host_);
101   }
102
103   virtual ~BufferedDataSourceTest() {
104     view_->close();
105     frame_->close();
106   }
107
108   MOCK_METHOD1(OnInitialize, void(bool));
109
110   void Initialize(const char* url, bool expected) {
111     GURL gurl(url);
112     response_generator_.reset(new TestResponseGenerator(gurl, kFileSize));
113
114     ExpectCreateResourceLoader();
115     EXPECT_CALL(*this, OnInitialize(expected));
116     data_source_->Initialize(
117         gurl, BufferedResourceLoader::kUnspecified, base::Bind(
118             &BufferedDataSourceTest::OnInitialize, base::Unretained(this)));
119     message_loop_.RunUntilIdle();
120
121     bool is_http = gurl.SchemeIs(kHttpScheme) || gurl.SchemeIs(kHttpsScheme);
122     EXPECT_EQ(data_source_->downloading(), is_http);
123   }
124
125   // Helper to initialize tests with a valid 206 response.
126   void InitializeWith206Response() {
127     Initialize(kHttpUrl, true);
128
129     EXPECT_CALL(host_, SetTotalBytes(response_generator_->content_length()));
130     Respond(response_generator_->Generate206(0));
131   }
132
133   // Helper to initialize tests with a valid file:// response.
134   void InitializeWithFileResponse() {
135     Initialize(kFileUrl, true);
136
137     EXPECT_CALL(host_, SetTotalBytes(kFileSize));
138     EXPECT_CALL(host_, AddBufferedByteRange(0, kFileSize));
139     Respond(response_generator_->GenerateFileResponse(0));
140   }
141
142   // Stops any active loaders and shuts down the data source.
143   //
144   // This typically happens when the page is closed and for our purposes is
145   // appropriate to do when tearing down a test.
146   void Stop() {
147     if (data_source_->loading()) {
148       loader()->didFail(url_loader(), response_generator_->GenerateError());
149       message_loop_.RunUntilIdle();
150     }
151
152     data_source_->Stop(media::NewExpectedClosure());
153     message_loop_.RunUntilIdle();
154   }
155
156   void ExpectCreateResourceLoader() {
157     EXPECT_CALL(*data_source_, CreateResourceLoader(_, _))
158         .WillOnce(Invoke(data_source_.get(),
159                          &MockBufferedDataSource::CreateMockResourceLoader));
160     message_loop_.RunUntilIdle();
161   }
162
163   void Respond(const WebURLResponse& response) {
164     loader()->didReceiveResponse(url_loader(), response);
165     message_loop_.RunUntilIdle();
166   }
167
168   void ReceiveData(int size) {
169     scoped_ptr<char[]> data(new char[size]);
170     memset(data.get(), 0xA5, size);  // Arbitrary non-zero value.
171
172     loader()->didReceiveData(url_loader(), data.get(), size, size);
173     message_loop_.RunUntilIdle();
174   }
175
176   void FinishLoading() {
177     data_source_->set_loading(false);
178     loader()->didFinishLoading(url_loader(), 0, -1);
179     message_loop_.RunUntilIdle();
180   }
181
182   MOCK_METHOD1(ReadCallback, void(int size));
183
184   void ReadAt(int64 position) {
185     data_source_->Read(position, kDataSize, buffer_,
186                        base::Bind(&BufferedDataSourceTest::ReadCallback,
187                                   base::Unretained(this)));
188     message_loop_.RunUntilIdle();
189   }
190
191   // Accessors for private variables on |data_source_|.
192   BufferedResourceLoader* loader() {
193     return data_source_->loader_.get();
194   }
195   WebURLLoader* url_loader() {
196     return loader()->active_loader_->loader_.get();
197   }
198
199   Preload preload() { return data_source_->preload_; }
200   BufferedResourceLoader::DeferStrategy defer_strategy() {
201     return loader()->defer_strategy_;
202   }
203   int data_source_bitrate() { return data_source_->bitrate_; }
204   int data_source_playback_rate() { return data_source_->playback_rate_; }
205   int loader_bitrate() { return loader()->bitrate_; }
206   int loader_playback_rate() { return loader()->playback_rate_; }
207
208   scoped_ptr<MockBufferedDataSource> data_source_;
209
210   scoped_ptr<TestResponseGenerator> response_generator_;
211   MockWebFrameClient client_;
212   WebView* view_;
213   WebFrame* frame_;
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, MediaPlaybackRateChanged) {
558   InitializeWith206Response();
559
560   data_source_->MediaPlaybackRateChanged(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