3885384462898ad163f77d973200e35ed9646391
[platform/framework/web/crosswalk.git] / src / content / browser / fileapi / recursive_operation_delegate_unittest.cc
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.
4
5 #include "storage/browser/fileapi/recursive_operation_delegate.h"
6
7 #include <vector>
8
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"
21
22 using storage::FileSystemContext;
23 using storage::FileSystemOperationContext;
24 using storage::FileSystemURL;
25
26 namespace content {
27 namespace {
28
29 class LoggingRecursiveOperation : public storage::RecursiveOperationDelegate {
30  public:
31   struct LogEntry {
32     enum Type {
33       PROCESS_FILE,
34       PROCESS_DIRECTORY,
35       POST_PROCESS_DIRECTORY
36     };
37     Type type;
38     FileSystemURL url;
39   };
40
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 {}
49
50   const std::vector<LogEntry>& log_entries() const { return log_entries_; }
51
52   // RecursiveOperationDelegate overrides.
53   void Run() override { NOTREACHED(); }
54
55   void RunRecursively() override { StartRecursiveOperation(root_, callback_); }
56
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));
64   }
65
66   void ProcessDirectory(const FileSystemURL& url,
67                         const StatusCallback& callback) override {
68     RecordLogEntry(LogEntry::PROCESS_DIRECTORY, url);
69     callback.Run(base::File::FILE_OK);
70   }
71
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);
76   }
77
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);
84   }
85
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;
92     }
93
94     callback.Run(file_info.is_directory ?
95                  base::File::FILE_ERROR_NOT_A_FILE :
96                  base::File::FILE_OK);
97   }
98
99   FileSystemURL root_;
100   StatusCallback callback_;
101   std::vector<LogEntry> log_entries_;
102
103   base::WeakPtrFactory<LoggingRecursiveOperation> weak_factory_;
104   DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation);
105 };
106
107 void ReportStatus(base::File::Error* out_error,
108                   base::File::Error error) {
109   DCHECK(out_error);
110   *out_error = error;
111 }
112
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;
122   }
123
124   operation->Cancel();
125 }
126
127 }  // namespace
128
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"));
134   }
135
136   void TearDown() override { sandbox_file_system_.TearDown(); }
137
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);
144   }
145
146   storage::FileSystemFileUtil* file_util() {
147     return sandbox_file_system_.file_util();
148   }
149
150   FileSystemURL URLForPath(const std::string& path) const {
151     return sandbox_file_system_.CreateURLFromUTF8(path);
152   }
153
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;
162   }
163
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;
170   }
171
172  private:
173   base::MessageLoop message_loop_;
174
175   // Common temp base for nondestructive uses.
176   base::ScopedTempDir base_;
177   SandboxFileSystemTestHelper sandbox_file_system_;
178 };
179
180 TEST_F(RecursiveOperationDelegateTest, RootIsFile) {
181   FileSystemURL src_file(CreateFile("src"));
182
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);
192
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);
199 }
200
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"));
207
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);
217
218   const std::vector<LoggingRecursiveOperation::LogEntry>& log_entries =
219       operation->log_entries();
220   ASSERT_EQ(8U, log_entries.size());
221
222   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
223             log_entries[0].type);
224   EXPECT_EQ(src_root, log_entries[0].url);
225
226   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
227             log_entries[1].type);
228   EXPECT_EQ(src_root, log_entries[1].url);
229
230   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE,
231             log_entries[2].type);
232   EXPECT_EQ(src_file1, log_entries[2].url);
233
234   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY,
235             log_entries[3].type);
236   EXPECT_EQ(src_dir1, log_entries[3].url);
237
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));
248
249   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
250             log_entries[6].type);
251   EXPECT_EQ(src_dir1, log_entries[6].url);
252
253   EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY,
254             log_entries[7].type);
255   EXPECT_EQ(src_root, log_entries[7].url);
256 }
257
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"));
263
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();
271
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);
276 }
277
278 }  // namespace content