xref: /aosp_15_r20/external/cronet/net/http/http_cache_writers_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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(&parallel_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