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 3 // found in the LICENSE file. 4 5 #include "base/bind.h" 6 #include "base/files/file_util.h" 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/run_loop.h" 9 #include "base/single_thread_task_runner.h" 10 #include "base/thread_task_runner_handle.h" 11 #include "content/browser/appcache/appcache_disk_cache.h" 12 #include "net/base/io_buffer.h" 13 #include "net/base/net_errors.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace content { 17 18 class AppCacheDiskCacheTest : public testing::Test { 19 public: 20 AppCacheDiskCacheTest() {} 21 22 virtual void SetUp() OVERRIDE { 23 // Use the current thread for the DiskCache's cache_thread. 24 message_loop_.reset(new base::MessageLoopForIO()); 25 cache_thread_ = base::ThreadTaskRunnerHandle::Get(); 26 ASSERT_TRUE(directory_.CreateUniqueTempDir()); 27 completion_callback_ = base::Bind( 28 &AppCacheDiskCacheTest::OnComplete, 29 base::Unretained(this)); 30 } 31 32 virtual void TearDown() OVERRIDE { 33 base::RunLoop().RunUntilIdle(); 34 message_loop_.reset(NULL); 35 } 36 37 void FlushCacheTasks() { 38 base::RunLoop().RunUntilIdle(); 39 } 40 41 void OnComplete(int err) { 42 completion_results_.push_back(err); 43 } 44 45 base::ScopedTempDir directory_; 46 scoped_ptr<base::MessageLoop> message_loop_; 47 scoped_refptr<base::SingleThreadTaskRunner> cache_thread_; 48 net::CompletionCallback completion_callback_; 49 std::vector<int> completion_results_; 50 51 static const int k10MBytes = 10 * 1024 * 1024; 52 }; 53 54 TEST_F(AppCacheDiskCacheTest, DisablePriorToInitCompletion) { 55 AppCacheDiskCache::Entry* entry = NULL; 56 57 // Create an instance and start it initializing, queue up 58 // one of each kind of "entry" function. 59 scoped_ptr<AppCacheDiskCache> disk_cache(new AppCacheDiskCache); 60 EXPECT_FALSE(disk_cache->is_disabled()); 61 disk_cache->InitWithDiskBackend( 62 directory_.path(), k10MBytes, false, cache_thread_, completion_callback_); 63 disk_cache->CreateEntry(1, &entry, completion_callback_); 64 disk_cache->OpenEntry(2, &entry, completion_callback_); 65 disk_cache->DoomEntry(3, completion_callback_); 66 67 // Pull the plug on all that. 68 EXPECT_FALSE(disk_cache->is_disabled()); 69 disk_cache->Disable(); 70 EXPECT_TRUE(disk_cache->is_disabled()); 71 72 FlushCacheTasks(); 73 74 EXPECT_EQ(NULL, entry); 75 EXPECT_EQ(4u, completion_results_.size()); 76 for (std::vector<int>::const_iterator iter = completion_results_.begin(); 77 iter < completion_results_.end(); ++iter) { 78 EXPECT_EQ(net::ERR_ABORTED, *iter); 79 } 80 81 // Ensure the directory can be deleted at this point. 82 EXPECT_TRUE(base::DirectoryExists(directory_.path())); 83 EXPECT_FALSE(base::IsDirectoryEmpty(directory_.path())); 84 EXPECT_TRUE(base::DeleteFile(directory_.path(), true)); 85 EXPECT_FALSE(base::DirectoryExists(directory_.path())); 86 } 87 88 TEST_F(AppCacheDiskCacheTest, DisableAfterInitted) { 89 // Create an instance and let it fully init. 90 scoped_ptr<AppCacheDiskCache> disk_cache(new AppCacheDiskCache); 91 EXPECT_FALSE(disk_cache->is_disabled()); 92 disk_cache->InitWithDiskBackend( 93 directory_.path(), k10MBytes, false, cache_thread_, completion_callback_); 94 FlushCacheTasks(); 95 EXPECT_EQ(1u, completion_results_.size()); 96 EXPECT_EQ(net::OK, completion_results_[0]); 97 98 // Pull the plug 99 disk_cache->Disable(); 100 FlushCacheTasks(); 101 102 // Ensure the directory can be deleted at this point. 103 EXPECT_TRUE(base::DirectoryExists(directory_.path())); 104 EXPECT_FALSE(base::IsDirectoryEmpty(directory_.path())); 105 EXPECT_TRUE(base::DeleteFile(directory_.path(), true)); 106 EXPECT_FALSE(base::DirectoryExists(directory_.path())); 107 108 // Methods should return immediately when disabled and not invoke 109 // the callback at all. 110 AppCacheDiskCache::Entry* entry = NULL; 111 completion_results_.clear(); 112 EXPECT_EQ(net::ERR_ABORTED, 113 disk_cache->CreateEntry(1, &entry, completion_callback_)); 114 EXPECT_EQ(net::ERR_ABORTED, 115 disk_cache->OpenEntry(2, &entry, completion_callback_)); 116 EXPECT_EQ(net::ERR_ABORTED, 117 disk_cache->DoomEntry(3, completion_callback_)); 118 FlushCacheTasks(); 119 EXPECT_TRUE(completion_results_.empty()); 120 } 121 122 // Flaky on Android: http://crbug.com/339534 123 TEST_F(AppCacheDiskCacheTest, DISABLED_DisableWithEntriesOpen) { 124 // Create an instance and let it fully init. 125 scoped_ptr<AppCacheDiskCache> disk_cache(new AppCacheDiskCache); 126 EXPECT_FALSE(disk_cache->is_disabled()); 127 disk_cache->InitWithDiskBackend( 128 directory_.path(), k10MBytes, false, cache_thread_, completion_callback_); 129 FlushCacheTasks(); 130 EXPECT_EQ(1u, completion_results_.size()); 131 EXPECT_EQ(net::OK, completion_results_[0]); 132 133 // Note: We don't have detailed expectations of the DiskCache 134 // operations because on android it's really SimpleCache which 135 // does behave differently. 136 // 137 // What matters for the corruption handling and service reinitiazation 138 // is that the directory can be deleted after the calling Disable() method, 139 // and we do have expectations about that. 140 141 // Create/open some entries. 142 AppCacheDiskCache::Entry* entry1 = NULL; 143 AppCacheDiskCache::Entry* entry2 = NULL; 144 disk_cache->CreateEntry(1, &entry1, completion_callback_); 145 disk_cache->CreateEntry(2, &entry2, completion_callback_); 146 FlushCacheTasks(); 147 EXPECT_TRUE(entry1); 148 EXPECT_TRUE(entry2); 149 150 // Write something to one of the entries and flush it. 151 const char* kData = "Hello"; 152 const int kDataLen = strlen(kData) + 1; 153 scoped_refptr<net::IOBuffer> write_buf(new net::WrappedIOBuffer(kData)); 154 entry1->Write(0, 0, write_buf.get(), kDataLen, completion_callback_); 155 FlushCacheTasks(); 156 157 // Queue up a read and a write. 158 scoped_refptr<net::IOBuffer> read_buf = new net::IOBuffer(kDataLen); 159 entry1->Read(0, 0, read_buf.get(), kDataLen, completion_callback_); 160 entry2->Write(0, 0, write_buf.get(), kDataLen, completion_callback_); 161 162 // Pull the plug 163 disk_cache->Disable(); 164 FlushCacheTasks(); 165 166 // Ensure the directory can be deleted at this point. 167 EXPECT_TRUE(base::DirectoryExists(directory_.path())); 168 EXPECT_FALSE(base::IsDirectoryEmpty(directory_.path())); 169 EXPECT_TRUE(base::DeleteFile(directory_.path(), true)); 170 EXPECT_FALSE(base::DirectoryExists(directory_.path())); 171 172 disk_cache.reset(NULL); 173 174 // Also, new IO operations should fail immediately. 175 EXPECT_EQ( 176 net::ERR_ABORTED, 177 entry1->Read(0, 0, read_buf.get(), kDataLen, completion_callback_)); 178 entry1->Close(); 179 entry2->Close(); 180 181 FlushCacheTasks(); 182 } 183 184 } // namespace content 185