1 // Copyright 2013 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 "webkit/browser/fileapi/quota/quota_backend_impl.h" 6 7 #include <string> 8 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/message_loop/message_loop.h" 11 #include "testing/gtest/include/gtest/gtest.h" 12 #include "webkit/browser/fileapi/file_system_usage_cache.h" 13 #include "webkit/browser/fileapi/obfuscated_file_util.h" 14 #include "webkit/browser/quota/quota_manager.h" 15 16 namespace fileapi { 17 18 namespace { 19 20 const char kOrigin[] = "http://example.com"; 21 22 bool DidReserveQuota(bool accepted, 23 base::PlatformFileError* error_out, 24 base::PlatformFileError error) { 25 DCHECK(error_out); 26 *error_out = error; 27 return accepted; 28 } 29 30 class MockQuotaManagerProxy : public quota::QuotaManagerProxy { 31 public: 32 MockQuotaManagerProxy() 33 : QuotaManagerProxy(NULL, NULL), 34 storage_modified_count_(0), 35 usage_(0), quota_(0) {} 36 37 // We don't mock them. 38 virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {} 39 virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {} 40 virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id, 41 const GURL& origin, 42 quota::StorageType type, 43 bool enabled) OVERRIDE {} 44 45 virtual void NotifyStorageModified( 46 quota::QuotaClient::ID client_id, 47 const GURL& origin, 48 quota::StorageType type, 49 int64 delta) OVERRIDE { 50 ++storage_modified_count_; 51 usage_ += delta; 52 ASSERT_LT(usage_, quota_); 53 } 54 55 virtual void GetUsageAndQuota( 56 base::SequencedTaskRunner* original_task_runner, 57 const GURL& origin, 58 quota::StorageType type, 59 const GetUsageAndQuotaCallback& callback) OVERRIDE { 60 callback.Run(quota::kQuotaStatusOk, usage_, quota_); 61 } 62 63 int storage_modified_count() { return storage_modified_count_; } 64 int64 usage() { return usage_; } 65 void set_usage(int64 usage) { usage_ = usage; } 66 void set_quota(int64 quota) { quota_ = quota; } 67 68 protected: 69 virtual ~MockQuotaManagerProxy() {} 70 71 private: 72 int storage_modified_count_; 73 int64 usage_; 74 int64 quota_; 75 76 DISALLOW_COPY_AND_ASSIGN(MockQuotaManagerProxy); 77 }; 78 79 } // namespace 80 81 class QuotaBackendImplTest : public testing::Test { 82 public: 83 QuotaBackendImplTest() 84 : file_system_usage_cache_(file_task_runner()), 85 quota_manager_proxy_(new MockQuotaManagerProxy) {} 86 87 virtual void SetUp() OVERRIDE { 88 ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); 89 file_util_.reset(ObfuscatedFileUtil::CreateForTesting( 90 NULL, data_dir_.path(), file_task_runner())); 91 backend_.reset(new QuotaBackendImpl(file_task_runner(), 92 file_util_.get(), 93 &file_system_usage_cache_, 94 quota_manager_proxy_.get())); 95 } 96 97 virtual void TearDown() OVERRIDE { 98 backend_.reset(); 99 quota_manager_proxy_ = NULL; 100 file_util_.reset(); 101 message_loop_.RunUntilIdle(); 102 } 103 104 protected: 105 void InitializeForOriginAndType(const GURL& origin, FileSystemType type) { 106 ASSERT_TRUE(file_util_->InitOriginDatabase(origin, true /* create */)); 107 ASSERT_TRUE(file_util_->origin_database_ != NULL); 108 109 std::string type_string = 110 SandboxFileSystemBackendDelegate::GetTypeString(type); 111 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; 112 base::FilePath path = file_util_->GetDirectoryForOriginAndType( 113 origin, type_string, true /* create */, &error); 114 ASSERT_EQ(base::PLATFORM_FILE_OK, error); 115 116 ASSERT_TRUE(file_system_usage_cache_.UpdateUsage( 117 GetUsageCachePath(origin, type), 0)); 118 } 119 120 base::SequencedTaskRunner* file_task_runner() { 121 return base::MessageLoopProxy::current().get(); 122 } 123 124 base::FilePath GetUsageCachePath(const GURL& origin, FileSystemType type) { 125 base::FilePath path; 126 base::PlatformFileError error = 127 backend_->GetUsageCachePath(origin, type, &path); 128 EXPECT_EQ(base::PLATFORM_FILE_OK, error); 129 EXPECT_FALSE(path.empty()); 130 return path; 131 } 132 133 base::MessageLoop message_loop_; 134 base::ScopedTempDir data_dir_; 135 scoped_ptr<ObfuscatedFileUtil> file_util_; 136 FileSystemUsageCache file_system_usage_cache_; 137 scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_; 138 scoped_ptr<QuotaBackendImpl> backend_; 139 140 private: 141 DISALLOW_COPY_AND_ASSIGN(QuotaBackendImplTest); 142 }; 143 144 TEST_F(QuotaBackendImplTest, ReserveQuota_Basic) { 145 FileSystemType type = fileapi::kFileSystemTypeTemporary; 146 InitializeForOriginAndType(GURL(kOrigin), type); 147 quota_manager_proxy_->set_quota(10000); 148 149 const int64 kDelta1 = 1000; 150 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; 151 backend_->ReserveQuota(GURL(kOrigin), type, kDelta1, 152 base::Bind(&DidReserveQuota, true, &error)); 153 EXPECT_EQ(base::PLATFORM_FILE_OK, error); 154 EXPECT_EQ(kDelta1, quota_manager_proxy_->usage()); 155 156 const int64 kDelta2 = -300; 157 error = base::PLATFORM_FILE_ERROR_FAILED; 158 backend_->ReserveQuota(GURL(kOrigin), type, kDelta2, 159 base::Bind(&DidReserveQuota, true, &error)); 160 EXPECT_EQ(base::PLATFORM_FILE_OK, error); 161 EXPECT_EQ(kDelta1 + kDelta2, quota_manager_proxy_->usage()); 162 163 EXPECT_EQ(2, quota_manager_proxy_->storage_modified_count()); 164 } 165 166 TEST_F(QuotaBackendImplTest, ReserveQuota_NoSpace) { 167 FileSystemType type = fileapi::kFileSystemTypeTemporary; 168 InitializeForOriginAndType(GURL(kOrigin), type); 169 quota_manager_proxy_->set_quota(100); 170 171 const int64 kDelta = 1000; 172 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; 173 backend_->ReserveQuota(GURL(kOrigin), type, kDelta, 174 base::Bind(&DidReserveQuota, true, &error)); 175 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, error); 176 EXPECT_EQ(0, quota_manager_proxy_->usage()); 177 178 EXPECT_EQ(0, quota_manager_proxy_->storage_modified_count()); 179 } 180 181 TEST_F(QuotaBackendImplTest, ReserveQuota_Revert) { 182 FileSystemType type = fileapi::kFileSystemTypeTemporary; 183 InitializeForOriginAndType(GURL(kOrigin), type); 184 quota_manager_proxy_->set_quota(10000); 185 186 const int64 kDelta = 1000; 187 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; 188 backend_->ReserveQuota(GURL(kOrigin), type, kDelta, 189 base::Bind(&DidReserveQuota, false, &error)); 190 EXPECT_EQ(base::PLATFORM_FILE_OK, error); 191 EXPECT_EQ(0, quota_manager_proxy_->usage()); 192 193 EXPECT_EQ(2, quota_manager_proxy_->storage_modified_count()); 194 } 195 196 TEST_F(QuotaBackendImplTest, ReleaseReservedQuota) { 197 FileSystemType type = fileapi::kFileSystemTypeTemporary; 198 InitializeForOriginAndType(GURL(kOrigin), type); 199 const int64 kInitialUsage = 2000; 200 quota_manager_proxy_->set_usage(kInitialUsage); 201 quota_manager_proxy_->set_quota(10000); 202 203 const int64 kSize = 1000; 204 backend_->ReleaseReservedQuota(GURL(kOrigin), type, kSize); 205 EXPECT_EQ(kInitialUsage - kSize, quota_manager_proxy_->usage()); 206 207 EXPECT_EQ(1, quota_manager_proxy_->storage_modified_count()); 208 } 209 210 TEST_F(QuotaBackendImplTest, CommitQuotaUsage) { 211 FileSystemType type = fileapi::kFileSystemTypeTemporary; 212 InitializeForOriginAndType(GURL(kOrigin), type); 213 quota_manager_proxy_->set_quota(10000); 214 base::FilePath path = GetUsageCachePath(GURL(kOrigin), type); 215 216 const int64 kDelta1 = 1000; 217 backend_->CommitQuotaUsage(GURL(kOrigin), type, kDelta1); 218 EXPECT_EQ(kDelta1, quota_manager_proxy_->usage()); 219 int64 usage = 0; 220 EXPECT_TRUE(file_system_usage_cache_.GetUsage(path, &usage)); 221 EXPECT_EQ(kDelta1, usage); 222 223 const int64 kDelta2 = -300; 224 backend_->CommitQuotaUsage(GURL(kOrigin), type, kDelta2); 225 EXPECT_EQ(kDelta1 + kDelta2, quota_manager_proxy_->usage()); 226 usage = 0; 227 EXPECT_TRUE(file_system_usage_cache_.GetUsage(path, &usage)); 228 EXPECT_EQ(kDelta1 + kDelta2, usage); 229 230 EXPECT_EQ(2, quota_manager_proxy_->storage_modified_count()); 231 } 232 233 TEST_F(QuotaBackendImplTest, DirtyCount) { 234 FileSystemType type = fileapi::kFileSystemTypeTemporary; 235 InitializeForOriginAndType(GURL(kOrigin), type); 236 base::FilePath path = GetUsageCachePath(GURL(kOrigin), type); 237 238 backend_->IncrementDirtyCount(GURL(kOrigin), type); 239 uint32 dirty = 0; 240 ASSERT_TRUE(file_system_usage_cache_.GetDirty(path, &dirty)); 241 EXPECT_EQ(1u, dirty); 242 243 backend_->DecrementDirtyCount(GURL(kOrigin), type); 244 ASSERT_TRUE(file_system_usage_cache_.GetDirty(path, &dirty)); 245 EXPECT_EQ(0u, dirty); 246 } 247 248 } // namespace fileapi 249