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"
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/location.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "content/public/test/sandbox_file_system_test_helper.h"
18 #include "storage/browser/fileapi/file_system_file_util.h"
19 #include "storage/browser/fileapi/file_system_operation.h"
20 #include "storage/browser/fileapi/file_system_operation_runner.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using storage::FileSystemContext
;
24 using storage::FileSystemOperationContext
;
25 using storage::FileSystemURL
;
30 class LoggingRecursiveOperation
: public storage::RecursiveOperationDelegate
{
36 POST_PROCESS_DIRECTORY
42 LoggingRecursiveOperation(FileSystemContext
* file_system_context
,
43 const FileSystemURL
& root
,
44 const StatusCallback
& callback
)
45 : storage::RecursiveOperationDelegate(file_system_context
),
48 weak_factory_(this) {}
49 ~LoggingRecursiveOperation() override
{}
51 const std::vector
<LogEntry
>& log_entries() const { return log_entries_
; }
53 // RecursiveOperationDelegate overrides.
54 void Run() override
{ NOTREACHED(); }
56 void RunRecursively() override
{ StartRecursiveOperation(root_
, callback_
); }
58 void ProcessFile(const FileSystemURL
& url
,
59 const StatusCallback
& callback
) override
{
60 RecordLogEntry(LogEntry::PROCESS_FILE
, url
);
61 operation_runner()->GetMetadata(
63 base::Bind(&LoggingRecursiveOperation::DidGetMetadata
,
64 weak_factory_
.GetWeakPtr(), callback
));
67 void ProcessDirectory(const FileSystemURL
& url
,
68 const StatusCallback
& callback
) override
{
69 RecordLogEntry(LogEntry::PROCESS_DIRECTORY
, url
);
70 callback
.Run(base::File::FILE_OK
);
73 void PostProcessDirectory(const FileSystemURL
& url
,
74 const StatusCallback
& callback
) override
{
75 RecordLogEntry(LogEntry::POST_PROCESS_DIRECTORY
, url
);
76 callback
.Run(base::File::FILE_OK
);
80 void RecordLogEntry(LogEntry::Type type
, const FileSystemURL
& url
) {
84 log_entries_
.push_back(entry
);
87 void DidGetMetadata(const StatusCallback
& callback
,
88 base::File::Error result
,
89 const base::File::Info
& file_info
) {
90 if (result
!= base::File::FILE_OK
) {
95 callback
.Run(file_info
.is_directory
?
96 base::File::FILE_ERROR_NOT_A_FILE
:
101 StatusCallback callback_
;
102 std::vector
<LogEntry
> log_entries_
;
104 base::WeakPtrFactory
<LoggingRecursiveOperation
> weak_factory_
;
105 DISALLOW_COPY_AND_ASSIGN(LoggingRecursiveOperation
);
108 void ReportStatus(base::File::Error
* out_error
,
109 base::File::Error error
) {
114 // To test the Cancel() during operation, calls Cancel() of |operation|
115 // after |counter| times message posting.
116 void CallCancelLater(storage::RecursiveOperationDelegate
* operation
,
119 base::ThreadTaskRunnerHandle::Get()->PostTask(
121 base::Bind(&CallCancelLater
, base::Unretained(operation
), counter
- 1));
130 class RecursiveOperationDelegateTest
: public testing::Test
{
132 void SetUp() override
{
133 EXPECT_TRUE(base_
.CreateUniqueTempDir());
134 sandbox_file_system_
.SetUp(base_
.path().AppendASCII("filesystem"));
137 void TearDown() override
{ sandbox_file_system_
.TearDown(); }
139 scoped_ptr
<FileSystemOperationContext
> NewContext() {
140 FileSystemOperationContext
* context
=
141 sandbox_file_system_
.NewOperationContext();
142 // Grant enough quota for all test cases.
143 context
->set_allowed_bytes_growth(1000000);
144 return make_scoped_ptr(context
);
147 storage::FileSystemFileUtil
* file_util() {
148 return sandbox_file_system_
.file_util();
151 FileSystemURL
URLForPath(const std::string
& path
) const {
152 return sandbox_file_system_
.CreateURLFromUTF8(path
);
155 FileSystemURL
CreateFile(const std::string
& path
) {
156 FileSystemURL url
= URLForPath(path
);
157 bool created
= false;
158 EXPECT_EQ(base::File::FILE_OK
,
159 file_util()->EnsureFileExists(NewContext().get(),
161 EXPECT_TRUE(created
);
165 FileSystemURL
CreateDirectory(const std::string
& path
) {
166 FileSystemURL url
= URLForPath(path
);
167 EXPECT_EQ(base::File::FILE_OK
,
168 file_util()->CreateDirectory(NewContext().get(), url
,
169 false /* exclusive */, true));
174 base::MessageLoop message_loop_
;
176 // Common temp base for nondestructive uses.
177 base::ScopedTempDir base_
;
178 SandboxFileSystemTestHelper sandbox_file_system_
;
181 TEST_F(RecursiveOperationDelegateTest
, RootIsFile
) {
182 FileSystemURL
src_file(CreateFile("src"));
184 base::File::Error error
= base::File::FILE_ERROR_FAILED
;
185 scoped_ptr
<FileSystemOperationContext
> context
= NewContext();
186 scoped_ptr
<LoggingRecursiveOperation
> operation(
187 new LoggingRecursiveOperation(
188 context
->file_system_context(), src_file
,
189 base::Bind(&ReportStatus
, &error
)));
190 operation
->RunRecursively();
191 base::RunLoop().RunUntilIdle();
192 ASSERT_EQ(base::File::FILE_OK
, error
);
194 const std::vector
<LoggingRecursiveOperation::LogEntry
>& log_entries
=
195 operation
->log_entries();
196 ASSERT_EQ(1U, log_entries
.size());
197 const LoggingRecursiveOperation::LogEntry
& entry
= log_entries
[0];
198 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE
, entry
.type
);
199 EXPECT_EQ(src_file
, entry
.url
);
202 TEST_F(RecursiveOperationDelegateTest
, RootIsDirectory
) {
203 FileSystemURL
src_root(CreateDirectory("src"));
204 FileSystemURL
src_dir1(CreateDirectory("src/dir1"));
205 FileSystemURL
src_file1(CreateFile("src/file1"));
206 FileSystemURL
src_file2(CreateFile("src/dir1/file2"));
207 FileSystemURL
src_file3(CreateFile("src/dir1/file3"));
209 base::File::Error error
= base::File::FILE_ERROR_FAILED
;
210 scoped_ptr
<FileSystemOperationContext
> context
= NewContext();
211 scoped_ptr
<LoggingRecursiveOperation
> operation(
212 new LoggingRecursiveOperation(
213 context
->file_system_context(), src_root
,
214 base::Bind(&ReportStatus
, &error
)));
215 operation
->RunRecursively();
216 base::RunLoop().RunUntilIdle();
217 ASSERT_EQ(base::File::FILE_OK
, error
);
219 const std::vector
<LoggingRecursiveOperation::LogEntry
>& log_entries
=
220 operation
->log_entries();
221 ASSERT_EQ(8U, log_entries
.size());
223 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE
,
224 log_entries
[0].type
);
225 EXPECT_EQ(src_root
, log_entries
[0].url
);
227 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY
,
228 log_entries
[1].type
);
229 EXPECT_EQ(src_root
, log_entries
[1].url
);
231 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE
,
232 log_entries
[2].type
);
233 EXPECT_EQ(src_file1
, log_entries
[2].url
);
235 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_DIRECTORY
,
236 log_entries
[3].type
);
237 EXPECT_EQ(src_dir1
, log_entries
[3].url
);
239 // The order of src/dir1/file2 and src/dir1/file3 depends on the file system
240 // implementation (can be swapped).
241 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE
,
242 log_entries
[4].type
);
243 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::PROCESS_FILE
,
244 log_entries
[5].type
);
245 EXPECT_TRUE((src_file2
== log_entries
[4].url
&&
246 src_file3
== log_entries
[5].url
) ||
247 (src_file3
== log_entries
[4].url
&&
248 src_file2
== log_entries
[5].url
));
250 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY
,
251 log_entries
[6].type
);
252 EXPECT_EQ(src_dir1
, log_entries
[6].url
);
254 EXPECT_EQ(LoggingRecursiveOperation::LogEntry::POST_PROCESS_DIRECTORY
,
255 log_entries
[7].type
);
256 EXPECT_EQ(src_root
, log_entries
[7].url
);
259 TEST_F(RecursiveOperationDelegateTest
, Cancel
) {
260 FileSystemURL
src_root(CreateDirectory("src"));
261 FileSystemURL
src_dir1(CreateDirectory("src/dir1"));
262 FileSystemURL
src_file1(CreateFile("src/file1"));
263 FileSystemURL
src_file2(CreateFile("src/dir1/file2"));
265 base::File::Error error
= base::File::FILE_ERROR_FAILED
;
266 scoped_ptr
<FileSystemOperationContext
> context
= NewContext();
267 scoped_ptr
<LoggingRecursiveOperation
> operation(
268 new LoggingRecursiveOperation(
269 context
->file_system_context(), src_root
,
270 base::Bind(&ReportStatus
, &error
)));
271 operation
->RunRecursively();
273 // Invoke Cancel(), after 5 times message posting.
274 CallCancelLater(operation
.get(), 5);
275 base::RunLoop().RunUntilIdle();
276 ASSERT_EQ(base::File::FILE_ERROR_ABORT
, error
);
279 } // namespace content