| OLD | NEW |
| (Empty) |
| 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_reservation_manager.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 9 #include "base/file_util.h" | |
| 10 #include "base/files/file.h" | |
| 11 #include "base/files/scoped_temp_dir.h" | |
| 12 #include "base/message_loop/message_loop.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 #include "webkit/browser/fileapi/quota/open_file_handle.h" | |
| 16 #include "webkit/browser/fileapi/quota/quota_reservation.h" | |
| 17 | |
| 18 namespace fileapi { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 const char kOrigin[] = "http://example.com"; | |
| 23 const FileSystemType kType = kFileSystemTypeTemporary; | |
| 24 const int64 kInitialFileSize = 1; | |
| 25 | |
| 26 typedef QuotaReservationManager::ReserveQuotaCallback ReserveQuotaCallback; | |
| 27 | |
| 28 int64 GetFileSize(const base::FilePath& path) { | |
| 29 int64 size = 0; | |
| 30 base::GetFileSize(path, &size); | |
| 31 return size; | |
| 32 } | |
| 33 | |
| 34 void SetFileSize(const base::FilePath& path, int64 size) { | |
| 35 base::File file(path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE); | |
| 36 ASSERT_TRUE(file.IsValid()); | |
| 37 ASSERT_TRUE(file.SetLength(size)); | |
| 38 } | |
| 39 | |
| 40 class FakeBackend : public QuotaReservationManager::QuotaBackend { | |
| 41 public: | |
| 42 FakeBackend() | |
| 43 : on_memory_usage_(kInitialFileSize), | |
| 44 on_disk_usage_(kInitialFileSize) {} | |
| 45 virtual ~FakeBackend() {} | |
| 46 | |
| 47 virtual void ReserveQuota(const GURL& origin, | |
| 48 FileSystemType type, | |
| 49 int64 delta, | |
| 50 const ReserveQuotaCallback& callback) OVERRIDE { | |
| 51 EXPECT_EQ(GURL(kOrigin), origin); | |
| 52 EXPECT_EQ(kType, type); | |
| 53 on_memory_usage_ += delta; | |
| 54 base::MessageLoopProxy::current()->PostTask( | |
| 55 FROM_HERE, | |
| 56 base::Bind(base::IgnoreResult(callback), base::File::FILE_OK, delta)); | |
| 57 } | |
| 58 | |
| 59 virtual void ReleaseReservedQuota(const GURL& origin, | |
| 60 FileSystemType type, | |
| 61 int64 size) OVERRIDE { | |
| 62 EXPECT_LE(0, size); | |
| 63 EXPECT_EQ(GURL(kOrigin), origin); | |
| 64 EXPECT_EQ(kType, type); | |
| 65 on_memory_usage_ -= size; | |
| 66 } | |
| 67 | |
| 68 virtual void CommitQuotaUsage(const GURL& origin, | |
| 69 FileSystemType type, | |
| 70 int64 delta) OVERRIDE { | |
| 71 EXPECT_EQ(GURL(kOrigin), origin); | |
| 72 EXPECT_EQ(kType, type); | |
| 73 on_disk_usage_ += delta; | |
| 74 on_memory_usage_ += delta; | |
| 75 } | |
| 76 | |
| 77 virtual void IncrementDirtyCount(const GURL& origin, | |
| 78 FileSystemType type) OVERRIDE {} | |
| 79 virtual void DecrementDirtyCount(const GURL& origin, | |
| 80 FileSystemType type) OVERRIDE {} | |
| 81 | |
| 82 int64 on_memory_usage() { return on_memory_usage_; } | |
| 83 int64 on_disk_usage() { return on_disk_usage_; } | |
| 84 | |
| 85 private: | |
| 86 int64 on_memory_usage_; | |
| 87 int64 on_disk_usage_; | |
| 88 | |
| 89 DISALLOW_COPY_AND_ASSIGN(FakeBackend); | |
| 90 }; | |
| 91 | |
| 92 class FakeWriter { | |
| 93 public: | |
| 94 explicit FakeWriter(scoped_ptr<OpenFileHandle> handle) | |
| 95 : handle_(handle.Pass()), | |
| 96 path_(handle_->platform_path()), | |
| 97 max_written_offset_(handle_->GetEstimatedFileSize()), | |
| 98 append_mode_write_amount_(0), | |
| 99 dirty_(false) { | |
| 100 } | |
| 101 | |
| 102 ~FakeWriter() { | |
| 103 if (handle_) | |
| 104 EXPECT_FALSE(dirty_); | |
| 105 } | |
| 106 | |
| 107 int64 Truncate(int64 length) { | |
| 108 int64 consumed = 0; | |
| 109 | |
| 110 if (max_written_offset_ < length) { | |
| 111 consumed = length - max_written_offset_; | |
| 112 max_written_offset_ = length; | |
| 113 } | |
| 114 SetFileSize(path_, length); | |
| 115 return consumed; | |
| 116 } | |
| 117 | |
| 118 int64 Write(int64 max_offset) { | |
| 119 dirty_ = true; | |
| 120 | |
| 121 int64 consumed = 0; | |
| 122 if (max_written_offset_ < max_offset) { | |
| 123 consumed = max_offset - max_written_offset_; | |
| 124 max_written_offset_ = max_offset; | |
| 125 } | |
| 126 if (GetFileSize(path_) < max_offset) | |
| 127 SetFileSize(path_, max_offset); | |
| 128 return consumed; | |
| 129 } | |
| 130 | |
| 131 int64 Append(int64 amount) { | |
| 132 dirty_ = true; | |
| 133 append_mode_write_amount_ += amount; | |
| 134 SetFileSize(path_, GetFileSize(path_) + amount); | |
| 135 return amount; | |
| 136 } | |
| 137 | |
| 138 void ReportUsage() { | |
| 139 handle_->UpdateMaxWrittenOffset(max_written_offset_); | |
| 140 handle_->AddAppendModeWriteAmount(append_mode_write_amount_); | |
| 141 max_written_offset_ = handle_->GetEstimatedFileSize(); | |
| 142 append_mode_write_amount_ = 0; | |
| 143 dirty_ = false; | |
| 144 } | |
| 145 | |
| 146 void ClearWithoutUsageReport() { | |
| 147 handle_.reset(); | |
| 148 } | |
| 149 | |
| 150 private: | |
| 151 scoped_ptr<OpenFileHandle> handle_; | |
| 152 base::FilePath path_; | |
| 153 int64 max_written_offset_; | |
| 154 int64 append_mode_write_amount_; | |
| 155 bool dirty_; | |
| 156 }; | |
| 157 | |
| 158 void ExpectSuccess(bool* done, base::File::Error error) { | |
| 159 EXPECT_FALSE(*done); | |
| 160 *done = true; | |
| 161 EXPECT_EQ(base::File::FILE_OK, error); | |
| 162 } | |
| 163 | |
| 164 void RefreshReservation(QuotaReservation* reservation, int64 size) { | |
| 165 DCHECK(reservation); | |
| 166 | |
| 167 bool done = false; | |
| 168 reservation->RefreshReservation(size, base::Bind(&ExpectSuccess, &done)); | |
| 169 base::RunLoop().RunUntilIdle(); | |
| 170 EXPECT_TRUE(done); | |
| 171 } | |
| 172 | |
| 173 } // namespace | |
| 174 | |
| 175 class QuotaReservationManagerTest : public testing::Test { | |
| 176 public: | |
| 177 QuotaReservationManagerTest() {} | |
| 178 virtual ~QuotaReservationManagerTest() {} | |
| 179 | |
| 180 virtual void SetUp() OVERRIDE { | |
| 181 ASSERT_TRUE(work_dir_.CreateUniqueTempDir()); | |
| 182 file_path_ = work_dir_.path().Append(FILE_PATH_LITERAL("hoge")); | |
| 183 SetFileSize(file_path_, kInitialFileSize); | |
| 184 | |
| 185 scoped_ptr<QuotaReservationManager::QuotaBackend> backend(new FakeBackend); | |
| 186 reservation_manager_.reset(new QuotaReservationManager(backend.Pass())); | |
| 187 } | |
| 188 | |
| 189 virtual void TearDown() OVERRIDE { | |
| 190 reservation_manager_.reset(); | |
| 191 } | |
| 192 | |
| 193 FakeBackend* fake_backend() { | |
| 194 return static_cast<FakeBackend*>(reservation_manager_->backend_.get()); | |
| 195 } | |
| 196 | |
| 197 QuotaReservationManager* reservation_manager() { | |
| 198 return reservation_manager_.get(); | |
| 199 } | |
| 200 | |
| 201 const base::FilePath& file_path() const { | |
| 202 return file_path_; | |
| 203 } | |
| 204 | |
| 205 private: | |
| 206 base::MessageLoop message_loop_; | |
| 207 base::ScopedTempDir work_dir_; | |
| 208 base::FilePath file_path_; | |
| 209 scoped_ptr<QuotaReservationManager> reservation_manager_; | |
| 210 | |
| 211 DISALLOW_COPY_AND_ASSIGN(QuotaReservationManagerTest); | |
| 212 }; | |
| 213 | |
| 214 TEST_F(QuotaReservationManagerTest, BasicTest) { | |
| 215 scoped_refptr<QuotaReservation> reservation = | |
| 216 reservation_manager()->CreateReservation(GURL(kOrigin), kType); | |
| 217 | |
| 218 { | |
| 219 RefreshReservation(reservation.get(), 10 + 20 + 3); | |
| 220 int64 cached_reserved_quota = reservation->remaining_quota(); | |
| 221 FakeWriter writer(reservation->GetOpenFileHandle(file_path())); | |
| 222 | |
| 223 cached_reserved_quota -= writer.Write(kInitialFileSize + 10); | |
| 224 EXPECT_LE(0, cached_reserved_quota); | |
| 225 cached_reserved_quota -= writer.Append(20); | |
| 226 EXPECT_LE(0, cached_reserved_quota); | |
| 227 | |
| 228 writer.ReportUsage(); | |
| 229 } | |
| 230 | |
| 231 EXPECT_EQ(3, reservation->remaining_quota()); | |
| 232 EXPECT_EQ(kInitialFileSize + 10 + 20, GetFileSize(file_path())); | |
| 233 EXPECT_EQ(kInitialFileSize + 10 + 20, fake_backend()->on_disk_usage()); | |
| 234 EXPECT_EQ(kInitialFileSize + 10 + 20 + 3, fake_backend()->on_memory_usage()); | |
| 235 | |
| 236 { | |
| 237 RefreshReservation(reservation.get(), 5); | |
| 238 FakeWriter writer(reservation->GetOpenFileHandle(file_path())); | |
| 239 | |
| 240 EXPECT_EQ(0, writer.Truncate(3)); | |
| 241 | |
| 242 writer.ReportUsage(); | |
| 243 } | |
| 244 | |
| 245 EXPECT_EQ(5, reservation->remaining_quota()); | |
| 246 EXPECT_EQ(3, GetFileSize(file_path())); | |
| 247 EXPECT_EQ(3, fake_backend()->on_disk_usage()); | |
| 248 EXPECT_EQ(3 + 5, fake_backend()->on_memory_usage()); | |
| 249 | |
| 250 reservation = NULL; | |
| 251 | |
| 252 EXPECT_EQ(3, fake_backend()->on_memory_usage()); | |
| 253 } | |
| 254 | |
| 255 TEST_F(QuotaReservationManagerTest, MultipleWriter) { | |
| 256 scoped_refptr<QuotaReservation> reservation = | |
| 257 reservation_manager()->CreateReservation(GURL(kOrigin), kType); | |
| 258 | |
| 259 { | |
| 260 RefreshReservation(reservation.get(), 10 + 20 + 30 + 40 + 5); | |
| 261 int64 cached_reserved_quota = reservation->remaining_quota(); | |
| 262 FakeWriter writer1(reservation->GetOpenFileHandle(file_path())); | |
| 263 FakeWriter writer2(reservation->GetOpenFileHandle(file_path())); | |
| 264 FakeWriter writer3(reservation->GetOpenFileHandle(file_path())); | |
| 265 | |
| 266 cached_reserved_quota -= writer1.Write(kInitialFileSize + 10); | |
| 267 EXPECT_LE(0, cached_reserved_quota); | |
| 268 cached_reserved_quota -= writer2.Write(kInitialFileSize + 20); | |
| 269 cached_reserved_quota -= writer3.Append(30); | |
| 270 EXPECT_LE(0, cached_reserved_quota); | |
| 271 cached_reserved_quota -= writer3.Append(40); | |
| 272 EXPECT_LE(0, cached_reserved_quota); | |
| 273 | |
| 274 writer1.ReportUsage(); | |
| 275 writer2.ReportUsage(); | |
| 276 writer3.ReportUsage(); | |
| 277 } | |
| 278 | |
| 279 EXPECT_EQ(kInitialFileSize + 20 + 30 + 40, GetFileSize(file_path())); | |
| 280 EXPECT_EQ(kInitialFileSize + 10 + 20 + 30 + 40 + 5, | |
| 281 fake_backend()->on_memory_usage()); | |
| 282 EXPECT_EQ(kInitialFileSize + 20 + 30 + 40, fake_backend()->on_disk_usage()); | |
| 283 | |
| 284 reservation = NULL; | |
| 285 | |
| 286 EXPECT_EQ(kInitialFileSize + 20 + 30 + 40, fake_backend()->on_disk_usage()); | |
| 287 } | |
| 288 | |
| 289 TEST_F(QuotaReservationManagerTest, MultipleClient) { | |
| 290 scoped_refptr<QuotaReservation> reservation1 = | |
| 291 reservation_manager()->CreateReservation(GURL(kOrigin), kType); | |
| 292 RefreshReservation(reservation1, 10); | |
| 293 int64 cached_reserved_quota1 = reservation1->remaining_quota(); | |
| 294 | |
| 295 scoped_refptr<QuotaReservation> reservation2 = | |
| 296 reservation_manager()->CreateReservation(GURL(kOrigin), kType); | |
| 297 RefreshReservation(reservation2, 20); | |
| 298 int64 cached_reserved_quota2 = reservation2->remaining_quota(); | |
| 299 | |
| 300 scoped_ptr<FakeWriter> writer1( | |
| 301 new FakeWriter(reservation1->GetOpenFileHandle(file_path()))); | |
| 302 | |
| 303 scoped_ptr<FakeWriter> writer2( | |
| 304 new FakeWriter(reservation2->GetOpenFileHandle(file_path()))); | |
| 305 | |
| 306 cached_reserved_quota1 -= writer1->Write(kInitialFileSize + 10); | |
| 307 EXPECT_LE(0, cached_reserved_quota1); | |
| 308 | |
| 309 cached_reserved_quota2 -= writer2->Append(20); | |
| 310 EXPECT_LE(0, cached_reserved_quota2); | |
| 311 | |
| 312 writer1->ReportUsage(); | |
| 313 RefreshReservation(reservation1.get(), 2); | |
| 314 cached_reserved_quota1 = reservation1->remaining_quota(); | |
| 315 | |
| 316 writer2->ReportUsage(); | |
| 317 RefreshReservation(reservation2.get(), 3); | |
| 318 cached_reserved_quota2 = reservation2->remaining_quota(); | |
| 319 | |
| 320 writer1.reset(); | |
| 321 writer2.reset(); | |
| 322 | |
| 323 EXPECT_EQ(kInitialFileSize + 10 + 20, GetFileSize(file_path())); | |
| 324 EXPECT_EQ(kInitialFileSize + 10 + 20 + 2 + 3, | |
| 325 fake_backend()->on_memory_usage()); | |
| 326 EXPECT_EQ(kInitialFileSize + 10 + 20, fake_backend()->on_disk_usage()); | |
| 327 | |
| 328 reservation1 = NULL; | |
| 329 EXPECT_EQ(kInitialFileSize + 10 + 20 + 3, fake_backend()->on_memory_usage()); | |
| 330 | |
| 331 reservation2 = NULL; | |
| 332 EXPECT_EQ(kInitialFileSize + 10 + 20, fake_backend()->on_memory_usage()); | |
| 333 } | |
| 334 | |
| 335 TEST_F(QuotaReservationManagerTest, ClientCrash) { | |
| 336 scoped_refptr<QuotaReservation> reservation1 = | |
| 337 reservation_manager()->CreateReservation(GURL(kOrigin), kType); | |
| 338 RefreshReservation(reservation1.get(), 15); | |
| 339 | |
| 340 scoped_refptr<QuotaReservation> reservation2 = | |
| 341 reservation_manager()->CreateReservation(GURL(kOrigin), kType); | |
| 342 RefreshReservation(reservation2.get(), 20); | |
| 343 | |
| 344 { | |
| 345 FakeWriter writer(reservation1->GetOpenFileHandle(file_path())); | |
| 346 | |
| 347 writer.Write(kInitialFileSize + 10); | |
| 348 | |
| 349 reservation1->OnClientCrash(); | |
| 350 writer.ClearWithoutUsageReport(); | |
| 351 } | |
| 352 reservation1 = NULL; | |
| 353 | |
| 354 EXPECT_EQ(kInitialFileSize + 10, GetFileSize(file_path())); | |
| 355 EXPECT_EQ(kInitialFileSize + 15 + 20, fake_backend()->on_memory_usage()); | |
| 356 EXPECT_EQ(kInitialFileSize + 10, fake_backend()->on_disk_usage()); | |
| 357 | |
| 358 reservation2 = NULL; | |
| 359 EXPECT_EQ(kInitialFileSize + 10, fake_backend()->on_memory_usage()); | |
| 360 } | |
| 361 | |
| 362 } // namespace fileapi | |
| OLD | NEW |