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