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