Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(172)

Side by Side Diff: net/http/http_cache_shared_writers_unittest.cc

Issue 2519473002: Fixes the cache lock issue. (Closed)
Patch Set: Test only change to fix a memory leak. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
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_transaction.h"
6 #include "net/http/http_transaction.h"
7 #include "net/http/http_transaction_test_util.h"
8 #include "net/http/mock_http_cache.h"
9 #include "net/test/gtest_util.h"
10
11 using net::test::IsError;
12 using net::test::IsOk;
13
14 namespace net {
15
jkarlin 2017/02/07 15:20:31 The helper functions should be under namespace {
shivanisha 2017/02/07 20:56:47 Done
16 // helpers
17 void ReadAndVerifyTransaction(HttpTransaction* transaction,
18 const MockTransaction& transaction_info) {
19 std::string content;
20 int rv = ReadTransaction(transaction, &content);
21
22 EXPECT_THAT(rv, IsOk());
23 std::string expected(transaction_info.data);
24 EXPECT_EQ(expected, content);
25 }
26
27 // The 1st transaction reads from the network and the subsequent transactions
28 // are able to read from the cache even before the complete response is written
29 // to the cache.
30 int ReadSharedWritersCacheRead(std::vector<Context*>& context_list,
31 std::vector<std::string>& results) {
32 int rv;
33
34 size_t i = 0;
35 HttpTransaction* transaction = nullptr;
36 do {
37 Context* c = context_list.at(i);
38 transaction = c->trans.get();
39 scoped_refptr<IOBuffer> buf(new IOBuffer(256));
40 rv = transaction->Read(buf.get(), 256, c->callback.callback());
41 if (rv == ERR_IO_PENDING)
42 rv = c->callback.WaitForResult();
43
44 if (rv > 0)
45 results.at(i).append(buf->data(), rv);
46 else if (rv < 0)
47 return rv;
48
49 i = (i == context_list.size() - 1) ? 0 : i + 1;
50 } while (rv > 0);
51
52 return OK;
53 }
54
55 void ReadAndVerifySharedWritersCacheRead(
56 std::vector<Context*>& context_list,
57 const MockTransaction& transaction_info) {
58 std::vector<std::string> contents(context_list.size());
59 int rv = ReadSharedWritersCacheRead(context_list, contents);
60
61 EXPECT_THAT(rv, IsOk());
62 std::string expected(transaction_info.data);
63 for (size_t i = 0; i < contents.size(); i++) {
64 EXPECT_EQ(expected, contents.at(i));
65 }
66 }
67
68 // The 1st transaction reads from the network and read is invoked on other
69 // transactions even before the 1st one's io callback is invoked. The other
70 // transactions should have data written in their read buffers as part
71 // of the 1st transaction's callback.
72 int ReadSharedWritersJoinedRead(std::vector<Context*>& context_list,
73 std::vector<std::string>& results) {
74 int rv = 0;
75 do {
76 // Invoke Read for all transactions.
77 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
78 for (size_t i = 0; i < context_list.size(); i++) {
79 HttpTransaction* transaction = context_list[i]->trans.get();
80 buffers[i] = new IOBuffer(30);
81 rv = transaction->Read(buffers[i].get(), 30,
82 context_list[i]->callback.callback());
83 // Invoking stop caching here should not have any impact since there are
84 // multiple transactions waiting for this resource.
85 if (i == 0)
86 transaction->StopCaching();
87 }
88 if (rv == ERR_IO_PENDING) {
89 for (size_t i = 0; i < context_list.size(); i++) {
90 Context* ct = context_list[i];
91 rv = ct->callback.WaitForResult();
92 }
93 }
94
95 if (rv > 0) {
96 for (size_t i = 0; i < results.size(); i++) {
97 results[i].append(buffers[i]->data(), rv);
98 }
99 } else if (rv < 0) {
100 return rv;
101 }
102 } while (rv > 0);
103
104 return OK;
105 }
106
107 void ReadAndVerifySharedWritersJoinedRead(
108 const MockTransaction& transaction_info,
109 std::vector<Context*>& context_list) {
110 std::vector<std::string> results(context_list.size());
111 int rv = ReadSharedWritersJoinedRead(context_list, results);
112
113 EXPECT_THAT(rv, IsOk());
114 std::string expected(transaction_info.data);
115 for (size_t i = 0; i < results.size(); i++) {
116 EXPECT_EQ(expected, results[i]);
117 }
118 }
119
120 int ReadSharedWritersJoinedReadDoneReading(std::vector<Context*>& context_list,
121 std::vector<std::string>& results) {
122 int rv = 0;
123 int cnt = 0;
124 do {
125 // Invoke Read for all transactions.
126 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
127 for (size_t i = 0; i < context_list.size(); i++) {
128 HttpTransaction* transaction = context_list[i]->trans.get();
129 buffers[i] = new IOBuffer(30);
130 rv = transaction->Read(buffers[i].get(), 30,
131 context_list[i]->callback.callback());
132 }
133 if (rv == ERR_IO_PENDING) {
134 for (size_t i = 0; i < context_list.size(); i++) {
135 Context* ct = context_list[i];
136 rv = ct->callback.WaitForResult();
137 }
138 }
139
140 if (rv > 0) {
141 for (size_t i = 0; i < results.size(); i++) {
142 results[i].append(buffers[i]->data(), rv);
143 }
144 } else if (rv < 0) {
145 return rv;
146 }
147
148 cnt++;
149 if (cnt == 2) {
150 context_list[0]->trans.get()->DoneReading();
151 }
152 } while (cnt < 2);
153
154 return OK;
155 }
156
157 void ReadAndVerifySharedWritersJoinedReadDoneReading(
158 const MockTransaction& transaction_info,
159 std::vector<Context*>& context_list) {
160 std::vector<std::string> results(context_list.size());
161 int rv = ReadSharedWritersJoinedReadDoneReading(context_list, results);
162
163 EXPECT_THAT(rv, IsOk());
164 std::string expected(transaction_info.data);
165 for (size_t i = 0; i < results.size(); i++) {
166 EXPECT_EQ(expected, results[i]);
167 }
168 }
169 // The 1st transaction reads from the network and read is invoked on other
170 // transactions even before the 1st one's io callback is invoked. Also, the
171 // first transaction is deleted before the io callback is invoked. The other
172 // transactions should have data written in their read buffers as part
173 // of the 1st transaction's callback.
174 int ReadSharedWritersJoinedReadDeleteCurrentWriter(
175 std::vector<Context*>& context_list,
176 std::vector<std::string>& results) {
177 int rv = 0;
178 bool first_iter = true;
179 do {
180 // Invoke Read for all transactions.
181 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
182 for (size_t i = 0; i < context_list.size(); i++) {
183 HttpTransaction* transaction = context_list[i]->trans.get();
184 buffers[i] = new IOBuffer(30);
185 rv = transaction->Read(buffers[i].get(), 30,
186 context_list[i]->callback.callback());
187 }
188
189 // Delete the 1st transaction.
190 if (first_iter) {
191 Context* c = context_list[0];
192 context_list.erase(context_list.begin());
193 delete c;
194 buffers.erase(buffers.begin());
195 }
196
197 if (rv == ERR_IO_PENDING) {
198 for (size_t i = 0; i < context_list.size(); i++) {
199 Context* ct = context_list[i];
200 rv = ct->callback.WaitForResult();
201 }
202 }
203
204 if (rv > 0) {
205 for (size_t i = 0; i < context_list.size(); i++) {
206 results[i].append(buffers[i]->data(), rv);
207 }
208 } else if (rv < 0) {
209 return rv;
210 }
211
212 first_iter = false;
213 } while (rv > 0);
214
215 return OK;
216 }
217
218 void ReadAndVerifySharedWritersJoinedReadDeleteCurrentWriter(
219 const MockTransaction& transaction_info,
220 std::vector<Context*>& context_list) {
221 std::vector<std::string> results(context_list.size() - 1);
222 int rv =
223 ReadSharedWritersJoinedReadDeleteCurrentWriter(context_list, results);
224
225 EXPECT_THAT(rv, IsOk());
226 std::string expected(transaction_info.data);
227 for (size_t i = 0; i < results.size(); i++) {
228 EXPECT_EQ(expected, results[i]);
229 }
230 }
231 int ReadSharedWritersJoinedReadDeleteWaitingWriter(
232 std::vector<Context*>& context_list,
233 std::vector<std::string>& results) {
234 int rv = 0;
235 bool first_iter = true;
236 do {
237 // Invoke Read for all transactions.
238 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
239 for (size_t i = 0; i < context_list.size(); i++) {
240 HttpTransaction* transaction = context_list[i]->trans.get();
241 buffers[i] = new IOBuffer(30);
242 rv = transaction->Read(buffers[i].get(), 30,
243 context_list[i]->callback.callback());
244 }
245
246 // Remove a waiting writer transaction.
247 if (first_iter) {
248 auto it = context_list.begin();
249 it++;
250 if (it != context_list.end()) {
251 Context* c = *it;
252 context_list.erase(it);
253 delete c;
254 auto it1 = buffers.begin();
255 it1++;
256 buffers.erase(it1);
257 }
258 }
259
260 if (rv == ERR_IO_PENDING) {
261 for (size_t i = 0; i < context_list.size(); i++) {
262 Context* ct = context_list[i];
263 rv = ct->callback.WaitForResult();
264 }
265 }
266
267 if (rv > 0) {
268 for (size_t i = 0; i < context_list.size(); i++) {
269 results[i].append(buffers[i]->data(), rv);
270 }
271 } else if (rv < 0) {
272 return rv;
273 }
274
275 first_iter = false;
276 } while (rv > 0);
277
278 return OK;
279 }
280
281 void ReadAndVerifySharedWritersDeleteWaitingWriter(
282 const MockTransaction& transaction_info,
283 std::vector<Context*>& context_list) {
284 std::vector<std::string> results(context_list.size() - 1);
285 int rv =
286 ReadSharedWritersJoinedReadDeleteWaitingWriter(context_list, results);
287
288 EXPECT_THAT(rv, IsOk());
289 std::string expected(transaction_info.data);
290 for (size_t i = 0; i < results.size(); i++) {
291 EXPECT_EQ(expected, results[i]);
292 }
293 }
294 int ReadSharedWritersJoinedReadDeleteIdleWriter(
295 std::vector<Context*>& context_list,
296 std::vector<std::string>& results) {
297 int rv = 0;
298 bool first_iter = true;
299 do {
300 // Invoke Read for all transactions.
301 std::vector<scoped_refptr<IOBuffer>> buffers(context_list.size());
302 for (size_t i = 0; i < context_list.size(); i++) {
303 HttpTransaction* transaction = context_list[i]->trans.get();
304 buffers[i] = new IOBuffer(30);
305 // Do not invoke Read on the first transaction.
306 if (first_iter && i == 0)
307 continue;
308 rv = transaction->Read(buffers[i].get(), 30,
309 context_list[i]->callback.callback());
310 }
311
312 // Remove the idle writer transaction.
313 if (first_iter) {
314 auto it = context_list.begin();
315 Context* c = *it;
316 context_list.erase(it);
317 delete c;
318 auto it1 = buffers.begin();
319 buffers.erase(it1);
320 }
321
322 if (rv == ERR_IO_PENDING) {
323 for (size_t i = 0; i < context_list.size(); i++) {
324 Context* ct = context_list[i];
325 rv = ct->callback.WaitForResult();
326 }
327 }
328
329 if (rv > 0) {
330 for (size_t i = 0; i < context_list.size(); i++) {
331 results[i].append(buffers[i]->data(), rv);
332 }
333 } else if (rv < 0) {
334 return rv;
335 }
336
337 first_iter = false;
338 } while (rv > 0);
339
340 return OK;
341 }
342
343 void ReadAndVerifySharedWritersDeleteIdleWriter(
344 const MockTransaction& transaction_info,
345 std::vector<Context*>& context_list) {
346 std::vector<std::string> results(context_list.size() - 1);
347 int rv = ReadSharedWritersJoinedReadDeleteIdleWriter(context_list, results);
348
349 EXPECT_THAT(rv, IsOk());
350 std::string expected(transaction_info.data);
351 for (size_t i = 0; i < results.size(); i++) {
352 EXPECT_EQ(expected, results[i]);
353 }
354 }
355
356 int ReadSharedWritersJoinedReadCacheWriteFailure(
357 std::vector<Context*>& context_list,
358 std::vector<std::string>& results,
359 MockHttpCache& cache) {
360 int rv = 0;
361 MockHttpRequest request(kSimpleGET_Transaction);
362
363 // Fail the request.
364 cache.disk_cache()->set_soft_failures(true);
365
366 // We have to open the entry again to propagate the failure flag.
367 disk_cache::Entry* en;
368 cache.OpenBackendEntry(kSimpleGET_Transaction.url, &en);
369 en->Close();
370
371 // Invoke Read for two transactions so they become current_writer_ and
372 // waiting_writers_ respectively.
373 std::vector<scoped_refptr<IOBuffer>> buf(2);
374 size_t i = 0, j = 0;
375 do {
376 HttpTransaction* transaction = context_list[i]->trans.get();
377 buf[j] = new IOBuffer(30);
378 rv = transaction->Read(buf[j].get(), 30,
379 context_list[i]->callback.callback());
380 i = context_list.size() - 1;
381 j++;
382 } while (j < buf.size());
383
384 // current_writer_ which is transaction [0] should continue without writing
385 // to the cache, idle writer ([3]) should fail on its next Read call and
386 // waiting_writers_ ([6]) should return a failure back.
387 if (rv == ERR_IO_PENDING) {
388 Context* ct = *(context_list.begin());
389 rv = ct->callback.WaitForResult();
390 }
391
392 // Only [0] should succeed in the Read.
393 results[0].append(buf[0]->data(), 30);
394
395 // Invoke Start on 4 and 5. 4 will fail to read from the cache, doom the
396 // entry and go on to create a new entry. 5 will also get added to that
397 // entry.
398 for (size_t i = 4; i <= 5; i++) {
399 Context* c = context_list[i];
400 c->result =
401 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
402 }
403
404 base::RunLoop().RunUntilIdle();
405
406 // 3 and 6 failed, delete them.
407 Context* c = context_list[3];
408 scoped_refptr<IOBuffer> buf1 = new IOBuffer(30);
409 int rv_fail = c->trans->Read(buf1.get(), 30, c->callback.callback());
410 EXPECT_THAT(rv_fail, ERR_CACHE_WRITE_FAILURE);
411
412 Context* c6 = context_list[6];
413 for (auto itr = context_list.begin(); itr != context_list.end();) {
414 if (*itr == c || *itr == c6) {
415 Context* ct = *itr;
416 itr = context_list.erase(itr);
417 delete ct;
418 } else {
419 itr++;
420 }
421 }
422
423 cache.disk_cache()->set_soft_failures(false);
424
425 base::RunLoop().RunUntilIdle();
426
427 // Read for the rest of the transactions.
428 Context* c0 = context_list[0];
429 Context* c3 = context_list[3];
430 for (size_t i = 0; i < context_list.size(); i++) {
431 if (i == 1 || i == 2 || i == 4)
432 continue;
433 std::string res;
434 ReadTransaction(context_list[i]->trans.get(), &res);
435 results[i].append(res);
436 }
437
438 base::RunLoop().RunUntilIdle();
439
440 // Delete the done transactions so that pending queue can be processed.
441 // The reader transactions will error out with ERR_CACHE_MISS because of cache
442 // failures.
443 Context* c1 = context_list[1];
444 Context* c2 = context_list[2];
445 auto itr = context_list.begin();
446 for (; itr != context_list.end();) {
447 Context* c = *itr;
448 if (c == c0 || c == c1 || c == c2 || c == c3) {
449 itr = context_list.erase(itr);
450 delete c;
451 } else {
452 itr++;
453 }
454 }
455
456 std::string res;
457 ReadTransaction(context_list[0]->trans.get(), &res);
458 results[4].append(res);
459
460 return OK;
461 }
462
463 void ReadAndVerifySharedWritersJoinedReadCacheWriteFailure(
464 const MockTransaction& transaction_info,
465 std::vector<Context*>& context_list,
466 MockHttpCache& cache) {
467 std::vector<std::string> results(context_list.size());
468 int rv = ReadSharedWritersJoinedReadCacheWriteFailure(context_list, results,
469 cache);
470
471 EXPECT_THAT(rv, IsOk());
472 std::string expected(transaction_info.data);
473 for (size_t i = 0; i < context_list.size(); i++) {
474 EXPECT_EQ(expected, results[i]);
475 }
476 }
477
478 // Tests.
479
480 TEST(HttpCache, SimpleGET_SharedWritingCacheRead) {
481 MockHttpCache cache;
482
483 MockHttpRequest request(kSimpleGET_Transaction);
484
485 std::vector<Context*> context_list;
486 const int kNumTransactions = 5;
487
488 for (int i = 0; i < kNumTransactions; ++i) {
489 context_list.push_back(new Context());
490 Context* c = context_list[i];
491
492 c->result = cache.CreateTransaction(&c->trans);
493 ASSERT_THAT(c->result, IsOk());
494 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
495
496 c->result =
497 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
498 }
499
500 // All requests are waiting for the active entry.
501 for (int i = 0; i < kNumTransactions; ++i) {
502 Context* c = context_list[i];
503 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
504 }
505
506 // Allow all requests to move from the Create queue to the active entry.
507 base::RunLoop().RunUntilIdle();
508
509 // The first request should be a writer at this point, and the subsequent
510 // requests should be pending.
511
512 EXPECT_EQ(1, cache.network_layer()->transaction_count());
513 EXPECT_EQ(0, cache.disk_cache()->open_count());
514 EXPECT_EQ(1, cache.disk_cache()->create_count());
515
516 // All requests depend on the writer, and the writer is between Start and
517 // Read, i.e. idle.
518 for (int i = 0; i < kNumTransactions; ++i) {
519 Context* c = context_list[i];
520 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
521 }
522
523 for (int i = 0; i < kNumTransactions; ++i) {
524 Context* c = context_list[i];
525 if (c->result == ERR_IO_PENDING)
526 c->result = c->callback.WaitForResult();
527 }
528
529 ReadAndVerifySharedWritersCacheRead(context_list, kSimpleGET_Transaction);
530
531 // We should not have had to re-open the disk entry
532
533 EXPECT_EQ(1, cache.network_layer()->transaction_count());
534 EXPECT_EQ(0, cache.disk_cache()->open_count());
535 EXPECT_EQ(1, cache.disk_cache()->create_count());
536
537 for (int i = 0; i < kNumTransactions; ++i) {
538 Context* c = context_list[i];
539 delete c;
540 }
541 }
542
543 TEST(HttpCache, SimpleGET_SharedWritingJoinedRead) {
544 MockHttpCache cache;
545
546 MockHttpRequest request(kSimpleGET_Transaction);
547
548 std::vector<Context*> context_list;
549 const int kNumTransactions = 5;
550
551 for (int i = 0; i < kNumTransactions; ++i) {
552 context_list.push_back(new Context());
553 Context* c = context_list[i];
554
555 c->result = cache.CreateTransaction(&c->trans);
556 ASSERT_THAT(c->result, IsOk());
557 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
558
559 c->result =
560 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
561 }
562
563 // All requests are waiting for the active entry.
564 for (int i = 0; i < kNumTransactions; ++i) {
565 Context* c = context_list[i];
566 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
567 }
568
569 // Allow all requests to move from the Create queue to the active entry.
570 base::RunLoop().RunUntilIdle();
571
572 // The first request should be a writer at this point, and the subsequent
573 // requests should be pending.
574
575 EXPECT_EQ(1, cache.network_layer()->transaction_count());
576 EXPECT_EQ(0, cache.disk_cache()->open_count());
577 EXPECT_EQ(1, cache.disk_cache()->create_count());
578 // All requests depend on the writer, and the writer is between Start and
579 // Read, i.e. idle.
580 for (int i = 0; i < kNumTransactions; ++i) {
581 Context* c = context_list[i];
582 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
583 }
584
585 std::vector<HttpTransaction*> transactions;
586 for (int i = 0; i < kNumTransactions; ++i) {
587 Context* c = context_list[i];
588 if (c->result == ERR_IO_PENDING)
589 c->result = c->callback.WaitForResult();
590 transactions.push_back(c->trans.get());
591 }
592
593 ReadAndVerifySharedWritersJoinedRead(kSimpleGET_Transaction, context_list);
594
595 // We should not have had to re-open the disk entry
596
597 EXPECT_EQ(1, cache.network_layer()->transaction_count());
598 EXPECT_EQ(0, cache.disk_cache()->open_count());
599 EXPECT_EQ(1, cache.disk_cache()->create_count());
600
601 for (int i = 0; i < kNumTransactions; ++i) {
602 Context* c = context_list[i];
603 delete c;
604 }
605 }
606
607 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDoneReading) {
608 MockHttpCache cache;
609
610 MockHttpRequest request(kSimpleGET_Transaction);
611
612 std::vector<Context*> context_list;
613 const int kNumTransactions = 5;
614
615 for (int i = 0; i < kNumTransactions; ++i) {
616 context_list.push_back(new Context());
617 Context* c = context_list[i];
618
619 c->result = cache.CreateTransaction(&c->trans);
620 ASSERT_THAT(c->result, IsOk());
621 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
622
623 c->result =
624 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
625 }
626
627 // All requests are waiting for the active entry.
628 for (int i = 0; i < kNumTransactions; ++i) {
629 Context* c = context_list[i];
630 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
631 }
632
633 // Allow all requests to move from the Create queue to the active entry.
634 base::RunLoop().RunUntilIdle();
635
636 // The first request should be a writer at this point, and the subsequent
637 // requests should be pending.
638
639 EXPECT_EQ(1, cache.network_layer()->transaction_count());
640 EXPECT_EQ(0, cache.disk_cache()->open_count());
641 EXPECT_EQ(1, cache.disk_cache()->create_count());
642
643 // All requests depend on the writer, and the writer is between Start and
644 // Read, i.e. idle.
645 for (int i = 0; i < kNumTransactions; ++i) {
646 Context* c = context_list[i];
647 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
648 }
649
650 std::vector<HttpTransaction*> transactions;
651 for (int i = 0; i < kNumTransactions; ++i) {
652 Context* c = context_list[i];
653 if (c->result == ERR_IO_PENDING)
654 c->result = c->callback.WaitForResult();
655 transactions.push_back(c->trans.get());
656 }
657
658 ReadAndVerifySharedWritersJoinedReadDoneReading(kSimpleGET_Transaction,
659 context_list);
660
661 // We should not have had to re-open the disk entry
662
663 EXPECT_EQ(1, cache.network_layer()->transaction_count());
664 EXPECT_EQ(0, cache.disk_cache()->open_count());
665 EXPECT_EQ(1, cache.disk_cache()->create_count());
666
667 for (int i = 0; i < kNumTransactions; ++i) {
668 Context* c = context_list[i];
669 delete c;
670 }
671 }
672
673 // Tests the following:
674 // - A 200 will doom the entry and the transaction will continue to read from
675 // the network.
676 // - Doomed entry's SharedWriters will continue to read and write to the cache.
677 // - Doomed entry's SharedWriters' waiting_for_validation_ will create another
678 // entry.
679 // - The new entry will also have another SharedWriters for subsequent
680 // transactions.
681 TEST(HttpCache, SharedWritingValidation200) {
682 MockHttpCache cache;
683
684 MockHttpRequest request(kSimpleGET_Transaction);
685 request.load_flags |= LOAD_VALIDATE_CACHE;
686 MockHttpRequest reader_request(kSimpleGET_Transaction);
687 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
688 MockHttpRequest request_no_validate(kSimpleGET_Transaction);
689
690 std::vector<Context*> context_list;
691 const int kNumTransactions = 6;
692
693 for (int i = 0; i < kNumTransactions; ++i) {
694 context_list.push_back(new Context());
695 Context* c = context_list[i];
696
697 c->result = cache.CreateTransaction(&c->trans);
698 ASSERT_THAT(c->result, IsOk());
699 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
700
701 MockHttpRequest* this_request = &request;
702 if (i == 1 || i == 2)
703 this_request = &reader_request;
704
705 if (i == 5)
706 this_request = &request_no_validate;
707
708 c->result = c->trans->Start(this_request, c->callback.callback(),
709 NetLogWithSource());
710 }
711
712 // All requests are waiting for the active entry.
713 for (int i = 0; i < kNumTransactions; ++i) {
714 Context* c = context_list[i];
715 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
716 }
717
718 // Allow all requests to move from the Create queue to the active entry.
719 base::RunLoop().RunUntilIdle();
720
721 // The first [0] request should be a writer at this point, and should have
722 // created
723 // SharedWriters, [1] and [2] will be in pending_queue and [3] and [4] should
724 // have validated and [5] will have skipped validation and be ready to read.
725
726 EXPECT_EQ(3, cache.network_layer()->transaction_count());
727 EXPECT_EQ(0, cache.disk_cache()->open_count());
728 EXPECT_EQ(2, cache.disk_cache()->create_count());
729
730 Context* c = context_list[0];
731 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
732 c->result = c->callback.WaitForResult();
733
734 // First request is done with the headers, now [3] will start validation.
735 Context* c3 = context_list[3];
736 ASSERT_THAT(c3->result, IsError(ERR_IO_PENDING));
737
738 // Let [3] get a 200 , thus leading to dooming the entry, [4] and [5] will
739 // move to entry's pending_queue.
740 c3->result = c3->callback.WaitForResult();
741
742 // [3] will complete reading the response using its own network transaction
743 // and not writing to the cache.
744 ReadAndVerifyTransaction(c3->trans.get(), kSimpleGET_Transaction);
745
746 // [0] will complete reading the response using SharedWriter's network
747 // transaction and then the entry should be finalized.
748 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
749
750 // [4] should be added to a new entry and should contiue reading and writing
751 // to the cache (also create SharedWriters)
752 for (int i = 4; i <= 5; i++) {
753 Context* c = context_list[i];
754 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
755 c->result = c->callback.WaitForResult();
756 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
757 // [5] will join SharedWriters at this point when [4] completes validation.
758 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
759 }
760 // [1] and [2] will become readers and read from the cache.
761 for (int i = 1; i <= 2; i++) {
762 Context* c = context_list[i];
763 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
764 c->result = c->callback.WaitForResult();
765 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
766 ReadAndVerifyTransaction(c->trans.get(), kSimpleGET_Transaction);
767 }
768
769 // We should not have had to re-open the disk entry
770 EXPECT_EQ(3, cache.network_layer()->transaction_count());
771 EXPECT_EQ(0, cache.disk_cache()->open_count());
772 EXPECT_EQ(2, cache.disk_cache()->create_count());
773
774 for (int i = 0; i < kNumTransactions; ++i) {
775 Context* c = context_list[i];
776 delete c;
777 }
778 }
779
780 // Tests a validating transaction deletion while it is waiting for its callback
781 // to be invoked.
782 TEST(HttpCache, SharedWritingDeleteValidationTrans) {
783 MockHttpCache cache;
784
785 MockHttpRequest request(kSimpleGET_Transaction);
786 request.load_flags |= LOAD_VALIDATE_CACHE;
787 MockHttpRequest reader_request(kSimpleGET_Transaction);
788 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
789
790 std::vector<Context*> context_list;
791 const int kNumTransactions = 5;
792
793 for (int i = 0; i < kNumTransactions; ++i) {
794 context_list.push_back(new Context());
795 Context* c = context_list[i];
796
797 c->result = cache.CreateTransaction(&c->trans);
798 ASSERT_THAT(c->result, IsOk());
799 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
800
801 MockHttpRequest* this_request = &request;
802 if (i == 1 || i == 2)
803 this_request = &reader_request;
804
805 if (i == 3 || i == 4)
806 continue;
807
808 c->result = c->trans->Start(this_request, c->callback.callback(),
809 NetLogWithSource());
810 }
811
812 // All requests are waiting for the active entry.
813 for (int i = 0; i < kNumTransactions; ++i) {
814 if (i == 3 || i == 4)
815 continue;
816 Context* c = context_list[i];
817 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
818 }
819
820 // Allow all requests to move from the Create queue to the active entry.
821 base::RunLoop().RunUntilIdle();
822
823 EXPECT_EQ(1, cache.network_layer()->transaction_count());
824 EXPECT_EQ(0, cache.disk_cache()->open_count());
825 EXPECT_EQ(1, cache.disk_cache()->create_count());
826
827 // Start [3], [4].
828 for (size_t i = 3; i <= 4; i++) {
829 Context* c = context_list[i];
830 c->result =
831 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
832 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
833 }
834
835 // Delete [3] as it is the current validating trans.
836 Context* c3 = context_list[3];
837 for (auto it = context_list.begin(); it != context_list.end(); it++) {
838 if (*it == c3) {
839 context_list.erase(it);
840 delete c3;
841 break;
842 }
843 }
844
845 // Complete start state machine for [4].
846 base::RunLoop().RunUntilIdle();
847
848 // [0] will complete reading the response using SharedWriter's network
849 // transaction and then the entry should be finalized.
850 Context* c0 = context_list[0];
851 ReadAndVerifyTransaction(c0->trans.get(), kSimpleGET_Transaction);
852
853 // [4] (now [3]) should doom the entry and continue reading with its network
854 // transaction.
855 Context* c4 = context_list[3];
856 ReadAndVerifyTransaction(c4->trans.get(), kSimpleGET_Transaction);
857
858 // 1st entry will get destroyed and [1] and [2] will being readers will get a
859 // ERR_CACHE_MISS.
860 for (int i = 1; i <= 2; i++) {
861 Context* c = context_list[i];
862 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
863 c->result = c->callback.WaitForResult();
864 ASSERT_THAT(c->result, IsError(ERR_CACHE_MISS));
865 }
866
867 // We should not have had to re-open the disk entry
868 EXPECT_EQ(2, cache.network_layer()->transaction_count());
869 EXPECT_EQ(0, cache.disk_cache()->open_count());
870 EXPECT_EQ(1, cache.disk_cache()->create_count());
871
872 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
873 Context* c = *i;
874 delete c;
875 }
876 }
877
878 // Tests a transaction deletion while it is waiting for validation.
879 TEST(HttpCache, SharedWritingDeleteWaitingForValidation) {
880 MockHttpCache cache;
881
882 MockHttpRequest request(kSimpleGET_Transaction);
883 request.load_flags |= LOAD_VALIDATE_CACHE;
884 MockHttpRequest reader_request(kSimpleGET_Transaction);
885 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
886
887 std::vector<Context*> context_list;
888 const int kNumTransactions = 5;
889
890 for (int i = 0; i < kNumTransactions; ++i) {
891 context_list.push_back(new Context());
892 Context* c = context_list[i];
893
894 c->result = cache.CreateTransaction(&c->trans);
895 ASSERT_THAT(c->result, IsOk());
896 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
897
898 MockHttpRequest* this_request = &request;
899 if (i == 1 || i == 2)
900 this_request = &reader_request;
901
902 if (i == 3 || i == 4)
903 continue;
904
905 c->result = c->trans->Start(this_request, c->callback.callback(),
906 NetLogWithSource());
907 }
908
909 // All requests are waiting for the active entry.
910 for (int i = 0; i < kNumTransactions; ++i) {
911 if (i == 3 || i == 4)
912 continue;
913 Context* c = context_list[i];
914 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
915 }
916
917 // Allow all requests to move from the Create queue to the active entry.
918 base::RunLoop().RunUntilIdle();
919
920 EXPECT_EQ(1, cache.network_layer()->transaction_count());
921 EXPECT_EQ(0, cache.disk_cache()->open_count());
922 EXPECT_EQ(1, cache.disk_cache()->create_count());
923
924 // Start [3], [4].
925 for (size_t i = 3; i <= 4; i++) {
926 Context* c = context_list[i];
927 c->result =
928 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
929 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
930 }
931
932 // Delete [4] as it is the waiting for validation trans.
933 Context* c4 = context_list[4];
934 for (auto it = context_list.begin(); it != context_list.end(); it++) {
935 if (*it == c4) {
936 context_list.erase(it);
937 delete c4;
938 break;
939 }
940 }
941
942 // Complete start state machine for [3].
943 base::RunLoop().RunUntilIdle();
944
945 // [0] will complete reading the response using SharedWriter's network
946 // transaction and then the entry should be finalized.
947 Context* c0 = context_list[0];
948 ReadAndVerifyTransaction(c0->trans.get(), kSimpleGET_Transaction);
949
950 // [3] should doom the entry and continue reading with its network
951 // transaction.
952 Context* c3 = context_list[3];
953 ReadAndVerifyTransaction(c3->trans.get(), kSimpleGET_Transaction);
954
955 // 1st entry will get destroyed and [1] and [2] will being readers will get a
956 // ERR_CACHE_MISS.
957 for (int i = 1; i <= 2; i++) {
958 Context* c = context_list[i];
959 ASSERT_THAT(c->result, IsError(ERR_IO_PENDING));
960 c->result = c->callback.WaitForResult();
961 ASSERT_THAT(c->result, IsError(ERR_CACHE_MISS));
962 }
963
964 // We should not have had to re-open the disk entry
965 EXPECT_EQ(2, cache.network_layer()->transaction_count());
966 EXPECT_EQ(0, cache.disk_cache()->open_count());
967 EXPECT_EQ(1, cache.disk_cache()->create_count());
968
969 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
970 Context* c = *i;
971 delete c;
972 }
973 }
974
975 // Tests the impact of cache write failure on Shared Writing.
976 TEST(HttpCache, SharedWritingCacheWriteFailure) {
977 MockHttpCache cache;
978
979 MockHttpRequest request(kSimpleGET_Transaction);
980 request.load_flags |= LOAD_VALIDATE_CACHE;
981 MockHttpRequest reader_request(kSimpleGET_Transaction);
982 reader_request.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
983 MockHttpRequest request_no_validate(kSimpleGET_Transaction);
984
985 std::vector<Context*> context_list;
986 const int kNumTransactions = 7;
987
988 for (int i = 0; i < kNumTransactions; ++i) {
989 context_list.push_back(new Context());
990 Context* c = context_list[i];
991
992 c->result = cache.CreateTransaction(&c->trans);
993 ASSERT_THAT(c->result, IsOk());
994 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
995
996 MockHttpRequest* this_request = &request;
997 if (i == 1 || i == 2)
998 this_request = &reader_request;
999
1000 if (i == 3 || i == 6)
1001 this_request = &request_no_validate;
1002
1003 if (i == 4 || i == 5)
1004 continue;
1005
1006 c->result = c->trans->Start(this_request, c->callback.callback(),
1007 NetLogWithSource());
1008 }
1009
1010 // All requests are waiting for the active entry.
1011 for (int i = 0; i < kNumTransactions; ++i) {
1012 if (i == 4 || i == 5)
1013 continue;
1014 Context* c = context_list[i];
1015 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1016 }
1017
1018 // Allow all requests to move from the Create queue to the active entry.
1019 base::RunLoop().RunUntilIdle();
1020
1021 // At this point, 0,5 and 3 are idle writers, 1 and 2 are pending readers and
1022 // 4
1023 // will now become the validating_trans_.
1024
1025 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1026 EXPECT_EQ(0, cache.disk_cache()->open_count());
1027 EXPECT_EQ(1, cache.disk_cache()->create_count());
1028
1029 ReadAndVerifySharedWritersJoinedReadCacheWriteFailure(kSimpleGET_Transaction,
1030 context_list, cache);
1031
1032 // We should not have had to re-open the disk entry
1033 EXPECT_EQ(3, cache.network_layer()->transaction_count());
1034 EXPECT_EQ(1, cache.disk_cache()->open_count());
1035 EXPECT_EQ(3, cache.disk_cache()->create_count());
1036
1037 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1038 Context* c = *i;
1039 delete c;
1040 }
1041 }
1042
1043 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteCurrentWriter) {
1044 MockHttpCache cache;
1045
1046 MockHttpRequest request(kSimpleGET_Transaction);
1047
1048 std::vector<Context*> context_list;
1049 const int kNumTransactions = 5;
1050
1051 for (int i = 0; i < kNumTransactions; ++i) {
1052 context_list.push_back(new Context());
1053 Context* c = context_list[i];
1054
1055 c->result = cache.CreateTransaction(&c->trans);
1056 ASSERT_THAT(c->result, IsOk());
1057 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1058
1059 c->result =
1060 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
1061 }
1062
1063 // All requests are waiting for the active entry.
1064 for (int i = 0; i < kNumTransactions; ++i) {
1065 Context* c = context_list[i];
1066 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1067 }
1068
1069 // Allow all requests to move from the Create queue to the active entry.
1070 base::RunLoop().RunUntilIdle();
1071
1072 // The first request should be a writer at this point, and the subsequent
1073 // requests should be pending.
1074
1075 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1076 EXPECT_EQ(0, cache.disk_cache()->open_count());
1077 EXPECT_EQ(1, cache.disk_cache()->create_count());
1078
1079 // All requests depend on the writer, and the writer is between Start and
1080 // Read, i.e. idle.
1081 for (int i = 0; i < kNumTransactions; ++i) {
1082 Context* c = context_list[i];
1083 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1084 }
1085
1086 std::vector<HttpTransaction*> transactions;
1087 for (int i = 0; i < kNumTransactions; ++i) {
1088 Context* c = context_list[i];
1089 if (c->result == ERR_IO_PENDING)
1090 c->result = c->callback.WaitForResult();
1091 transactions.push_back(c->trans.get());
1092 }
1093
1094 ReadAndVerifySharedWritersJoinedReadDeleteCurrentWriter(
1095 kSimpleGET_Transaction, context_list);
1096
1097 // We should not have had to re-open the disk entry
1098 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1099 EXPECT_EQ(0, cache.disk_cache()->open_count());
1100 EXPECT_EQ(1, cache.disk_cache()->create_count());
1101
1102 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1103 Context* c = *i;
1104 delete c;
1105 }
1106 }
1107
1108 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteWaitingWriter) {
1109 MockHttpCache cache;
1110
1111 MockHttpRequest request(kSimpleGET_Transaction);
1112
1113 std::vector<Context*> context_list;
1114 const int kNumTransactions = 5;
1115
1116 for (int i = 0; i < kNumTransactions; ++i) {
1117 context_list.push_back(new Context());
1118 Context* c = context_list[i];
1119
1120 c->result = cache.CreateTransaction(&c->trans);
1121 ASSERT_THAT(c->result, IsOk());
1122 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1123
1124 c->result =
1125 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
1126 }
1127
1128 // All requests are waiting for the active entry.
1129 for (int i = 0; i < kNumTransactions; ++i) {
1130 Context* c = context_list[i];
1131 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1132 }
1133
1134 // Allow all requests to move from the Create queue to the active entry.
1135 base::RunLoop().RunUntilIdle();
1136
1137 // The first request should be a writer at this point, and the subsequent
1138 // requests should be pending.
1139
1140 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1141 EXPECT_EQ(0, cache.disk_cache()->open_count());
1142 EXPECT_EQ(1, cache.disk_cache()->create_count());
1143
1144 // All requests depend on the writer, and the writer is between Start and
1145 // Read, i.e. idle.
1146 for (int i = 0; i < kNumTransactions; ++i) {
1147 Context* c = context_list[i];
1148 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1149 }
1150
1151 std::vector<HttpTransaction*> transactions;
1152 for (int i = 0; i < kNumTransactions; ++i) {
1153 Context* c = context_list[i];
1154 if (c->result == ERR_IO_PENDING)
1155 c->result = c->callback.WaitForResult();
1156 transactions.push_back(c->trans.get());
1157 }
1158
1159 ReadAndVerifySharedWritersDeleteWaitingWriter(kSimpleGET_Transaction,
1160 context_list);
1161
1162 // We should not have had to re-open the disk entry
1163 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1164 EXPECT_EQ(0, cache.disk_cache()->open_count());
1165 EXPECT_EQ(1, cache.disk_cache()->create_count());
1166
1167 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1168 Context* c = *i;
1169 delete c;
1170 }
1171 }
1172
1173 TEST(HttpCache, SimpleGET_SharedWritingJoinedReadDeleteIdleWriter) {
1174 MockHttpCache cache;
1175
1176 MockHttpRequest request(kSimpleGET_Transaction);
1177
1178 std::vector<Context*> context_list;
1179 const int kNumTransactions = 5;
1180
1181 for (int i = 0; i < kNumTransactions; ++i) {
1182 context_list.push_back(new Context());
1183 Context* c = context_list[i];
1184
1185 c->result = cache.CreateTransaction(&c->trans);
1186 ASSERT_THAT(c->result, IsOk());
1187 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1188
1189 c->result =
1190 c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
1191 }
1192
1193 // All requests are waiting for the active entry.
1194 for (int i = 0; i < kNumTransactions; ++i) {
1195 Context* c = context_list[i];
1196 EXPECT_EQ(LOAD_STATE_WAITING_FOR_CACHE, c->trans->GetLoadState());
1197 }
1198
1199 // Allow all requests to move from the Create queue to the active entry.
1200 base::RunLoop().RunUntilIdle();
1201
1202 // The first request should be a writer at this point, and the subsequent
1203 // requests should be pending.
1204
1205 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1206 EXPECT_EQ(0, cache.disk_cache()->open_count());
1207 EXPECT_EQ(1, cache.disk_cache()->create_count());
1208
1209 // All requests depend on the writer, and the writer is between Start and
1210 // Read, i.e. idle.
1211 for (int i = 0; i < kNumTransactions; ++i) {
1212 Context* c = context_list[i];
1213 EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
1214 }
1215
1216 std::vector<HttpTransaction*> transactions;
1217 for (int i = 0; i < kNumTransactions; ++i) {
1218 Context* c = context_list[i];
1219 if (c->result == ERR_IO_PENDING)
1220 c->result = c->callback.WaitForResult();
1221 transactions.push_back(c->trans.get());
1222 }
1223
1224 ReadAndVerifySharedWritersDeleteIdleWriter(kSimpleGET_Transaction,
1225 context_list);
1226 // We should not have had to re-open the disk entry
1227 EXPECT_EQ(1, cache.network_layer()->transaction_count());
1228 EXPECT_EQ(0, cache.disk_cache()->open_count());
1229 EXPECT_EQ(1, cache.disk_cache()->create_count());
1230
1231 for (auto i = context_list.begin(); i != context_list.end(); ++i) {
1232 Context* c = *i;
1233 delete c;
1234 }
1235 }
1236
1237 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698