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.
5 #include "webkit/browser/fileapi/quota/quota_reservation_manager.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"
18 using fileapi::FileSystemType
;
19 using fileapi::kFileSystemTypeTemporary
;
20 using fileapi::OpenFileHandle
;
21 using fileapi::QuotaReservation
;
22 using fileapi::QuotaReservationManager
;
28 const char kOrigin
[] = "http://example.com";
29 const FileSystemType kType
= kFileSystemTypeTemporary
;
30 const int64 kInitialFileSize
= 1;
32 typedef QuotaReservationManager::ReserveQuotaCallback ReserveQuotaCallback
;
34 int64
GetFileSize(const base::FilePath
& path
) {
36 base::GetFileSize(path
, &size
);
40 void SetFileSize(const base::FilePath
& path
, int64 size
) {
41 base::File
file(path
, base::File::FLAG_OPEN_ALWAYS
| base::File::FLAG_WRITE
);
42 ASSERT_TRUE(file
.IsValid());
43 ASSERT_TRUE(file
.SetLength(size
));
46 class FakeBackend
: public QuotaReservationManager::QuotaBackend
{
49 : on_memory_usage_(kInitialFileSize
),
50 on_disk_usage_(kInitialFileSize
) {}
51 virtual ~FakeBackend() {}
53 virtual void ReserveQuota(const GURL
& origin
,
56 const ReserveQuotaCallback
& callback
) OVERRIDE
{
57 EXPECT_EQ(GURL(kOrigin
), origin
);
58 EXPECT_EQ(kType
, type
);
59 on_memory_usage_
+= delta
;
60 base::MessageLoopProxy::current()->PostTask(
62 base::Bind(base::IgnoreResult(callback
), base::File::FILE_OK
, delta
));
65 virtual void ReleaseReservedQuota(const GURL
& origin
,
67 int64 size
) OVERRIDE
{
69 EXPECT_EQ(GURL(kOrigin
), origin
);
70 EXPECT_EQ(kType
, type
);
71 on_memory_usage_
-= size
;
74 virtual void CommitQuotaUsage(const GURL
& origin
,
76 int64 delta
) OVERRIDE
{
77 EXPECT_EQ(GURL(kOrigin
), origin
);
78 EXPECT_EQ(kType
, type
);
79 on_disk_usage_
+= delta
;
80 on_memory_usage_
+= delta
;
83 virtual void IncrementDirtyCount(const GURL
& origin
,
84 FileSystemType type
) OVERRIDE
{}
85 virtual void DecrementDirtyCount(const GURL
& origin
,
86 FileSystemType type
) OVERRIDE
{}
88 int64
on_memory_usage() { return on_memory_usage_
; }
89 int64
on_disk_usage() { return on_disk_usage_
; }
92 int64 on_memory_usage_
;
95 DISALLOW_COPY_AND_ASSIGN(FakeBackend
);
100 explicit FakeWriter(scoped_ptr
<OpenFileHandle
> handle
)
101 : handle_(handle
.Pass()),
102 path_(handle_
->platform_path()),
103 max_written_offset_(handle_
->GetEstimatedFileSize()),
104 append_mode_write_amount_(0),
110 EXPECT_FALSE(dirty_
);
113 int64
Truncate(int64 length
) {
116 if (max_written_offset_
< length
) {
117 consumed
= length
- max_written_offset_
;
118 max_written_offset_
= length
;
120 SetFileSize(path_
, length
);
124 int64
Write(int64 max_offset
) {
128 if (max_written_offset_
< max_offset
) {
129 consumed
= max_offset
- max_written_offset_
;
130 max_written_offset_
= max_offset
;
132 if (GetFileSize(path_
) < max_offset
)
133 SetFileSize(path_
, max_offset
);
137 int64
Append(int64 amount
) {
139 append_mode_write_amount_
+= amount
;
140 SetFileSize(path_
, GetFileSize(path_
) + amount
);
145 handle_
->UpdateMaxWrittenOffset(max_written_offset_
);
146 handle_
->AddAppendModeWriteAmount(append_mode_write_amount_
);
147 max_written_offset_
= handle_
->GetEstimatedFileSize();
148 append_mode_write_amount_
= 0;
152 void ClearWithoutUsageReport() {
157 scoped_ptr
<OpenFileHandle
> handle_
;
158 base::FilePath path_
;
159 int64 max_written_offset_
;
160 int64 append_mode_write_amount_
;
164 void ExpectSuccess(bool* done
, base::File::Error error
) {
167 EXPECT_EQ(base::File::FILE_OK
, error
);
170 void RefreshReservation(QuotaReservation
* reservation
, int64 size
) {
174 reservation
->RefreshReservation(size
, base::Bind(&ExpectSuccess
, &done
));
175 base::RunLoop().RunUntilIdle();
181 class QuotaReservationManagerTest
: public testing::Test
{
183 QuotaReservationManagerTest() {}
184 virtual ~QuotaReservationManagerTest() {}
186 virtual void SetUp() OVERRIDE
{
187 ASSERT_TRUE(work_dir_
.CreateUniqueTempDir());
188 file_path_
= work_dir_
.path().Append(FILE_PATH_LITERAL("hoge"));
189 SetFileSize(file_path_
, kInitialFileSize
);
191 scoped_ptr
<QuotaReservationManager::QuotaBackend
> backend(new FakeBackend
);
192 reservation_manager_
.reset(new QuotaReservationManager(backend
.Pass()));
195 virtual void TearDown() OVERRIDE
{
196 reservation_manager_
.reset();
199 FakeBackend
* fake_backend() {
200 return static_cast<FakeBackend
*>(reservation_manager_
->backend_
.get());
203 QuotaReservationManager
* reservation_manager() {
204 return reservation_manager_
.get();
207 const base::FilePath
& file_path() const {
212 base::MessageLoop message_loop_
;
213 base::ScopedTempDir work_dir_
;
214 base::FilePath file_path_
;
215 scoped_ptr
<QuotaReservationManager
> reservation_manager_
;
217 DISALLOW_COPY_AND_ASSIGN(QuotaReservationManagerTest
);
220 TEST_F(QuotaReservationManagerTest
, BasicTest
) {
221 scoped_refptr
<QuotaReservation
> reservation
=
222 reservation_manager()->CreateReservation(GURL(kOrigin
), kType
);
225 RefreshReservation(reservation
.get(), 10 + 20 + 3);
226 int64 cached_reserved_quota
= reservation
->remaining_quota();
227 FakeWriter
writer(reservation
->GetOpenFileHandle(file_path()));
229 cached_reserved_quota
-= writer
.Write(kInitialFileSize
+ 10);
230 EXPECT_LE(0, cached_reserved_quota
);
231 cached_reserved_quota
-= writer
.Append(20);
232 EXPECT_LE(0, cached_reserved_quota
);
234 writer
.ReportUsage();
237 EXPECT_EQ(3, reservation
->remaining_quota());
238 EXPECT_EQ(kInitialFileSize
+ 10 + 20, GetFileSize(file_path()));
239 EXPECT_EQ(kInitialFileSize
+ 10 + 20, fake_backend()->on_disk_usage());
240 EXPECT_EQ(kInitialFileSize
+ 10 + 20 + 3, fake_backend()->on_memory_usage());
243 RefreshReservation(reservation
.get(), 5);
244 FakeWriter
writer(reservation
->GetOpenFileHandle(file_path()));
246 EXPECT_EQ(0, writer
.Truncate(3));
248 writer
.ReportUsage();
251 EXPECT_EQ(5, reservation
->remaining_quota());
252 EXPECT_EQ(3, GetFileSize(file_path()));
253 EXPECT_EQ(3, fake_backend()->on_disk_usage());
254 EXPECT_EQ(3 + 5, fake_backend()->on_memory_usage());
258 EXPECT_EQ(3, fake_backend()->on_memory_usage());
261 TEST_F(QuotaReservationManagerTest
, MultipleWriter
) {
262 scoped_refptr
<QuotaReservation
> reservation
=
263 reservation_manager()->CreateReservation(GURL(kOrigin
), kType
);
266 RefreshReservation(reservation
.get(), 10 + 20 + 30 + 40 + 5);
267 int64 cached_reserved_quota
= reservation
->remaining_quota();
268 FakeWriter
writer1(reservation
->GetOpenFileHandle(file_path()));
269 FakeWriter
writer2(reservation
->GetOpenFileHandle(file_path()));
270 FakeWriter
writer3(reservation
->GetOpenFileHandle(file_path()));
272 cached_reserved_quota
-= writer1
.Write(kInitialFileSize
+ 10);
273 EXPECT_LE(0, cached_reserved_quota
);
274 cached_reserved_quota
-= writer2
.Write(kInitialFileSize
+ 20);
275 cached_reserved_quota
-= writer3
.Append(30);
276 EXPECT_LE(0, cached_reserved_quota
);
277 cached_reserved_quota
-= writer3
.Append(40);
278 EXPECT_LE(0, cached_reserved_quota
);
280 writer1
.ReportUsage();
281 writer2
.ReportUsage();
282 writer3
.ReportUsage();
285 EXPECT_EQ(kInitialFileSize
+ 20 + 30 + 40, GetFileSize(file_path()));
286 EXPECT_EQ(kInitialFileSize
+ 10 + 20 + 30 + 40 + 5,
287 fake_backend()->on_memory_usage());
288 EXPECT_EQ(kInitialFileSize
+ 20 + 30 + 40, fake_backend()->on_disk_usage());
292 EXPECT_EQ(kInitialFileSize
+ 20 + 30 + 40, fake_backend()->on_disk_usage());
295 TEST_F(QuotaReservationManagerTest
, MultipleClient
) {
296 scoped_refptr
<QuotaReservation
> reservation1
=
297 reservation_manager()->CreateReservation(GURL(kOrigin
), kType
);
298 RefreshReservation(reservation1
, 10);
299 int64 cached_reserved_quota1
= reservation1
->remaining_quota();
301 scoped_refptr
<QuotaReservation
> reservation2
=
302 reservation_manager()->CreateReservation(GURL(kOrigin
), kType
);
303 RefreshReservation(reservation2
, 20);
304 int64 cached_reserved_quota2
= reservation2
->remaining_quota();
306 scoped_ptr
<FakeWriter
> writer1(
307 new FakeWriter(reservation1
->GetOpenFileHandle(file_path())));
309 scoped_ptr
<FakeWriter
> writer2(
310 new FakeWriter(reservation2
->GetOpenFileHandle(file_path())));
312 cached_reserved_quota1
-= writer1
->Write(kInitialFileSize
+ 10);
313 EXPECT_LE(0, cached_reserved_quota1
);
315 cached_reserved_quota2
-= writer2
->Append(20);
316 EXPECT_LE(0, cached_reserved_quota2
);
318 writer1
->ReportUsage();
319 RefreshReservation(reservation1
.get(), 2);
320 cached_reserved_quota1
= reservation1
->remaining_quota();
322 writer2
->ReportUsage();
323 RefreshReservation(reservation2
.get(), 3);
324 cached_reserved_quota2
= reservation2
->remaining_quota();
329 EXPECT_EQ(kInitialFileSize
+ 10 + 20, GetFileSize(file_path()));
330 EXPECT_EQ(kInitialFileSize
+ 10 + 20 + 2 + 3,
331 fake_backend()->on_memory_usage());
332 EXPECT_EQ(kInitialFileSize
+ 10 + 20, fake_backend()->on_disk_usage());
335 EXPECT_EQ(kInitialFileSize
+ 10 + 20 + 3, fake_backend()->on_memory_usage());
338 EXPECT_EQ(kInitialFileSize
+ 10 + 20, fake_backend()->on_memory_usage());
341 TEST_F(QuotaReservationManagerTest
, ClientCrash
) {
342 scoped_refptr
<QuotaReservation
> reservation1
=
343 reservation_manager()->CreateReservation(GURL(kOrigin
), kType
);
344 RefreshReservation(reservation1
.get(), 15);
346 scoped_refptr
<QuotaReservation
> reservation2
=
347 reservation_manager()->CreateReservation(GURL(kOrigin
), kType
);
348 RefreshReservation(reservation2
.get(), 20);
351 FakeWriter
writer(reservation1
->GetOpenFileHandle(file_path()));
353 writer
.Write(kInitialFileSize
+ 10);
355 reservation1
->OnClientCrash();
356 writer
.ClearWithoutUsageReport();
360 EXPECT_EQ(kInitialFileSize
+ 10, GetFileSize(file_path()));
361 EXPECT_EQ(kInitialFileSize
+ 15 + 20, fake_backend()->on_memory_usage());
362 EXPECT_EQ(kInitialFileSize
+ 10, fake_backend()->on_disk_usage());
365 EXPECT_EQ(kInitialFileSize
+ 10, fake_backend()->on_memory_usage());
368 } // namespace content