Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: webkit/media/buffered_data_source_unittest.cc

Issue 8649002: Rewrite BufferedDataSource tests to use real BufferedResourceLoader objects. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: bam Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm>
6
7 #include "base/bind.h" 5 #include "base/bind.h"
8 #include "base/test/test_timeouts.h"
9 #include "media/base/media_log.h" 6 #include "media/base/media_log.h"
10 #include "media/base/mock_callback.h" 7 #include "media/base/mock_callback.h"
11 #include "media/base/mock_filter_host.h" 8 #include "media/base/mock_filter_host.h"
12 #include "media/base/mock_filters.h" 9 #include "media/base/mock_filters.h"
13 #include "net/base/net_errors.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h" 10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" 11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
17 #include "webkit/media/buffered_data_source.h" 12 #include "webkit/media/buffered_data_source.h"
13 #include "webkit/media/response_generator.h"
18 #include "webkit/mocks/mock_webframeclient.h" 14 #include "webkit/mocks/mock_webframeclient.h"
19 #include "webkit/mocks/mock_weburlloader.h" 15 #include "webkit/mocks/mock_weburlloader.h"
20 16
21 using ::testing::_; 17 using ::testing::_;
22 using ::testing::Assign; 18 using ::testing::Assign;
23 using ::testing::AtLeast;
24 using ::testing::DeleteArg;
25 using ::testing::DoAll;
26 using ::testing::InSequence;
27 using ::testing::Invoke; 19 using ::testing::Invoke;
28 using ::testing::InvokeWithoutArgs; 20 using ::testing::Mock;
29 using ::testing::NotNull;
30 using ::testing::Return;
31 using ::testing::ReturnRef;
32 using ::testing::SetArgumentPointee;
33 using ::testing::StrictMock; 21 using ::testing::StrictMock;
34 using ::testing::NiceMock; 22 using ::testing::NiceMock;
35 using ::testing::WithArgs;
36 23
37 using WebKit::WebFrame; 24 using WebKit::WebFrame;
38 using WebKit::WebString;
39 using WebKit::WebURLError;
40 using WebKit::WebURLResponse; 25 using WebKit::WebURLResponse;
41 using WebKit::WebView; 26 using WebKit::WebView;
42 27
43 using webkit_glue::MockWebFrameClient; 28 using webkit_glue::MockWebFrameClient;
44 using webkit_glue::MockWebURLLoader; 29 using webkit_glue::MockWebURLLoader;
45 30
46 namespace webkit_media { 31 namespace webkit_media {
47 32
48 static const char* kHttpUrl = "http://test"; 33 // Overrides CreateResourceLoader() to permit injecting a MockWebURLLoader.
49 static const char* kFileUrl = "file://test"; 34 // Also keeps track of whether said MockWebURLLoader is actively loading.
50 static const int kDataSize = 1024;
51 static const int kMaxCacheMissesBeforeFailTest = 20;
52
53 enum NetworkState {
54 NONE,
55 LOADED,
56 LOADING
57 };
58
59 // A mock BufferedDataSource to inject mock BufferedResourceLoader through
60 // CreateResourceLoader() method.
61 class MockBufferedDataSource : public BufferedDataSource { 35 class MockBufferedDataSource : public BufferedDataSource {
62 public: 36 public:
63 MockBufferedDataSource(MessageLoop* message_loop, WebFrame* frame) 37 MockBufferedDataSource(MessageLoop* message_loop, WebFrame* frame)
64 : BufferedDataSource(message_loop, frame, new media::MediaLog()) { 38 : BufferedDataSource(message_loop, frame, new media::MediaLog()),
65 } 39 loading_(false) {
66 40 }
67 virtual base::TimeDelta GetTimeoutMilliseconds() { 41
68 return base::TimeDelta::FromMilliseconds( 42 MOCK_METHOD2(CreateResourceLoader, BufferedResourceLoader*(int64, int64));
69 TestTimeouts::tiny_timeout_ms()); 43 BufferedResourceLoader* CreateMockResourceLoader(int64 first_byte_position,
70 } 44 int64 last_byte_position) {
71 45 CHECK(!loading_) << "Previous resource load wasn't cancelled";
72 MOCK_METHOD2(CreateResourceLoader, 46
73 BufferedResourceLoader*(int64 first_position, 47 BufferedResourceLoader* loader =
74 int64 last_position)); 48 BufferedDataSource::CreateResourceLoader(first_byte_position,
49 last_byte_position);
50
51 // Keep track of active loading state via loadAsynchronously() and cancel().
52 NiceMock<MockWebURLLoader>* url_loader = new NiceMock<MockWebURLLoader>();
53 ON_CALL(*url_loader, loadAsynchronously(_, _))
54 .WillByDefault(Assign(&loading_, true));
55 ON_CALL(*url_loader, cancel())
56 .WillByDefault(Assign(&loading_, false));
57
58 // TODO(scherkus): this is a real leak detected by http://crbug.com/100914
59 // but the fix will have to wait for a more invasive follow up patch.
60 //
61 // If you're curious what the fix is, we no longer need the reference
62 // counting added to BufferedResourceLoader in r23274 since we started
63 // using WebURLLoader in r69429.
64 Mock::AllowLeak(url_loader);
65
66 loader->SetURLLoaderForTest(url_loader);
67 return loader;
68 }
69
70 bool loading() { return loading_; }
71 void set_loading(bool loading) { loading_ = loading; }
75 72
76 private: 73 private:
74 // Whether the resource load has starting loading but yet to been cancelled.
75 bool loading_;
76
77 DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource); 77 DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource);
78 }; 78 };
79 79
80 class MockBufferedResourceLoader : public BufferedResourceLoader {
81 public:
82 MockBufferedResourceLoader()
83 : BufferedResourceLoader(GURL(), 0, 0, kThresholdDefer,
84 0, 0, new media::MediaLog()) {
85 }
86
87 MOCK_METHOD3(Start, void(net::OldCompletionCallback* read_callback,
88 const base::Closure& network_callback,
89 WebFrame* frame));
90 MOCK_METHOD0(Stop, void());
91 MOCK_METHOD4(Read, void(int64 position, int read_size, uint8* buffer,
92 net::OldCompletionCallback* callback));
93 MOCK_METHOD0(content_length, int64());
94 MOCK_METHOD0(instance_size, int64());
95 MOCK_METHOD0(range_supported, bool());
96 MOCK_METHOD0(network_activity, bool());
97 MOCK_METHOD0(url, const GURL&());
98 MOCK_METHOD0(GetBufferedFirstBytePosition, int64());
99 MOCK_METHOD0(GetBufferedLastBytePosition, int64());
100
101 protected:
102 ~MockBufferedResourceLoader() {}
103
104 DISALLOW_COPY_AND_ASSIGN(MockBufferedResourceLoader);
105 };
106
107 class BufferedDataSourceTest : public testing::Test { 80 class BufferedDataSourceTest : public testing::Test {
108 public: 81 public:
109 BufferedDataSourceTest() 82 BufferedDataSourceTest()
110 : view_(WebView::create(NULL)) { 83 : responses_(GURL("http://localhost/foo.webm"), 5000000),
Ami GONE FROM CHROMIUM 2011/11/22 22:06:23 Can this 5M (and the 4M elsewhere in this file) be
scherkus (not reviewing) 2011/11/23 04:22:41 the 5M/4M are test specific but I'll go ahead and
84 view_(WebView::create(NULL)),
85 message_loop_(MessageLoop::current()) {
111 view_->initializeMainFrame(&client_); 86 view_->initializeMainFrame(&client_);
112 message_loop_ = MessageLoop::current(); 87
113 88 data_source_ = new MockBufferedDataSource(message_loop_,
114 for (size_t i = 0; i < sizeof(data_); ++i) { 89 view_->mainFrame());
115 data_[i] = i; 90 data_source_->set_host(&host_);
116 }
117 } 91 }
118 92
119 virtual ~BufferedDataSourceTest() { 93 virtual ~BufferedDataSourceTest() {
120 view_->close(); 94 view_->close();
121 } 95 }
122 96
123 void ExpectCreateAndStartResourceLoader(int start_error) { 97 void Initialize(media::PipelineStatus expected) {
98 data_source_->Initialize(responses_.gurl().spec(),
99 media::NewExpectedStatusCB(expected));
100 message_loop_->RunAllPending();
101 }
102
103 // Helper to initialize tests with a valid 206 response.
104 void InitializeWith206Response() {
105 ExpectCreateResourceLoader();
106 Initialize(media::PIPELINE_OK);
107
108 EXPECT_CALL(host_, SetLoaded(false));
109 EXPECT_CALL(host_, SetTotalBytes(responses_.content_length()));
110 EXPECT_CALL(host_, SetBufferedBytes(0));
111 Respond(responses_.Generate206(0));
112 }
113
114 // Stops all active loaders and shuts down the data source.
115 //
116 // This typically happens when the page is closed and for our purposes is
117 // appropriate to do when tearing down a test.
118 void Stop() {
119 CHECK(data_source_->loading())
120 << "You don't need to stop if there is nothing loading";
121
122 loader()->didFail(url_loader(), responses_.GenerateError());
123 message_loop_->RunAllPending();
124
125 data_source_->Stop(media::NewExpectedClosure());
126 message_loop_->RunAllPending();
127 }
128
129 void ExpectCreateResourceLoader() {
124 EXPECT_CALL(*data_source_, CreateResourceLoader(_, _)) 130 EXPECT_CALL(*data_source_, CreateResourceLoader(_, _))
125 .WillOnce(Return(loader_.get())); 131 .WillOnce(Invoke(data_source_.get(),
126 132 &MockBufferedDataSource::CreateMockResourceLoader));
127 EXPECT_CALL(*loader_, Start(NotNull(), _, NotNull())) 133 message_loop_->RunAllPending();
128 .WillOnce( 134 }
129 DoAll(Assign(&error_, start_error), 135
130 Invoke(this, 136 void Respond(const WebURLResponse& response) {
131 &BufferedDataSourceTest::InvokeStartCallback))); 137 loader()->didReceiveResponse(url_loader(), response);
132 } 138 message_loop_->RunAllPending();
133 139 }
134 void InitializeDataSource(const char* url, int error, 140
135 bool partial_response, int64 instance_size, 141 void FinishRead() {
136 NetworkState networkState) { 142 loader()->didReceiveData(url_loader(), data_, kDataSize, kDataSize);
137 // Saves the url first. 143 message_loop_->RunAllPending();
138 gurl_ = GURL(url); 144 }
139 145
140 data_source_ = new MockBufferedDataSource(MessageLoop::current(), 146 void FinishLoading() {
141 view_->mainFrame()); 147 data_source_->set_loading(false);
142 data_source_->set_host(&host_); 148 loader()->didFinishLoading(url_loader(), 0);
143 149 message_loop_->RunAllPending();
144 scoped_refptr<NiceMock<MockBufferedResourceLoader> > first_loader( 150 }
145 new NiceMock<MockBufferedResourceLoader>()); 151
146 152 MOCK_METHOD1(ReadCallback, void(size_t size));
147 // Creates the mock loader to be injected. 153
148 loader_ = first_loader; 154 void ReadAt(int64 position) {
149 155 EXPECT_CALL(*this, ReadCallback(kDataSize));
150 bool initialized_ok = (error == net::OK); 156 data_source_->Read(position, kDataSize, buffer_,
151 bool loaded = networkState == LOADED; 157 base::Bind(&BufferedDataSourceTest::ReadCallback,
152 { 158 base::Unretained(this)));
153 InSequence s; 159 message_loop_->RunAllPending();
154 ExpectCreateAndStartResourceLoader(error); 160 }
155 161
156 // In the case of an invalid partial response we expect a second loader 162 void ReadAtWithError(int64 position) {
157 // to be created.
158 if (partial_response && (error == net::ERR_INVALID_RESPONSE)) {
159 // Verify that the initial loader is stopped.
160 EXPECT_CALL(*loader_, url())
161 .WillRepeatedly(ReturnRef(gurl_));
162 EXPECT_CALL(*loader_, Stop());
163
164 // Replace loader_ with a new instance.
165 loader_ = new NiceMock<MockBufferedResourceLoader>();
166
167 // Create and start. Make sure Start() is called on the new loader.
168 ExpectCreateAndStartResourceLoader(net::OK);
169
170 // Update initialization variable since we know the second loader will
171 // return OK.
172 initialized_ok = true;
173 }
174 }
175
176 // Attach a static function that deletes the memory referred by the
177 // "callback" parameter.
178 ON_CALL(*loader_, Read(_, _, _ , _))
179 .WillByDefault(DeleteArg<3>());
180
181 ON_CALL(*loader_, instance_size())
182 .WillByDefault(Return(instance_size));
183
184 // range_supported() return true if we expect to get a partial response.
185 ON_CALL(*loader_, range_supported())
186 .WillByDefault(Return(partial_response));
187
188 ON_CALL(*loader_, url())
189 .WillByDefault(ReturnRef(gurl_));
190 media::PipelineStatus expected_init_status = media::PIPELINE_OK;
191 if (initialized_ok) {
192 // Expected loaded or not.
193 EXPECT_CALL(host_, SetLoaded(loaded));
194
195 if (instance_size != -1)
196 EXPECT_CALL(host_, SetTotalBytes(instance_size));
197
198 if (loaded)
199 EXPECT_CALL(host_, SetBufferedBytes(instance_size));
200 else
201 EXPECT_CALL(host_, SetBufferedBytes(0));
202
203 if (!partial_response || instance_size == -1)
204 EXPECT_CALL(host_, SetStreaming(true));
205
206 } else {
207 expected_init_status = media::PIPELINE_ERROR_NETWORK;
208 EXPECT_CALL(*loader_, Stop());
209 }
210
211 // Actual initialization of the data source.
212 data_source_->Initialize(url,
213 media::NewExpectedStatusCB(expected_init_status));
214 message_loop_->RunAllPending();
215
216 if (initialized_ok) {
217 // Verify the size of the data source.
218 int64 size;
219 if (instance_size != -1 && (loaded || partial_response)) {
220 EXPECT_TRUE(data_source_->GetSize(&size));
221 EXPECT_EQ(instance_size, size);
222 } else {
223 EXPECT_TRUE(data_source_->IsStreaming());
224 }
225 }
226 }
227
228 void StopDataSource() {
229 if (loader_) {
230 InSequence s;
231 EXPECT_CALL(*loader_, Stop());
232 }
233
234 data_source_->Stop(media::NewExpectedClosure());
235 message_loop_->RunAllPending();
236 }
237
238 void InvokeStartCallback(
239 net::OldCompletionCallback* callback,
240 const base::Closure& network_callback,
241 WebFrame* frame) {
242 callback->RunWithParams(Tuple1<int>(error_));
243 delete callback;
244 // TODO(hclam): Save network_callback.
245 }
246
247 void InvokeReadCallback(int64 position, int size, uint8* buffer,
248 net::OldCompletionCallback* callback) {
249 if (error_ > 0)
250 memcpy(buffer, data_ + static_cast<int>(position), error_);
251 callback->RunWithParams(Tuple1<int>(error_));
252 delete callback;
253 }
254
255 void ReadDataSourceHit(int64 position, int size, int read_size) {
256 EXPECT_TRUE(loader_);
257
258 InSequence s;
259 // Expect the read is delegated to the resource loader.
260 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull()))
261 .WillOnce(DoAll(Assign(&error_, read_size),
262 Invoke(this,
263 &BufferedDataSourceTest::InvokeReadCallback)));
264
265 // The read has succeeded, so read callback will be called.
266 EXPECT_CALL(*this, ReadCallback(read_size));
267
268 data_source_->Read(
269 position, size, buffer_,
270 base::Bind(&BufferedDataSourceTest::ReadCallback,
271 base::Unretained(this)));
272 message_loop_->RunAllPending();
273
274 // Make sure data is correct.
275 EXPECT_EQ(0,
276 memcmp(buffer_, data_ + static_cast<int>(position), read_size));
277 }
278
279 void ReadDataSourceHang(int64 position, int size) {
280 EXPECT_TRUE(loader_);
281
282 // Expect a call to read, but the call never returns.
283 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull()));
284 data_source_->Read(
285 position, size, buffer_,
286 base::Bind(&BufferedDataSourceTest::ReadCallback,
287 base::Unretained(this)));
288 message_loop_->RunAllPending();
289
290 // Now expect the read to return after aborting the data source.
291 EXPECT_CALL(*this, ReadCallback(_));
292 EXPECT_CALL(*loader_, Stop());
293 data_source_->Abort();
294 message_loop_->RunAllPending();
295
296 // The loader has now been stopped. Set this to null so that when the
297 // DataSource is stopped, it does not expect a call to stop the loader.
298 loader_ = NULL;
299 }
300
301 void ReadDataSourceMiss(int64 position, int size, int start_error) {
302 EXPECT_TRUE(loader_);
303
304 // 1. Reply with a cache miss for the read.
305 {
306 InSequence s;
307 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull()))
308 .WillOnce(DoAll(Assign(&error_, net::ERR_CACHE_MISS),
309 Invoke(this,
310 &BufferedDataSourceTest::InvokeReadCallback)));
311 EXPECT_CALL(*loader_, Stop());
312 }
313
314 // 2. Then the current loader will be stop and destroyed.
315 NiceMock<MockBufferedResourceLoader> *new_loader =
316 new NiceMock<MockBufferedResourceLoader>();
317 EXPECT_CALL(*data_source_, CreateResourceLoader(position, -1))
318 .WillOnce(Return(new_loader));
319
320 // 3. Then the new loader will be started.
321 EXPECT_CALL(*new_loader, Start(NotNull(), _, NotNull()))
322 .WillOnce(DoAll(Assign(&error_, start_error),
323 Invoke(this,
324 &BufferedDataSourceTest::InvokeStartCallback)));
325
326 if (start_error == net::OK) {
327 EXPECT_CALL(*new_loader, range_supported())
328 .WillRepeatedly(Return(loader_->range_supported()));
329
330 // 4a. Then again a read request is made to the new loader.
331 EXPECT_CALL(*new_loader, Read(position, size, NotNull(), NotNull()))
332 .WillOnce(DoAll(Assign(&error_, size),
333 Invoke(this,
334 &BufferedDataSourceTest::InvokeReadCallback)));
335
336 EXPECT_CALL(*this, ReadCallback(size));
337 } else {
338 // 4b. The read callback is called with an error because Start() on the
339 // new loader returned an error.
340 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
341 }
342
343 data_source_->Read(
344 position, size, buffer_,
345 base::Bind(&BufferedDataSourceTest::ReadCallback,
346 base::Unretained(this)));
347 message_loop_->RunAllPending();
348
349 // Make sure data is correct.
350 if (start_error == net::OK)
351 EXPECT_EQ(0, memcmp(buffer_, data_ + static_cast<int>(position), size));
352
353 loader_ = new_loader;
354 }
355
356 void ReadDataSourceFailed(int64 position, int size, int error) {
357 EXPECT_TRUE(loader_);
358
359 // 1. Expect the read is delegated to the resource loader.
360 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull()))
361 .WillOnce(DoAll(Assign(&error_, error),
362 Invoke(this,
363 &BufferedDataSourceTest::InvokeReadCallback)));
364
365 // 2. Host will then receive an error.
366 EXPECT_CALL(*loader_, Stop());
367
368 // 3. The read has failed, so read callback will be called.
369 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); 163 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
370 164 data_source_->Read(position, kDataSize, buffer_,
371 data_source_->Read( 165 base::Bind(&BufferedDataSourceTest::ReadCallback,
372 position, size, buffer_, 166 base::Unretained(this)));
373 base::Bind(&BufferedDataSourceTest::ReadCallback, 167 message_loop_->RunAllPending();
374 base::Unretained(this))); 168 }
375 169
376 message_loop_->RunAllPending(); 170 // Accessors for private variables on |data_source_|.
377 } 171 BufferedResourceLoader* loader() {
378 172 return data_source_->loader_.get();
379 BufferedResourceLoader* InvokeCacheMissCreateResourceLoader(int64 start, 173 }
380 int64 end) { 174 NiceMock<MockWebURLLoader>* url_loader() {
381 NiceMock<MockBufferedResourceLoader>* new_loader = 175 return static_cast<NiceMock<MockWebURLLoader>*>(
Ami GONE FROM CHROMIUM 2011/11/22 22:06:23 Does this really need to return the Mock subtype (
scherkus (not reviewing) 2011/11/23 04:22:41 Nope! It used to but we no longer require the moc
382 new NiceMock<MockBufferedResourceLoader>(); 176 loader()->url_loader_.get());
383 177 }
384 EXPECT_CALL(*new_loader, Start(NotNull(), _, NotNull())) 178
385 .WillOnce(DoAll(Assign(&error_, net::OK), 179 media::Preload preload() { return data_source_->preload_; }
386 Invoke(this, 180 BufferedResourceLoader::DeferStrategy defer_strategy() {
387 &BufferedDataSourceTest::InvokeStartCallback))); 181 return loader()->defer_strategy_;
388 182 }
389 EXPECT_CALL(*new_loader, range_supported()) 183 int data_source_bitrate() { return data_source_->bitrate_; }
390 .WillRepeatedly(Return(loader_->range_supported())); 184 int data_source_playback_rate() { return data_source_->playback_rate_; }
391 185 int loader_bitrate() { return loader()->bitrate_; }
392 int error = net::ERR_FAILED; 186 int loader_playback_rate() { return loader()->playback_rate_; }
393 if (cache_miss_count_ < kMaxCacheMissesBeforeFailTest) { 187
394 cache_miss_count_++; 188
395 error = net::ERR_CACHE_MISS;
396 }
397
398 EXPECT_CALL(*new_loader, Read(start, _, NotNull(), NotNull()))
399 .WillOnce(DoAll(Assign(&error_, error),
400 Invoke(this,
401 &BufferedDataSourceTest::InvokeReadCallback)));
402
403 loader_ = new_loader;
404 return new_loader;
405 }
406
407 void ReadDataSourceAlwaysCacheMiss(int64 position, int size) {
408 cache_miss_count_ = 0;
409
410 EXPECT_CALL(*data_source_, CreateResourceLoader(position, -1))
411 .WillRepeatedly(Invoke(
412 this,
413 &BufferedDataSourceTest::InvokeCacheMissCreateResourceLoader));
414
415 EXPECT_CALL(*loader_, Read(position, size, NotNull(), NotNull()))
416 .WillOnce(DoAll(Assign(&error_, net::ERR_CACHE_MISS),
417 Invoke(this,
418 &BufferedDataSourceTest::InvokeReadCallback)));
419
420 EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
421
422 data_source_->Read(
423 position, size, buffer_,
424 base::Bind(&BufferedDataSourceTest::ReadCallback,
425 base::Unretained(this)));
426
427 message_loop_->RunAllPending();
428
429 EXPECT_LT(cache_miss_count_, kMaxCacheMissesBeforeFailTest);
430 }
431
432 MOCK_METHOD1(ReadCallback, void(size_t size));
433
434 scoped_refptr<NiceMock<MockBufferedResourceLoader> > loader_;
435 scoped_refptr<MockBufferedDataSource> data_source_; 189 scoped_refptr<MockBufferedDataSource> data_source_;
436 190
191 ResponseGenerator responses_;
Ami GONE FROM CHROMIUM 2011/11/22 22:06:23 s/responses_/response_generator_/
scherkus (not reviewing) 2011/11/23 04:22:41 Done.
437 MockWebFrameClient client_; 192 MockWebFrameClient client_;
438 WebView* view_; 193 WebView* view_;
439 194
440 StrictMock<media::MockFilterHost> host_; 195 StrictMock<media::MockFilterHost> host_;
441 GURL gurl_;
442 MessageLoop* message_loop_; 196 MessageLoop* message_loop_;
443 197
444 int error_;
445 uint8 buffer_[1024];
446 uint8 data_[1024];
447
448 int cache_miss_count_;
449
450 private: 198 private:
199 static const size_t kDataSize = 1024;
200
201 // Used for calling BufferedDataSource::Read().
202 uint8 buffer_[kDataSize];
203
204 // Used for calling BufferedResourceLoader::didReceiveData().
205 char data_[kDataSize];
206
451 DISALLOW_COPY_AND_ASSIGN(BufferedDataSourceTest); 207 DISALLOW_COPY_AND_ASSIGN(BufferedDataSourceTest);
452 }; 208 };
453 209
454 TEST_F(BufferedDataSourceTest, InitializationSuccess) { 210 TEST_F(BufferedDataSourceTest, Range_Supported) {
455 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); 211 ExpectCreateResourceLoader();
456 StopDataSource(); 212 Initialize(media::PIPELINE_OK);
457 } 213
458 214 EXPECT_CALL(host_, SetLoaded(false));
459 TEST_F(BufferedDataSourceTest, InitiailizationFailed) { 215 EXPECT_CALL(host_, SetTotalBytes(responses_.content_length()));
460 InitializeDataSource(kHttpUrl, net::ERR_FILE_NOT_FOUND, false, 0, NONE); 216 EXPECT_CALL(host_, SetBufferedBytes(0));
461 StopDataSource(); 217 Respond(responses_.Generate206(0));
462 } 218 Stop();
463 219 }
464 TEST_F(BufferedDataSourceTest, MissingContentLength) { 220
465 InitializeDataSource(kHttpUrl, net::OK, true, -1, LOADING); 221 TEST_F(BufferedDataSourceTest, Range_NotFound) {
466 StopDataSource(); 222 ExpectCreateResourceLoader();
467 } 223 Initialize(media::PIPELINE_ERROR_NETWORK);
468 224
469 TEST_F(BufferedDataSourceTest, RangeRequestNotSupported) { 225 // It'll try again.
Ami GONE FROM CHROMIUM 2011/11/22 22:06:23 (here and below) Is this business of blindly retry
scherkus (not reviewing) 2011/11/23 04:22:41 bug worthy
470 InitializeDataSource(kHttpUrl, net::OK, false, 1024, LOADING); 226 ExpectCreateResourceLoader();
471 StopDataSource(); 227 Respond(responses_.Generate404());
472 } 228
473 229 // Now it's done and will fail.
474 // Test the case where we get a 206 response, but no Content-Range header. 230 Respond(responses_.Generate404());
475 TEST_F(BufferedDataSourceTest, MissingContentRange) { 231 }
476 InitializeDataSource(kHttpUrl, net::ERR_INVALID_RESPONSE, true, 1024, 232
477 LOADING); 233 TEST_F(BufferedDataSourceTest, Range_NotSupported) {
478 StopDataSource(); 234 ExpectCreateResourceLoader();
479 } 235 Initialize(media::PIPELINE_OK);
480 236
481 TEST_F(BufferedDataSourceTest, 237 // It'll try again.
Ami GONE FROM CHROMIUM 2011/11/22 22:06:23 I think we have a crbug to realize range->200 shou
scherkus (not reviewing) 2011/11/23 04:22:41 Done.
482 MissingContentLengthAndRangeRequestNotSupported) { 238 ExpectCreateResourceLoader();
483 InitializeDataSource(kHttpUrl, net::OK, false, -1, LOADING); 239 Respond(responses_.Generate200());
484 StopDataSource(); 240
485 } 241 // Now it'll succeed.
486 242 EXPECT_CALL(host_, SetLoaded(false));
487 TEST_F(BufferedDataSourceTest, ReadCacheHit) { 243 EXPECT_CALL(host_, SetTotalBytes(responses_.content_length()));
488 InitializeDataSource(kHttpUrl, net::OK, true, 25, LOADING); 244 EXPECT_CALL(host_, SetBufferedBytes(0));
489 245 EXPECT_CALL(host_, SetStreaming(true));
490 // Performs read with cache hit. 246 Respond(responses_.Generate200());
491 ReadDataSourceHit(10, 10, 10); 247 Stop();
492 248 }
493 // Performs read with cache hit but partially filled. 249
494 ReadDataSourceHit(20, 10, 5); 250 TEST_F(BufferedDataSourceTest, Range_MissingContentRange) {
495 251 ExpectCreateResourceLoader();
496 StopDataSource(); 252 Initialize(media::PIPELINE_ERROR_NETWORK);
497 } 253
498 254 // It'll try again.
499 TEST_F(BufferedDataSourceTest, ReadCacheMiss) { 255 ExpectCreateResourceLoader();
500 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); 256 Respond(responses_.Generate206(0, ResponseGenerator::kNoContentRange));
501 ReadDataSourceMiss(1000, 10, net::OK); 257
502 ReadDataSourceMiss(20, 10, net::OK); 258 // Now it's done and will fail.
503 StopDataSource(); 259 Respond(responses_.Generate206(0, ResponseGenerator::kNoContentRange));
Ami GONE FROM CHROMIUM 2011/11/22 22:06:23 Shouldn't this be failing back to a non-range requ
scherkus (not reviewing) 2011/11/23 04:22:41 this is a 206 response that's missing content rang
260 }
261
262 TEST_F(BufferedDataSourceTest, Range_MissingContentLength) {
263 ExpectCreateResourceLoader();
264 Initialize(media::PIPELINE_OK);
265
266 // It'll manage without a Content-Length response.
267 EXPECT_CALL(host_, SetLoaded(false));
268 EXPECT_CALL(host_, SetTotalBytes(responses_.content_length()));
269 EXPECT_CALL(host_, SetBufferedBytes(0));
270 Respond(responses_.Generate206(0, ResponseGenerator::kNoContentLength));
271 Stop();
272 }
273
274 TEST_F(BufferedDataSourceTest, Range_WrongContentRange) {
275 ExpectCreateResourceLoader();
276 Initialize(media::PIPELINE_ERROR_NETWORK);
277
278 // It'll try again.
279 ExpectCreateResourceLoader();
280 Respond(responses_.Generate206(1337));
281
282 // Now it's done and will fail.
283 Respond(responses_.Generate206(1337));
504 } 284 }
505 285
506 // Test the case where the initial response from the server indicates that 286 // Test the case where the initial response from the server indicates that
507 // Range requests are supported, but a later request prove otherwise. 287 // Range requests are supported, but a later request prove otherwise.
508 TEST_F(BufferedDataSourceTest, ServerLiesAboutRangeSupport) { 288 TEST_F(BufferedDataSourceTest, Range_ServerLied) {
509 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); 289 InitializeWith206Response();
510 ReadDataSourceHit(10, 10, 10); 290
511 ReadDataSourceMiss(1000, 10, net::ERR_INVALID_RESPONSE); 291 // Read causing a new request to be made -- we'll expect it to error.
512 StopDataSource(); 292 ExpectCreateResourceLoader();
513 } 293 ReadAtWithError(4000000);
514 294
515 TEST_F(BufferedDataSourceTest, ReadHang) { 295 // Return a 200 in response to a range request.
516 InitializeDataSource(kHttpUrl, net::OK, true, 25, LOADING); 296 Respond(responses_.Generate200());
517 ReadDataSourceHang(10, 10); 297 }
518 StopDataSource(); 298
519 } 299 TEST_F(BufferedDataSourceTest, Range_AbortWhileReading) {
520 300 InitializeWith206Response();
521 TEST_F(BufferedDataSourceTest, ReadFailed) { 301
522 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING); 302 // Make sure there's a pending read -- we'll expect it to error.
523 ReadDataSourceHit(10, 10, 10); 303 ReadAtWithError(0);
524 ReadDataSourceFailed(10, 10, net::ERR_CONNECTION_RESET); 304
525 StopDataSource(); 305 // Abort!!!
526 } 306 data_source_->Abort();
527 307 message_loop_->RunAllPending();
528 // Helper that sets |*value| to true. Useful for binding into a Closure. 308 }
309
310 TEST_F(BufferedDataSourceTest, Range_TooManyRetries) {
311 InitializeWith206Response();
312
313 // Make sure there's a pending read -- we'll expect it to error.
314 ReadAtWithError(0);
315
316 // It'll try three times.
317 ExpectCreateResourceLoader();
318 FinishLoading();
319 Respond(responses_.Generate206(0));
320
321 ExpectCreateResourceLoader();
322 FinishLoading();
323 Respond(responses_.Generate206(0));
324
325 ExpectCreateResourceLoader();
326 FinishLoading();
327 Respond(responses_.Generate206(0));
328
329 // It'll error after this.
Ami GONE FROM CHROMIUM 2011/11/22 22:06:23 I wish expecting an error in all these tests didn'
scherkus (not reviewing) 2011/11/23 04:22:41 The reason I don't call Stop() is because we don't
Ami GONE FROM CHROMIUM 2011/11/24 01:20:38 Your choice (maybe code it and see what it looks l
330 FinishLoading();
331 }
332
529 static void SetTrue(bool* value) { 333 static void SetTrue(bool* value) {
530 *value = true; 334 *value = true;
531 } 335 }
532 336
533 // This test makes sure that Stop() does not require a task to run on 337 // This test makes sure that Stop() does not require a task to run on
534 // |message_loop_| before it calls its callback. This prevents accidental 338 // |message_loop_| before it calls its callback. This prevents accidental
535 // introduction of a pipeline teardown deadlock. The pipeline owner blocks 339 // introduction of a pipeline teardown deadlock. The pipeline owner blocks
536 // the render message loop while waiting for Stop() to complete. Since this 340 // the render message loop while waiting for Stop() to complete. Since this
537 // object runs on the render message loop, Stop() will not complete if it 341 // object runs on the render message loop, Stop() will not complete if it
538 // requires a task to run on the the message loop that is being blocked. 342 // requires a task to run on the the message loop that is being blocked.
539 TEST_F(BufferedDataSourceTest, StopDoesNotUseMessageLoopForCallback) { 343 TEST_F(BufferedDataSourceTest, StopDoesNotUseMessageLoopForCallback) {
540 InitializeDataSource(kFileUrl, net::OK, true, 1024, LOADED); 344 InitializeWith206Response();
541 345
542 // Stop() the data source, using a callback that lets us verify that it was 346 // Stop() the data source, using a callback that lets us verify that it was
543 // called before Stop() returns. This is to make sure that the callback does 347 // called before Stop() returns. This is to make sure that the callback does
544 // not require |message_loop_| to execute tasks before being called. 348 // not require |message_loop_| to execute tasks before being called.
545 bool stop_done_called = false; 349 bool stop_done_called = false;
546 data_source_->Stop(base::Bind(&SetTrue, &stop_done_called)); 350 data_source_->Stop(base::Bind(&SetTrue, &stop_done_called));
547 351
548 // Verify that the callback was called inside the Stop() call. 352 // Verify that the callback was called inside the Stop() call.
549 EXPECT_TRUE(stop_done_called); 353 EXPECT_TRUE(stop_done_called);
550
551 message_loop_->RunAllPending(); 354 message_loop_->RunAllPending();
552 } 355 }
553 356
554 TEST_F(BufferedDataSourceTest, AbortDuringPendingRead) { 357 TEST_F(BufferedDataSourceTest, DefaultValues) {
555 InitializeDataSource(kFileUrl, net::OK, true, 1024, LOADED); 358 InitializeWith206Response();
556
557 // Setup a way to verify that Read() is not called on the loader.
558 // We are doing this to make sure that the ReadTask() is still on
559 // the message loop queue when Abort() is called.
560 bool read_called = false;
561 ON_CALL(*loader_, Read(_, _, _ , _))
562 .WillByDefault(DoAll(Assign(&read_called, true),
563 DeleteArg<3>()));
564
565 // Initiate a Read() on the data source, but don't allow the
566 // message loop to run.
567 data_source_->Read(
568 0, 10, buffer_,
569 base::Bind(&BufferedDataSourceTest::ReadCallback,
570 base::Unretained(static_cast<BufferedDataSourceTest*>(this))));
571
572 // Call Abort() with the read pending.
573 EXPECT_CALL(*this, ReadCallback(-1));
574 EXPECT_CALL(*loader_, Stop());
575 data_source_->Abort();
576
577 // Verify that Read()'s after the Abort() issue callback with an error.
578 EXPECT_CALL(*this, ReadCallback(-1));
579 data_source_->Read(
580 0, 10, buffer_,
581 base::Bind(&BufferedDataSourceTest::ReadCallback,
582 base::Unretained(static_cast<BufferedDataSourceTest*>(this))));
583
584 // Stop() the data source like normal.
585 data_source_->Stop(media::NewExpectedClosure());
586
587 // Allow cleanup task to run.
588 message_loop_->RunAllPending();
589
590 // Verify that Read() was not called on the loader.
591 EXPECT_FALSE(read_called);
592 }
593
594 // Test that we only allow a limited number of cache misses for a
595 // single Read() request.
596 TEST_F(BufferedDataSourceTest, BoundedCacheMisses) {
597 InitializeDataSource(kHttpUrl, net::OK, true, 1024, LOADING);
598
599 ReadDataSourceAlwaysCacheMiss(0, 10);
600
601 StopDataSource();
602 }
603
604 // TODO(scherkus): de-dupe from buffered_resource_loader_unittest.cc
605 ACTION_P(RequestCanceled, loader) {
606 WebURLError error;
607 error.reason = net::ERR_ABORTED;
608 error.domain = WebString::fromUTF8(net::kErrorDomain);
609 loader->didFail(NULL, error);
610 }
611
612 // A more realistic BufferedDataSource that uses BufferedResourceLoader instead
613 // of a mocked version but injects a MockWebURLLoader.
614 //
615 // TODO(scherkus): re-write these tests to use this class then drop the "2"
616 // suffix.
617 class MockBufferedDataSource2 : public BufferedDataSource {
618 public:
619 MockBufferedDataSource2(MessageLoop* message_loop, WebFrame* frame)
620 : BufferedDataSource(message_loop, frame, new media::MediaLog()),
621 url_loader_(NULL) {
622 }
623
624 virtual base::TimeDelta GetTimeoutMilliseconds() {
625 return base::TimeDelta::FromMilliseconds(
626 TestTimeouts::tiny_timeout_ms());
627 }
628
629 virtual BufferedResourceLoader* CreateResourceLoader(int64 first_position,
630 int64 last_position) {
631 loader_ = BufferedDataSource::CreateResourceLoader(first_position,
632 last_position);
633
634 url_loader_ = new NiceMock<MockWebURLLoader>();
635 ON_CALL(*url_loader_, cancel())
636 .WillByDefault(RequestCanceled(loader_));
637
638 loader_->SetURLLoaderForTest(url_loader_);
639 return loader_;
640 }
641
642 const scoped_refptr<BufferedResourceLoader>& loader() { return loader_; }
643 NiceMock<MockWebURLLoader>* url_loader() { return url_loader_; }
644
645 private:
646 scoped_refptr<BufferedResourceLoader> loader_;
647 NiceMock<MockWebURLLoader>* url_loader_;
648
649 DISALLOW_COPY_AND_ASSIGN(MockBufferedDataSource2);
650 };
651
652 class BufferedDataSourceTest2 : public testing::Test {
653 public:
654 BufferedDataSourceTest2()
655 : view_(WebView::create(NULL)),
656 message_loop_(MessageLoop::current()) {
657 view_->initializeMainFrame(&client_);
658 }
659
660 virtual ~BufferedDataSourceTest2() {
661 view_->close();
662 }
663
664 void InitializeDataSource(const char* url) {
665 gurl_ = GURL(url);
666
667 data_source_ = new MockBufferedDataSource2(message_loop_,
668 view_->mainFrame());
669 data_source_->set_host(&host_);
670 data_source_->Initialize(url,
671 media::NewExpectedStatusCB(media::PIPELINE_OK));
672 message_loop_->RunAllPending();
673
674 // Simulate 206 response for a 5,000,000 byte length file.
675 WebURLResponse response(gurl_);
676 response.setHTTPHeaderField(WebString::fromUTF8("Accept-Ranges"),
677 WebString::fromUTF8("bytes"));
678 response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"),
679 WebString::fromUTF8("bytes 0-4999999/5000000"));
680 response.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
681 WebString::fromUTF8("5000000"));
682 response.setExpectedContentLength(5000000);
683 response.setHTTPStatusCode(206);
684
685 // We should receive corresponding information about the media resource.
686 EXPECT_CALL(host_, SetLoaded(false));
687 EXPECT_CALL(host_, SetTotalBytes(5000000));
688 EXPECT_CALL(host_, SetBufferedBytes(0));
689
690 data_source_->loader()->didReceiveResponse(data_source_->url_loader(),
691 response);
692
693 message_loop_->RunAllPending();
694 }
695
696 void StopDataSource() {
697 data_source_->Stop(media::NewExpectedClosure());
698 message_loop_->RunAllPending();
699 }
700
701 MOCK_METHOD1(ReadCallback, void(size_t size));
702 media::DataSource::ReadCallback NewReadCallback(size_t size) {
703 EXPECT_CALL(*this, ReadCallback(size));
704 return base::Bind(&BufferedDataSourceTest2::ReadCallback,
705 base::Unretained(this));
706 }
707
708 // Accessors for private variables on |data_source_|.
709 media::Preload preload() { return data_source_->preload_; }
710 BufferedResourceLoader::DeferStrategy defer_strategy() {
711 return data_source_->loader()->defer_strategy_;
712 }
713 int data_source_bitrate() { return data_source_->bitrate_; }
714 int data_source_playback_rate() { return data_source_->playback_rate_; }
715 int loader_bitrate() { return data_source_->loader()->bitrate_; }
716 int loader_playback_rate() { return data_source_->loader()->playback_rate_; }
717
718 scoped_refptr<MockBufferedDataSource2> data_source_;
719
720 GURL gurl_;
721 MockWebFrameClient client_;
722 WebView* view_;
723
724 StrictMock<media::MockFilterHost> host_;
725 MessageLoop* message_loop_;
726
727 private:
728 DISALLOW_COPY_AND_ASSIGN(BufferedDataSourceTest2);
729 };
730
731 TEST_F(BufferedDataSourceTest2, Default) {
732 InitializeDataSource("http://localhost/foo.webm");
733 359
734 // Ensure we have sane values for default loading scenario. 360 // Ensure we have sane values for default loading scenario.
735 EXPECT_EQ(media::AUTO, preload()); 361 EXPECT_EQ(media::AUTO, preload());
736 EXPECT_EQ(BufferedResourceLoader::kThresholdDefer, defer_strategy()); 362 EXPECT_EQ(BufferedResourceLoader::kThresholdDefer, defer_strategy());
737 363
738 EXPECT_EQ(0, data_source_bitrate()); 364 EXPECT_EQ(0, data_source_bitrate());
739 EXPECT_EQ(0.0f, data_source_playback_rate()); 365 EXPECT_EQ(0.0f, data_source_playback_rate());
740 EXPECT_EQ(0, loader_bitrate()); 366 EXPECT_EQ(0, loader_bitrate());
741 EXPECT_EQ(0.0f, loader_playback_rate()); 367 EXPECT_EQ(0.0f, loader_playback_rate());
742 368 Stop();
743 StopDataSource();
744 } 369 }
745 370
746 TEST_F(BufferedDataSourceTest2, SetBitrate) { 371 TEST_F(BufferedDataSourceTest, SetBitrate) {
747 InitializeDataSource("http://localhost/foo.webm"); 372 InitializeWith206Response();
748 373
749 data_source_->SetBitrate(1234); 374 data_source_->SetBitrate(1234);
750 message_loop_->RunAllPending(); 375 message_loop_->RunAllPending();
751 EXPECT_EQ(1234, data_source_bitrate()); 376 EXPECT_EQ(1234, data_source_bitrate());
752 EXPECT_EQ(1234, loader_bitrate()); 377 EXPECT_EQ(1234, loader_bitrate());
753 378
754 // Read so far ahead to cause the loader to get recreated. 379 // Read so far ahead to cause the loader to get recreated.
755 BufferedResourceLoader* old_loader = data_source_->loader(); 380 BufferedResourceLoader* old_loader = loader();
756 381 ExpectCreateResourceLoader();
757 uint8 buffer[1024]; 382 ReadAtWithError(4000000);
758 data_source_->Read(4000000, 1024, buffer, 383 Respond(responses_.Generate206(4000000));
759 NewReadCallback(media::DataSource::kReadError));
760 message_loop_->RunAllPending();
761 384
762 // Verify loader changed but still has same bitrate. 385 // Verify loader changed but still has same bitrate.
763 EXPECT_NE(old_loader, data_source_->loader().get()); 386 EXPECT_NE(old_loader, loader());
764 EXPECT_EQ(1234, loader_bitrate()); 387 EXPECT_EQ(1234, loader_bitrate());
765 388 Stop();
766 StopDataSource();
767 } 389 }
768 390
769 TEST_F(BufferedDataSourceTest2, SetPlaybackRate) { 391 TEST_F(BufferedDataSourceTest, SetPlaybackRate) {
770 InitializeDataSource("http://localhost/foo.webm"); 392 InitializeWith206Response();
771 393
772 data_source_->SetPlaybackRate(2.0f); 394 data_source_->SetPlaybackRate(2.0f);
773 message_loop_->RunAllPending(); 395 message_loop_->RunAllPending();
774 EXPECT_EQ(2.0f, data_source_playback_rate()); 396 EXPECT_EQ(2.0f, data_source_playback_rate());
775 EXPECT_EQ(2.0f, loader_playback_rate()); 397 EXPECT_EQ(2.0f, loader_playback_rate());
776 398
777 // Read so far ahead to cause the loader to get recreated. 399 // Read so far ahead to cause the loader to get recreated.
778 BufferedResourceLoader* old_loader = data_source_->loader(); 400 BufferedResourceLoader* old_loader = loader();
779 401 ExpectCreateResourceLoader();
780 uint8 buffer[1024]; 402 ReadAtWithError(4000000);
781 data_source_->Read(4000000, 1024, buffer, 403 Respond(responses_.Generate206(4000000));
782 NewReadCallback(media::DataSource::kReadError));
783 message_loop_->RunAllPending();
784 404
785 // Verify loader changed but still has same bitrate. 405 // Verify loader changed but still has same bitrate.
786 EXPECT_NE(old_loader, data_source_->loader().get()); 406 EXPECT_NE(old_loader, loader());
787 EXPECT_EQ(2.0f, loader_playback_rate()); 407 Stop();
408 }
788 409
789 StopDataSource(); 410 TEST_F(BufferedDataSourceTest, Read) {
411 InitializeWith206Response();
412
413 ReadAt(0);
414
415 // When the read completes we'll update our network status.
416 EXPECT_CALL(host_, SetBufferedBytes(1024));
417 EXPECT_CALL(host_, SetNetworkActivity(true));
418 FinishRead();
419
420 // During teardown we'll also report our final network status.
421 EXPECT_CALL(host_, SetBufferedBytes(1024));
422 EXPECT_CALL(host_, SetNetworkActivity(false));
423 Stop();
790 } 424 }
791 425
792 } // namespace webkit_media 426 } // namespace webkit_media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698