1 // Copyright 2014 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/test/async_file_test_helper.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/run_loop.h"
13 #include "storage/browser/blob/shareable_file_reference.h"
14 #include "storage/browser/file_system/file_system_backend.h"
15 #include "storage/browser/file_system/file_system_context.h"
16 #include "storage/browser/file_system/file_system_operation_runner.h"
17 #include "storage/browser/file_system/file_system_url.h"
18 #include "storage/browser/quota/quota_manager.h"
19 #include "storage/common/file_system/file_system_util.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 namespace storage {
23 
24 using FileEntryList = FileSystemOperation::FileEntryList;
25 
26 namespace {
27 
AssignAndQuit(base::RunLoop * run_loop,base::File::Error * result_out,base::File::Error result)28 void AssignAndQuit(base::RunLoop* run_loop,
29                    base::File::Error* result_out,
30                    base::File::Error result) {
31   *result_out = result;
32   run_loop->Quit();
33 }
34 
AssignAndQuitCallback(base::RunLoop * run_loop,base::File::Error * result)35 base::OnceCallback<void(base::File::Error)> AssignAndQuitCallback(
36     base::RunLoop* run_loop,
37     base::File::Error* result) {
38   return base::BindOnce(&AssignAndQuit, run_loop, base::Unretained(result));
39 }
40 
GetMetadataCallback(base::RunLoop * run_loop,base::File::Error * result_out,base::File::Info * file_info_out,base::File::Error result,const base::File::Info & file_info)41 void GetMetadataCallback(base::RunLoop* run_loop,
42                          base::File::Error* result_out,
43                          base::File::Info* file_info_out,
44                          base::File::Error result,
45                          const base::File::Info& file_info) {
46   *result_out = result;
47   if (file_info_out)
48     *file_info_out = file_info;
49   run_loop->Quit();
50 }
51 
CreateSnapshotFileCallback(base::RunLoop * run_loop,base::File::Error * result_out,base::FilePath * platform_path_out,base::File::Error result,const base::File::Info & file_info,const base::FilePath & platform_path,scoped_refptr<ShareableFileReference> file_ref)52 void CreateSnapshotFileCallback(
53     base::RunLoop* run_loop,
54     base::File::Error* result_out,
55     base::FilePath* platform_path_out,
56     base::File::Error result,
57     const base::File::Info& file_info,
58     const base::FilePath& platform_path,
59     scoped_refptr<ShareableFileReference> file_ref) {
60   DCHECK(!file_ref.get());
61   *result_out = result;
62   if (platform_path_out)
63     *platform_path_out = platform_path;
64   run_loop->Quit();
65 }
66 
ReadDirectoryCallback(base::RunLoop * run_loop,base::File::Error * result_out,FileEntryList * entries_out,base::File::Error result,FileEntryList entries,bool has_more)67 void ReadDirectoryCallback(base::RunLoop* run_loop,
68                            base::File::Error* result_out,
69                            FileEntryList* entries_out,
70                            base::File::Error result,
71                            FileEntryList entries,
72                            bool has_more) {
73   *result_out = result;
74   entries_out->insert(entries_out->end(), entries.begin(), entries.end());
75   if (result != base::File::FILE_OK || !has_more)
76     run_loop->Quit();
77 }
78 
DidGetUsageAndQuota(blink::mojom::QuotaStatusCode * status_out,int64_t * usage_out,int64_t * quota_out,base::OnceClosure done_callback,blink::mojom::QuotaStatusCode status,int64_t usage,int64_t quota)79 void DidGetUsageAndQuota(blink::mojom::QuotaStatusCode* status_out,
80                          int64_t* usage_out,
81                          int64_t* quota_out,
82                          base::OnceClosure done_callback,
83                          blink::mojom::QuotaStatusCode status,
84                          int64_t usage,
85                          int64_t quota) {
86   if (status_out)
87     *status_out = status;
88   if (usage_out)
89     *usage_out = usage;
90   if (quota_out)
91     *quota_out = quota;
92   if (done_callback)
93     std::move(done_callback).Run();
94 }
95 
96 }  // namespace
97 
98 const int64_t AsyncFileTestHelper::kDontCheckSize = -1;
99 
Copy(FileSystemContext * context,const FileSystemURL & src,const FileSystemURL & dest)100 base::File::Error AsyncFileTestHelper::Copy(FileSystemContext* context,
101                                             const FileSystemURL& src,
102                                             const FileSystemURL& dest) {
103   return CopyWithProgress(context, src, dest, CopyProgressCallback());
104 }
105 
CopyWithProgress(FileSystemContext * context,const FileSystemURL & src,const FileSystemURL & dest,const CopyProgressCallback & progress_callback)106 base::File::Error AsyncFileTestHelper::CopyWithProgress(
107     FileSystemContext* context,
108     const FileSystemURL& src,
109     const FileSystemURL& dest,
110     const CopyProgressCallback& progress_callback) {
111   base::File::Error result = base::File::FILE_ERROR_FAILED;
112   base::RunLoop run_loop;
113   context->operation_runner()->Copy(src, dest, FileSystemOperation::OPTION_NONE,
114                                     FileSystemOperation::ERROR_BEHAVIOR_ABORT,
115                                     progress_callback,
116                                     AssignAndQuitCallback(&run_loop, &result));
117   run_loop.Run();
118   return result;
119 }
120 
Move(FileSystemContext * context,const FileSystemURL & src,const FileSystemURL & dest)121 base::File::Error AsyncFileTestHelper::Move(FileSystemContext* context,
122                                             const FileSystemURL& src,
123                                             const FileSystemURL& dest) {
124   base::File::Error result = base::File::FILE_ERROR_FAILED;
125   base::RunLoop run_loop;
126   context->operation_runner()->Move(src, dest, FileSystemOperation::OPTION_NONE,
127                                     AssignAndQuitCallback(&run_loop, &result));
128   run_loop.Run();
129   return result;
130 }
131 
Remove(FileSystemContext * context,const FileSystemURL & url,bool recursive)132 base::File::Error AsyncFileTestHelper::Remove(FileSystemContext* context,
133                                               const FileSystemURL& url,
134                                               bool recursive) {
135   base::File::Error result = base::File::FILE_ERROR_FAILED;
136   base::RunLoop run_loop;
137   context->operation_runner()->Remove(
138       url, recursive, AssignAndQuitCallback(&run_loop, &result));
139   run_loop.Run();
140   return result;
141 }
142 
ReadDirectory(FileSystemContext * context,const FileSystemURL & url,FileEntryList * entries)143 base::File::Error AsyncFileTestHelper::ReadDirectory(FileSystemContext* context,
144                                                      const FileSystemURL& url,
145                                                      FileEntryList* entries) {
146   base::File::Error result = base::File::FILE_ERROR_FAILED;
147   DCHECK(entries);
148   entries->clear();
149   base::RunLoop run_loop;
150   context->operation_runner()->ReadDirectory(
151       url,
152       base::BindRepeating(&ReadDirectoryCallback, &run_loop, &result, entries));
153   run_loop.Run();
154   return result;
155 }
156 
CreateDirectory(FileSystemContext * context,const FileSystemURL & url)157 base::File::Error AsyncFileTestHelper::CreateDirectory(
158     FileSystemContext* context,
159     const FileSystemURL& url) {
160   base::File::Error result = base::File::FILE_ERROR_FAILED;
161   base::RunLoop run_loop;
162   context->operation_runner()->CreateDirectory(
163       url, false /* exclusive */, false /* recursive */,
164       AssignAndQuitCallback(&run_loop, &result));
165   run_loop.Run();
166   return result;
167 }
168 
CreateFile(FileSystemContext * context,const FileSystemURL & url)169 base::File::Error AsyncFileTestHelper::CreateFile(FileSystemContext* context,
170                                                   const FileSystemURL& url) {
171   base::File::Error result = base::File::FILE_ERROR_FAILED;
172   base::RunLoop run_loop;
173   context->operation_runner()->CreateFile(
174       url, false /* exclusive */, AssignAndQuitCallback(&run_loop, &result));
175   run_loop.Run();
176   return result;
177 }
178 
CreateFileWithData(FileSystemContext * context,const FileSystemURL & url,const char * buf,int buf_size)179 base::File::Error AsyncFileTestHelper::CreateFileWithData(
180     FileSystemContext* context,
181     const FileSystemURL& url,
182     const char* buf,
183     int buf_size) {
184   base::ScopedTempDir dir;
185   if (!dir.CreateUniqueTempDir())
186     return base::File::FILE_ERROR_FAILED;
187   base::FilePath local_path = dir.GetPath().AppendASCII("tmp");
188   if (!base::WriteFile(local_path, base::StringPiece(buf, buf_size)))
189     return base::File::FILE_ERROR_FAILED;
190   base::File::Error result = base::File::FILE_ERROR_FAILED;
191   base::RunLoop run_loop;
192   context->operation_runner()->CopyInForeignFile(
193       local_path, url, AssignAndQuitCallback(&run_loop, &result));
194   run_loop.Run();
195   return result;
196 }
197 
TruncateFile(FileSystemContext * context,const FileSystemURL & url,size_t size)198 base::File::Error AsyncFileTestHelper::TruncateFile(FileSystemContext* context,
199                                                     const FileSystemURL& url,
200                                                     size_t size) {
201   base::RunLoop run_loop;
202   base::File::Error result = base::File::FILE_ERROR_FAILED;
203   context->operation_runner()->Truncate(
204       url, size, AssignAndQuitCallback(&run_loop, &result));
205   run_loop.Run();
206   return result;
207 }
208 
GetMetadata(FileSystemContext * context,const FileSystemURL & url,base::File::Info * file_info)209 base::File::Error AsyncFileTestHelper::GetMetadata(
210     FileSystemContext* context,
211     const FileSystemURL& url,
212     base::File::Info* file_info) {
213   base::File::Error result = base::File::FILE_ERROR_FAILED;
214   base::RunLoop run_loop;
215   context->operation_runner()->GetMetadata(
216       url,
217       FileSystemOperation::GET_METADATA_FIELD_IS_DIRECTORY |
218           FileSystemOperation::GET_METADATA_FIELD_SIZE |
219           FileSystemOperation::GET_METADATA_FIELD_LAST_MODIFIED,
220       base::BindOnce(&GetMetadataCallback, &run_loop, &result, file_info));
221   run_loop.Run();
222   return result;
223 }
224 
GetPlatformPath(FileSystemContext * context,const FileSystemURL & url,base::FilePath * platform_path)225 base::File::Error AsyncFileTestHelper::GetPlatformPath(
226     FileSystemContext* context,
227     const FileSystemURL& url,
228     base::FilePath* platform_path) {
229   base::File::Error result = base::File::FILE_ERROR_FAILED;
230   base::RunLoop run_loop;
231   context->operation_runner()->CreateSnapshotFile(
232       url, base::BindOnce(&CreateSnapshotFileCallback, &run_loop, &result,
233                           platform_path));
234   run_loop.Run();
235   return result;
236 }
237 
FileExists(FileSystemContext * context,const FileSystemURL & url,int64_t expected_size)238 bool AsyncFileTestHelper::FileExists(FileSystemContext* context,
239                                      const FileSystemURL& url,
240                                      int64_t expected_size) {
241   base::File::Info file_info;
242   base::File::Error result = GetMetadata(context, url, &file_info);
243   if (result != base::File::FILE_OK || file_info.is_directory)
244     return false;
245   return expected_size == kDontCheckSize || file_info.size == expected_size;
246 }
247 
DirectoryExists(FileSystemContext * context,const FileSystemURL & url)248 bool AsyncFileTestHelper::DirectoryExists(FileSystemContext* context,
249                                           const FileSystemURL& url) {
250   base::File::Info file_info;
251   base::File::Error result = GetMetadata(context, url, &file_info);
252   return (result == base::File::FILE_OK) && file_info.is_directory;
253 }
254 
GetUsageAndQuota(QuotaManager * quota_manager,const url::Origin & origin,FileSystemType type,int64_t * usage,int64_t * quota)255 blink::mojom::QuotaStatusCode AsyncFileTestHelper::GetUsageAndQuota(
256     QuotaManager* quota_manager,
257     const url::Origin& origin,
258     FileSystemType type,
259     int64_t* usage,
260     int64_t* quota) {
261   blink::mojom::QuotaStatusCode status =
262       blink::mojom::QuotaStatusCode::kUnknown;
263   base::RunLoop run_loop;
264   quota_manager->GetUsageAndQuota(
265       origin, FileSystemTypeToQuotaStorageType(type),
266       base::BindOnce(&DidGetUsageAndQuota, &status, usage, quota,
267                      run_loop.QuitWhenIdleClosure()));
268   run_loop.Run();
269   return status;
270 }
271 
TouchFile(FileSystemContext * context,const FileSystemURL & url,const base::Time & last_access_time,const base::Time & last_modified_time)272 base::File::Error AsyncFileTestHelper::TouchFile(
273     FileSystemContext* context,
274     const FileSystemURL& url,
275     const base::Time& last_access_time,
276     const base::Time& last_modified_time) {
277   base::File::Error result = base::File::FILE_ERROR_FAILED;
278   base::RunLoop run_loop;
279   context->operation_runner()->TouchFile(
280       url, last_access_time, last_modified_time,
281       AssignAndQuitCallback(&run_loop, &result));
282   run_loop.Run();
283   return result;
284 }
285 
286 }  // namespace storage
287