Index: content/browser/service_worker/service_worker_cache_unittest.cc |
diff --git a/content/browser/service_worker/service_worker_cache_unittest.cc b/content/browser/service_worker/service_worker_cache_unittest.cc |
index 0d1c8fad3a5fdbc987da3ade8c243806eae0ce71..3e68aafccc593191084811b9f666272972a3c2a7 100644 |
--- a/content/browser/service_worker/service_worker_cache_unittest.cc |
+++ b/content/browser/service_worker/service_worker_cache_unittest.cc |
@@ -40,9 +40,88 @@ storage::BlobProtocolHandler* CreateMockBlobProtocolHandler( |
blob_storage_context, NULL, base::MessageLoopProxy::current().get()); |
} |
+// A disk_cache::Backend wrapper that can delay operations. |
+class DelayableBackend : public disk_cache::Backend { |
+ public: |
+ DelayableBackend(scoped_ptr<disk_cache::Backend> backend) |
+ : backend_(backend.Pass()), delay_open_(false) {} |
+ |
+ // disk_cache::Backend overrides |
+ virtual net::CacheType GetCacheType() const override { |
+ return backend_->GetCacheType(); |
+ } |
+ virtual int32 GetEntryCount() const override { |
+ return backend_->GetEntryCount(); |
+ } |
+ virtual int OpenEntry(const std::string& key, |
+ disk_cache::Entry** entry, |
+ const CompletionCallback& callback) override { |
+ if (delay_open_) { |
+ open_entry_callback_ = |
+ base::Bind(&DelayableBackend::OpenEntryDelayedImpl, |
+ base::Unretained(this), key, entry, callback); |
+ return net::ERR_IO_PENDING; |
+ } |
+ |
+ return backend_->OpenEntry(key, entry, callback); |
+ } |
+ virtual int CreateEntry(const std::string& key, |
+ disk_cache::Entry** entry, |
+ const CompletionCallback& callback) override { |
+ return backend_->CreateEntry(key, entry, callback); |
+ } |
+ virtual int DoomEntry(const std::string& key, |
+ const CompletionCallback& callback) override { |
+ return backend_->DoomEntry(key, callback); |
+ } |
+ virtual int DoomAllEntries(const CompletionCallback& callback) override { |
+ return backend_->DoomAllEntries(callback); |
+ } |
+ virtual int DoomEntriesBetween(base::Time initial_time, |
+ base::Time end_time, |
+ const CompletionCallback& callback) override { |
+ return backend_->DoomEntriesBetween(initial_time, end_time, callback); |
+ } |
+ virtual int DoomEntriesSince(base::Time initial_time, |
+ const CompletionCallback& callback) override { |
+ return backend_->DoomEntriesSince(initial_time, callback); |
+ } |
+ virtual scoped_ptr<Iterator> CreateIterator() override { |
+ return backend_->CreateIterator(); |
+ } |
+ virtual void GetStats( |
+ std::vector<std::pair<std::string, std::string>>* stats) override { |
+ return backend_->GetStats(stats); |
+ } |
+ virtual void OnExternalCacheHit(const std::string& key) override { |
+ return backend_->OnExternalCacheHit(key); |
+ } |
+ |
+ // Call to continue a delayed open. |
+ void OpenEntryContinue() { |
+ EXPECT_FALSE(open_entry_callback_.is_null()); |
+ open_entry_callback_.Run(); |
+ } |
+ |
+ void set_delay_open(bool value) { delay_open_ = value; } |
+ |
+ private: |
+ void OpenEntryDelayedImpl(const std::string& key, |
+ disk_cache::Entry** entry, |
+ const CompletionCallback& callback) { |
+ int rv = backend_->OpenEntry(key, entry, callback); |
+ if (rv != net::ERR_IO_PENDING) |
+ callback.Run(rv); |
+ } |
+ |
+ scoped_ptr<disk_cache::Backend> backend_; |
+ bool delay_open_; |
+ base::Closure open_entry_callback_; |
+}; |
+ |
} // namespace |
-// A ServiceWorkerCache that can optionally pause during backend creation. |
+// A ServiceWorkerCache that can optionally delay during backend creation. |
class TestServiceWorkerCache : public ServiceWorkerCache { |
public: |
TestServiceWorkerCache( |
@@ -56,11 +135,11 @@ class TestServiceWorkerCache : public ServiceWorkerCache { |
request_context, |
quota_manager_proxy, |
blob_context), |
- pause_backend_creation_(false) {} |
+ delay_backend_creation_(false) {} |
virtual void CreateBackend(const ErrorCallback& callback) override { |
backend_creation_callback_ = callback; |
- if (pause_backend_creation_) |
+ if (delay_backend_creation_) |
return; |
ContinueCreateBackend(); |
} |
@@ -69,14 +148,23 @@ class TestServiceWorkerCache : public ServiceWorkerCache { |
ServiceWorkerCache::CreateBackend(backend_creation_callback_); |
} |
- void set_pause_backend_creation(bool pause) { |
- pause_backend_creation_ = pause; |
+ void set_delay_backend_creation(bool delay) { |
+ delay_backend_creation_ = delay; |
+ } |
+ |
+ // Swap the existing backend with a delayable one. The backend must have been |
+ // created before calling this. |
+ DelayableBackend* UseDelayableBackend() { |
+ EXPECT_TRUE(backend_); |
+ DelayableBackend* delayable_backend = new DelayableBackend(backend_.Pass()); |
+ backend_.reset(delayable_backend); |
+ return delayable_backend; |
} |
private: |
virtual ~TestServiceWorkerCache() override {} |
- bool pause_backend_creation_; |
+ bool delay_backend_creation_; |
ErrorCallback backend_creation_callback_; |
DISALLOW_COPY_AND_ASSIGN(TestServiceWorkerCache); |
@@ -683,7 +771,7 @@ TEST_F(ServiceWorkerCacheTest, MemoryBackedSizePersistent) { |
} |
TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackendNeverCreated) { |
- cache_->set_pause_backend_creation( |
+ cache_->set_delay_backend_creation( |
true); // Will hang the test if a backend is created. |
EXPECT_TRUE(Close()); |
VerifyAllOpsFail(); |
@@ -696,10 +784,10 @@ TEST_P(ServiceWorkerCacheTestP, OpsFailOnClosedBackend) { |
VerifyAllOpsFail(); |
} |
-TEST_F(ServiceWorkerCacheTest, ClosedDuringPut) { |
+TEST_P(ServiceWorkerCacheTestP, ClosedDuringPutInitBackend) { |
// Even though Close is called in the middle of a Put operation (during |
- // backend creation), the put operation should still finish. |
- cache_->set_pause_backend_creation(true); |
+ // backend creation), the put operation should exit early. |
+ cache_->set_delay_backend_creation(true); |
scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
cache_->Put(CopyFetchRequest(body_request_), |
CopyFetchResponse(body_response_), |
@@ -708,22 +796,22 @@ TEST_F(ServiceWorkerCacheTest, ClosedDuringPut) { |
cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
base::Unretained(this), close_loop.get())); |
base::RunLoop().RunUntilIdle(); |
- EXPECT_FALSE(callback_response_); |
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
EXPECT_FALSE(callback_closed_); |
cache_->ContinueCreateBackend(); |
close_loop->Run(); |
- EXPECT_TRUE(callback_response_); |
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
EXPECT_TRUE(callback_closed_); |
VerifyAllOpsFail(); |
} |
-TEST_F(ServiceWorkerCacheTest, ClosedDuringMatch) { |
+TEST_P(ServiceWorkerCacheTestP, ClosedDuringMatchInitBackend) { |
// Even though Close is called in the middle of a Match operation (during |
- // backend creation), the match operation should still finish. |
- cache_->set_pause_backend_creation(true); |
+ // backend creation), the match operation should exit early. |
+ cache_->set_delay_backend_creation(true); |
scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
cache_->Match(CopyFetchRequest(body_request_), |
base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, |
@@ -737,16 +825,16 @@ TEST_F(ServiceWorkerCacheTest, ClosedDuringMatch) { |
cache_->ContinueCreateBackend(); |
close_loop->Run(); |
- EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_); |
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
EXPECT_TRUE(callback_closed_); |
VerifyAllOpsFail(); |
} |
-TEST_F(ServiceWorkerCacheTest, ClosedDuringDelete) { |
+TEST_P(ServiceWorkerCacheTestP, ClosedDuringDeleteInitBackend) { |
// Even though Close is called in the middle of a Delete operation (during |
- // backend creation), the delete operation should still finish. |
- cache_->set_pause_backend_creation(true); |
+ // backend creation), the delete operation should exit early. |
+ cache_->set_delay_backend_creation(true); |
scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
cache_->Delete(CopyFetchRequest(body_request_), |
base::Bind(&ServiceWorkerCacheTest::ErrorTypeCallback, |
@@ -760,30 +848,59 @@ TEST_F(ServiceWorkerCacheTest, ClosedDuringDelete) { |
cache_->ContinueCreateBackend(); |
close_loop->Run(); |
- EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_); |
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
EXPECT_TRUE(callback_closed_); |
VerifyAllOpsFail(); |
} |
-TEST_F(ServiceWorkerCacheTest, ClosedDuringKeys) { |
+TEST_P(ServiceWorkerCacheTestP, ClosedDuringKeysInitBackend) { |
// Even though Close is called in the middle of a Keys operation (during |
- // backend creation), the keys operation should still finish. |
- cache_->set_pause_backend_creation(true); |
+ // backend creation), the keys operation should exit early. |
+ cache_->set_delay_backend_creation(true); |
scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
- callback_error_ = ServiceWorkerCache::ErrorTypeNotFound; |
cache_->Keys(base::Bind(&ServiceWorkerCacheTest::RequestsCallback, |
base::Unretained(this), nullptr)); |
cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
base::Unretained(this), close_loop.get())); |
base::RunLoop().RunUntilIdle(); |
- EXPECT_EQ(ServiceWorkerCache::ErrorTypeNotFound, callback_error_); |
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
EXPECT_FALSE(callback_closed_); |
cache_->ContinueCreateBackend(); |
close_loop->Run(); |
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
+ EXPECT_TRUE(callback_closed_); |
+ |
+ VerifyAllOpsFail(); |
+} |
+ |
+TEST_P(ServiceWorkerCacheTestP, ClosedDuringPutOpenEntry) { |
+ EXPECT_TRUE(Keys()); // Opens the backend. |
+ DelayableBackend* delayable_backend = cache_->UseDelayableBackend(); |
+ delayable_backend->set_delay_open(true); |
+ |
+ // Run Put and Close. Put will delay on OpenEntry, Close will wait for Put to |
+ // finish. |
+ scoped_ptr<base::RunLoop> close_loop(new base::RunLoop()); |
+ cache_->Put(CopyFetchRequest(body_request_), |
+ CopyFetchResponse(body_response_), |
+ base::Bind(&ServiceWorkerCacheTest::ResponseAndErrorCallback, |
+ base::Unretained(this), nullptr)); |
+ cache_->Close(base::Bind(&ServiceWorkerCacheTest::CloseCallback, |
+ base::Unretained(this), close_loop.get())); |
+ |
+ base::RunLoop().RunUntilIdle(); |
+ // Verify that neither operation has finished. |
EXPECT_EQ(ServiceWorkerCache::ErrorTypeOK, callback_error_); |
+ EXPECT_FALSE(callback_closed_); |
+ |
+ delayable_backend->OpenEntryContinue(); |
+ |
+ close_loop->Run(); |
+ // Put failed because the backend was closed while it was running. |
+ EXPECT_EQ(ServiceWorkerCache::ErrorTypeStorage, callback_error_); |
EXPECT_TRUE(callback_closed_); |
VerifyAllOpsFail(); |