• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&parallel_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