Chromium Code Reviews| 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 |