Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / fileapi / recursive_operation_delegate_unittest.cc
blob8fe83df4c0b160241490064f6e02fae6b92787c8
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 "webkit/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 "testing/gtest/include/gtest/gtest.h"
18 #include "webkit/browser/fileapi/file_system_file_util.h"
19 #include "webkit/browser/fileapi/file_system_operation.h"
20 #include "webkit/browser/fileapi/file_system_operation_runner.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 virtual ~LoggingRecursiveOperation() {}
50 const std::vector<LogEntry>& log_entries() const { return log_entries_; }
52 // RecursiveOperationDelegate overrides.
53 virtual void Run() OVERRIDE {
54 NOTREACHED();
57 virtual void RunRecursively() OVERRIDE {
58 StartRecursiveOperation(root_, callback_);
61 virtual void ProcessFile(const FileSystemURL& url,
62 const StatusCallback& callback) OVERRIDE {
63 RecordLogEntry(LogEntry::PROCESS_FILE, url);
64 operation_runner()->GetMetadata(
65 url,
66 base::Bind(&LoggingRecursiveOperation::DidGetMetadata,
67 weak_factory_.GetWeakPtr(), callback));
70 virtual void ProcessDirectory(const FileSystemURL& url,
71 const StatusCallback& callback) OVERRIDE {
72 RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url);
73 callback.Run(base::File::FILE_OK);
76 virtual void PostProcessDirectory(const FileSystemURL& url,
77 const StatusCallback& callback) OVERRIDE {
78 RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY, url);
79 callback.Run(base::File::FILE_OK);
82 private:
83 void RecordLogEntry(LogEntry::Type type, const FileSystemURL& url) {
84 LogEntry entry;
85 entry.type = type;
86 entry.url = url;
87 log_entries_.push_back(entry);
90 void DidGetMetadata(const StatusCallback& callback,
91 base::File::Error result,
92 const base::File::Info& file_info) {
93 if (result != base::File::FILE_OK) {
94 callback.Run(result);
95 return;
98 callback.Run(file_info.is_directory ?
99 base::File::FILE_ERROR_NOT_A_FILE :
100 base::File::FILE_OK);
103 FileSystemURL root_;
104 StatusCallback callback_;
105 std::vector<LogEntry> log_entries_;
107 base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_;
108 DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation);
111 void ReportStatus(base::File::Error* out_error,
112 base::File::Error error) {
113 DCHECK(out_error);
114 *out_error = error;
117 // To test the Cancel() during operation, calls Cancel() of |operation|
118 // after |counter| times message posting.
119 void CallCancelLater(storage::RecursiveOperationDelegate* operation,
120 int counter) {
121 if (counter > 0) {
122 base::MessageLoopProxy::current()->PostTask(
123 FROM_HERE,
124 base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1));
125 return;
128 operation->Cancel();
131 } // namespace
133 class RecursiveOperationDelegateTest : public testing::Test {
134 protected:
135 virtual void SetUp() OVERRIDE {
136 EXPECT_TRUE(base_.CreateUniqueTempDir());
137 sandbox_file_system_.SetUp(base_.path().AppendASCII("filesystem"));
140 virtual void TearDown() OVERRIDE {
141 sandbox_file_system_.TearDown();
144 scoped_ptr<FileSystemOperationContext> NewContext() {
145 FileSystemOperationContext* context =
146 sandbox_file_system_.NewOperationContext();
147 // Grant enough quota for all test cases.
148 context->set_allowed_bytes_growth(1000000);
149 return make_scoped_ptr(context);
152 storage::FileSystemFileUtil* file_util() {
153 return sandbox_file_system_.file_util();
156 FileSystemURL URLForPath(const std::string& path) const {
157 return sandbox_file_system_.CreateURLFromUTF8(path);
160 FileSystemURL CreateFile(const std::string& path) {
161 FileSystemURL url = URLForPath(path);
162 bool created = false;
163 EXPECT_EQ(base::File::FILE_OK,
164 file_util()->EnsureFileExists(NewContext().get(),
165 url, &created));
166 EXPECT_TRUE(created);
167 return url;
170 FileSystemURL CreateDirectory(const std::string& path) {
171 FileSystemURL url = URLForPath(path);
172 EXPECT_EQ(base::File::FILE_OK,
173 file_util()->CreateDirectory(NewContext().get(), url,
174 false /* exclusive */, true));
175 return url;
178 private:
179 base::MessageLoop message_loop_;
181 // Common temp base for nondestructive uses.
182 base::ScopedTempDir base_;
183 SandboxFileSystemTestHelper sandbox_file_system_;
186 TEST_F(RecursiveOperationDelegateTest, RootIsFile) {
187 FileSystemURL src_file(CreateFile("src"));
189 base::File::Error error = base::File::FILE_ERROR_FAILED;
190 scoped_ptr<FileSystemOperationContext> context = NewContext();
191 scoped_ptr<LoggingRecursiveOperation> operation(
192 new LoggingRecursiveOperation(
193 context->file_system_context(), src_file,
194 base::Bind(&ReportStatus, &error)));
195 operation->RunRecursively();
196 base::RunLoop().RunUntilIdle();
197 ASSERT_EQ(base::File::FILE_OK, error);
199 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
200 operation->log_entries();
201 ASSERT_EQ(1U, log_entries.size());
202 const LoggingRecursiveOperation::LogEntry& entry = log_entries[0];
203 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE, entry.type);
204 EXPECT_EQ(src_file, entry.url);
207 TEST_F(RecursiveOperationDelegateTest, RootIsDirectory) {
208 FileSystemURL src_root(CreateDirectory("src"));
209 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
210 FileSystemURL src_file1(CreateFile("src/file1"));
211 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
212 FileSystemURL src_file3(CreateFile("src/dir1/file3"));
214 base::File::Error error = base::File::FILE_ERROR_FAILED;
215 scoped_ptr<FileSystemOperationContext> context = NewContext();
216 scoped_ptr<LoggingRecursiveOperation> operation(
217 new LoggingRecursiveOperation(
218 context->file_system_context(), src_root,
219 base::Bind(&ReportStatus, &error)));
220 operation->RunRecursively();
221 base::RunLoop().RunUntilIdle();
222 ASSERT_EQ(base::File::FILE_OK, error);
224 const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
225 operation->log_entries();
226 ASSERT_EQ(8U, log_entries.size());
228 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
229 log_entries[0].type);
230 EXPECT_EQ(src_root, log_entries[0].url);
232 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
233 log_entries[1].type);
234 EXPECT_EQ(src_root, log_entries[1].url);
236 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
237 log_entries[2].type);
238 EXPECT_EQ(src_file1, log_entries[2].url);
240 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
241 log_entries[3].type);
242 EXPECT_EQ(src_dir1, log_entries[3].url);
244 // The order of src/dir1/file2 and src/dir1/file3 depends on the file system
245 // implementation (can be swapped).
246 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
247 log_entries[4].type);
248 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
249 log_entries[5].type);
250 EXPECT_TRUE((src_file2 == log_entries[4].url &&
251 src_file3 == log_entries[5].url) ||
252 (src_file3 == log_entries[4].url &&
253 src_file2 == log_entries[5].url));
255 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
256 log_entries[6].type);
257 EXPECT_EQ(src_dir1, log_entries[6].url);
259 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
260 log_entries[7].type);
261 EXPECT_EQ(src_root, log_entries[7].url);
264 TEST_F(RecursiveOperationDelegateTest, Cancel) {
265 FileSystemURL src_root(CreateDirectory("src"));
266 FileSystemURL src_dir1(CreateDirectory("src/dir1"));
267 FileSystemURL src_file1(CreateFile("src/file1"));
268 FileSystemURL src_file2(CreateFile("src/dir1/file2"));
270 base::File::Error error = base::File::FILE_ERROR_FAILED;
271 scoped_ptr<FileSystemOperationContext> context = NewContext();
272 scoped_ptr<LoggingRecursiveOperation> operation(
273 new LoggingRecursiveOperation(
274 context->file_system_context(), src_root,
275 base::Bind(&ReportStatus, &error)));
276 operation->RunRecursively();
278 // Invoke Cancel(), after 5 times message posting.
279 CallCancelLater(operation.get(), 5);
280 base::RunLoop().RunUntilIdle();
281 ASSERT_EQ(base::File::FILE_ERROR_ABORT, error);
284 } // namespace content