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 <algorithm>
6#include <string>
7
8#include "base/bind.h"
9#include "base/format_macros.h"
10#include "base/message_loop/message_loop.h"
11#include "base/strings/stringprintf.h"
12#include "media/base/media_log.h"
13#include "media/base/seekable_buffer.h"
14#include "media/blink/buffered_resource_loader.h"
15#include "media/blink/mock_webframeclient.h"
16#include "media/blink/mock_weburlloader.h"
17#include "net/base/net_errors.h"
18#include "net/http/http_request_headers.h"
19#include "net/http/http_util.h"
20#include "third_party/WebKit/public/platform/WebString.h"
21#include "third_party/WebKit/public/platform/WebURLError.h"
22#include "third_party/WebKit/public/platform/WebURLRequest.h"
23#include "third_party/WebKit/public/platform/WebURLResponse.h"
24#include "third_party/WebKit/public/web/WebLocalFrame.h"
25#include "third_party/WebKit/public/web/WebView.h"
26
27using ::testing::_;
28using ::testing::InSequence;
29using ::testing::Return;
30using ::testing::Truly;
31using ::testing::NiceMock;
32
33using blink::WebLocalFrame;
34using blink::WebString;
35using blink::WebURLError;
36using blink::WebURLResponse;
37using blink::WebView;
38
39namespace media {
40
41static const char* kHttpUrl = "http://test";
42static const char kHttpRedirectToSameDomainUrl1[] = "http://test/ing";
43static const char kHttpRedirectToSameDomainUrl2[] = "http://test/ing2";
44static const char kHttpRedirectToDifferentDomainUrl1[] = "http://test2";
45
46static const int kDataSize = 1024;
47static const int kHttpOK = 200;
48static const int kHttpPartialContent = 206;
49
50enum NetworkState {
51  NONE,
52  LOADED,
53  LOADING
54};
55
56// Predicate that tests that request disallows compressed data.
57static bool CorrectAcceptEncoding(const blink::WebURLRequest &request) {
58  std::string value = request.httpHeaderField(
59      WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding)).utf8();
60  return (value.find("identity;q=1") != std::string::npos) &&
61         (value.find("*;q=0") != std::string::npos);
62}
63
64class BufferedResourceLoaderTest : public testing::Test {
65 public:
66  BufferedResourceLoaderTest()
67      : view_(WebView::create(NULL)), frame_(WebLocalFrame::create(&client_)) {
68    view_->setMainFrame(frame_);
69
70    for (int i = 0; i < kDataSize; ++i) {
71      data_[i] = i;
72    }
73  }
74
75  virtual ~BufferedResourceLoaderTest() {
76    view_->close();
77    frame_->close();
78  }
79
80  void Initialize(const char* url, int first_position, int last_position) {
81    gurl_ = GURL(url);
82    first_position_ = first_position;
83    last_position_ = last_position;
84
85    loader_.reset(new BufferedResourceLoader(
86        gurl_, BufferedResourceLoader::kUnspecified,
87        first_position_, last_position_,
88        BufferedResourceLoader::kCapacityDefer, 0, 0,
89        new MediaLog()));
90
91    // |test_loader_| will be used when Start() is called.
92    url_loader_ = new NiceMock<MockWebURLLoader>();
93    loader_->test_loader_ = scoped_ptr<blink::WebURLLoader>(url_loader_);
94  }
95
96  void SetLoaderBuffer(int forward_capacity, int backward_capacity) {
97    loader_->buffer_.set_forward_capacity(forward_capacity);
98    loader_->buffer_.set_backward_capacity(backward_capacity);
99    loader_->buffer_.Clear();
100  }
101
102  void Start() {
103    InSequence s;
104    EXPECT_CALL(*url_loader_, loadAsynchronously(Truly(CorrectAcceptEncoding),
105                                                 loader_.get()));
106
107    EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
108    loader_->Start(
109        base::Bind(&BufferedResourceLoaderTest::StartCallback,
110                   base::Unretained(this)),
111        base::Bind(&BufferedResourceLoaderTest::LoadingCallback,
112                   base::Unretained(this)),
113        base::Bind(&BufferedResourceLoaderTest::ProgressCallback,
114                   base::Unretained(this)),
115        view_->mainFrame());
116  }
117
118  void FullResponse(int64 instance_size) {
119    FullResponse(instance_size, BufferedResourceLoader::kOk);
120  }
121
122  void FullResponse(int64 instance_size,
123                    BufferedResourceLoader::Status status) {
124    EXPECT_CALL(*this, StartCallback(status));
125
126    WebURLResponse response(gurl_);
127    response.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
128                                WebString::fromUTF8(base::StringPrintf("%"
129                                    PRId64, instance_size)));
130    response.setExpectedContentLength(instance_size);
131    response.setHTTPStatusCode(kHttpOK);
132    loader_->didReceiveResponse(url_loader_, response);
133
134    if (status == BufferedResourceLoader::kOk) {
135      EXPECT_EQ(instance_size, loader_->content_length());
136      EXPECT_EQ(instance_size, loader_->instance_size());
137    }
138
139    EXPECT_FALSE(loader_->range_supported());
140  }
141
142  void PartialResponse(int64 first_position, int64 last_position,
143                       int64 instance_size) {
144    PartialResponse(first_position, last_position, instance_size, false, true);
145  }
146
147  void PartialResponse(int64 first_position, int64 last_position,
148                       int64 instance_size, bool chunked, bool accept_ranges) {
149    EXPECT_CALL(*this, StartCallback(BufferedResourceLoader::kOk));
150
151    WebURLResponse response(gurl_);
152    response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"),
153                                WebString::fromUTF8(base::StringPrintf("bytes "
154                                            "%" PRId64 "-%" PRId64 "/%" PRId64,
155                                            first_position,
156                                            last_position,
157                                            instance_size)));
158
159    // HTTP 1.1 doesn't permit Content-Length with Transfer-Encoding: chunked.
160    int64 content_length = -1;
161    if (chunked) {
162      response.setHTTPHeaderField(WebString::fromUTF8("Transfer-Encoding"),
163                                  WebString::fromUTF8("chunked"));
164    } else {
165      content_length = last_position - first_position + 1;
166    }
167    response.setExpectedContentLength(content_length);
168
169    // A server isn't required to return Accept-Ranges even though it might.
170    if (accept_ranges) {
171      response.setHTTPHeaderField(WebString::fromUTF8("Accept-Ranges"),
172                                  WebString::fromUTF8("bytes"));
173    }
174
175    response.setHTTPStatusCode(kHttpPartialContent);
176    loader_->didReceiveResponse(url_loader_, response);
177
178    // XXX: what's the difference between these two? For example in the chunked
179    // range request case, Content-Length is unspecified (because it's chunked)
180    // but Content-Range: a-b/c can be returned, where c == Content-Length
181    //
182    // Can we eliminate one?
183    EXPECT_EQ(content_length, loader_->content_length());
184    EXPECT_EQ(instance_size, loader_->instance_size());
185
186    // A valid partial response should always result in this being true.
187    EXPECT_TRUE(loader_->range_supported());
188  }
189
190  void Redirect(const char* url) {
191    GURL redirectUrl(url);
192    blink::WebURLRequest newRequest(redirectUrl);
193    blink::WebURLResponse redirectResponse(gurl_);
194
195    loader_->willSendRequest(url_loader_, newRequest, redirectResponse);
196
197    base::MessageLoop::current()->RunUntilIdle();
198  }
199
200  void StopWhenLoad() {
201    InSequence s;
202    EXPECT_CALL(*url_loader_, cancel());
203    loader_->Stop();
204    loader_.reset();
205  }
206
207  // Helper method to write to |loader_| from |data_|.
208  void WriteLoader(int position, int size) {
209    EXPECT_CALL(*this, ProgressCallback(position + size - 1));
210    loader_->didReceiveData(url_loader_,
211                            reinterpret_cast<char*>(data_ + position),
212                            size,
213                            size);
214  }
215
216  void WriteData(int size) {
217    EXPECT_CALL(*this, ProgressCallback(_));
218
219    scoped_ptr<char[]> data(new char[size]);
220    loader_->didReceiveData(url_loader_, data.get(), size, size);
221  }
222
223  void WriteUntilThreshold() {
224    int buffered = loader_->buffer_.forward_bytes();
225    int capacity = loader_->buffer_.forward_capacity();
226    CHECK_LT(buffered, capacity);
227
228    EXPECT_CALL(*this, LoadingCallback(
229        BufferedResourceLoader::kLoadingDeferred));
230    WriteData(capacity - buffered);
231  }
232
233  // Helper method to read from |loader_|.
234  void ReadLoader(int64 position, int size, uint8* buffer) {
235    loader_->Read(position, size, buffer,
236                  base::Bind(&BufferedResourceLoaderTest::ReadCallback,
237                             base::Unretained(this)));
238  }
239
240  // Verifies that data in buffer[0...size] is equal to data_[pos...pos+size].
241  void VerifyBuffer(uint8* buffer, int pos, int size) {
242    EXPECT_EQ(0, memcmp(buffer, data_ + pos, size));
243  }
244
245  void ConfirmLoaderOffsets(int64 expected_offset,
246                            int expected_first_offset,
247                            int expected_last_offset) {
248    EXPECT_EQ(loader_->offset_, expected_offset);
249    EXPECT_EQ(loader_->first_offset_, expected_first_offset);
250    EXPECT_EQ(loader_->last_offset_, expected_last_offset);
251  }
252
253  void ConfirmBufferState(int backward_bytes,
254                          int backward_capacity,
255                          int forward_bytes,
256                          int forward_capacity) {
257    EXPECT_EQ(backward_bytes, loader_->buffer_.backward_bytes());
258    EXPECT_EQ(backward_capacity, loader_->buffer_.backward_capacity());
259    EXPECT_EQ(forward_bytes, loader_->buffer_.forward_bytes());
260    EXPECT_EQ(forward_capacity, loader_->buffer_.forward_capacity());
261  }
262
263  void ConfirmLoaderBufferBackwardCapacity(int expected_backward_capacity) {
264    EXPECT_EQ(loader_->buffer_.backward_capacity(),
265              expected_backward_capacity);
266  }
267
268  void ConfirmLoaderBufferForwardCapacity(int expected_forward_capacity) {
269    EXPECT_EQ(loader_->buffer_.forward_capacity(), expected_forward_capacity);
270  }
271
272  // Makes sure the |loader_| buffer window is in a reasonable range.
273  void CheckBufferWindowBounds() {
274    // Corresponds to value defined in buffered_resource_loader.cc.
275    static const int kMinBufferCapacity = 2 * 1024 * 1024;
276    EXPECT_GE(loader_->buffer_.forward_capacity(), kMinBufferCapacity);
277    EXPECT_GE(loader_->buffer_.backward_capacity(), kMinBufferCapacity);
278
279    // Corresponds to value defined in buffered_resource_loader.cc.
280    static const int kMaxBufferCapacity = 20 * 1024 * 1024;
281    EXPECT_LE(loader_->buffer_.forward_capacity(), kMaxBufferCapacity);
282    EXPECT_LE(loader_->buffer_.backward_capacity(), kMaxBufferCapacity);
283  }
284
285  MOCK_METHOD1(StartCallback, void(BufferedResourceLoader::Status));
286  MOCK_METHOD2(ReadCallback, void(BufferedResourceLoader::Status, int));
287  MOCK_METHOD1(LoadingCallback, void(BufferedResourceLoader::LoadingState));
288  MOCK_METHOD1(ProgressCallback, void(int64));
289
290 protected:
291  GURL gurl_;
292  int64 first_position_;
293  int64 last_position_;
294
295  scoped_ptr<BufferedResourceLoader> loader_;
296  NiceMock<MockWebURLLoader>* url_loader_;
297
298  MockWebFrameClient client_;
299  WebView* view_;
300  WebLocalFrame* frame_;
301
302  base::MessageLoop message_loop_;
303
304  uint8 data_[kDataSize];
305
306 private:
307  DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoaderTest);
308};
309
310TEST_F(BufferedResourceLoaderTest, StartStop) {
311  Initialize(kHttpUrl, -1, -1);
312  Start();
313  StopWhenLoad();
314}
315
316// Tests that a bad HTTP response is recived, e.g. file not found.
317TEST_F(BufferedResourceLoaderTest, BadHttpResponse) {
318  Initialize(kHttpUrl, -1, -1);
319  Start();
320
321  EXPECT_CALL(*this, StartCallback(BufferedResourceLoader::kFailed));
322
323  WebURLResponse response(gurl_);
324  response.setHTTPStatusCode(404);
325  response.setHTTPStatusText("Not Found\n");
326  loader_->didReceiveResponse(url_loader_, response);
327  StopWhenLoad();
328}
329
330// Tests that partial content is requested but not fulfilled.
331TEST_F(BufferedResourceLoaderTest, NotPartialResponse) {
332  Initialize(kHttpUrl, 100, -1);
333  Start();
334  FullResponse(1024, BufferedResourceLoader::kFailed);
335  StopWhenLoad();
336}
337
338// Tests that a 200 response is received.
339TEST_F(BufferedResourceLoaderTest, FullResponse) {
340  Initialize(kHttpUrl, -1, -1);
341  Start();
342  FullResponse(1024);
343  StopWhenLoad();
344}
345
346// Tests that a partial content response is received.
347TEST_F(BufferedResourceLoaderTest, PartialResponse) {
348  Initialize(kHttpUrl, 100, 200);
349  Start();
350  PartialResponse(100, 200, 1024);
351  StopWhenLoad();
352}
353
354TEST_F(BufferedResourceLoaderTest, PartialResponse_Chunked) {
355  Initialize(kHttpUrl, 100, 200);
356  Start();
357  PartialResponse(100, 200, 1024, true, true);
358  StopWhenLoad();
359}
360
361TEST_F(BufferedResourceLoaderTest, PartialResponse_NoAcceptRanges) {
362  Initialize(kHttpUrl, 100, 200);
363  Start();
364  PartialResponse(100, 200, 1024, false, false);
365  StopWhenLoad();
366}
367
368TEST_F(BufferedResourceLoaderTest, PartialResponse_ChunkedNoAcceptRanges) {
369  Initialize(kHttpUrl, 100, 200);
370  Start();
371  PartialResponse(100, 200, 1024, true, false);
372  StopWhenLoad();
373}
374
375// Tests that an invalid partial response is received.
376TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) {
377  Initialize(kHttpUrl, 0, 10);
378  Start();
379
380  EXPECT_CALL(*this, StartCallback(BufferedResourceLoader::kFailed));
381
382  WebURLResponse response(gurl_);
383  response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"),
384                              WebString::fromUTF8(base::StringPrintf("bytes "
385                                  "%d-%d/%d", 1, 10, 1024)));
386  response.setExpectedContentLength(10);
387  response.setHTTPStatusCode(kHttpPartialContent);
388  loader_->didReceiveResponse(url_loader_, response);
389  StopWhenLoad();
390}
391
392// Tests the logic of sliding window for data buffering and reading.
393TEST_F(BufferedResourceLoaderTest, BufferAndRead) {
394  Initialize(kHttpUrl, 10, 29);
395  loader_->UpdateDeferStrategy(BufferedResourceLoader::kCapacityDefer);
396  Start();
397  PartialResponse(10, 29, 30);
398
399  uint8 buffer[10];
400  InSequence s;
401
402  // Writes 10 bytes and read them back.
403  WriteLoader(10, 10);
404  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
405  ReadLoader(10, 10, buffer);
406  VerifyBuffer(buffer, 10, 10);
407
408  // Writes 10 bytes and read 2 times.
409  WriteLoader(20, 10);
410  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
411  ReadLoader(20, 5, buffer);
412  VerifyBuffer(buffer, 20, 5);
413  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
414  ReadLoader(25, 5, buffer);
415  VerifyBuffer(buffer, 25, 5);
416
417  // Read backward within buffer.
418  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
419  ReadLoader(10, 10, buffer);
420  VerifyBuffer(buffer, 10, 10);
421
422  // Read backward outside buffer.
423  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
424  ReadLoader(9, 10, buffer);
425
426  // Response has completed.
427  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFinished));
428  loader_->didFinishLoading(url_loader_, 0, -1);
429
430  // Try to read 10 from position 25 will just return with 5 bytes.
431  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
432  ReadLoader(25, 10, buffer);
433  VerifyBuffer(buffer, 25, 5);
434
435  // Try to read outside buffered range after request has completed.
436  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
437  ReadLoader(5, 10, buffer);
438
439  // Try to read beyond the instance size.
440  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 0));
441  ReadLoader(30, 10, buffer);
442}
443
444// Tests the logic of expanding the data buffer for large reads.
445TEST_F(BufferedResourceLoaderTest, ReadExtendBuffer) {
446  Initialize(kHttpUrl, 10, 0x014FFFFFF);
447  SetLoaderBuffer(10, 20);
448  Start();
449  PartialResponse(10, 0x014FFFFFF, 0x015000000);
450
451  uint8 buffer[20];
452  InSequence s;
453
454  // Write more than forward capacity and read it back. Ensure forward capacity
455  // gets reset after reading.
456  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
457  WriteLoader(10, 20);
458
459  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 20));
460  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
461  ReadLoader(10, 20, buffer);
462
463  VerifyBuffer(buffer, 10, 20);
464  ConfirmLoaderBufferForwardCapacity(10);
465
466  // Make and outstanding read request larger than forward capacity. Ensure
467  // forward capacity gets extended.
468  ReadLoader(30, 20, buffer);
469  ConfirmLoaderBufferForwardCapacity(20);
470
471  // Fulfill outstanding request. Ensure forward capacity gets reset.
472  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 20));
473  WriteLoader(30, 20);
474
475  VerifyBuffer(buffer, 30, 20);
476  ConfirmLoaderBufferForwardCapacity(10);
477
478  // Try to read further ahead than kForwardWaitThreshold allows. Ensure
479  // forward capacity is not changed.
480  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
481  ReadLoader(0x00300000, 1, buffer);
482
483  ConfirmLoaderBufferForwardCapacity(10);
484
485  // Try to read more than maximum forward capacity. Ensure forward capacity is
486  // not changed.
487  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
488  ReadLoader(30, 0x01400001, buffer);
489
490  ConfirmLoaderBufferForwardCapacity(10);
491
492  StopWhenLoad();
493}
494
495TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) {
496  Initialize(kHttpUrl, 10, 0x00FFFFFF);
497  Start();
498  PartialResponse(10, 0x00FFFFFF, 0x01000000);
499
500  uint8 buffer[10];
501  InSequence s;
502
503  // Read very far ahead will get a cache miss.
504  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
505  ReadLoader(0x00FFFFFF, 1, buffer);
506
507  // The following call will not call ReadCallback() because it is waiting for
508  // data to arrive.
509  ReadLoader(10, 10, buffer);
510
511  // Writing to loader will fulfill the read request.
512  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
513  WriteLoader(10, 20);
514  VerifyBuffer(buffer, 10, 10);
515
516  // The following call cannot be fulfilled now.
517  ReadLoader(25, 10, buffer);
518
519  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFinished));
520  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
521  loader_->didFinishLoading(url_loader_, 0, -1);
522}
523
524TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) {
525  Initialize(kHttpUrl, 10, 29);
526  Start();
527  PartialResponse(10, 29, 30);
528
529  uint8 buffer[10];
530  InSequence s;
531
532  // We should convert any error we receive to BufferedResourceLoader::kFailed.
533  ReadLoader(10, 10, buffer);
534  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFailed));
535  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
536  WebURLError error;
537  error.reason = net::ERR_TIMED_OUT;
538  error.isCancellation = false;
539  loader_->didFail(url_loader_, error);
540}
541
542TEST_F(BufferedResourceLoaderTest, RequestFailedWithNoPendingReads) {
543  Initialize(kHttpUrl, 10, 29);
544  Start();
545  PartialResponse(10, 29, 30);
546
547  uint8 buffer[10];
548  InSequence s;
549
550  // Write enough data so that a read would technically complete had the request
551  // not failed.
552  WriteLoader(10, 20);
553
554  // Fail without a pending read.
555  WebURLError error;
556  error.reason = net::ERR_TIMED_OUT;
557  error.isCancellation = false;
558  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFailed));
559  loader_->didFail(url_loader_, error);
560
561  // Now we should immediately fail any read even if we have data buffered.
562  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
563  ReadLoader(10, 10, buffer);
564}
565
566TEST_F(BufferedResourceLoaderTest, RequestCancelledWhenRead) {
567  Initialize(kHttpUrl, 10, 29);
568  Start();
569  PartialResponse(10, 29, 30);
570
571  uint8 buffer[10];
572  InSequence s;
573
574  // We should convert any error we receive to BufferedResourceLoader::kFailed.
575  ReadLoader(10, 10, buffer);
576  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFailed));
577  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
578  WebURLError error;
579  error.reason = 0;
580  error.isCancellation = true;
581  loader_->didFail(url_loader_, error);
582}
583
584// Tests the data buffering logic of NeverDefer strategy.
585TEST_F(BufferedResourceLoaderTest, NeverDeferStrategy) {
586  Initialize(kHttpUrl, 10, 99);
587  SetLoaderBuffer(10, 20);
588  loader_->UpdateDeferStrategy(BufferedResourceLoader::kNeverDefer);
589  Start();
590  PartialResponse(10, 99, 100);
591
592  uint8 buffer[10];
593
594  // Read past the buffer size; should not defer regardless.
595  WriteLoader(10, 10);
596  WriteLoader(20, 50);
597
598  // Should move past window.
599  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
600  ReadLoader(10, 10, buffer);
601
602  StopWhenLoad();
603}
604
605// Tests the data buffering logic of ReadThenDefer strategy.
606TEST_F(BufferedResourceLoaderTest, ReadThenDeferStrategy) {
607  Initialize(kHttpUrl, 10, 99);
608  SetLoaderBuffer(10, 20);
609  loader_->UpdateDeferStrategy(BufferedResourceLoader::kReadThenDefer);
610  Start();
611  PartialResponse(10, 99, 100);
612
613  uint8 buffer[10];
614
615  // Make an outstanding read request.
616  ReadLoader(10, 10, buffer);
617
618  // Receive almost enough data to cover, shouldn't defer.
619  WriteLoader(10, 9);
620
621  // As soon as we have received enough data to fulfill the read, defer.
622  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
623  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
624  WriteLoader(19, 1);
625
626  VerifyBuffer(buffer, 10, 10);
627
628  // Read again which should disable deferring since there should be nothing
629  // left in our internal buffer.
630  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
631  ReadLoader(20, 10, buffer);
632
633  // Over-fulfill requested bytes, then deferring should be enabled again.
634  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
635  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
636  WriteLoader(20, 40);
637
638  VerifyBuffer(buffer, 20, 10);
639
640  // Read far ahead, which should disable deferring. In this case we still have
641  // bytes in our internal buffer.
642  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
643  ReadLoader(80, 10, buffer);
644
645  // Fulfill requested bytes, then deferring should be enabled again.
646  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
647  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
648  WriteLoader(60, 40);
649
650  VerifyBuffer(buffer, 80, 10);
651
652  StopWhenLoad();
653}
654
655// Tests the data buffering logic of kCapacityDefer strategy.
656TEST_F(BufferedResourceLoaderTest, ThresholdDeferStrategy) {
657  Initialize(kHttpUrl, 10, 99);
658  SetLoaderBuffer(10, 20);
659  Start();
660  PartialResponse(10, 99, 100);
661
662  uint8 buffer[10];
663  InSequence s;
664
665  // Write half of capacity: keep not deferring.
666  WriteData(5);
667
668  // Write rest of space until capacity: start deferring.
669  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
670  WriteData(5);
671
672  // Read a byte from the buffer: stop deferring.
673  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 1));
674  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
675  ReadLoader(10, 1, buffer);
676
677  // Write a byte to hit capacity: start deferring.
678  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
679  WriteData(6);
680
681  StopWhenLoad();
682}
683
684TEST_F(BufferedResourceLoaderTest, Tricky_ReadForwardsPastBuffered) {
685  Initialize(kHttpUrl, 10, 99);
686  SetLoaderBuffer(10, 10);
687  Start();
688  PartialResponse(10, 99, 100);
689
690  uint8 buffer[256];
691  InSequence s;
692
693  // PRECONDITION
694  WriteUntilThreshold();
695  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 1));
696  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
697  ReadLoader(10, 1, buffer);
698  ConfirmBufferState(1, 10, 9, 10);
699  ConfirmLoaderOffsets(11, 0, 0);
700
701  // *** TRICKY BUSINESS, PT. I ***
702  // Read past buffered: stop deferring.
703  //
704  // In order for the read to complete we must:
705  //   1) Stop deferring to receive more data.
706  //
707  // BEFORE
708  //   offset=11 [xxxxxxxxx_]
709  //                       ^ ^^^ requested 4 bytes @ offset 20
710  // AFTER
711  //   offset=24 [__________]
712  //
713  ReadLoader(20, 4, buffer);
714
715  // Write a little, make sure we didn't start deferring.
716  WriteData(2);
717
718  // Write the rest, read should complete.
719  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 4));
720  WriteData(2);
721
722  // POSTCONDITION
723  ConfirmBufferState(4, 10, 0, 10);
724  ConfirmLoaderOffsets(24, 0, 0);
725
726  StopWhenLoad();
727}
728
729TEST_F(BufferedResourceLoaderTest, Tricky_ReadBackwardsPastBuffered) {
730  Initialize(kHttpUrl, 10, 99);
731  SetLoaderBuffer(10, 10);
732  Start();
733  PartialResponse(10, 99, 100);
734
735  uint8 buffer[256];
736  InSequence s;
737
738  // PRECONDITION
739  WriteUntilThreshold();
740  ConfirmBufferState(0, 10, 10, 10);
741  ConfirmLoaderOffsets(10, 0, 0);
742
743  // *** TRICKY BUSINESS, PT. II ***
744  // Read backwards a little too much: cache miss.
745  //
746  // BEFORE
747  //   offset=10 [__________|xxxxxxxxxx]
748  //                       ^ ^^^ requested 10 bytes @ offset 9
749  // AFTER
750  //   offset=10 [__________|xxxxxxxxxx]  !!! cache miss !!!
751  //
752  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
753  ReadLoader(9, 4, buffer);
754
755  // POSTCONDITION
756  ConfirmBufferState(0, 10, 10, 10);
757  ConfirmLoaderOffsets(10, 0, 0);
758
759  StopWhenLoad();
760}
761
762TEST_F(BufferedResourceLoaderTest, Tricky_SmallReadWithinThreshold) {
763  Initialize(kHttpUrl, 10, 99);
764  SetLoaderBuffer(10, 10);
765  Start();
766  PartialResponse(10, 99, 100);
767
768  uint8 buffer[256];
769  InSequence s;
770
771  // PRECONDITION
772  WriteUntilThreshold();
773  ConfirmBufferState(0, 10, 10, 10);
774  ConfirmLoaderOffsets(10, 0, 0);
775
776  // *** TRICKY BUSINESS, PT. III ***
777  // Read past forward capacity but within capacity: stop deferring.
778  //
779  // In order for the read to complete we must:
780  //   1) Adjust offset forward to create capacity.
781  //   2) Stop deferring to receive more data.
782  //
783  // BEFORE
784  //   offset=10 [xxxxxxxxxx]
785  //                             ^^^^ requested 4 bytes @ offset 24
786  // ADJUSTED OFFSET
787  //   offset=20 [__________]
788  //                  ^^^^ requested 4 bytes @ offset 24
789  // AFTER
790  //   offset=28 [__________]
791  //
792  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
793  ReadLoader(24, 4, buffer);
794  ConfirmLoaderOffsets(20, 4, 8);
795
796  // Write a little, make sure we didn't start deferring.
797  WriteData(4);
798
799  // Write the rest, read should complete.
800  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 4));
801  WriteData(4);
802
803  // POSTCONDITION
804  ConfirmBufferState(8, 10, 0, 10);
805  ConfirmLoaderOffsets(28, 0, 0);
806
807  StopWhenLoad();
808}
809
810TEST_F(BufferedResourceLoaderTest, Tricky_LargeReadWithinThreshold) {
811  Initialize(kHttpUrl, 10, 99);
812  SetLoaderBuffer(10, 10);
813  Start();
814  PartialResponse(10, 99, 100);
815
816  uint8 buffer[256];
817  InSequence s;
818
819  // PRECONDITION
820  WriteUntilThreshold();
821  ConfirmBufferState(0, 10, 10, 10);
822  ConfirmLoaderOffsets(10, 0, 0);
823
824  // *** TRICKY BUSINESS, PT. IV ***
825  // Read a large amount past forward capacity but within
826  // capacity: stop deferring.
827  //
828  // In order for the read to complete we must:
829  //   1) Adjust offset forward to create capacity.
830  //   2) Expand capacity to make sure we don't defer as data arrives.
831  //   3) Stop deferring to receive more data.
832  //
833  // BEFORE
834  //   offset=10 [xxxxxxxxxx]
835  //                             ^^^^^^^^^^^^ requested 12 bytes @ offset 24
836  // ADJUSTED OFFSET
837  //   offset=20 [__________]
838  //                  ^^^^^^ ^^^^^^ requested 12 bytes @ offset 24
839  // ADJUSTED CAPACITY
840  //   offset=20 [________________]
841  //                  ^^^^^^^^^^^^ requested 12 bytes @ offset 24
842  // AFTER
843  //   offset=36 [__________]
844  //
845  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
846  ReadLoader(24, 12, buffer);
847  ConfirmLoaderOffsets(20, 4, 16);
848  ConfirmBufferState(10, 10, 0, 16);
849
850  // Write a little, make sure we didn't start deferring.
851  WriteData(10);
852
853  // Write the rest, read should complete and capacity should go back to normal.
854  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 12));
855  WriteData(6);
856  ConfirmLoaderBufferForwardCapacity(10);
857
858  // POSTCONDITION
859  ConfirmBufferState(6, 10, 0, 10);
860  ConfirmLoaderOffsets(36, 0, 0);
861
862  StopWhenLoad();
863}
864
865TEST_F(BufferedResourceLoaderTest, Tricky_LargeReadBackwards) {
866  Initialize(kHttpUrl, 10, 99);
867  SetLoaderBuffer(10, 10);
868  Start();
869  PartialResponse(10, 99, 100);
870
871  uint8 buffer[256];
872  InSequence s;
873
874  // PRECONDITION
875  WriteUntilThreshold();
876  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
877  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
878  ReadLoader(10, 10, buffer);
879  WriteUntilThreshold();
880  ConfirmBufferState(10, 10, 10, 10);
881  ConfirmLoaderOffsets(20, 0, 0);
882
883  // *** TRICKY BUSINESS, PT. V ***
884  // Read a large amount that involves backwards data: stop deferring.
885  //
886  // In order for the read to complete we must:
887  //   1) Adjust offset *backwards* to create capacity.
888  //   2) Expand capacity to make sure we don't defer as data arrives.
889  //   3) Stop deferring to receive more data.
890  //
891  // BEFORE
892  //   offset=20 [xxxxxxxxxx|xxxxxxxxxx]
893  //                    ^^^^ ^^^^^^^^^^ ^^^^ requested 18 bytes @ offset 16
894  // ADJUSTED OFFSET
895  //   offset=16 [____xxxxxx|xxxxxxxxxx]xxxx
896  //                         ^^^^^^^^^^ ^^^^^^^^ requested 18 bytes @ offset 16
897  // ADJUSTED CAPACITY
898  //   offset=16 [____xxxxxx|xxxxxxxxxxxxxx____]
899  //                         ^^^^^^^^^^^^^^^^^^ requested 18 bytes @ offset 16
900  // AFTER
901  //   offset=34 [xxxxxxxxxx|__________]
902  //
903  EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
904  ReadLoader(16, 18, buffer);
905  ConfirmLoaderOffsets(16, 0, 18);
906  ConfirmBufferState(6, 10, 14, 18);
907
908  // Write a little, make sure we didn't start deferring.
909  WriteData(2);
910
911  // Write the rest, read should complete and capacity should go back to normal.
912  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 18));
913  WriteData(2);
914  ConfirmLoaderBufferForwardCapacity(10);
915
916  // POSTCONDITION
917  ConfirmBufferState(4, 10, 0, 10);
918  ConfirmLoaderOffsets(34, 0, 0);
919
920  StopWhenLoad();
921}
922
923TEST_F(BufferedResourceLoaderTest, Tricky_ReadPastThreshold) {
924  const int kSize = 5 * 1024 * 1024;
925  const int kThreshold = 2 * 1024 * 1024;
926
927  Initialize(kHttpUrl, 10, kSize);
928  SetLoaderBuffer(10, 10);
929  Start();
930  PartialResponse(10, kSize - 1, kSize);
931
932  uint8 buffer[256];
933  InSequence s;
934
935  // PRECONDITION
936  WriteUntilThreshold();
937  ConfirmBufferState(0, 10, 10, 10);
938  ConfirmLoaderOffsets(10, 0, 0);
939
940  // *** TRICKY BUSINESS, PT. VI ***
941  // Read past the forward wait threshold: cache miss.
942  //
943  // BEFORE
944  //   offset=10 [xxxxxxxxxx] ...
945  //                              ^^^^ requested 10 bytes @ threshold
946  // AFTER
947  //   offset=10 [xxxxxxxxxx]  !!! cache miss !!!
948  //
949  EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
950  ReadLoader(kThreshold + 20, 10, buffer);
951
952  // POSTCONDITION
953  ConfirmBufferState(0, 10, 10, 10);
954  ConfirmLoaderOffsets(10, 0, 0);
955
956  StopWhenLoad();
957}
958
959TEST_F(BufferedResourceLoaderTest, HasSingleOrigin) {
960  // Make sure no redirect case works as expected.
961  Initialize(kHttpUrl, -1, -1);
962  Start();
963  FullResponse(1024);
964  EXPECT_TRUE(loader_->HasSingleOrigin());
965  StopWhenLoad();
966
967  // Test redirect to the same domain.
968  Initialize(kHttpUrl, -1, -1);
969  Start();
970  Redirect(kHttpRedirectToSameDomainUrl1);
971  FullResponse(1024);
972  EXPECT_TRUE(loader_->HasSingleOrigin());
973  StopWhenLoad();
974
975  // Test redirect twice to the same domain.
976  Initialize(kHttpUrl, -1, -1);
977  Start();
978  Redirect(kHttpRedirectToSameDomainUrl1);
979  Redirect(kHttpRedirectToSameDomainUrl2);
980  FullResponse(1024);
981  EXPECT_TRUE(loader_->HasSingleOrigin());
982  StopWhenLoad();
983
984  // Test redirect to a different domain.
985  Initialize(kHttpUrl, -1, -1);
986  Start();
987  Redirect(kHttpRedirectToDifferentDomainUrl1);
988  FullResponse(1024);
989  EXPECT_FALSE(loader_->HasSingleOrigin());
990  StopWhenLoad();
991
992  // Test redirect to the same domain and then to a different domain.
993  Initialize(kHttpUrl, -1, -1);
994  Start();
995  Redirect(kHttpRedirectToSameDomainUrl1);
996  Redirect(kHttpRedirectToDifferentDomainUrl1);
997  FullResponse(1024);
998  EXPECT_FALSE(loader_->HasSingleOrigin());
999  StopWhenLoad();
1000}
1001
1002TEST_F(BufferedResourceLoaderTest, BufferWindow_Default) {
1003  Initialize(kHttpUrl, -1, -1);
1004  Start();
1005
1006  // Test ensures that default construction of a BufferedResourceLoader has sane
1007  // values.
1008  //
1009  // Please do not change these values in order to make a test pass! Instead,
1010  // start a conversation on what the default buffer window capacities should
1011  // be.
1012  ConfirmLoaderBufferBackwardCapacity(2 * 1024 * 1024);
1013  ConfirmLoaderBufferForwardCapacity(2 * 1024 * 1024);
1014
1015  StopWhenLoad();
1016}
1017
1018TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_Unknown) {
1019  Initialize(kHttpUrl, -1, -1);
1020  Start();
1021  loader_->SetBitrate(0);
1022  CheckBufferWindowBounds();
1023  StopWhenLoad();
1024}
1025
1026TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_BelowLowerBound) {
1027  Initialize(kHttpUrl, -1, -1);
1028  Start();
1029  loader_->SetBitrate(1024 * 8);  // 1 Kbps.
1030  CheckBufferWindowBounds();
1031  StopWhenLoad();
1032}
1033
1034TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_WithinBounds) {
1035  Initialize(kHttpUrl, -1, -1);
1036  Start();
1037  loader_->SetBitrate(2 * 1024 * 1024 * 8);  // 2 Mbps.
1038  CheckBufferWindowBounds();
1039  StopWhenLoad();
1040}
1041
1042TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_AboveUpperBound) {
1043  Initialize(kHttpUrl, -1, -1);
1044  Start();
1045  loader_->SetBitrate(100 * 1024 * 1024 * 8);  // 100 Mbps.
1046  CheckBufferWindowBounds();
1047  StopWhenLoad();
1048}
1049
1050TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_Negative) {
1051  Initialize(kHttpUrl, -1, -1);
1052  Start();
1053  loader_->SetPlaybackRate(-10);
1054  CheckBufferWindowBounds();
1055  StopWhenLoad();
1056}
1057
1058TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_Zero) {
1059  Initialize(kHttpUrl, -1, -1);
1060  Start();
1061  loader_->SetPlaybackRate(0);
1062  CheckBufferWindowBounds();
1063  StopWhenLoad();
1064}
1065
1066TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_BelowLowerBound) {
1067  Initialize(kHttpUrl, -1, -1);
1068  Start();
1069  loader_->SetPlaybackRate(0.1f);
1070  CheckBufferWindowBounds();
1071  StopWhenLoad();
1072}
1073
1074TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_WithinBounds) {
1075  Initialize(kHttpUrl, -1, -1);
1076  Start();
1077  loader_->SetPlaybackRate(10);
1078  CheckBufferWindowBounds();
1079  StopWhenLoad();
1080}
1081
1082TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_AboveUpperBound) {
1083  Initialize(kHttpUrl, -1, -1);
1084  Start();
1085  loader_->SetPlaybackRate(100);
1086  CheckBufferWindowBounds();
1087  StopWhenLoad();
1088}
1089
1090static void ExpectContentRange(
1091    const std::string& str, bool expect_success,
1092    int64 expected_first, int64 expected_last, int64 expected_size) {
1093  int64 first, last, size;
1094  ASSERT_EQ(expect_success, BufferedResourceLoader::ParseContentRange(
1095      str, &first, &last, &size)) << str;
1096  if (!expect_success)
1097    return;
1098  EXPECT_EQ(first, expected_first);
1099  EXPECT_EQ(last, expected_last);
1100  EXPECT_EQ(size, expected_size);
1101}
1102
1103static void ExpectContentRangeFailure(const std::string& str) {
1104  ExpectContentRange(str, false, 0, 0, 0);
1105}
1106
1107static void ExpectContentRangeSuccess(
1108    const std::string& str,
1109    int64 expected_first, int64 expected_last, int64 expected_size) {
1110  ExpectContentRange(str, true, expected_first, expected_last, expected_size);
1111}
1112
1113TEST(BufferedResourceLoaderStandaloneTest, ParseContentRange) {
1114  ExpectContentRangeFailure("cytes 0-499/500");
1115  ExpectContentRangeFailure("bytes 0499/500");
1116  ExpectContentRangeFailure("bytes 0-499500");
1117  ExpectContentRangeFailure("bytes 0-499/500-blorg");
1118  ExpectContentRangeFailure("bytes 0-499/500-1");
1119  ExpectContentRangeFailure("bytes 0-499/400");
1120  ExpectContentRangeFailure("bytes 0-/400");
1121  ExpectContentRangeFailure("bytes -300/400");
1122  ExpectContentRangeFailure("bytes 20-10/400");
1123
1124  ExpectContentRangeSuccess("bytes 0-499/500", 0, 499, 500);
1125  ExpectContentRangeSuccess("bytes 0-0/500", 0, 0, 500);
1126  ExpectContentRangeSuccess("bytes 10-11/50", 10, 11, 50);
1127  ExpectContentRangeSuccess("bytes 10-11/*", 10, 11,
1128                            kPositionNotSpecified);
1129}
1130
1131}  // namespace media
1132