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