Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / fileapi / recursive_operation_delegate_unittest.cc
blob3885384462898ad163f77d973200e35ed9646391
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 "storage/browser/fileapi/recursive_operation_delegate.h"
7 #include <vector>
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/run_loop.h"
16 #include "content/public/test/sandbox_file_system_test_helper.h"
17 #include "storage/browser/fileapi/file_system_file_util.h"
18 #include "storage/browser/fileapi/file_system_operation.h"
19 #include "storage/browser/fileapi/file_system_operation_runner.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using storage::FileSystemContext;
23 using storage::FileSystemOperationContext;
24 using storage::FileSystemURL;
26 namespace content {
27 namespace {
29 class LoggingRecursiveOperation : public storage::RecursiveOperationDelegate {
30 public:
31 struct LogEntry {
32 enum Type {
33 PROCESS_FILE,
34 PROCESS_DIRECTORY,
35 POST_PROCESS_DIRECTORY
37 Type type;
38 FileSystemURL url;
41 LoggingRecursiveOperation(FileSystemContext* file_system_context,
42 const FileSystemURL& root,
43 const StatusCallback& callback)
44 : storage::RecursiveOperationDelegate(file_system_context),
45 root_(root),
46 callback_(callback),
47 weak_factory_(this) {}
48 ~LoggingRecursiveOperation() override {}
50 const std::vector<LogEntry>& log_entries() const { return log_entries_; }
52 // RecursiveOperationDelegate overrides.
53 void Run() override { NOTREACHED(); }
55 void RunRecursively() override { StartRecursiveOperation(root_, callback_); }
57 void ProcessFile(const FileSystemURL& url,
58 const StatusCallback& callback) override {
59 RecordLogEntry(LogEntry::PROCESS_FILE, url);
60 operation_runner()->GetMetadata(
61 url,
62 base::Bind(&LoggingRecursiveOperation::DidGetMetadata,
63 weak_factory_.GetWeakPtr(), callback));
66 void ProcessDirectory(const FileSystemURL& url,
67 const StatusCallback& callback) override {
68 RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url);
69 callback.Run(base::File::FILE_OK);
72 void PostProcessDirectory(const FileSystemURL& url,
73 const StatusCallback& callback) override {
74 RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url);
75 callback.Run(base::File::FILE_OK);
78 private:
79 void RecordLogEntry(LogEntry::Type type, const FileSystemURL& url) {
80 LogEntry entry;
81 entry.type = type;
82 entry.url = url;
83 log_entries_.push_back(entry);
86 void DidGetMetadata(const StatusCallback& callback,
87 base::File::Error result,
88 const base::File::Info& file_info) {
89 if (result != base::File::FILE_OK) {
90 callback.Run(result);
91 return;
94 callback.Run(file_info.is_directory ?
95 base::File::FILE_ERROR_NOT_A_FILE :
96 base::File::FILE_OK);
99 FileSystemURL root_;
100 StatusCallback callback_;
101 std::vector<LogEntry> log_entries_;
103 base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_;
104 DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation);
107 void ReportStatus(base::File::Error* out_error,
108 base::File::Error error) {
109 DCHECK(out_error);
110 *out_error = error;
113 // To test the Cancel() during operation, calls Cancel() of |operation|
114 // after |counter| times message posting.
115 void CallCancelLater(storage::RecursiveOperationDelegate* operation,
116 int counter) {
117 if (counter > 0) {
118 base::MessageLoopProxy::current()->PostTask(
119 FROM_HERE,
120 base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1));
121 return;
124 operation->Cancel();
127 } // namespace
129 class RecursiveOperationDelegateTest : public testing::Test {
130 protected:
131 void SetUp() override {
132 EXPECT_TRUE(base_.CreateUniqueTempDir());
133 sandbox_file_system_.SetUp(base_.path().AppendASCII("filesystem"));
136 void TearDown() override { sandbox_file_system_.TearDown(); }
138 scoped_ptr<FileSystemOperationContext> NewContext() {
139 FileSystemOperationContext* context =
140 sandbox_file_system_.NewOperationContext();
141 // Grant enough quota for all test cases.
142 context->set_allowed_bytes_growth(1000000);
143 return make_scoped_ptr(context);
146 storage::FileSystemFileUtil* file_util() {
147 return sandbox_file_system_.file_util();
150 FileSystemURL URLForPath(const std::string& path) const {
151 return sandbox_file_system_.CreateURLFromUTF8(path);
154 FileSystemURL CreateFile(const std::string& path) {
155 FileSystemURL url = URLForPath(path);
156 bool created = false;
157 EXPECT_EQ(base::File::FILE_OK,
158 file_util()->EnsureFileExists(NewContext().get(),
159 url, &created));
160 EXPECT_TRUE(created);
161 return url;
164 FileSystemURL CreateDirectory(const std::string& path) {
165 FileSystemURL url = URLForPath(path);
166 EXPECT_EQ(base::File::FILE_OK,
167 file_util()->CreateDirectory(NewContext().get(), url,
168 false /* exclusive */, true));
169 return url;
172 private:
173 base::MessageLoop message_loop_;
175 // Common temp base for nondestructive uses.
176 base::ScopedTempDir base_;
177 SandboxFileSystemTestHelper sandbox_file_system_;
180 TEST_F(RecursiveOperationDelegateTest, RootIsFile) {
181 FileSystemURL src_file(CreateFile("src"));
183 base::File::Error error = base::File::FILE_ERROR_FAILED;
184 scoped_ptr<FileSystemOperationContext> context = NewContext();
185 scoped_ptr<LoggingRecursiveOperation> operation(
186 new LoggingRecursiveOperation(
187 context->file_system_context(), src_file,
188 base::Bind(&ReportStatus, &error)));
189 operation->RunRecursively();
190 base::RunLoop().RunUntilIdle();
191 ASSERT_EQ(base::File::FILE_OK, error);
193 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
194 operation->log_entries();
195 ASSERT_EQ(1U, log_entries.size());
196 const LoggingRecursiveOperation::LogEntry& entry = log_entries[0];
197 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, entry.type);
198 EXPECT_EQ(src_file, entry.url);
201 TEST_F(RecursiveOperationDelegateTest, RootIsDirectory) {
202 FileSystemURL src_root(CreateDirectory("src"));
203 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
204 FileSystemURL src_file1(CreateFile("src/file1"));
205 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
206 FileSystemURL src_file3(CreateFile("src/dir1/file3"));
208 base::File::Error error = base::File::FILE_ERROR_FAILED;
209 scoped_ptr<FileSystemOperationContext> context = NewContext();
210 scoped_ptr<LoggingRecursiveOperation> operation(
211 new LoggingRecursiveOperation(
212 context->file_system_context(), src_root,
213 base::Bind(&ReportStatus, &error)));
214 operation->RunRecursively();
215 base::RunLoop().RunUntilIdle();
216 ASSERT_EQ(base::File::FILE_OK, error);
218 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
219 operation->log_entries();
220 ASSERT_EQ(8U, log_entries.size());
222 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
223 log_entries[0].type);
224 EXPECT_EQ(src_root, log_entries[0].url);
226 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
227 log_entries[1].type);
228 EXPECT_EQ(src_root, log_entries[1].url);
230 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
231 log_entries[2].type);
232 EXPECT_EQ(src_file1, log_entries[2].url);
234 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
235 log_entries[3].type);
236 EXPECT_EQ(src_dir1, log_entries[3].url);
238 // The order of src/dir1/file2 and src/dir1/file3 depends on the file system
239 // implementation (can be swapped).
240 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
241 log_entries[4].type);
242 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
243 log_entries[5].type);
244 EXPECT_TRUE((src_file2 == log_entries[4].url &&
245 src_file3 == log_entries[5].url) ||
246 (src_file3 == log_entries[4].url &&
247 src_file2 == log_entries[5].url));
249 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
250 log_entries[6].type);
251 EXPECT_EQ(src_dir1, log_entries[6].url);
253 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
254 log_entries[7].type);
255 EXPECT_EQ(src_root, log_entries[7].url);
258 TEST_F(RecursiveOperationDelegateTest, Cancel) {
259 FileSystemURL src_root(CreateDirectory("src"));
260 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
261 FileSystemURL src_file1(CreateFile("src/file1"));
262 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
264 base::File::Error error = base::File::FILE_ERROR_FAILED;
265 scoped_ptr<FileSystemOperationContext> context = NewContext();
266 scoped_ptr<LoggingRecursiveOperation> operation(
267 new LoggingRecursiveOperation(
268 context->file_system_context(), src_root,
269 base::Bind(&ReportStatus, &error)));
270 operation->RunRecursively();
272 // Invoke Cancel(), after 5 times message posting.
273 CallCancelLater(operation.get(), 5);
274 base::RunLoop().RunUntilIdle();
275 ASSERT_EQ(base::File::FILE_ERROR_ABORT, error);
278 } // namespace content