1 // Copyright 2017 The Chromium Authors
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 "net/http/http_cache_writers.h"
6
7 #include <limits>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/functional/bind.h"
14 #include "base/memory/raw_ptr_exclusion.h"
15 #include "base/run_loop.h"
16 #include "crypto/secure_hash.h"
17 #include "net/http/http_cache.h"
18 #include "net/http/http_cache_transaction.h"
19 #include "net/http/http_response_info.h"
20 #include "net/http/http_transaction.h"
21 #include "net/http/http_transaction_test_util.h"
22 #include "net/http/mock_http_cache.h"
23 #include "net/http/partial_data.h"
24 #include "net/test/gtest_util.h"
25 #include "net/test/test_with_task_environment.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using net::test::IsError;
30 using net::test::IsOk;
31
32 namespace net {
33
34 namespace {
35 // Helper function, generating valid HTTP cache key from `url`.
36 // See also: HttpCache::GenerateCacheKey(..)
GenerateCacheKey(const std::string & url)37 std::string GenerateCacheKey(const std::string& url) {
38 return "1/0/" + url;
39 }
40 } // namespace
41
42 class WritersTest;
43
44 class TestHttpCacheTransaction : public HttpCache::Transaction {
45 typedef WebSocketHandshakeStreamBase::CreateHelper CreateHelper;
46
47 public:
TestHttpCacheTransaction(RequestPriority priority,HttpCache * cache)48 TestHttpCacheTransaction(RequestPriority priority, HttpCache* cache)
49 : HttpCache::Transaction(priority, cache) {}
50 ~TestHttpCacheTransaction() override = default;
51
mode() const52 Transaction::Mode mode() const override { return Transaction::READ_WRITE; }
53 };
54
55 class TestHttpCache : public HttpCache {
56 public:
TestHttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,std::unique_ptr<BackendFactory> backend_factory)57 TestHttpCache(std::unique_ptr<HttpTransactionFactory> network_layer,
58 std::unique_ptr<BackendFactory> backend_factory)
59 : HttpCache(std::move(network_layer), std::move(backend_factory)) {}
60
WritersDoneWritingToEntry(ActiveEntry * entry,bool success,bool should_keep_entry,TransactionSet make_readers)61 void WritersDoneWritingToEntry(ActiveEntry* entry,
62 bool success,
63 bool should_keep_entry,
64 TransactionSet make_readers) override {
65 done_writing_to_entry_count_ += 1;
66 make_readers_size_ = make_readers.size();
67 }
68
WritersDoomEntryRestartTransactions(ActiveEntry * entry)69 void WritersDoomEntryRestartTransactions(ActiveEntry* entry) override {}
70
WritersDoneWritingToEntryCount() const71 int WritersDoneWritingToEntryCount() const {
72 return done_writing_to_entry_count_;
73 }
74
MakeReadersSize() const75 size_t MakeReadersSize() const { return make_readers_size_; }
76
77 private:
78 int done_writing_to_entry_count_ = 0;
79 size_t make_readers_size_ = 0u;
80 };
81
82 class WritersTest : public TestWithTaskEnvironment {
83 public:
84 enum class DeleteTransactionType { NONE, ACTIVE, WAITING, IDLE };
WritersTest()85 WritersTest()
86 : scoped_transaction_(kSimpleGET_Transaction),
87 test_cache_(std::make_unique<MockNetworkLayer>(),
88 std::make_unique<MockBackendFactory>()),
89 request_(kSimpleGET_Transaction) {
90 scoped_transaction_.response_headers =
91 "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n"
92 "Content-Length: 22\n"
93 "Etag: \"foopy\"\n";
94 request_ = MockHttpRequest(scoped_transaction_);
95 }
96
~WritersTest()97 ~WritersTest() override {
98 if (disk_entry_)
99 disk_entry_->Close();
100 }
101
CreateWriters()102 void CreateWriters() {
103 cache_.CreateBackendEntry(GenerateCacheKey(kSimpleGET_Transaction.url),
104 &disk_entry_, nullptr);
105 entry_ = std::make_unique<HttpCache::ActiveEntry>(disk_entry_, false);
106 (static_cast<MockDiskEntry*>(disk_entry_))->AddRef();
107 writers_ = std::make_unique<HttpCache::Writers>(&test_cache_, entry_.get());
108 }
109
CreateNetworkTransaction()110 std::unique_ptr<HttpTransaction> CreateNetworkTransaction() {
111 std::unique_ptr<HttpTransaction> transaction;
112 MockNetworkLayer* network_layer = cache_.network_layer();
113 network_layer->CreateTransaction(DEFAULT_PRIORITY, &transaction);
114 return transaction;
115 }
116
CreateWritersAddTransaction(HttpCache::ParallelWritingPattern parallel_writing_pattern_=HttpCache::PARALLEL_WRITING_JOIN,bool content_encoding_present=false)117 void CreateWritersAddTransaction(
118 HttpCache::ParallelWritingPattern parallel_writing_pattern_ =
119 HttpCache::PARALLEL_WRITING_JOIN,
120 bool content_encoding_present = false) {
121 TestCompletionCallback callback;
122
123 // Create and Start a mock network transaction.
124 std::unique_ptr<HttpTransaction> network_transaction;
125 network_transaction = CreateNetworkTransaction();
126 network_transaction->Start(&request_, callback.callback(),
127 NetLogWithSource());
128 base::RunLoop().RunUntilIdle();
129 response_info_ = *(network_transaction->GetResponseInfo());
130 if (content_encoding_present)
131 response_info_.headers->AddHeader("Content-Encoding", "gzip");
132
133 // Create a mock cache transaction.
134 std::unique_ptr<TestHttpCacheTransaction> transaction =
135 std::make_unique<TestHttpCacheTransaction>(DEFAULT_PRIORITY,
136 cache_.http_cache());
137
138 CreateWriters();
139 EXPECT_TRUE(writers_->IsEmpty());
140 HttpCache::Writers::TransactionInfo info(
141 transaction->partial(), transaction->is_truncated(), response_info_);
142
143 writers_->AddTransaction(transaction.get(), parallel_writing_pattern_,
144 transaction->priority(), info);
145 writers_->SetNetworkTransaction(transaction.get(),
146 std::move(network_transaction));
147 EXPECT_TRUE(writers_->HasTransaction(transaction.get()));
148 transactions_.push_back(std::move(transaction));
149 }
150
CreateWritersAddTransactionPriority(net::RequestPriority priority,HttpCache::ParallelWritingPattern parallel_writing_pattern_=HttpCache::PARALLEL_WRITING_JOIN)151 void CreateWritersAddTransactionPriority(
152 net::RequestPriority priority,
153 HttpCache::ParallelWritingPattern parallel_writing_pattern_ =
154 HttpCache::PARALLEL_WRITING_JOIN) {
155 CreateWritersAddTransaction(parallel_writing_pattern_);
156 TestHttpCacheTransaction* transaction = transactions_.begin()->get();
157 transaction->SetPriority(priority);
158 }
159
AddTransactionToExistingWriters()160 void AddTransactionToExistingWriters() {
161 EXPECT_TRUE(writers_);
162
163 // Create a mock cache transaction.
164 std::unique_ptr<TestHttpCacheTransaction> transaction =
165 std::make_unique<TestHttpCacheTransaction>(DEFAULT_PRIORITY,
166 cache_.http_cache());
167
168 HttpCache::Writers::TransactionInfo info(transaction->partial(),
169 transaction->is_truncated(),
170 *(transaction->GetResponseInfo()));
171 info.response_info = response_info_;
172 writers_->AddTransaction(transaction.get(),
173 HttpCache::PARALLEL_WRITING_JOIN,
174 transaction->priority(), info);
175 transactions_.push_back(std::move(transaction));
176 }
177
Read(std::string * result)178 int Read(std::string* result) {
179 EXPECT_TRUE(transactions_.size() >= (size_t)1);
180 TestHttpCacheTransaction* transaction = transactions_.begin()->get();
181 TestCompletionCallback callback;
182
183 std::string content;
184 int rv = 0;
185 do {
186 auto buf = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
187 rv = writers_->Read(buf.get(), kDefaultBufferSize, callback.callback(),
188 transaction);
189 if (rv == ERR_IO_PENDING) {
190 rv = callback.WaitForResult();
191 base::RunLoop().RunUntilIdle();
192 }
193
194 if (rv > 0)
195 content.append(buf->data(), rv);
196 else if (rv < 0)
197 return rv;
198 } while (rv > 0);
199
200 result->swap(content);
201 return OK;
202 }
203
ReadFewBytes(std::string * result)204 int ReadFewBytes(std::string* result) {
205 EXPECT_TRUE(transactions_.size() >= (size_t)1);
206 TestHttpCacheTransaction* transaction = transactions_.begin()->get();
207 TestCompletionCallback callback;
208
209 std::string content;
210 int rv = 0;
211 auto buf = base::MakeRefCounted<IOBufferWithSize>(5);
212 rv = writers_->Read(buf.get(), 5, callback.callback(), transaction);
213 if (rv == ERR_IO_PENDING) {
214 rv = callback.WaitForResult();
215 base::RunLoop().RunUntilIdle();
216 }
217
218 if (rv > 0)
219 result->append(buf->data(), rv);
220 else if (rv < 0)
221 return rv;
222
223 return OK;
224 }
225
ReadVerifyTwoDifferentBufferLengths(const std::vector<int> & buffer_lengths)226 void ReadVerifyTwoDifferentBufferLengths(
227 const std::vector<int>& buffer_lengths) {
228 EXPECT_EQ(2u, buffer_lengths.size());
229 EXPECT_EQ(2u, transactions_.size());
230
231 std::vector<std::string> results(buffer_lengths.size());
232
233 // Check only the 1st Read and not the complete response because the smaller
234 // buffer transaction will need to read the remaining response from the
235 // cache which will be tested when integrated with TestHttpCacheTransaction
236 // layer.
237
238 int rv = 0;
239
240 std::vector<scoped_refptr<IOBuffer>> bufs;
241 for (auto buffer_length : buffer_lengths)
242 bufs.push_back(base::MakeRefCounted<IOBufferWithSize>(buffer_length));
243
244 std::vector<TestCompletionCallback> callbacks(buffer_lengths.size());
245
246 // Multiple transactions should be able to read with different sized
247 // buffers.
248 for (size_t i = 0; i < transactions_.size(); i++) {
249 rv = writers_->Read(bufs[i].get(), buffer_lengths[i],
250 callbacks[i].callback(), transactions_[i].get());
251 EXPECT_EQ(ERR_IO_PENDING, rv); // Since the default is asynchronous.
252 }
253
254 // If first buffer is smaller, then the second one will only read the
255 // smaller length as well.
256 std::vector<int> expected_lengths = {buffer_lengths[0],
257 buffer_lengths[0] < buffer_lengths[1]
258 ? buffer_lengths[0]
259 : buffer_lengths[1]};
260
261 for (size_t i = 0; i < callbacks.size(); i++) {
262 rv = callbacks[i].WaitForResult();
263 EXPECT_EQ(expected_lengths[i], rv);
264 results[i].append(bufs[i]->data(), expected_lengths[i]);
265 }
266
267 EXPECT_EQ(results[0].substr(0, expected_lengths[1]), results[1]);
268
269 std::string expected(kSimpleGET_Transaction.data);
270 EXPECT_EQ(expected.substr(0, expected_lengths[1]), results[1]);
271 }
272
273 // Each transaction invokes Read simultaneously. If |deleteType| is not NONE,
274 // then it deletes the transaction of given type during the read process.
ReadAllDeleteTransaction(DeleteTransactionType deleteType)275 void ReadAllDeleteTransaction(DeleteTransactionType deleteType) {
276 EXPECT_LE(3u, transactions_.size());
277
278 unsigned int delete_index = std::numeric_limits<unsigned int>::max();
279 switch (deleteType) {
280 case DeleteTransactionType::NONE:
281 break;
282 case DeleteTransactionType::ACTIVE:
283 delete_index = 0;
284 break;
285 case DeleteTransactionType::WAITING:
286 delete_index = 1;
287 break;
288 case DeleteTransactionType::IDLE:
289 delete_index = 2;
290 break;
291 }
292
293 std::vector<std::string> results(transactions_.size());
294 int rv = 0;
295 bool first_iter = true;
296 do {
297 std::vector<scoped_refptr<IOBuffer>> bufs;
298 std::vector<TestCompletionCallback> callbacks(transactions_.size());
299
300 for (size_t i = 0; i < transactions_.size(); i++) {
301 bufs.push_back(
302 base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize));
303
304 // If we have deleted a transaction in the first iteration, then do not
305 // invoke Read on it, in subsequent iterations.
306 if (!first_iter && deleteType != DeleteTransactionType::NONE &&
307 i == delete_index)
308 continue;
309
310 // For it to be an idle transaction, do not invoke Read.
311 if (deleteType == DeleteTransactionType::IDLE && i == delete_index)
312 continue;
313
314 rv = writers_->Read(bufs[i].get(), kDefaultBufferSize,
315 callbacks[i].callback(), transactions_[i].get());
316 EXPECT_EQ(ERR_IO_PENDING, rv); // Since the default is asynchronous.
317 }
318
319 if (first_iter && deleteType != DeleteTransactionType::NONE) {
320 writers_->RemoveTransaction(transactions_.at(delete_index).get(),
321 false /* success */);
322 }
323
324 // Verify Add Transaction should succeed mid-read.
325 AddTransactionToExistingWriters();
326
327 std::vector<int> rvs;
328 for (size_t i = 0; i < callbacks.size(); i++) {
329 if (i == delete_index && deleteType != DeleteTransactionType::NONE)
330 continue;
331 rv = callbacks[i].WaitForResult();
332 rvs.push_back(rv);
333 }
334
335 // Verify all transactions should read the same length buffer.
336 for (size_t i = 1; i < rvs.size(); i++) {
337 ASSERT_EQ(rvs[i - 1], rvs[i]);
338 }
339
340 if (rv > 0) {
341 for (size_t i = 0; i < results.size(); i++) {
342 if (i == delete_index && deleteType != DeleteTransactionType::NONE &&
343 deleteType != DeleteTransactionType::ACTIVE) {
344 continue;
345 }
346 results.at(i).append(bufs[i]->data(), rv);
347 }
348 }
349 first_iter = false;
350 } while (rv > 0);
351
352 for (size_t i = 0; i < results.size(); i++) {
353 if (i == delete_index && deleteType != DeleteTransactionType::NONE &&
354 deleteType != DeleteTransactionType::ACTIVE) {
355 continue;
356 }
357 EXPECT_EQ(kSimpleGET_Transaction.data, results[i]);
358 }
359
360 EXPECT_EQ(OK, rv);
361 }
362
363 // Creates a transaction and performs two reads. Returns after the second read
364 // has begun but before its callback has run.
StopMidRead()365 void StopMidRead() {
366 CreateWritersAddTransaction();
367 EXPECT_FALSE(writers_->IsEmpty());
368 EXPECT_EQ(1u, transactions_.size());
369 TestHttpCacheTransaction* transaction = transactions_[0].get();
370
371 // Read a few bytes so that truncation is possible.
372 TestCompletionCallback callback;
373 auto buf = base::MakeRefCounted<IOBufferWithSize>(5);
374 int rv = writers_->Read(buf.get(), 5, callback.callback(), transaction);
375 EXPECT_EQ(ERR_IO_PENDING, rv); // Since the default is asynchronous.
376 EXPECT_EQ(5, callback.GetResult(rv));
377
378 // Start reading a few more bytes and return.
379 buf = base::MakeRefCounted<IOBufferWithSize>(5);
380 rv = writers_->Read(buf.get(), 5, base::BindOnce([](int rv) {}),
381 transaction);
382 EXPECT_EQ(ERR_IO_PENDING, rv);
383 }
384
ReadAll()385 void ReadAll() { ReadAllDeleteTransaction(DeleteTransactionType::NONE); }
386
ReadCacheWriteFailure(std::vector<std::string> * results)387 int ReadCacheWriteFailure(std::vector<std::string>* results) {
388 int rv = 0;
389 int active_transaction_rv = 0;
390 bool first_iter = true;
391 do {
392 std::vector<scoped_refptr<IOBuffer>> bufs;
393 std::vector<TestCompletionCallback> callbacks(results->size());
394
395 // Fail the request.
396 cache_.disk_cache()->set_soft_failures_mask(MockDiskEntry::FAIL_ALL);
397
398 // We have to open the entry again to propagate the failure flag.
399 disk_cache::Entry* en;
400 cache_.OpenBackendEntry(GenerateCacheKey(kSimpleGET_Transaction.url),
401 &en);
402 en->Close();
403
404 for (size_t i = 0; i < transactions_.size(); i++) {
405 bufs.push_back(base::MakeRefCounted<IOBufferWithSize>(30));
406
407 if (!first_iter && i > 0)
408 break;
409 rv = writers_->Read(bufs[i].get(), 30, callbacks[i].callback(),
410 transactions_[i].get());
411 EXPECT_EQ(ERR_IO_PENDING, rv); // Since the default is asynchronous.
412 }
413
414 for (size_t i = 0; i < callbacks.size(); i++) {
415 // Only active transaction should succeed.
416 if (i == 0) {
417 active_transaction_rv = callbacks[i].WaitForResult();
418 EXPECT_LE(0, active_transaction_rv);
419 results->at(0).append(bufs[i]->data(), active_transaction_rv);
420 } else if (first_iter) {
421 rv = callbacks[i].WaitForResult();
422 EXPECT_EQ(ERR_CACHE_WRITE_FAILURE, rv);
423 }
424 }
425
426 first_iter = false;
427 } while (active_transaction_rv > 0);
428
429 return active_transaction_rv;
430 }
431
ReadNetworkFailure(std::vector<std::string> * results,Error error)432 int ReadNetworkFailure(std::vector<std::string>* results, Error error) {
433 int rv = 0;
434 std::vector<scoped_refptr<IOBuffer>> bufs;
435 std::vector<TestCompletionCallback> callbacks(results->size());
436
437 for (size_t i = 0; i < transactions_.size(); i++) {
438 bufs.push_back(base::MakeRefCounted<IOBufferWithSize>(30));
439
440 rv = writers_->Read(bufs[i].get(), 30, callbacks[i].callback(),
441 transactions_[i].get());
442 EXPECT_EQ(ERR_IO_PENDING, rv); // Since the default is asynchronous.
443 }
444
445 for (auto& callback : callbacks) {
446 rv = callback.WaitForResult();
447 EXPECT_EQ(error, rv);
448 }
449
450 return error;
451 }
452
StopCaching()453 bool StopCaching() {
454 TestHttpCacheTransaction* transaction = transactions_.begin()->get();
455 EXPECT_TRUE(transaction);
456 return writers_->StopCaching(transaction);
457 }
458
RemoveFirstTransaction()459 void RemoveFirstTransaction() {
460 TestHttpCacheTransaction* transaction = transactions_.begin()->get();
461 EXPECT_TRUE(transaction);
462 writers_->RemoveTransaction(transaction, false /* success */);
463 }
464
UpdateAndVerifyPriority(RequestPriority priority)465 void UpdateAndVerifyPriority(RequestPriority priority) {
466 writers_->UpdatePriority();
467 EXPECT_EQ(priority, writers_->priority_);
468 }
469
ShouldKeepEntry() const470 bool ShouldKeepEntry() const { return writers_->should_keep_entry_; }
471
Truncated() const472 bool Truncated() const {
473 const int kResponseInfoIndex = 0; // Keep updated with HttpCache.
474 TestCompletionCallback callback;
475 int io_buf_len = entry_->disk_entry->GetDataSize(kResponseInfoIndex);
476 if (io_buf_len == 0)
477 return false;
478
479 auto read_buffer = base::MakeRefCounted<IOBufferWithSize>(io_buf_len);
480 int rv = disk_entry_->ReadData(kResponseInfoIndex, 0, read_buffer.get(),
481 io_buf_len, callback.callback());
482 rv = callback.GetResult(rv);
483 HttpResponseInfo response_info;
484 bool truncated;
485 HttpCache::ParseResponseInfo(read_buffer->data(), io_buf_len,
486 &response_info, &truncated);
487 return truncated;
488 }
489
ShouldTruncate()490 bool ShouldTruncate() { return writers_->ShouldTruncate(); }
491
CanAddWriters()492 bool CanAddWriters() {
493 HttpCache::ParallelWritingPattern parallel_writing_pattern_;
494 return writers_->CanAddWriters(¶llel_writing_pattern_);
495 }
496
497 ScopedMockTransaction scoped_transaction_;
498 MockHttpCache cache_;
499 std::unique_ptr<HttpCache::Writers> writers_;
500 // This field is not a raw_ptr<> because it was filtered by the rewriter for:
501 // #addr-of
502 RAW_PTR_EXCLUSION disk_cache::Entry* disk_entry_ = nullptr;
503 std::unique_ptr<HttpCache::ActiveEntry> entry_;
504 TestHttpCache test_cache_;
505
506 // Should be before transactions_ since it is accessed in the network
507 // transaction's destructor.
508 MockHttpRequest request_;
509
510 HttpResponseInfo response_info_;
511 static const int kDefaultBufferSize = 256;
512
513 std::vector<std::unique_ptr<TestHttpCacheTransaction>> transactions_;
514 };
515
516 const int WritersTest::kDefaultBufferSize;
517
518 // Tests successful addition of a transaction.
TEST_F(WritersTest,AddTransaction)519 TEST_F(WritersTest, AddTransaction) {
520 CreateWritersAddTransaction();
521 EXPECT_FALSE(writers_->IsEmpty());
522
523 // Verify keep_entry_ is true by default.
524 EXPECT_TRUE(ShouldKeepEntry());
525 }
526
527 // Tests successful addition of multiple transactions.
TEST_F(WritersTest,AddManyTransactions)528 TEST_F(WritersTest, AddManyTransactions) {
529 CreateWritersAddTransaction();
530 EXPECT_FALSE(writers_->IsEmpty());
531
532 for (int i = 0; i < 5; i++)
533 AddTransactionToExistingWriters();
534
535 EXPECT_EQ(6, writers_->GetTransactionsCount());
536 }
537
538 // Tests that CanAddWriters should return false if it is writing exclusively.
TEST_F(WritersTest,AddTransactionsExclusive)539 TEST_F(WritersTest, AddTransactionsExclusive) {
540 CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE);
541 EXPECT_FALSE(writers_->IsEmpty());
542
543 EXPECT_FALSE(CanAddWriters());
544 }
545
546 // Tests StopCaching should not stop caching if there are multiple writers.
TEST_F(WritersTest,StopCachingMultipleWriters)547 TEST_F(WritersTest, StopCachingMultipleWriters) {
548 CreateWritersAddTransaction();
549 EXPECT_FALSE(writers_->IsEmpty());
550
551 EXPECT_TRUE(CanAddWriters());
552 AddTransactionToExistingWriters();
553
554 EXPECT_FALSE(StopCaching());
555 EXPECT_TRUE(CanAddWriters());
556 }
557
558 // Tests StopCaching should stop caching if there is a single writer.
TEST_F(WritersTest,StopCaching)559 TEST_F(WritersTest, StopCaching) {
560 CreateWritersAddTransaction();
561 EXPECT_FALSE(writers_->IsEmpty());
562
563 EXPECT_TRUE(StopCaching());
564 EXPECT_FALSE(CanAddWriters());
565 }
566
567 // Tests that when the writers object completes, it passes any non-pending
568 // transactions to WritersDoneWritingToEntry.
TEST_F(WritersTest,MakeReaders)569 TEST_F(WritersTest, MakeReaders) {
570 CreateWritersAddTransaction();
571 AddTransactionToExistingWriters();
572 AddTransactionToExistingWriters();
573
574 std::string remaining_content;
575 Read(&remaining_content);
576
577 EXPECT_EQ(1, test_cache_.WritersDoneWritingToEntryCount());
578 EXPECT_FALSE(Truncated());
579 EXPECT_EQ(2u, test_cache_.MakeReadersSize());
580 }
581
582 // Tests StopCaching should be successful when invoked mid-read.
TEST_F(WritersTest,StopCachingMidReadKeepEntry)583 TEST_F(WritersTest, StopCachingMidReadKeepEntry) {
584 StopMidRead();
585
586 // Stop caching and keep the entry after the transaction finishes.
587 writers_->StopCaching(true /* keep_entry */);
588
589 // Cannot add more writers while we are in network read-only state.
590 EXPECT_FALSE(CanAddWriters());
591
592 // Complete the pending read;
593 base::RunLoop().RunUntilIdle();
594
595 // Read the rest of the content and the cache entry should have truncated.
596 std::string remaining_content;
597 Read(&remaining_content);
598 EXPECT_EQ(1, test_cache_.WritersDoneWritingToEntryCount());
599 EXPECT_TRUE(Truncated());
600 }
601
602 // Tests StopCaching should be successful when invoked mid-read.
TEST_F(WritersTest,StopCachingMidReadDropEntry)603 TEST_F(WritersTest, StopCachingMidReadDropEntry) {
604 StopMidRead();
605
606 writers_->StopCaching(false /* keep_entry */);
607
608 // Cannot add more writers while we are in network read only state.
609 EXPECT_FALSE(CanAddWriters());
610
611 // Complete the pending read.
612 base::RunLoop().RunUntilIdle();
613
614 // Read the rest of the content and the cache entry shouldn't have truncated.
615 std::string remaining_content;
616 Read(&remaining_content);
617 EXPECT_EQ(1, test_cache_.WritersDoneWritingToEntryCount());
618 EXPECT_FALSE(Truncated());
619 }
620
621 // Tests removing of an idle transaction and change in priority.
TEST_F(WritersTest,RemoveIdleTransaction)622 TEST_F(WritersTest, RemoveIdleTransaction) {
623 CreateWritersAddTransactionPriority(HIGHEST);
624 UpdateAndVerifyPriority(HIGHEST);
625
626 AddTransactionToExistingWriters();
627 UpdateAndVerifyPriority(HIGHEST);
628
629 EXPECT_FALSE(writers_->IsEmpty());
630 EXPECT_EQ(2, writers_->GetTransactionsCount());
631
632 RemoveFirstTransaction();
633 EXPECT_EQ(1, writers_->GetTransactionsCount());
634
635 UpdateAndVerifyPriority(DEFAULT_PRIORITY);
636 }
637
638 // Tests that Read is successful.
TEST_F(WritersTest,Read)639 TEST_F(WritersTest, Read) {
640 CreateWritersAddTransaction();
641 EXPECT_FALSE(writers_->IsEmpty());
642
643 std::string content;
644 int rv = Read(&content);
645
646 EXPECT_THAT(rv, IsOk());
647 std::string expected(kSimpleGET_Transaction.data);
648 EXPECT_EQ(expected, content);
649 }
650
651 // Tests that multiple transactions can read the same data simultaneously.
TEST_F(WritersTest,ReadMultiple)652 TEST_F(WritersTest, ReadMultiple) {
653 CreateWritersAddTransaction();
654 EXPECT_FALSE(writers_->IsEmpty());
655
656 EXPECT_TRUE(CanAddWriters());
657 AddTransactionToExistingWriters();
658 AddTransactionToExistingWriters();
659
660 ReadAll();
661
662 EXPECT_EQ(1, test_cache_.WritersDoneWritingToEntryCount());
663 }
664
665 // Tests that multiple transactions can read the same data simultaneously.
TEST_F(WritersTest,ReadMultipleDifferentBufferSizes)666 TEST_F(WritersTest, ReadMultipleDifferentBufferSizes) {
667 CreateWritersAddTransaction();
668 EXPECT_FALSE(writers_->IsEmpty());
669
670 EXPECT_TRUE(CanAddWriters());
671 AddTransactionToExistingWriters();
672
673 std::vector<int> buffer_lengths{20, 10};
674 ReadVerifyTwoDifferentBufferLengths(buffer_lengths);
675 }
676
677 // Same as above but tests the first transaction having smaller buffer size
678 // than the next.
TEST_F(WritersTest,ReadMultipleDifferentBufferSizes1)679 TEST_F(WritersTest, ReadMultipleDifferentBufferSizes1) {
680 CreateWritersAddTransaction();
681 EXPECT_FALSE(writers_->IsEmpty());
682
683 EXPECT_TRUE(CanAddWriters());
684 AddTransactionToExistingWriters();
685
686 std::vector<int> buffer_lengths{10, 20};
687 ReadVerifyTwoDifferentBufferLengths(buffer_lengths);
688 }
689
690 // Tests that ongoing Read completes even when active transaction is deleted
691 // mid-read. Any transactions waiting should be able to get the read buffer.
TEST_F(WritersTest,ReadMultipleDeleteActiveTransaction)692 TEST_F(WritersTest, ReadMultipleDeleteActiveTransaction) {
693 CreateWritersAddTransaction();
694 EXPECT_FALSE(writers_->IsEmpty());
695
696 EXPECT_TRUE(CanAddWriters());
697 AddTransactionToExistingWriters();
698 AddTransactionToExistingWriters();
699
700 ReadAllDeleteTransaction(DeleteTransactionType::ACTIVE);
701 EXPECT_EQ(1, test_cache_.WritersDoneWritingToEntryCount());
702 }
703
704 // Tests that ongoing Read is ignored when an active transaction is deleted
705 // mid-read and there are no more transactions. It should also successfully
706 // initiate truncation of the entry.
TEST_F(WritersTest,MidReadDeleteActiveTransaction)707 TEST_F(WritersTest, MidReadDeleteActiveTransaction) {
708 StopMidRead();
709
710 // Removed the transaction while the read is pending.
711 RemoveFirstTransaction();
712
713 EXPECT_EQ(1, test_cache_.WritersDoneWritingToEntryCount());
714 EXPECT_TRUE(Truncated());
715 EXPECT_TRUE(writers_->IsEmpty());
716 }
717
718 // Tests that removing a waiting for read transaction does not impact other
719 // transactions.
TEST_F(WritersTest,ReadMultipleDeleteWaitingTransaction)720 TEST_F(WritersTest, ReadMultipleDeleteWaitingTransaction) {
721 CreateWritersAddTransaction();
722 EXPECT_FALSE(writers_->IsEmpty());
723
724 EXPECT_TRUE(CanAddWriters());
725 AddTransactionToExistingWriters();
726 AddTransactionToExistingWriters();
727 AddTransactionToExistingWriters();
728
729 std::vector<std::string> contents(4);
730 ReadAllDeleteTransaction(DeleteTransactionType::WAITING);
731 }
732
733 // Tests that removing an idle transaction does not impact other transactions.
TEST_F(WritersTest,ReadMultipleDeleteIdleTransaction)734 TEST_F(WritersTest, ReadMultipleDeleteIdleTransaction) {
735 CreateWritersAddTransaction();
736 EXPECT_FALSE(writers_->IsEmpty());
737
738 EXPECT_TRUE(CanAddWriters());
739 AddTransactionToExistingWriters();
740 AddTransactionToExistingWriters();
741
742 std::vector<std::string> contents(3);
743 ReadAllDeleteTransaction(DeleteTransactionType::IDLE);
744 }
745
746 // Tests cache write failure.
TEST_F(WritersTest,ReadMultipleCacheWriteFailed)747 TEST_F(WritersTest, ReadMultipleCacheWriteFailed) {
748 CreateWritersAddTransaction();
749 EXPECT_FALSE(writers_->IsEmpty());
750
751 EXPECT_TRUE(CanAddWriters());
752 AddTransactionToExistingWriters();
753 AddTransactionToExistingWriters();
754
755 std::vector<std::string> contents(3);
756 int rv = ReadCacheWriteFailure(&contents);
757
758 EXPECT_THAT(rv, IsOk());
759 std::string expected(kSimpleGET_Transaction.data);
760
761 // Only active_transaction_ should succeed.
762 EXPECT_EQ(expected, contents.at(0));
763 }
764
765 // Tests that network read failure fails all transactions: active, waiting and
766 // idle.
TEST_F(WritersTest,ReadMultipleNetworkReadFailed)767 TEST_F(WritersTest, ReadMultipleNetworkReadFailed) {
768 ScopedMockTransaction transaction(kSimpleGET_Transaction);
769 transaction.read_return_code = ERR_INTERNET_DISCONNECTED;
770 MockHttpRequest request(transaction);
771 request_ = request;
772
773 CreateWritersAddTransaction();
774 EXPECT_FALSE(writers_->IsEmpty());
775
776 EXPECT_TRUE(CanAddWriters());
777 AddTransactionToExistingWriters();
778 AddTransactionToExistingWriters();
779
780 std::vector<std::string> contents(3);
781 int rv = ReadNetworkFailure(&contents, ERR_INTERNET_DISCONNECTED);
782
783 EXPECT_EQ(ERR_INTERNET_DISCONNECTED, rv);
784 }
785
786 // Tests GetLoadState.
TEST_F(WritersTest,GetLoadState)787 TEST_F(WritersTest, GetLoadState) {
788 CreateWritersAddTransaction();
789 EXPECT_FALSE(writers_->IsEmpty());
790
791 EXPECT_EQ(LOAD_STATE_IDLE, writers_->GetLoadState());
792 }
793
794 // Tests truncating logic.
TEST_F(WritersTest,TruncateEntryFail)795 TEST_F(WritersTest, TruncateEntryFail) {
796 CreateWritersAddTransaction();
797
798 EXPECT_FALSE(writers_->IsEmpty());
799
800 RemoveFirstTransaction();
801
802 // Should return false since no content was written to the entry.
803 EXPECT_FALSE(ShouldTruncate());
804 EXPECT_FALSE(ShouldKeepEntry());
805 }
806
807 // Set network read only.
TEST_F(WritersTest,StopCachingWithKeepEntry)808 TEST_F(WritersTest, StopCachingWithKeepEntry) {
809 CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE);
810 EXPECT_FALSE(writers_->network_read_only());
811
812 writers_->StopCaching(true /* keep_entry */);
813 EXPECT_TRUE(writers_->network_read_only());
814 EXPECT_TRUE(ShouldKeepEntry());
815 }
816
TEST_F(WritersTest,StopCachingWithNotKeepEntry)817 TEST_F(WritersTest, StopCachingWithNotKeepEntry) {
818 CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_NOT_JOIN_RANGE);
819 EXPECT_FALSE(writers_->network_read_only());
820
821 writers_->StopCaching(false /* keep_entry */);
822 EXPECT_TRUE(writers_->network_read_only());
823 EXPECT_FALSE(ShouldKeepEntry());
824 }
825
826 // Tests that if content-encoding is set, the entry should not be marked as
827 // truncated, since we should not be creating range requests for compressed
828 // entries.
TEST_F(WritersTest,ContentEncodingShouldNotTruncate)829 TEST_F(WritersTest, ContentEncodingShouldNotTruncate) {
830 CreateWritersAddTransaction(HttpCache::PARALLEL_WRITING_JOIN,
831 true /* content_encoding_present */);
832 std::string result;
833 ReadFewBytes(&result);
834
835 EXPECT_FALSE(ShouldTruncate());
836 EXPECT_FALSE(ShouldKeepEntry());
837 }
838
839 } // namespace net
840