OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
DaleCurtis
2015/10/19 21:45:25
Overall there's too much use of rand() in this fil
| |
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 <deque> | |
6 #include <string> | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/callback_helpers.h" | |
11 #include "media/blink/multibuffer.h" | |
12 #include "media/blink/multibuffer_reader.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 const int kBlockSizeShift = 8; | |
16 const size_t kBlockSize = 1UL << kBlockSizeShift; | |
17 | |
18 namespace media { | |
19 class TestMultiBufferDataProvider; | |
20 | |
21 std::vector<TestMultiBufferDataProvider*> writers; | |
22 | |
23 class TestMultiBufferDataProvider : public media::MultiBuffer::DataProvider { | |
24 public: | |
25 TestMultiBufferDataProvider(MultiBufferBlockId pos, | |
26 size_t file_size, | |
27 int max_blocks_after_defer, | |
28 bool must_read_whole_file) : | |
29 pos_(pos), | |
30 blocks_until_deferred_(1 << 30), | |
31 max_blocks_after_defer_(max_blocks_after_defer), | |
32 file_size_(file_size), | |
33 must_read_whole_file_(must_read_whole_file) { | |
34 writers.push_back(this); | |
35 } | |
36 | |
37 ~TestMultiBufferDataProvider() override { | |
38 if (must_read_whole_file_) { | |
39 CHECK_GE(pos_.block_num() * kBlockSize, file_size_); | |
40 } | |
41 for (size_t i = 0; i < writers.size(); i++) { | |
42 if (writers[i] == this) { | |
43 writers[i] = writers.back(); | |
44 writers.pop_back(); | |
45 return; | |
46 } | |
47 } | |
48 LOG(FATAL) << "Couldn't find myself in writers!"; | |
49 } | |
50 | |
51 MultiBufferBlockId Tell() const override { | |
52 return pos_; | |
53 } | |
54 | |
55 bool Available() const override { | |
56 return !fifo_.empty(); | |
57 } | |
58 | |
59 scoped_refptr<DataBuffer> Read() override { | |
60 DCHECK(Available()); | |
61 scoped_refptr<DataBuffer> ret = fifo_.front(); | |
62 fifo_.pop_front(); | |
63 ++pos_; | |
64 return ret; | |
65 } | |
66 | |
67 void SetAvailableCallback(const base::Closure& cb) override { | |
68 DCHECK(!Available()); | |
69 cb_ = cb; | |
70 } | |
71 | |
72 void SetDeferred(bool deferred) override { | |
73 if (deferred) { | |
74 if (max_blocks_after_defer_ > 0) { | |
75 blocks_until_deferred_ = rand() % max_blocks_after_defer_; | |
DaleCurtis
2015/10/19 21:45:25
Again, don't use rand unless you're prepared to de
| |
76 } else if (max_blocks_after_defer_ < 0) { | |
77 blocks_until_deferred_ = - max_blocks_after_defer_; | |
78 } else { | |
79 blocks_until_deferred_ = 0; | |
80 } | |
81 } else { | |
82 blocks_until_deferred_ = 1 << 30; | |
83 } | |
84 } | |
85 | |
86 bool Advance() { | |
87 if (blocks_until_deferred_ == 0) return false; | |
88 --blocks_until_deferred_; | |
89 | |
90 bool ret = true; | |
91 scoped_refptr<media::DataBuffer> block = new media::DataBuffer(kBlockSize); | |
92 size_t x = 0; | |
93 size_t byte_pos = (fifo_.size() + pos_.block_num()) * kBlockSize; | |
94 for (x = 0; x < kBlockSize; x++, byte_pos++) { | |
95 if (byte_pos >= file_size_) break; | |
96 block->writable_data()[x] = | |
97 static_cast<uint8_t>((byte_pos * 15485863) >> 16); | |
98 } | |
99 block->set_data_size(static_cast<int>(x)); | |
100 fifo_.push_back(block); | |
101 if (byte_pos == file_size_) { | |
102 fifo_.push_back(DataBuffer::CreateEOSBuffer()); | |
103 ret = false; | |
104 } | |
105 cb_.Run(); | |
106 return ret; | |
107 } | |
108 | |
109 private: | |
110 std::deque<scoped_refptr<media::DataBuffer> > fifo_; | |
111 MultiBufferBlockId pos_; | |
112 int32_t blocks_until_deferred_; | |
113 int32_t max_blocks_after_defer_; | |
114 size_t file_size_; | |
115 bool must_read_whole_file_; | |
116 base::Closure cb_; | |
117 }; | |
118 | |
119 class TestMultiBuffer : public media::MultiBuffer { | |
120 public: | |
121 explicit TestMultiBuffer(int32_t shift) : | |
122 media::MultiBuffer(shift), | |
123 create_ok_(true), | |
124 max_writers_(10000), | |
125 file_size_(1 << 30), | |
126 max_blocks_after_defer_(0), | |
127 must_read_whole_file_(false), | |
128 writers_created_(0) { | |
129 } | |
130 | |
131 void SetMaxWriters(size_t max_writers) { | |
132 max_writers_ = max_writers; | |
133 } | |
134 | |
135 void CheckPresentState() { | |
136 MultiBufferBlockId last; | |
137 for (DataMap::iterator i = data_.begin(); | |
138 i != data_.end(); | |
139 ++i) { | |
140 CHECK(i->second); // Null poineters are not allowed in data_ | |
141 CHECK_NE(!!pinned_[i->first], lru_.Contains(i->first)) | |
142 << " i->first = " << i->first; | |
143 | |
144 if (!last.SameUrl(i->first)) { | |
145 last = MultiBufferBlockId(i->first.url_data(), 0); | |
146 } | |
147 while (last < i->first) { | |
148 CHECK_EQ(0, present_[last]) << " last = " << last; | |
149 ++last; | |
150 } | |
151 last = i->first; | |
152 CHECK_EQ(1, present_[last]) << " last = " << last; | |
153 ++last; | |
154 } | |
155 } | |
156 | |
157 void CheckLRUState() { | |
158 for (DataMap::iterator i = data_.begin(); | |
159 i != data_.end(); | |
160 ++i) { | |
161 CHECK(i->second); // Null poineters are not allowed in data_ | |
162 CHECK_NE(!!pinned_[i->first], lru_.Contains(i->first)) | |
163 << " i->first = " << i->first; | |
164 CHECK_EQ(1, present_[i->first]) << " i->first = " << i->first; | |
165 } | |
166 } | |
167 | |
168 void SetFileSize(size_t file_size) { | |
169 file_size_ = file_size; | |
170 } | |
171 | |
172 void SetMaxBlocksAfterDefer(int32_t max_blocks_after_defer) { | |
173 max_blocks_after_defer_ = max_blocks_after_defer; | |
174 } | |
175 | |
176 void SetMustReadWholeFile(bool must_read_whole_file) { | |
177 must_read_whole_file_ = must_read_whole_file; | |
178 } | |
179 | |
180 int32_t writers_created() const { | |
181 return writers_created_; | |
182 } | |
183 protected: | |
184 DataProvider* CreateWriter(const MultiBufferBlockId& pos) override { | |
185 DCHECK(create_ok_); | |
186 CHECK_LE(writers.size(), max_writers_); | |
187 writers_created_++; | |
188 return new TestMultiBufferDataProvider( | |
189 pos, file_size_, max_blocks_after_defer_, must_read_whole_file_); | |
190 } | |
191 void Prune(size_t max_to_free) override { | |
192 // Prune should not cause additional writers to be spawned. | |
193 create_ok_ = false; | |
194 MultiBuffer::Prune(max_to_free); | |
195 create_ok_ = true; | |
196 } | |
197 private: | |
198 bool create_ok_; | |
199 size_t max_writers_; | |
200 size_t file_size_; | |
201 int32_t max_blocks_after_defer_; | |
202 bool must_read_whole_file_; | |
203 int32_t writers_created_; | |
204 }; | |
205 | |
206 } | |
207 | |
208 class MultiBufferTest : public testing::Test { | |
209 public: | |
210 MultiBufferTest() : | |
211 multibuffer_(kBlockSizeShift) { | |
212 } | |
213 | |
214 void Advance() { | |
215 CHECK(media::writers.size()); | |
216 media::writers[rand() % media::writers.size()]->Advance(); | |
DaleCurtis
2015/10/19 21:45:25
Ditto.
| |
217 } | |
218 | |
219 bool AdvanceAll() { | |
220 bool advanced = false; | |
221 for (size_t i = 0; i < media::writers.size(); i++) { | |
222 advanced |= media::writers[i]->Advance(); | |
223 } | |
224 multibuffer_.CheckLRUState(); | |
225 return advanced; | |
226 } | |
227 | |
228 scoped_refptr<media::UrlData> GetUrl() { | |
229 return url_index_.GetByUrl(GURL("http://x"), media::UrlData::kUnspecified); | |
230 } | |
231 | |
232 protected: | |
233 media::TestMultiBuffer multibuffer_; | |
234 media::UrlIndex url_index_; | |
235 }; | |
236 | |
237 TEST_F(MultiBufferTest, ReadAll) { | |
238 multibuffer_.SetMaxWriters(1); | |
239 size_t pos = 0; | |
240 size_t end = 10000; | |
241 multibuffer_.SetFileSize(10000); | |
242 multibuffer_.SetMustReadWholeFile(true); | |
243 media::MultiBufferReader reader(&multibuffer_, | |
244 GetUrl(), | |
245 pos, | |
246 end, | |
247 base::Callback<void(int64_t, int64_t)>()); | |
248 reader.SetMaxBuffer(2000, 5000); | |
249 reader.SetPreload(1000, 1000); | |
250 while (pos < end) { | |
251 unsigned char buffer[27]; | |
252 buffer[17] = 17; | |
253 size_t to_read = std::min<size_t>(end - pos, 17); | |
254 int64_t bytes_read = reader.TryRead(buffer, to_read); | |
255 if (bytes_read) { | |
256 EXPECT_EQ(buffer[17], 17); | |
257 for (int64_t i = 0; i < bytes_read; i++) { | |
258 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); | |
259 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; | |
260 pos++; | |
261 } | |
262 } else { | |
263 Advance(); | |
264 } | |
265 } | |
266 } | |
267 | |
268 TEST_F(MultiBufferTest, UpdateUrlData) { | |
269 multibuffer_.SetMaxWriters(1); | |
270 size_t pos = 0; | |
271 size_t end = 10000; | |
272 multibuffer_.SetFileSize(10000); | |
273 scoped_refptr<media::UrlData> a = GetUrl(); | |
274 scoped_refptr<media::UrlData> b = | |
275 url_index_.GetByUrl(GURL("http://y"), media::UrlData::kUnspecified); | |
276 media::MultiBufferReader reader(&multibuffer_, | |
277 a, | |
278 pos, | |
279 end, | |
280 base::Callback<void(int64_t, int64_t)>()); | |
281 reader.SetPreload(1000, 1000); | |
282 multibuffer_.UpdateUrlData(a, b); | |
283 EXPECT_EQ(b, reader.GetUrlData()); | |
284 } | |
285 | |
286 | |
287 TEST_F(MultiBufferTest, ReadAllAdvanceFirst) { | |
288 multibuffer_.SetMaxWriters(1); | |
289 size_t pos = 0; | |
290 size_t end = 10000; | |
291 multibuffer_.SetFileSize(10000); | |
292 multibuffer_.SetMustReadWholeFile(true); | |
293 media::MultiBufferReader reader(&multibuffer_, | |
294 GetUrl(), | |
295 pos, | |
296 end, | |
297 base::Callback<void(int64_t, int64_t)>()); | |
298 reader.SetMaxBuffer(2000, 5000); | |
299 reader.SetPreload(1000, 1000); | |
300 while (pos < end) { | |
301 unsigned char buffer[27]; | |
302 buffer[17] = 17; | |
303 size_t to_read = std::min<size_t>(end - pos, 17); | |
304 while (AdvanceAll()); | |
305 int64_t bytes = reader.TryRead(buffer, to_read); | |
306 EXPECT_GT(bytes, 0); | |
307 EXPECT_EQ(buffer[17], 17); | |
308 for (int64_t i = 0; i < bytes; i++) { | |
309 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); | |
310 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; | |
311 pos++; | |
312 } | |
313 } | |
314 } | |
315 | |
316 // Checks that if the data provider provides too much data after we told it | |
317 // to defer, we kill it. | |
318 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer) { | |
319 multibuffer_.SetMaxWriters(1); | |
320 size_t pos = 0; | |
321 size_t end = 10000; | |
322 multibuffer_.SetFileSize(10000); | |
323 multibuffer_.SetMaxBlocksAfterDefer(-10000); | |
324 scoped_refptr<media::UrlData> url_data = GetUrl(); | |
325 url_data->set_range_supported(); | |
326 media::MultiBufferReader reader(&multibuffer_, | |
327 url_data, | |
328 pos, | |
329 end, | |
330 base::Callback<void(int64_t, int64_t)>()); | |
331 reader.SetMaxBuffer(2000, 5000); | |
332 reader.SetPreload(1000, 1000); | |
333 while (pos < end) { | |
334 unsigned char buffer[27]; | |
335 buffer[17] = 17; | |
336 size_t to_read = std::min<size_t>(end - pos, 17); | |
337 while (AdvanceAll()); | |
338 int64_t bytes = reader.TryRead(buffer, to_read); | |
339 EXPECT_GT(bytes, 0); | |
340 EXPECT_EQ(buffer[17], 17); | |
341 for (int64_t i = 0; i < bytes; i++) { | |
342 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); | |
343 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; | |
344 pos++; | |
345 } | |
346 } | |
347 EXPECT_GT(multibuffer_.writers_created(), 1); | |
348 } | |
349 | |
350 // Same as ReadAllAdvanceFirst_NeverDefer, but the url doesn't support | |
351 // ranges, so we don't destroy it no matter how much data it provides. | |
352 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer2) { | |
353 multibuffer_.SetMaxWriters(1); | |
354 size_t pos = 0; | |
355 size_t end = 10000; | |
356 multibuffer_.SetFileSize(10000); | |
357 multibuffer_.SetMustReadWholeFile(true); | |
358 multibuffer_.SetMaxBlocksAfterDefer(-10000); | |
359 scoped_refptr<media::UrlData> url_data = GetUrl(); | |
360 media::MultiBufferReader reader(&multibuffer_, | |
361 url_data, | |
362 pos, | |
363 end, | |
364 base::Callback<void(int64_t, int64_t)>()); | |
365 reader.SetMaxBuffer(2000, 5000); | |
366 reader.SetPreload(1000, 1000); | |
367 while (pos < end) { | |
368 unsigned char buffer[27]; | |
369 buffer[17] = 17; | |
370 size_t to_read = std::min<size_t>(end - pos, 17); | |
371 while (AdvanceAll()); | |
372 int64_t bytes = reader.TryRead(buffer, to_read); | |
373 EXPECT_GT(bytes, 0); | |
374 EXPECT_EQ(buffer[17], 17); | |
375 for (int64_t i = 0; i < bytes; i++) { | |
376 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); | |
377 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; | |
378 pos++; | |
379 } | |
380 } | |
381 } | |
382 | |
383 class ReadHelper { | |
384 public: | |
385 ReadHelper(scoped_refptr<media::UrlData> url, | |
386 size_t end, | |
387 size_t max_read_size, | |
388 media::MultiBuffer* multibuffer) : | |
389 pos_(0), | |
390 end_(end), | |
391 max_read_size_(max_read_size), | |
392 read_size_(0), | |
393 reader_(multibuffer, | |
394 url, | |
395 pos_, | |
396 end_, | |
397 base::Callback<void(int64_t, int64_t)>()) { | |
398 reader_.SetMaxBuffer(2000, 5000); | |
399 reader_.SetPreload(1000, 1000); | |
400 } | |
401 | |
402 bool Read() { | |
403 if (read_size_ == 0) return true; | |
404 unsigned char buffer[4096]; | |
405 CHECK_LE(read_size_, static_cast<int64_t>(sizeof(buffer))); | |
406 CHECK_EQ(pos_, reader_.Tell()); | |
407 int64_t bytes_read = reader_.TryRead(buffer, read_size_); | |
408 if (bytes_read) { | |
409 for (int64_t i = 0; i < bytes_read; i++) { | |
410 unsigned char expected = (pos_ * 15485863) >> 16; | |
411 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos_; | |
412 pos_++; | |
413 } | |
414 CHECK_EQ(pos_, reader_.Tell()); | |
415 return true; | |
416 } | |
417 return false; | |
418 } | |
419 | |
420 void StartRead() { | |
421 CHECK_EQ(pos_, reader_.Tell()); | |
422 read_size_ = std::min(1 + rand() % (max_read_size_ - 1), end_ - pos_); | |
423 if (!Read()) { | |
424 reader_.Wait(read_size_, | |
425 base::Bind(&ReadHelper::WaitCB, base::Unretained(this))); | |
426 } | |
427 } | |
428 | |
429 void WaitCB() { | |
430 CHECK(Read()); | |
431 } | |
432 | |
433 void Seek() { | |
434 pos_ = rand() % end_; | |
435 reader_.Seek(pos_); | |
436 CHECK_EQ(pos_, reader_.Tell()); | |
437 } | |
438 | |
439 private: | |
440 int64_t pos_; | |
441 int64_t end_; | |
442 int64_t max_read_size_; | |
443 int64_t read_size_; | |
444 media::MultiBufferReader reader_; | |
445 }; | |
446 | |
447 TEST_F(MultiBufferTest, RandomTest) { | |
448 size_t file_size = 1000000; | |
449 multibuffer_.SetFileSize(file_size); | |
450 multibuffer_.SetMaxBlocksAfterDefer(10); | |
451 std::vector<ReadHelper*> read_helpers; | |
452 scoped_refptr<media::UrlData> url = GetUrl(); | |
453 for (size_t i = 0; i < 20; i++) { | |
454 read_helpers.push_back(new ReadHelper(url, file_size, 1000, &multibuffer_)); | |
455 } | |
456 for (int i = 0; i < 10000; i++) { | |
457 if (rand() & 1) { | |
458 if (!media::writers.empty()) Advance(); | |
459 } else { | |
460 size_t j = rand() % read_helpers.size(); | |
461 if (rand() % 100 < 3) | |
462 read_helpers[j]->Seek(); | |
463 read_helpers[j]->StartRead(); | |
464 multibuffer_.CheckLRUState(); | |
465 } | |
466 } | |
467 multibuffer_.CheckPresentState(); | |
468 while (!read_helpers.empty()) { | |
469 delete read_helpers.back(); | |
470 read_helpers.pop_back(); | |
471 } | |
472 } | |
473 | |
474 TEST_F(MultiBufferTest, RandomTest_RangeSupported) { | |
475 size_t file_size = 1000000; | |
476 multibuffer_.SetFileSize(file_size); | |
477 multibuffer_.SetMaxBlocksAfterDefer(10); | |
478 std::vector<ReadHelper*> read_helpers; | |
479 scoped_refptr<media::UrlData> url = GetUrl(); | |
480 url->set_range_supported(); | |
481 for (size_t i = 0; i < 20; i++) { | |
482 read_helpers.push_back(new ReadHelper(url, file_size, 1000, &multibuffer_)); | |
483 } | |
484 for (int i = 0; i < 10000; i++) { | |
485 if (rand() & 1) { | |
486 if (!media::writers.empty()) Advance(); | |
487 } else { | |
488 size_t j = rand() % read_helpers.size(); | |
489 if (rand() % 100 < 3) | |
490 read_helpers[j]->Seek(); | |
491 read_helpers[j]->StartRead(); | |
492 multibuffer_.CheckLRUState(); | |
493 } | |
494 } | |
495 multibuffer_.CheckPresentState(); | |
496 while (!read_helpers.empty()) { | |
497 delete read_helpers.back(); | |
498 read_helpers.pop_back(); | |
499 } | |
500 } | |
OLD | NEW |