OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/service_worker/service_worker_cache.h" | 5 #include "content/browser/service_worker/service_worker_cache.h" |
6 | 6 |
7 #include "base/files/file_path.h" | 7 #include "base/files/file_path.h" |
8 #include "base/files/scoped_temp_dir.h" | 8 #include "base/files/scoped_temp_dir.h" |
9 #include "base/message_loop/message_loop_proxy.h" | 9 #include "base/message_loop/message_loop_proxy.h" |
10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 // Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns | 33 // Returns a BlobProtocolHandler that uses |blob_storage_context|. Caller owns |
34 // the memory. | 34 // the memory. |
35 storage::BlobProtocolHandler* CreateMockBlobProtocolHandler( | 35 storage::BlobProtocolHandler* CreateMockBlobProtocolHandler( |
36 storage::BlobStorageContext* blob_storage_context) { | 36 storage::BlobStorageContext* blob_storage_context) { |
37 // The FileSystemContext and MessageLoopProxy are not actually used but a | 37 // The FileSystemContext and MessageLoopProxy are not actually used but a |
38 // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor. | 38 // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor. |
39 return new storage::BlobProtocolHandler( | 39 return new storage::BlobProtocolHandler( |
40 blob_storage_context, NULL, base::MessageLoopProxy::current().get()); | 40 blob_storage_context, NULL, base::MessageLoopProxy::current().get()); |
41 } | 41 } |
42 | 42 |
| 43 // A disk_cache::Backend wrapper that can delay operations. |
| 44 class DelayableBackend : public disk_cache::Backend { |
| 45 public: |
| 46 DelayableBackend(scoped_ptr<disk_cache::Backend> backend) |
| 47 : backend_(backend.Pass()), delay_open_(false) {} |
| 48 |
| 49 // disk_cache::Backend overrides |
| 50 virtual net::CacheType GetCacheType() const override { |
| 51 return backend_->GetCacheType(); |
| 52 } |
| 53 virtual int32 GetEntryCount() const override { |
| 54 return backend_->GetEntryCount(); |
| 55 } |
| 56 virtual int OpenEntry(const std::string& key, |
| 57 disk_cache::Entry** entry, |
| 58 const CompletionCallback& callback) override { |
| 59 if (delay_open_) { |
| 60 open_entry_callback_ = |
| 61 base::Bind(&DelayableBackend::OpenEntryDelayedImpl, |
| 62 base::Unretained(this), key, entry, callback); |
| 63 return net::ERR_IO_PENDING; |
| 64 } |
| 65 |
| 66 return backend_->OpenEntry(key, entry, callback); |
| 67 } |
| 68 virtual int CreateEntry(const std::string& key, |
| 69 disk_cache::Entry** entry, |
| 70 const CompletionCallback& callback) override { |
| 71 return backend_->CreateEntry(key, entry, callback); |
| 72 } |
| 73 virtual int DoomEntry(const std::string& key, |
| 74 const CompletionCallback& callback) override { |
| 75 return backend_->DoomEntry(key, callback); |
| 76 } |
| 77 virtual int DoomAllEntries(const CompletionCallback& callback) override { |
| 78 return backend_->DoomAllEntries(callback); |
| 79 } |
| 80 virtual int DoomEntriesBetween(base::Time initial_time, |
| 81 base::Time end_time, |
| 82 const CompletionCallback& callback) override { |
| 83 return backend_->DoomEntriesBetween(initial_time, end_time, callback); |
| 84 } |
| 85 virtual int DoomEntriesSince(base::Time initial_time, |
| 86 const CompletionCallback& callback) override { |
| 87 return backend_->DoomEntriesSince(initial_time, callback); |
| 88 } |
| 89 virtual scoped_ptr<Iterator> CreateIterator() override { |
| 90 return backend_->CreateIterator(); |
| 91 } |
| 92 virtual void GetStats( |
| 93 std::vector<std::pair<std::string, std::string>>* stats) override { |
| 94 return backend_->GetStats(stats); |
| 95 } |
| 96 virtual void OnExternalCacheHit(const std::string& key) override { |
| 97 return backend_->OnExternalCacheHit(key); |
| 98 } |
| 99 |
| 100 // Call to continue a delayed open. |
| 101 void OpenEntryContinue() { |
| 102 EXPECT_FALSE(open_entry_callback_.is_null()); |
| 103 open_entry_callback_.Run(); |
| 104 } |
| 105 |
| 106 void set_delay_open(bool value) { delay_open_ = value; } |
| 107 |
| 108 private: |
| 109 void OpenEntryDelayedImpl(const std::string& key, |
| 110 disk_cache::Entry** entry, |
| 111 const CompletionCallback& callback) { |
| 112 int rv = backend_->OpenEntry(key, entry, callback); |
| 113 if (rv != net::ERR_IO_PENDING) |
| 114 callback.Run(rv); |
| 115 } |
| 116 |
| 117 scoped_ptr<disk_cache::Backend> backend_; |
| 118 bool delay_open_; |
| 119 base::Closure open_entry_callback_; |
| 120 }; |
| 121 |
43 } // namespace | 122 } // namespace |
44 | 123 |
45 // A ServiceWorkerCache that can optionally pause during backend creation. | 124 // A ServiceWorkerCache that can optionally delay during backend creation. |
46 class TestServiceWorkerCache : public ServiceWorkerCache { | 125 class TestServiceWorkerCache : public ServiceWorkerCache { |
47 public: | 126 public: |
48 TestServiceWorkerCache( | 127 TestServiceWorkerCache( |
49 const GURL& origin, | 128 const GURL& origin, |
50 const base::FilePath& path, | 129 const base::FilePath& path, |
51 net::URLRequestContext* request_context, | 130 net::URLRequestContext* request_context, |
52 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, | 131 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, |
53 base::WeakPtr<storage::BlobStorageContext> blob_context) | 132 base::WeakPtr<storage::BlobStorageContext> blob_context) |
54 : ServiceWorkerCache(origin, | 133 : ServiceWorkerCache(origin, |
55 path, | 134 path, |
56 request_context, | 135 request_context, |
57 quota_manager_proxy, | 136 quota_manager_proxy, |
58 blob_context), | 137 blob_context), |
59 pause_backend_creation_(false) {} | 138 delay_backend_creation_(false) {} |
60 | 139 |
61 virtual void CreateBackend(const ErrorCallback& callback) override { | 140 virtual void CreateBackend(const ErrorCallback& callback) override { |
62 backend_creation_callback_ = callback; | 141 backend_creation_callback_ = callback; |
63 if (pause_backend_creation_) | 142 if (delay_backend_creation_) |
64 return; | 143 return; |
65 ContinueCreateBackend(); | 144 ContinueCreateBackend(); |
66 } | 145 } |
67 | 146 |
68 void ContinueCreateBackend() { | 147 void ContinueCreateBackend() { |
69 ServiceWorkerCache::CreateBackend(backend_creation_callback_); | 148 ServiceWorkerCache::CreateBackend(backend_creation_callback_); |
70 } | 149 } |
71 | 150 |
72 void set_pause_backend_creation(bool pause) { | 151 void set_delay_backend_creation(bool delay) { |
73 pause_backend_creation_ = pause; | 152 delay_backend_creation_ = delay; |
| 153 } |
| 154 |
| 155 // Swap the existing backend with a delayable one. The backend must have been |
| 156 // created before calling this. |
| 157 DelayableBackend* UseDelayableBackend() { |
| 158 EXPECT_TRUE(backend_); |
| 159 DelayableBackend* delayable_backend = new DelayableBackend(backend_.Pass()); |
| 160 backend_.reset(delayable_backend); |
| 161 return delayable_backend; |
74 } | 162 } |
75 | 163 |
76 private: | 164 private: |
77 virtual ~TestServiceWorkerCache() override {} | 165 virtual ~TestServiceWorkerCache() override {} |
78 | 166 |
79 bool pause_backend_creation_; | 167 bool delay_backend_creation_; |
80 ErrorCallback backend_creation_callback_; | 168 ErrorCallback backend_creation_callback_; |
81 | 169 |
82 DISALLOW_COPY_AND_ASSIGN(TestServiceWorkerCache); | 170 DISALLOW_COPY_AND_ASSIGN(TestServiceWorkerCache); |
83 }; | 171 }; |
84 | 172 |
85 class ServiceWorkerCacheTest : public testing::Test { | 173 class ServiceWorkerCacheTest : public testing::Test { |
86 public: | 174 public: |
87 ServiceWorkerCacheTest() | 175 ServiceWorkerCacheTest() |
88 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), | 176 : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), |
89 callback_error_(ServiceWorkerCache::ErrorTypeOK), | 177 callback_error_(ServiceWorkerCache::ErrorTypeOK), |
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
676 EXPECT_EQ(0, cache_->MemoryBackedSize()); | 764 EXPECT_EQ(0, cache_->MemoryBackedSize()); |
677 } | 765 } |
678 | 766 |
679 TEST_F(ServiceWorkerCacheTest, MemoryBackedSizePersistent) { | 767 TEST_F(ServiceWorkerCacheTest, MemoryBackedSizePersistent) { |
680 EXPECT_EQ(0, cache_->MemoryBackedSize()); | 768 EXPECT_EQ(0, cache_->MemoryBackedSize()); |
681 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); | 769 EXPECT_TRUE(Put(no_body_request_, no_body_response_)); |
682 EXPECT_EQ(0, cache_->MemoryBackedSize()); | 770 EXPECT_EQ(0, cache_->MemoryBackedSize()); |
683 } | 771 } |
684 | 772 |
685 TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackendNeverCreated) { | 773 TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackendNeverCreated) { |
686 cache_->set_pause_backend_creation( | 774 cache_->set_delay_backend_creation( |
687 true); // Will hang the test if a backend is created. | 775 true); // Will hang the test if a backend is created. |
688 EXPECT_TRUE(Close()); | 776 EXPECT_TRUE(Close()); |
689 VerifyAllOpsFail(); | 777 VerifyAllOpsFail(); |
690 } | 778 } |
691 | 779 |
692 TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackend) { | 780 TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackend) { |
693 // Create the backend and put something in it. | 781 // Create the backend and put something in it. |
694 EXPECT_TRUE(Put(body_request_, body_response_)); | 782 EXPECT_TRUE(Put(body_request_, body_response_)); |
695 EXPECT_TRUE(Close()); | 783 EXPECT_TRUE(Close()); |
696 VerifyAllOpsFail(); | 784 VerifyAllOpsFail(); |
697 } | 785 } |
698 | 786 |
699 TEST_F(ServiceWorkerCacheTest, ClosedDuringPut) { | 787 TEST_P(ServiceWorkerCacheTestP, ClosedDuringPutInitBackend) { |
700 // Even though Close is called in the middle of a Put operation (during | 788 // Even though Close is called in the middle of a Put operation (during |
701 // backend creation), the put operation should still finish. | 789 // backend creation), the put operation should exit early. |
702 cache_->set_pause_backend_creation(true); | 790 cache_->set_delay_backend_creation(true); |
703 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); | 791 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
704 cache_->Put(CopyFetchRequest(body_request_), | 792 cache_->Put(CopyFetchRequest(body_request_), |
705 CopyFetchResponse(body_response_), | 793 CopyFetchResponse(body_response_), |
706 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, | 794 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, |
707 base::Unretained(this), nullptr)); | 795 base::Unretained(this), nullptr)); |
708 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, | 796 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
709 base::Unretained(this), close_loop.get())); | 797 base::Unretained(this), close_loop.get())); |
710 base::RunLoop().RunUntilIdle(); | 798 base::RunLoop().RunUntilIdle(); |
711 EXPECT_FALSE(callback_response_); | 799 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
712 EXPECT_FALSE(callback_closed_); | 800 EXPECT_FALSE(callback_closed_); |
713 | 801 |
714 cache_->ContinueCreateBackend(); | 802 cache_->ContinueCreateBackend(); |
715 | 803 |
716 close_loop->Run(); | 804 close_loop->Run(); |
717 EXPECT_TRUE(callback_response_); | 805 EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
718 EXPECT_TRUE(callback_closed_); | 806 EXPECT_TRUE(callback_closed_); |
719 | 807 |
720 VerifyAllOpsFail(); | 808 VerifyAllOpsFail(); |
721 } | 809 } |
722 | 810 |
723 TEST_F(ServiceWorkerCacheTest, ClosedDuringMatch) { | 811 TEST_P(ServiceWorkerCacheTestP, ClosedDuringMatchInitBackend) { |
724 // Even though Close is called in the middle of a Match operation (during | 812 // Even though Close is called in the middle of a Match operation (during |
725 // backend creation), the match operation should still finish. | 813 // backend creation), the match operation should exit early. |
726 cache_->set_pause_backend_creation(true); | 814 cache_->set_delay_backend_creation(true); |
727 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); | 815 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
728 cache_->Match(CopyFetchRequest(body_request_), | 816 cache_->Match(CopyFetchRequest(body_request_), |
729 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, | 817 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, |
730 base::Unretained(this), nullptr)); | 818 base::Unretained(this), nullptr)); |
731 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, | 819 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
732 base::Unretained(this), close_loop.get())); | 820 base::Unretained(this), close_loop.get())); |
733 base::RunLoop().RunUntilIdle(); | 821 base::RunLoop().RunUntilIdle(); |
734 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); | 822 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
735 EXPECT_FALSE(callback_closed_); | 823 EXPECT_FALSE(callback_closed_); |
736 | 824 |
737 cache_->ContinueCreateBackend(); | 825 cache_->ContinueCreateBackend(); |
738 | 826 |
739 close_loop->Run(); | 827 close_loop->Run(); |
740 EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_); | 828 EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
741 EXPECT_TRUE(callback_closed_); | 829 EXPECT_TRUE(callback_closed_); |
742 | 830 |
743 VerifyAllOpsFail(); | 831 VerifyAllOpsFail(); |
744 } | 832 } |
745 | 833 |
746 TEST_F(ServiceWorkerCacheTest, ClosedDuringDelete) { | 834 TEST_P(ServiceWorkerCacheTestP, ClosedDuringDeleteInitBackend) { |
747 // Even though Close is called in the middle of a Delete operation (during | 835 // Even though Close is called in the middle of a Delete operation (during |
748 // backend creation), the delete operation should still finish. | 836 // backend creation), the delete operation should exit early. |
749 cache_->set_pause_backend_creation(true); | 837 cache_->set_delay_backend_creation(true); |
750 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); | 838 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
751 cache_->Delete(CopyFetchRequest(body_request_), | 839 cache_->Delete(CopyFetchRequest(body_request_), |
752 base::Bind(&ServiceWorkerCacheTest::ErrorTypeCallback, | 840 base::Bind(&ServiceWorkerCacheTest::ErrorTypeCallback, |
753 base::Unretained(this), nullptr)); | 841 base::Unretained(this), nullptr)); |
754 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, | 842 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
755 base::Unretained(this), close_loop.get())); | 843 base::Unretained(this), close_loop.get())); |
756 base::RunLoop().RunUntilIdle(); | 844 base::RunLoop().RunUntilIdle(); |
757 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); | 845 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
758 EXPECT_FALSE(callback_closed_); | 846 EXPECT_FALSE(callback_closed_); |
759 | 847 |
760 cache_->ContinueCreateBackend(); | 848 cache_->ContinueCreateBackend(); |
761 | 849 |
762 close_loop->Run(); | 850 close_loop->Run(); |
763 EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_); | 851 EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
764 EXPECT_TRUE(callback_closed_); | 852 EXPECT_TRUE(callback_closed_); |
765 | 853 |
766 VerifyAllOpsFail(); | 854 VerifyAllOpsFail(); |
767 } | 855 } |
768 | 856 |
769 TEST_F(ServiceWorkerCacheTest, ClosedDuringKeys) { | 857 TEST_P(ServiceWorkerCacheTestP, ClosedDuringKeysInitBackend) { |
770 // Even though Close is called in the middle of a Keys operation (during | 858 // Even though Close is called in the middle of a Keys operation (during |
771 // backend creation), the keys operation should still finish. | 859 // backend creation), the keys operation should exit early. |
772 cache_->set_pause_backend_creation(true); | 860 cache_->set_delay_backend_creation(true); |
773 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); | 861 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
774 callback_error_ = ServiceWorkerCache::ErrorTypeNotFound; | |
775 cache_->Keys(base::Bind(&ServiceWorkerCacheTest::RequestsCallback, | 862 cache_->Keys(base::Bind(&ServiceWorkerCacheTest::RequestsCallback, |
776 base::Unretained(this), nullptr)); | 863 base::Unretained(this), nullptr)); |
777 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, | 864 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
778 base::Unretained(this), close_loop.get())); | 865 base::Unretained(this), close_loop.get())); |
779 base::RunLoop().RunUntilIdle(); | 866 base::RunLoop().RunUntilIdle(); |
780 EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_); | 867 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
781 EXPECT_FALSE(callback_closed_); | 868 EXPECT_FALSE(callback_closed_); |
782 | 869 |
783 cache_->ContinueCreateBackend(); | 870 cache_->ContinueCreateBackend(); |
784 | 871 |
785 close_loop->Run(); | 872 close_loop->Run(); |
786 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); | 873 EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
787 EXPECT_TRUE(callback_closed_); | 874 EXPECT_TRUE(callback_closed_); |
788 | 875 |
789 VerifyAllOpsFail(); | 876 VerifyAllOpsFail(); |
| 877 } |
| 878 |
| 879 TEST_P(ServiceWorkerCacheTestP, ClosedDuringPutOpenEntry) { |
| 880 EXPECT_TRUE(Keys()); // Opens the backend. |
| 881 DelayableBackend* delayable_backend = cache_->UseDelayableBackend(); |
| 882 delayable_backend->set_delay_open(true); |
| 883 |
| 884 // Run Put and Close. Put will delay on OpenEntry, Close will wait for Put to |
| 885 // finish. |
| 886 scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
| 887 cache_->Put(CopyFetchRequest(body_request_), |
| 888 CopyFetchResponse(body_response_), |
| 889 base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, |
| 890 base::Unretained(this), nullptr)); |
| 891 cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
| 892 base::Unretained(this), close_loop.get())); |
| 893 |
| 894 base::RunLoop().RunUntilIdle(); |
| 895 // Verify that neither operation has finished. |
| 896 EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
| 897 EXPECT_FALSE(callback_closed_); |
| 898 |
| 899 delayable_backend->OpenEntryContinue(); |
| 900 |
| 901 close_loop->Run(); |
| 902 // Put failed because the backend was closed while it was running. |
| 903 EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
| 904 EXPECT_TRUE(callback_closed_); |
| 905 |
| 906 VerifyAllOpsFail(); |
790 } | 907 } |
791 | 908 |
792 INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheTest, | 909 INSTANTIATE_TEST_CASE_P(ServiceWorkerCacheTest, |
793 ServiceWorkerCacheTestP, | 910 ServiceWorkerCacheTestP, |
794 ::testing::Values(false, true)); | 911 ::testing::Values(false, true)); |
795 | 912 |
796 } // namespace content | 913 } // namespace content |
OLD | NEW |