Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / content / browser / fileapi / file_writer_delegate_unittest.cc
blob1aacaccd2bbc9233bed20d0192f1bc7c640d5207
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.
5 #include <string>
6 #include <vector>
8 #include "base/basictypes.h"
9 #include "base/bind.h"
10 #include "base/bind_helpers.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 "content/public/test/async_file_test_helper.h"
15 #include "content/public/test/test_file_system_context.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/request_priority.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_job.h"
21 #include "net/url_request/url_request_job_factory.h"
22 #include "net/url_request/url_request_status.h"
23 #include "storage/browser/fileapi/file_system_context.h"
24 #include "storage/browser/fileapi/file_system_quota_util.h"
25 #include "storage/browser/fileapi/file_writer_delegate.h"
26 #include "storage/browser/fileapi/sandbox_file_stream_writer.h"
27 #include "storage/common/fileapi/file_system_mount_option.h"
28 #include "testing/platform_test.h"
29 #include "url/gurl.h"
31 using content::AsyncFileTestHelper;
32 using storage::FileSystemURL;
33 using storage::FileWriterDelegate;
35 namespace content {
37 namespace {
39 const GURL kOrigin("http://example.com");
40 const storage::FileSystemType kFileSystemType = storage::kFileSystemTypeTest;
42 const char kData[] = "The quick brown fox jumps over the lazy dog.\n";
43 const int kDataSize = arraysize(kData) - 1;
45 class Result {
46 public:
47 Result()
48 : status_(base::File::FILE_OK),
49 bytes_written_(0),
50 write_status_(FileWriterDelegate::SUCCESS_IO_PENDING) {}
52 base::File::Error status() const { return status_; }
53 int64 bytes_written() const { return bytes_written_; }
54 FileWriterDelegate::WriteProgressStatus write_status() const {
55 return write_status_;
58 void DidWrite(base::File::Error status, int64 bytes,
59 FileWriterDelegate::WriteProgressStatus write_status) {
60 write_status_ = write_status;
61 if (status == base::File::FILE_OK) {
62 bytes_written_ += bytes;
63 if (write_status_ != FileWriterDelegate::SUCCESS_IO_PENDING)
64 base::MessageLoop::current()->Quit();
65 } else {
66 EXPECT_EQ(base::File::FILE_OK, status_);
67 status_ = status;
68 base::MessageLoop::current()->Quit();
72 private:
73 // For post-operation status.
74 base::File::Error status_;
75 int64 bytes_written_;
76 FileWriterDelegate::WriteProgressStatus write_status_;
79 class BlobURLRequestJobFactory;
81 } // namespace (anonymous)
83 class FileWriterDelegateTest : public PlatformTest {
84 public:
85 FileWriterDelegateTest() {}
87 protected:
88 void SetUp() override;
89 void TearDown() override;
91 int64 usage() {
92 return file_system_context_->GetQuotaUtil(kFileSystemType)
93 ->GetOriginUsageOnFileTaskRunner(
94 file_system_context_.get(), kOrigin, kFileSystemType);
97 int64 GetFileSizeOnDisk(const char* test_file_path) {
98 // There might be in-flight flush/write.
99 base::MessageLoop::current()->PostTask(
100 FROM_HERE, base::Bind(&base::DoNothing));
101 base::RunLoop().RunUntilIdle();
103 FileSystemURL url = GetFileSystemURL(test_file_path);
104 base::File::Info file_info;
105 EXPECT_EQ(base::File::FILE_OK,
106 AsyncFileTestHelper::GetMetadata(
107 file_system_context_.get(), url, &file_info));
108 return file_info.size;
111 FileSystemURL GetFileSystemURL(const char* file_name) const {
112 return file_system_context_->CreateCrackedFileSystemURL(
113 kOrigin, kFileSystemType, base::FilePath().FromUTF8Unsafe(file_name));
116 FileWriterDelegate* CreateWriterDelegate(
117 const char* test_file_path,
118 int64 offset,
119 int64 allowed_growth) {
120 storage::SandboxFileStreamWriter* writer =
121 new storage::SandboxFileStreamWriter(
122 file_system_context_.get(),
123 GetFileSystemURL(test_file_path),
124 offset,
125 *file_system_context_->GetUpdateObservers(kFileSystemType));
126 writer->set_default_quota(allowed_growth);
127 return new FileWriterDelegate(scoped_ptr<storage::FileStreamWriter>(writer),
128 storage::FlushPolicy::FLUSH_ON_COMPLETION);
131 FileWriterDelegate::DelegateWriteCallback GetWriteCallback(Result* result) {
132 return base::Bind(&Result::DidWrite, base::Unretained(result));
135 // Creates and sets up a FileWriterDelegate for writing the given |blob_url|,
136 // and creates a new FileWriterDelegate for the file.
137 void PrepareForWrite(const char* test_file_path,
138 const GURL& blob_url,
139 int64 offset,
140 int64 allowed_growth) {
141 file_writer_delegate_.reset(
142 CreateWriterDelegate(test_file_path, offset, allowed_growth));
143 request_ = empty_context_.CreateRequest(
144 blob_url, net::DEFAULT_PRIORITY, file_writer_delegate_.get());
147 // This should be alive until the very end of this instance.
148 base::MessageLoopForIO loop_;
150 scoped_refptr<storage::FileSystemContext> file_system_context_;
152 net::URLRequestContext empty_context_;
153 scoped_ptr<FileWriterDelegate> file_writer_delegate_;
154 scoped_ptr<net::URLRequest> request_;
155 scoped_ptr<BlobURLRequestJobFactory> job_factory_;
157 base::ScopedTempDir dir_;
159 static const char* content_;
162 const char* FileWriterDelegateTest::content_ = NULL;
164 namespace {
166 static std::string g_content;
168 class FileWriterDelegateTestJob : public net::URLRequestJob {
169 public:
170 FileWriterDelegateTestJob(net::URLRequest* request,
171 net::NetworkDelegate* network_delegate,
172 const std::string& content)
173 : net::URLRequestJob(request, network_delegate),
174 content_(content),
175 remaining_bytes_(content.length()),
176 cursor_(0) {
179 void Start() override {
180 base::MessageLoop::current()->PostTask(
181 FROM_HERE,
182 base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
185 bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override {
186 if (remaining_bytes_ < buf_size)
187 buf_size = static_cast<int>(remaining_bytes_);
189 for (int i = 0; i < buf_size; ++i)
190 buf->data()[i] = content_[cursor_++];
191 remaining_bytes_ -= buf_size;
193 SetStatus(net::URLRequestStatus());
194 *bytes_read = buf_size;
195 return true;
198 int GetResponseCode() const override { return 200; }
200 protected:
201 ~FileWriterDelegateTestJob() override {}
203 private:
204 std::string content_;
205 int remaining_bytes_;
206 int cursor_;
209 class BlobURLRequestJobFactory : public net::URLRequestJobFactory {
210 public:
211 explicit BlobURLRequestJobFactory(const char** content_data)
212 : content_data_(content_data) {
215 net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
216 const std::string& scheme,
217 net::URLRequest* request,
218 net::NetworkDelegate* network_delegate) const override {
219 return new FileWriterDelegateTestJob(
220 request, network_delegate, *content_data_);
223 net::URLRequestJob* MaybeInterceptRedirect(
224 net::URLRequest* request,
225 net::NetworkDelegate* network_delegate,
226 const GURL& location) const override {
227 return nullptr;
230 net::URLRequestJob* MaybeInterceptResponse(
231 net::URLRequest* request,
232 net::NetworkDelegate* network_delegate) const override {
233 return nullptr;
236 bool IsHandledProtocol(const std::string& scheme) const override {
237 return scheme == "blob";
240 bool IsHandledURL(const GURL& url) const override {
241 return url.SchemeIs("blob");
244 bool IsSafeRedirectTarget(const GURL& location) const override {
245 return true;
248 private:
249 const char** content_data_;
251 DISALLOW_COPY_AND_ASSIGN(BlobURLRequestJobFactory);
254 } // namespace (anonymous)
256 void FileWriterDelegateTest::SetUp() {
257 ASSERT_TRUE(dir_.CreateUniqueTempDir());
259 file_system_context_ = CreateFileSystemContextForTesting(
260 NULL, dir_.path());
261 ASSERT_EQ(base::File::FILE_OK,
262 AsyncFileTestHelper::CreateFile(file_system_context_.get(),
263 GetFileSystemURL("test")));
264 job_factory_.reset(new BlobURLRequestJobFactory(&content_));
265 empty_context_.set_job_factory(job_factory_.get());
268 void FileWriterDelegateTest::TearDown() {
269 file_system_context_ = NULL;
270 base::RunLoop().RunUntilIdle();
273 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimit) {
274 const GURL kBlobURL("blob:nolimit");
275 content_ = kData;
277 PrepareForWrite("test", kBlobURL, 0, kint64max);
279 Result result;
280 ASSERT_EQ(0, usage());
281 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
282 base::MessageLoop::current()->Run();
284 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
285 file_writer_delegate_.reset();
287 ASSERT_EQ(kDataSize, usage());
288 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
289 EXPECT_EQ(kDataSize, result.bytes_written());
290 EXPECT_EQ(base::File::FILE_OK, result.status());
293 TEST_F(FileWriterDelegateTest, WriteSuccessWithJustQuota) {
294 const GURL kBlobURL("blob:just");
295 content_ = kData;
296 const int64 kAllowedGrowth = kDataSize;
297 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
299 Result result;
300 ASSERT_EQ(0, usage());
301 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
302 base::MessageLoop::current()->Run();
303 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
304 file_writer_delegate_.reset();
306 ASSERT_EQ(kAllowedGrowth, usage());
307 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
309 EXPECT_EQ(kAllowedGrowth, result.bytes_written());
310 EXPECT_EQ(base::File::FILE_OK, result.status());
313 TEST_F(FileWriterDelegateTest, DISABLED_WriteFailureByQuota) {
314 const GURL kBlobURL("blob:failure");
315 content_ = kData;
316 const int64 kAllowedGrowth = kDataSize - 1;
317 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
319 Result result;
320 ASSERT_EQ(0, usage());
321 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
322 base::MessageLoop::current()->Run();
323 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
324 file_writer_delegate_.reset();
326 ASSERT_EQ(kAllowedGrowth, usage());
327 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
329 EXPECT_EQ(kAllowedGrowth, result.bytes_written());
330 EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, result.status());
331 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
334 TEST_F(FileWriterDelegateTest, WriteZeroBytesSuccessfullyWithZeroQuota) {
335 const GURL kBlobURL("blob:zero");
336 content_ = "";
337 int64 kAllowedGrowth = 0;
338 PrepareForWrite("test", kBlobURL, 0, kAllowedGrowth);
340 Result result;
341 ASSERT_EQ(0, usage());
342 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
343 base::MessageLoop::current()->Run();
344 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
345 file_writer_delegate_.reset();
347 ASSERT_EQ(kAllowedGrowth, usage());
348 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
350 EXPECT_EQ(kAllowedGrowth, result.bytes_written());
351 EXPECT_EQ(base::File::FILE_OK, result.status());
352 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
355 TEST_F(FileWriterDelegateTest, WriteSuccessWithoutQuotaLimitConcurrent) {
356 scoped_ptr<FileWriterDelegate> file_writer_delegate2;
357 scoped_ptr<net::URLRequest> request2;
359 ASSERT_EQ(base::File::FILE_OK,
360 AsyncFileTestHelper::CreateFile(file_system_context_.get(),
361 GetFileSystemURL("test2")));
363 const GURL kBlobURL("blob:nolimitconcurrent");
364 const GURL kBlobURL2("blob:nolimitconcurrent2");
365 content_ = kData;
367 PrepareForWrite("test", kBlobURL, 0, kint64max);
369 // Credate another FileWriterDelegate for concurrent write.
370 file_writer_delegate2.reset(CreateWriterDelegate("test2", 0, kint64max));
371 request2 = empty_context_.CreateRequest(
372 kBlobURL2, net::DEFAULT_PRIORITY, file_writer_delegate2.get());
374 Result result, result2;
375 ASSERT_EQ(0, usage());
376 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
377 file_writer_delegate2->Start(request2.Pass(), GetWriteCallback(&result2));
378 base::MessageLoop::current()->Run();
379 if (result.write_status() == FileWriterDelegate::SUCCESS_IO_PENDING ||
380 result2.write_status() == FileWriterDelegate::SUCCESS_IO_PENDING)
381 base::MessageLoop::current()->Run();
383 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
384 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result2.write_status());
385 file_writer_delegate_.reset();
386 file_writer_delegate2.reset();
388 ASSERT_EQ(kDataSize * 2, usage());
389 EXPECT_EQ(GetFileSizeOnDisk("test") + GetFileSizeOnDisk("test2"), usage());
391 EXPECT_EQ(kDataSize, result.bytes_written());
392 EXPECT_EQ(base::File::FILE_OK, result.status());
393 EXPECT_EQ(kDataSize, result2.bytes_written());
394 EXPECT_EQ(base::File::FILE_OK, result2.status());
397 TEST_F(FileWriterDelegateTest, WritesWithQuotaAndOffset) {
398 const GURL kBlobURL("blob:failure-with-updated-quota");
399 content_ = kData;
401 // Writing kDataSize (=45) bytes data while allowed_growth is 100.
402 int64 offset = 0;
403 int64 allowed_growth = 100;
404 ASSERT_LT(kDataSize, allowed_growth);
405 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
408 Result result;
409 ASSERT_EQ(0, usage());
410 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
411 base::MessageLoop::current()->Run();
412 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
413 file_writer_delegate_.reset();
415 ASSERT_EQ(kDataSize, usage());
416 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
417 EXPECT_EQ(kDataSize, result.bytes_written());
418 EXPECT_EQ(base::File::FILE_OK, result.status());
421 // Trying to overwrite kDataSize bytes data while allowed_growth is 20.
422 offset = 0;
423 allowed_growth = 20;
424 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
427 Result result;
428 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
429 base::MessageLoop::current()->Run();
430 EXPECT_EQ(kDataSize, usage());
431 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
432 EXPECT_EQ(kDataSize, result.bytes_written());
433 EXPECT_EQ(base::File::FILE_OK, result.status());
434 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
437 // Trying to write kDataSize bytes data from offset 25 while
438 // allowed_growth is 55.
439 offset = 25;
440 allowed_growth = 55;
441 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
444 Result result;
445 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
446 base::MessageLoop::current()->Run();
447 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
448 file_writer_delegate_.reset();
450 EXPECT_EQ(offset + kDataSize, usage());
451 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
452 EXPECT_EQ(kDataSize, result.bytes_written());
453 EXPECT_EQ(base::File::FILE_OK, result.status());
456 // Trying to overwrite 45 bytes data while allowed_growth is -20.
457 offset = 0;
458 allowed_growth = -20;
459 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
460 int64 pre_write_usage = GetFileSizeOnDisk("test");
463 Result result;
464 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
465 base::MessageLoop::current()->Run();
466 ASSERT_EQ(FileWriterDelegate::SUCCESS_COMPLETED, result.write_status());
467 file_writer_delegate_.reset();
469 EXPECT_EQ(pre_write_usage, usage());
470 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
471 EXPECT_EQ(kDataSize, result.bytes_written());
472 EXPECT_EQ(base::File::FILE_OK, result.status());
475 // Trying to overwrite 45 bytes data with offset pre_write_usage - 20,
476 // while allowed_growth is 10.
477 const int kOverlap = 20;
478 offset = pre_write_usage - kOverlap;
479 allowed_growth = 10;
480 PrepareForWrite("test", kBlobURL, offset, allowed_growth);
483 Result result;
484 file_writer_delegate_->Start(request_.Pass(), GetWriteCallback(&result));
485 base::MessageLoop::current()->Run();
486 ASSERT_EQ(FileWriterDelegate::ERROR_WRITE_STARTED, result.write_status());
487 file_writer_delegate_.reset();
489 EXPECT_EQ(pre_write_usage + allowed_growth, usage());
490 EXPECT_EQ(GetFileSizeOnDisk("test"), usage());
491 EXPECT_EQ(kOverlap + allowed_growth, result.bytes_written());
492 EXPECT_EQ(base::File::FILE_ERROR_NO_SPACE, result.status());
496 } // namespace content