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 "media/base/filters.h"
6#include "media/base/mock_callback.h"
7#include "media/base/mock_filter_host.h"
8#include "media/base/mock_filters.h"
9#include "net/base/net_errors.h"
10#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
11#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLError.h"
12#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoader.h"
13#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h"
14#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h"
15#include "webkit/glue/media/simple_data_source.h"
16#include "webkit/mocks/mock_webframe.h"
17#include "webkit/mocks/mock_weburlloader.h"
18
19using ::testing::_;
20using ::testing::DoAll;
21using ::testing::InSequence;
22using ::testing::Invoke;
23using ::testing::NiceMock;
24using ::testing::NotNull;
25using ::testing::Return;
26using ::testing::SetArgumentPointee;
27using ::testing::StrictMock;
28using ::testing::WithArgs;
29
30using WebKit::WebURLError;
31using WebKit::WebURLLoader;
32using WebKit::WebURLRequest;
33using WebKit::WebURLResponse;
34
35namespace webkit_glue {
36
37static const int kDataSize = 1024;
38static const char kHttpUrl[] = "http://test";
39static const char kHttpsUrl[] = "https://test";
40static const char kFileUrl[] = "file://test";
41static const char kDataUrl[] =
42    "data:text/plain;base64,YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoK";
43static const char kDataUrlDecoded[] = "abcdefghijklmnopqrstuvwxyz";
44static const char kInvalidUrl[] = "whatever://test";
45static const char kHttpRedirectToSameDomainUrl1[] = "http://test/ing";
46static const char kHttpRedirectToSameDomainUrl2[] = "http://test/ing2";
47static const char kHttpRedirectToDifferentDomainUrl1[] = "http://test2";
48static const char kHttpRedirectToDifferentDomainUrl2[] = "http://test2/ing";
49
50class SimpleDataSourceTest : public testing::Test {
51 public:
52  SimpleDataSourceTest() {
53    for (int i = 0; i < kDataSize; ++i) {
54      data_[i] = i;
55    }
56  }
57
58  virtual ~SimpleDataSourceTest() {
59  }
60
61  void InitializeDataSource(const char* url,
62                            media::MockStatusCallback* callback) {
63    gurl_ = GURL(url);
64
65    frame_.reset(new NiceMock<MockWebFrame>());
66    url_loader_ = new NiceMock<MockWebURLLoader>();
67
68    data_source_ = new SimpleDataSource(MessageLoop::current(),
69                                        frame_.get());
70
71    // There is no need to provide a message loop to data source.
72    data_source_->set_host(&host_);
73    data_source_->SetURLLoaderForTest(url_loader_);
74
75    data_source_->Initialize(url, callback);
76    MessageLoop::current()->RunAllPending();
77  }
78
79  void RequestSucceeded(bool is_loaded) {
80    WebURLResponse response(gurl_);
81    response.setExpectedContentLength(kDataSize);
82
83    data_source_->didReceiveResponse(NULL, response);
84    int64 size;
85    EXPECT_TRUE(data_source_->GetSize(&size));
86    EXPECT_EQ(kDataSize, size);
87
88    for (int i = 0; i < kDataSize; ++i) {
89      data_source_->didReceiveData(NULL, data_ + i, 1, 1);
90    }
91
92    EXPECT_CALL(host_, SetLoaded(is_loaded));
93
94    InSequence s;
95    EXPECT_CALL(host_, SetTotalBytes(kDataSize));
96    EXPECT_CALL(host_, SetBufferedBytes(kDataSize));
97
98    data_source_->didFinishLoading(NULL, 0);
99
100    // Let the tasks to be executed.
101    MessageLoop::current()->RunAllPending();
102  }
103
104  void RequestFailed() {
105    InSequence s;
106
107    WebURLError error;
108    error.reason = net::ERR_FAILED;
109    data_source_->didFail(NULL, error);
110
111    // Let the tasks to be executed.
112    MessageLoop::current()->RunAllPending();
113  }
114
115  void Redirect(const char* url) {
116    GURL redirectUrl(url);
117    WebKit::WebURLRequest newRequest(redirectUrl);
118    WebKit::WebURLResponse redirectResponse(gurl_);
119
120    data_source_->willSendRequest(url_loader_, newRequest, redirectResponse);
121
122    MessageLoop::current()->RunAllPending();
123  }
124
125  void DestroyDataSource() {
126    data_source_->Stop(media::NewExpectedCallback());
127    MessageLoop::current()->RunAllPending();
128
129    data_source_ = NULL;
130  }
131
132  void AsyncRead() {
133    for (int i = 0; i < kDataSize; ++i) {
134      uint8 buffer[1];
135
136      EXPECT_CALL(*this, ReadCallback(1));
137      data_source_->Read(
138          i, 1, buffer,
139          NewCallback(this, &SimpleDataSourceTest::ReadCallback));
140      EXPECT_EQ(static_cast<uint8>(data_[i]), buffer[0]);
141    }
142  }
143
144  MOCK_METHOD1(ReadCallback, void(size_t size));
145
146 protected:
147  GURL gurl_;
148  scoped_ptr<MessageLoop> message_loop_;
149  NiceMock<MockWebURLLoader>* url_loader_;
150  scoped_refptr<SimpleDataSource> data_source_;
151  StrictMock<media::MockFilterHost> host_;
152  scoped_ptr<NiceMock<MockWebFrame> > frame_;
153
154  char data_[kDataSize];
155
156  DISALLOW_COPY_AND_ASSIGN(SimpleDataSourceTest);
157};
158
159TEST_F(SimpleDataSourceTest, InitializeHTTP) {
160  InitializeDataSource(kHttpUrl,
161                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
162  RequestSucceeded(false);
163  DestroyDataSource();
164}
165
166TEST_F(SimpleDataSourceTest, InitializeHTTPS) {
167  InitializeDataSource(kHttpsUrl,
168                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
169  RequestSucceeded(false);
170  DestroyDataSource();
171}
172
173TEST_F(SimpleDataSourceTest, InitializeFile) {
174  InitializeDataSource(kFileUrl,
175                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
176  RequestSucceeded(true);
177  DestroyDataSource();
178}
179
180TEST_F(SimpleDataSourceTest, InitializeData) {
181  frame_.reset(new NiceMock<MockWebFrame>());
182  url_loader_ = new NiceMock<MockWebURLLoader>();
183
184  data_source_ = new SimpleDataSource(MessageLoop::current(),
185                                      frame_.get());
186  // There is no need to provide a message loop to data source.
187  data_source_->set_host(&host_);
188  data_source_->SetURLLoaderForTest(url_loader_);
189
190  EXPECT_CALL(host_, SetLoaded(true));
191  EXPECT_CALL(host_, SetTotalBytes(sizeof(kDataUrlDecoded)));
192  EXPECT_CALL(host_, SetBufferedBytes(sizeof(kDataUrlDecoded)));
193
194  data_source_->Initialize(kDataUrl,
195      media::NewExpectedStatusCallback(media::PIPELINE_OK));
196  MessageLoop::current()->RunAllPending();
197
198  DestroyDataSource();
199}
200
201TEST_F(SimpleDataSourceTest, RequestFailed) {
202  InitializeDataSource(kHttpUrl,
203      media::NewExpectedStatusCallback(media::PIPELINE_ERROR_NETWORK));
204  RequestFailed();
205  DestroyDataSource();
206}
207
208TEST_F(SimpleDataSourceTest, StopWhenDownloading) {
209  // The callback should be deleted, but not executed.
210  // TODO(scherkus): should this really be the behaviour?  Seems strange...
211  StrictMock<media::MockStatusCallback>* callback =
212      new StrictMock<media::MockStatusCallback>();
213  EXPECT_CALL(*callback, Destructor());
214
215  InitializeDataSource(kHttpUrl, callback);
216
217  EXPECT_CALL(*url_loader_, cancel());
218  DestroyDataSource();
219}
220
221TEST_F(SimpleDataSourceTest, AsyncRead) {
222  InitializeDataSource(kFileUrl,
223                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
224  RequestSucceeded(true);
225  AsyncRead();
226  DestroyDataSource();
227}
228
229// NOTE: This test will need to be reworked a little once
230// http://code.google.com/p/chromium/issues/detail?id=72578
231// is fixed.
232TEST_F(SimpleDataSourceTest, HasSingleOrigin) {
233  // Make sure no redirect case works as expected.
234  InitializeDataSource(kHttpUrl,
235                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
236  RequestSucceeded(false);
237  EXPECT_TRUE(data_source_->HasSingleOrigin());
238  DestroyDataSource();
239
240  // Test redirect to the same domain.
241  InitializeDataSource(kHttpUrl,
242                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
243  Redirect(kHttpRedirectToSameDomainUrl1);
244  RequestSucceeded(false);
245  EXPECT_TRUE(data_source_->HasSingleOrigin());
246  DestroyDataSource();
247
248  // Test redirect twice to the same domain.
249  InitializeDataSource(kHttpUrl,
250                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
251  Redirect(kHttpRedirectToSameDomainUrl1);
252  Redirect(kHttpRedirectToSameDomainUrl2);
253  RequestSucceeded(false);
254  EXPECT_TRUE(data_source_->HasSingleOrigin());
255  DestroyDataSource();
256
257  // Test redirect to a different domain.
258  InitializeDataSource(kHttpUrl,
259                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
260  Redirect(kHttpRedirectToDifferentDomainUrl1);
261  RequestSucceeded(false);
262  EXPECT_FALSE(data_source_->HasSingleOrigin());
263  DestroyDataSource();
264
265  // Test redirect to the same domain and then to a different domain.
266  InitializeDataSource(kHttpUrl,
267                       media::NewExpectedStatusCallback(media::PIPELINE_OK));
268  Redirect(kHttpRedirectToSameDomainUrl1);
269  Redirect(kHttpRedirectToDifferentDomainUrl1);
270  RequestSucceeded(false);
271  EXPECT_FALSE(data_source_->HasSingleOrigin());
272  DestroyDataSource();
273}
274
275}  // namespace webkit_glue
276