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 "chrome/browser/chromeos/file_system_provider/fileapi/provider_async_file_util.h"
6
7#include <string>
8#include <vector>
9
10#include "base/files/file.h"
11#include "base/files/file_path.h"
12#include "base/files/scoped_temp_dir.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/memory/weak_ptr.h"
15#include "base/run_loop.h"
16#include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
17#include "chrome/browser/chromeos/file_system_provider/service.h"
18#include "chrome/browser/chromeos/file_system_provider/service_factory.h"
19#include "chrome/test/base/testing_browser_process.h"
20#include "chrome/test/base/testing_profile.h"
21#include "chrome/test/base/testing_profile_manager.h"
22#include "content/public/test/test_browser_thread_bundle.h"
23#include "content/public/test/test_file_system_context.h"
24#include "extensions/browser/extension_registry.h"
25#include "storage/browser/fileapi/async_file_util.h"
26#include "storage/browser/fileapi/external_mount_points.h"
27#include "storage/browser/fileapi/file_system_context.h"
28#include "storage/browser/fileapi/file_system_url.h"
29#include "storage/common/blob/shareable_file_reference.h"
30#include "testing/gtest/include/gtest/gtest.h"
31
32namespace chromeos {
33namespace file_system_provider {
34namespace {
35
36const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
37const char kFileSystemId[] = "testing-file-system";
38
39// Logs callbacks invocations on the tested operations.
40// TODO(mtomasz): Store and verify more arguments, once the operations return
41// anything else than just an error.
42class EventLogger {
43 public:
44  EventLogger() {}
45  virtual ~EventLogger() {}
46
47  void OnStatus(base::File::Error error) {
48    result_.reset(new base::File::Error(error));
49  }
50
51  void OnCreateOrOpen(base::File file,
52                      const base::Closure& on_close_callback) {
53    if (file.IsValid())
54      result_.reset(new base::File::Error(base::File::FILE_OK));
55
56    result_.reset(new base::File::Error(file.error_details()));
57  }
58
59  void OnEnsureFileExists(base::File::Error error, bool created) {
60    result_.reset(new base::File::Error(error));
61  }
62
63  void OnGetFileInfo(base::File::Error error,
64                     const base::File::Info& file_info) {
65    result_.reset(new base::File::Error(error));
66  }
67
68  void OnReadDirectory(base::File::Error error,
69                       const storage::AsyncFileUtil::EntryList& file_list,
70                       bool has_more) {
71    result_.reset(new base::File::Error(error));
72  }
73
74  void OnCreateSnapshotFile(
75      base::File::Error error,
76      const base::File::Info& file_info,
77      const base::FilePath& platform_path,
78      const scoped_refptr<storage::ShareableFileReference>& file_ref) {
79    result_.reset(new base::File::Error(error));
80  }
81
82  void OnCopyFileProgress(int64 size) {}
83
84  base::File::Error* result() { return result_.get(); }
85
86 private:
87  scoped_ptr<base::File::Error> result_;
88  DISALLOW_COPY_AND_ASSIGN(EventLogger);
89};
90
91// Creates a cracked FileSystemURL for tests.
92storage::FileSystemURL CreateFileSystemURL(const std::string& mount_point_name,
93                                           const base::FilePath& file_path) {
94  const std::string origin = std::string("chrome-extension://") + kExtensionId;
95  const storage::ExternalMountPoints* const mount_points =
96      storage::ExternalMountPoints::GetSystemInstance();
97  return mount_points->CreateCrackedFileSystemURL(
98      GURL(origin),
99      storage::kFileSystemTypeExternal,
100      base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path));
101}
102
103// Creates a Service instance. Used to be able to destroy the service in
104// TearDown().
105KeyedService* CreateService(content::BrowserContext* context) {
106  return new Service(Profile::FromBrowserContext(context),
107                     extensions::ExtensionRegistry::Get(context));
108}
109
110}  // namespace
111
112// Tests in this file are very lightweight and just test integration between
113// AsyncFileUtil and ProvideFileSystemInterface. Currently it tests if not
114// implemented operations return a correct error code. For not allowed
115// operations it is FILE_ERROR_ACCESS_DENIED, and for not implemented the error
116// is FILE_ERROR_INVALID_OPERATION.
117class FileSystemProviderProviderAsyncFileUtilTest : public testing::Test {
118 protected:
119  FileSystemProviderProviderAsyncFileUtilTest() {}
120  virtual ~FileSystemProviderProviderAsyncFileUtilTest() {}
121
122  virtual void SetUp() OVERRIDE {
123    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
124    profile_manager_.reset(
125        new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
126    ASSERT_TRUE(profile_manager_->SetUp());
127    profile_ = profile_manager_->CreateTestingProfile("testing-profile");
128    async_file_util_.reset(new internal::ProviderAsyncFileUtil);
129
130    file_system_context_ =
131        content::CreateFileSystemContextForTesting(NULL, data_dir_.path());
132
133    ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
134    Service* service = Service::Get(profile_);  // Owned by its factory.
135    service->SetFileSystemFactoryForTesting(
136        base::Bind(&FakeProvidedFileSystem::Create));
137
138    const bool result = service->MountFileSystem(kExtensionId,
139                                                 kFileSystemId,
140                                                 "Testing File System",
141                                                 false /* writable */);
142    ASSERT_TRUE(result);
143    const ProvidedFileSystemInfo& file_system_info =
144        service->GetProvidedFileSystem(kExtensionId, kFileSystemId)
145            ->GetFileSystemInfo();
146    const std::string mount_point_name =
147        file_system_info.mount_path().BaseName().AsUTF8Unsafe();
148
149    file_url_ =
150        CreateFileSystemURL(mount_point_name,
151                            base::FilePath::FromUTF8Unsafe(
152                                kFakeFilePath + 1 /* No leading slash. */));
153    ASSERT_TRUE(file_url_.is_valid());
154    directory_url_ = CreateFileSystemURL(
155        mount_point_name, base::FilePath::FromUTF8Unsafe("hello"));
156    ASSERT_TRUE(directory_url_.is_valid());
157    root_url_ = CreateFileSystemURL(mount_point_name, base::FilePath());
158    ASSERT_TRUE(root_url_.is_valid());
159  }
160
161  virtual void TearDown() OVERRIDE {
162    // Setting the testing factory to NULL will destroy the created service
163    // associated with the testing profile.
164    ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
165  }
166
167  scoped_ptr<storage::FileSystemOperationContext> CreateOperationContext() {
168    return make_scoped_ptr(
169        new storage::FileSystemOperationContext(file_system_context_.get()));
170  }
171
172  content::TestBrowserThreadBundle thread_bundle_;
173  base::ScopedTempDir data_dir_;
174  scoped_ptr<TestingProfileManager> profile_manager_;
175  TestingProfile* profile_;  // Owned by TestingProfileManager.
176  scoped_ptr<storage::AsyncFileUtil> async_file_util_;
177  scoped_refptr<storage::FileSystemContext> file_system_context_;
178  storage::FileSystemURL file_url_;
179  storage::FileSystemURL directory_url_;
180  storage::FileSystemURL root_url_;
181};
182
183TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_Create) {
184  EventLogger logger;
185
186  async_file_util_->CreateOrOpen(
187      CreateOperationContext(),
188      file_url_,
189      base::File::FLAG_CREATE,
190      base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger)));
191
192  ASSERT_TRUE(logger.result());
193  EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result());
194}
195
196TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_CreateAlways) {
197  EventLogger logger;
198
199  async_file_util_->CreateOrOpen(
200      CreateOperationContext(),
201      file_url_,
202      base::File::FLAG_CREATE_ALWAYS,
203      base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger)));
204
205  ASSERT_TRUE(logger.result());
206  EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result());
207}
208
209TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_OpenAlways) {
210  EventLogger logger;
211
212  async_file_util_->CreateOrOpen(
213      CreateOperationContext(),
214      file_url_,
215      base::File::FLAG_OPEN_ALWAYS,
216      base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger)));
217
218  ASSERT_TRUE(logger.result());
219  EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result());
220}
221
222TEST_F(FileSystemProviderProviderAsyncFileUtilTest,
223       CreateOrOpen_OpenTruncated) {
224  EventLogger logger;
225
226  async_file_util_->CreateOrOpen(
227      CreateOperationContext(),
228      file_url_,
229      base::File::FLAG_OPEN_TRUNCATED,
230      base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger)));
231
232  ASSERT_TRUE(logger.result());
233  EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result());
234}
235
236TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_Open) {
237  EventLogger logger;
238
239  async_file_util_->CreateOrOpen(
240      CreateOperationContext(),
241      file_url_,
242      base::File::FLAG_OPEN,
243      base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger)));
244
245  ASSERT_TRUE(logger.result());
246  EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, *logger.result());
247}
248
249TEST_F(FileSystemProviderProviderAsyncFileUtilTest, EnsureFileExists) {
250  EventLogger logger;
251
252  async_file_util_->EnsureFileExists(
253      CreateOperationContext(),
254      file_url_,
255      base::Bind(&EventLogger::OnEnsureFileExists, base::Unretained(&logger)));
256  base::RunLoop().RunUntilIdle();
257
258  ASSERT_TRUE(logger.result());
259  EXPECT_EQ(base::File::FILE_OK, *logger.result());
260}
261
262TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateDirectory) {
263  EventLogger logger;
264
265  async_file_util_->CreateDirectory(
266      CreateOperationContext(),
267      directory_url_,
268      false,  // exclusive
269      false,  // recursive
270      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
271  base::RunLoop().RunUntilIdle();
272
273  ASSERT_TRUE(logger.result());
274  EXPECT_EQ(base::File::FILE_OK, *logger.result());
275}
276
277TEST_F(FileSystemProviderProviderAsyncFileUtilTest, GetFileInfo) {
278  EventLogger logger;
279
280  async_file_util_->GetFileInfo(
281      CreateOperationContext(),
282      root_url_,
283      base::Bind(&EventLogger::OnGetFileInfo, base::Unretained(&logger)));
284  base::RunLoop().RunUntilIdle();
285
286  ASSERT_TRUE(logger.result());
287  EXPECT_EQ(base::File::FILE_OK, *logger.result());
288}
289
290TEST_F(FileSystemProviderProviderAsyncFileUtilTest, ReadDirectory) {
291  EventLogger logger;
292
293  async_file_util_->ReadDirectory(
294      CreateOperationContext(),
295      root_url_,
296      base::Bind(&EventLogger::OnReadDirectory, base::Unretained(&logger)));
297  base::RunLoop().RunUntilIdle();
298
299  ASSERT_TRUE(logger.result());
300  EXPECT_EQ(base::File::FILE_OK, *logger.result());
301}
302
303TEST_F(FileSystemProviderProviderAsyncFileUtilTest, Touch) {
304  EventLogger logger;
305
306  async_file_util_->Touch(
307      CreateOperationContext(),
308      file_url_,
309      base::Time(),  // last_modified_time
310      base::Time(),  // last_access_time
311      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
312
313  ASSERT_TRUE(logger.result());
314  EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result());
315}
316
317TEST_F(FileSystemProviderProviderAsyncFileUtilTest, Truncate) {
318  EventLogger logger;
319
320  async_file_util_->Truncate(
321      CreateOperationContext(),
322      file_url_,
323      0,  // length
324      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
325  base::RunLoop().RunUntilIdle();
326
327  ASSERT_TRUE(logger.result());
328  EXPECT_EQ(base::File::FILE_OK, *logger.result());
329}
330
331TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CopyFileLocal) {
332  EventLogger logger;
333
334  async_file_util_->CopyFileLocal(
335      CreateOperationContext(),
336      file_url_,  // src_url
337      file_url_,  // dst_url
338      storage::FileSystemOperation::OPTION_NONE,
339      base::Bind(&EventLogger::OnCopyFileProgress, base::Unretained(&logger)),
340      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
341  base::RunLoop().RunUntilIdle();
342
343  ASSERT_TRUE(logger.result());
344  EXPECT_EQ(base::File::FILE_OK, *logger.result());
345}
346
347TEST_F(FileSystemProviderProviderAsyncFileUtilTest, MoveFileLocal) {
348  EventLogger logger;
349
350  async_file_util_->MoveFileLocal(
351      CreateOperationContext(),
352      file_url_,  // src_url
353      file_url_,  // dst_url
354      storage::FileSystemOperation::OPTION_NONE,
355      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
356  base::RunLoop().RunUntilIdle();
357
358  ASSERT_TRUE(logger.result());
359  EXPECT_EQ(base::File::FILE_OK, *logger.result());
360}
361
362TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CopyInForeignFile) {
363  EventLogger logger;
364
365  async_file_util_->CopyInForeignFile(
366      CreateOperationContext(),
367      base::FilePath(),  // src_file_path
368      file_url_,         // dst_url
369      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
370
371  ASSERT_TRUE(logger.result());
372  EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result());
373}
374
375TEST_F(FileSystemProviderProviderAsyncFileUtilTest, DeleteFile) {
376  EventLogger logger;
377
378  async_file_util_->DeleteFile(
379      CreateOperationContext(),
380      file_url_,
381      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
382  base::RunLoop().RunUntilIdle();
383
384  ASSERT_TRUE(logger.result());
385  EXPECT_EQ(base::File::FILE_OK, *logger.result());
386}
387
388TEST_F(FileSystemProviderProviderAsyncFileUtilTest, DeleteDirectory) {
389  EventLogger logger;
390
391  async_file_util_->DeleteDirectory(
392      CreateOperationContext(),
393      directory_url_,
394      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
395  base::RunLoop().RunUntilIdle();
396
397  ASSERT_TRUE(logger.result());
398  EXPECT_EQ(base::File::FILE_OK, *logger.result());
399}
400
401TEST_F(FileSystemProviderProviderAsyncFileUtilTest, DeleteRecursively) {
402  EventLogger logger;
403
404  async_file_util_->DeleteRecursively(
405      CreateOperationContext(),
406      directory_url_,
407      base::Bind(&EventLogger::OnStatus, base::Unretained(&logger)));
408  base::RunLoop().RunUntilIdle();
409
410  ASSERT_TRUE(logger.result());
411  EXPECT_EQ(base::File::FILE_OK, *logger.result());
412}
413
414TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateSnapshotFile) {
415  EventLogger logger;
416
417  async_file_util_->CreateSnapshotFile(
418      CreateOperationContext(),
419      file_url_,
420      base::Bind(&EventLogger::OnCreateSnapshotFile,
421                 base::Unretained(&logger)));
422
423  ASSERT_TRUE(logger.result());
424  EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, *logger.result());
425}
426
427}  // namespace file_system_provider
428}  // namespace chromeos
429