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/mount_path_util.h"
6
7#include <string>
8
9#include "base/files/file.h"
10#include "base/memory/scoped_ptr.h"
11#include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
12#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
13#include "chrome/browser/chromeos/file_system_provider/service.h"
14#include "chrome/browser/chromeos/file_system_provider/service_factory.h"
15#include "chrome/browser/chromeos/login/users/fake_user_manager.h"
16#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/test/base/testing_browser_process.h"
19#include "chrome/test/base/testing_profile.h"
20#include "chrome/test/base/testing_profile_manager.h"
21#include "components/keyed_service/core/keyed_service.h"
22#include "content/public/browser/browser_context.h"
23#include "content/public/test/test_browser_thread_bundle.h"
24#include "extensions/browser/extension_registry.h"
25#include "storage/browser/fileapi/external_mount_points.h"
26#include "storage/browser/fileapi/isolated_context.h"
27#include "testing/gtest/include/gtest/gtest.h"
28
29namespace chromeos {
30namespace file_system_provider {
31namespace util {
32
33namespace {
34
35const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
36const char kFileSystemId[] = "File/System/Id";
37const char kDisplayName[] = "Camera Pictures";
38
39// Creates a FileSystemURL for tests.
40storage::FileSystemURL CreateFileSystemURL(
41    Profile* profile,
42    const ProvidedFileSystemInfo& file_system_info,
43    const base::FilePath& file_path) {
44  const std::string origin =
45      std::string("chrome-extension://") + file_system_info.extension_id();
46  const base::FilePath mount_path = file_system_info.mount_path();
47  const storage::ExternalMountPoints* const mount_points =
48      storage::ExternalMountPoints::GetSystemInstance();
49  DCHECK(mount_points);
50  DCHECK(file_path.IsAbsolute());
51  base::FilePath relative_path(file_path.value().substr(1));
52  return mount_points->CreateCrackedFileSystemURL(
53      GURL(origin),
54      storage::kFileSystemTypeExternal,
55      base::FilePath(mount_path.BaseName().Append(relative_path)));
56}
57
58// Creates a Service instance. Used to be able to destroy the service in
59// TearDown().
60KeyedService* CreateService(content::BrowserContext* context) {
61  return new Service(Profile::FromBrowserContext(context),
62                     extensions::ExtensionRegistry::Get(context));
63}
64
65}  // namespace
66
67class FileSystemProviderMountPathUtilTest : public testing::Test {
68 protected:
69  FileSystemProviderMountPathUtilTest() {}
70  virtual ~FileSystemProviderMountPathUtilTest() {}
71
72  virtual void SetUp() OVERRIDE {
73    profile_manager_.reset(
74        new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
75    ASSERT_TRUE(profile_manager_->SetUp());
76    profile_ = profile_manager_->CreateTestingProfile("testing-profile");
77    user_manager_ = new FakeUserManager();
78    user_manager_enabler_.reset(new ScopedUserManagerEnabler(user_manager_));
79    user_manager_->AddUser(profile_->GetProfileName());
80    ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
81    file_system_provider_service_ = Service::Get(profile_);
82    file_system_provider_service_->SetFileSystemFactoryForTesting(
83        base::Bind(&FakeProvidedFileSystem::Create));
84  }
85
86  virtual void TearDown() OVERRIDE {
87    // Setting the testing factory to NULL will destroy the created service
88    // associated with the testing profile.
89    ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
90  }
91
92  content::TestBrowserThreadBundle thread_bundle_;
93  scoped_ptr<TestingProfileManager> profile_manager_;
94  TestingProfile* profile_;  // Owned by TestingProfileManager.
95  scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_;
96  FakeUserManager* user_manager_;
97  Service* file_system_provider_service_;  // Owned by its factory.
98};
99
100TEST_F(FileSystemProviderMountPathUtilTest, GetMountPath) {
101  const base::FilePath result =
102      GetMountPath(profile_, kExtensionId, kFileSystemId);
103  const std::string expected =
104      "/provided/mbflcebpggnecokmikipoihdbecnjfoj:"
105      "File%2FSystem%2FId:testing-profile-hash";
106  EXPECT_EQ(expected, result.AsUTF8Unsafe());
107}
108
109TEST_F(FileSystemProviderMountPathUtilTest, IsFileSystemProviderLocalPath) {
110  const base::FilePath mount_path =
111      GetMountPath(profile_, kExtensionId, kFileSystemId);
112  const base::FilePath file_path =
113      base::FilePath::FromUTF8Unsafe("/hello/world.txt");
114  const base::FilePath local_file_path =
115      mount_path.Append(base::FilePath(file_path.value().substr(1)));
116
117  EXPECT_TRUE(IsFileSystemProviderLocalPath(mount_path));
118  EXPECT_TRUE(IsFileSystemProviderLocalPath(local_file_path));
119
120  EXPECT_FALSE(IsFileSystemProviderLocalPath(
121      base::FilePath::FromUTF8Unsafe("provided/hello-world/test.txt")));
122  EXPECT_FALSE(IsFileSystemProviderLocalPath(
123      base::FilePath::FromUTF8Unsafe("/provided")));
124  EXPECT_FALSE(
125      IsFileSystemProviderLocalPath(base::FilePath::FromUTF8Unsafe("/")));
126  EXPECT_FALSE(IsFileSystemProviderLocalPath(base::FilePath()));
127}
128
129TEST_F(FileSystemProviderMountPathUtilTest, Parser) {
130  const bool result = file_system_provider_service_->MountFileSystem(
131      kExtensionId, kFileSystemId, kDisplayName, false /* writable */);
132  ASSERT_TRUE(result);
133  const ProvidedFileSystemInfo file_system_info =
134      file_system_provider_service_->GetProvidedFileSystem(kExtensionId,
135                                                           kFileSystemId)
136          ->GetFileSystemInfo();
137
138  const base::FilePath kFilePath =
139      base::FilePath::FromUTF8Unsafe("/hello/world.txt");
140  const storage::FileSystemURL url =
141      CreateFileSystemURL(profile_, file_system_info, kFilePath);
142  EXPECT_TRUE(url.is_valid());
143
144  FileSystemURLParser parser(url);
145  EXPECT_TRUE(parser.Parse());
146
147  ProvidedFileSystemInterface* file_system = parser.file_system();
148  ASSERT_TRUE(file_system);
149  EXPECT_EQ(kFileSystemId, file_system->GetFileSystemInfo().file_system_id());
150  EXPECT_EQ(kFilePath.AsUTF8Unsafe(), parser.file_path().AsUTF8Unsafe());
151}
152
153TEST_F(FileSystemProviderMountPathUtilTest, Parser_RootPath) {
154  const bool result = file_system_provider_service_->MountFileSystem(
155      kExtensionId, kFileSystemId, kDisplayName, false /* writable */);
156  ASSERT_TRUE(result);
157  const ProvidedFileSystemInfo file_system_info =
158      file_system_provider_service_->GetProvidedFileSystem(kExtensionId,
159                                                           kFileSystemId)
160          ->GetFileSystemInfo();
161
162  const base::FilePath kFilePath = base::FilePath::FromUTF8Unsafe("/");
163  const storage::FileSystemURL url =
164      CreateFileSystemURL(profile_, file_system_info, kFilePath);
165  EXPECT_TRUE(url.is_valid());
166
167  FileSystemURLParser parser(url);
168  EXPECT_TRUE(parser.Parse());
169
170  ProvidedFileSystemInterface* file_system = parser.file_system();
171  ASSERT_TRUE(file_system);
172  EXPECT_EQ(kFileSystemId, file_system->GetFileSystemInfo().file_system_id());
173  EXPECT_EQ(kFilePath.AsUTF8Unsafe(), parser.file_path().AsUTF8Unsafe());
174}
175
176TEST_F(FileSystemProviderMountPathUtilTest, Parser_WrongUrl) {
177  const ProvidedFileSystemInfo file_system_info(
178      kExtensionId,
179      kFileSystemId,
180      kDisplayName,
181      false /* writable */,
182      GetMountPath(profile_, kExtensionId, kFileSystemId));
183
184  const base::FilePath kFilePath = base::FilePath::FromUTF8Unsafe("/hello");
185  const storage::FileSystemURL url =
186      CreateFileSystemURL(profile_, file_system_info, kFilePath);
187  // It is impossible to create a cracked URL for a mount point which doesn't
188  // exist, therefore is will always be invalid, and empty.
189  EXPECT_FALSE(url.is_valid());
190
191  FileSystemURLParser parser(url);
192  EXPECT_FALSE(parser.Parse());
193}
194
195TEST_F(FileSystemProviderMountPathUtilTest, Parser_IsolatedURL) {
196  const bool result = file_system_provider_service_->MountFileSystem(
197      kExtensionId, kFileSystemId, kDisplayName, false /* writable */);
198  ASSERT_TRUE(result);
199  const ProvidedFileSystemInfo file_system_info =
200      file_system_provider_service_->GetProvidedFileSystem(kExtensionId,
201                                                           kFileSystemId)
202          ->GetFileSystemInfo();
203
204  const base::FilePath kFilePath =
205      base::FilePath::FromUTF8Unsafe("/hello/world.txt");
206  const storage::FileSystemURL url =
207      CreateFileSystemURL(profile_, file_system_info, kFilePath);
208  EXPECT_TRUE(url.is_valid());
209
210  // Create an isolated URL for the original one.
211  storage::IsolatedContext* const isolated_context =
212      storage::IsolatedContext::GetInstance();
213  const std::string isolated_file_system_id =
214      isolated_context->RegisterFileSystemForPath(
215          storage::kFileSystemTypeProvided,
216          url.filesystem_id(),
217          url.path(),
218          NULL);
219
220  const base::FilePath isolated_virtual_path =
221      isolated_context->CreateVirtualRootPath(isolated_file_system_id)
222          .Append(kFilePath.BaseName().value());
223
224  const storage::FileSystemURL isolated_url =
225      isolated_context->CreateCrackedFileSystemURL(
226          url.origin(),
227          storage::kFileSystemTypeIsolated,
228          isolated_virtual_path);
229
230  EXPECT_TRUE(isolated_url.is_valid());
231
232  FileSystemURLParser parser(isolated_url);
233  EXPECT_TRUE(parser.Parse());
234
235  ProvidedFileSystemInterface* file_system = parser.file_system();
236  ASSERT_TRUE(file_system);
237  EXPECT_EQ(kFileSystemId, file_system->GetFileSystemInfo().file_system_id());
238  EXPECT_EQ(kFilePath.AsUTF8Unsafe(), parser.file_path().AsUTF8Unsafe());
239}
240
241TEST_F(FileSystemProviderMountPathUtilTest, LocalPathParser) {
242  const bool result = file_system_provider_service_->MountFileSystem(
243      kExtensionId, kFileSystemId, kDisplayName, false /* writable */);
244  ASSERT_TRUE(result);
245  const ProvidedFileSystemInfo file_system_info =
246      file_system_provider_service_->GetProvidedFileSystem(kExtensionId,
247                                                           kFileSystemId)
248          ->GetFileSystemInfo();
249
250  const base::FilePath kFilePath =
251      base::FilePath::FromUTF8Unsafe("/hello/world.txt");
252  const base::FilePath kLocalFilePath = file_system_info.mount_path().Append(
253      base::FilePath(kFilePath.value().substr(1)));
254
255  LOG(ERROR) << kLocalFilePath.value();
256  LocalPathParser parser(profile_, kLocalFilePath);
257  EXPECT_TRUE(parser.Parse());
258
259  ProvidedFileSystemInterface* file_system = parser.file_system();
260  ASSERT_TRUE(file_system);
261  EXPECT_EQ(kFileSystemId, file_system->GetFileSystemInfo().file_system_id());
262  EXPECT_EQ(kFilePath.AsUTF8Unsafe(), parser.file_path().AsUTF8Unsafe());
263}
264
265TEST_F(FileSystemProviderMountPathUtilTest, LocalPathParser_RootPath) {
266  const bool result = file_system_provider_service_->MountFileSystem(
267      kExtensionId, kFileSystemId, kDisplayName, false /* writable */);
268  ASSERT_TRUE(result);
269  const ProvidedFileSystemInfo file_system_info =
270      file_system_provider_service_->GetProvidedFileSystem(kExtensionId,
271                                                           kFileSystemId)
272          ->GetFileSystemInfo();
273
274  const base::FilePath kFilePath = base::FilePath::FromUTF8Unsafe("/");
275  const base::FilePath kLocalFilePath = file_system_info.mount_path();
276
277  LocalPathParser parser(profile_, kLocalFilePath);
278  EXPECT_TRUE(parser.Parse());
279
280  ProvidedFileSystemInterface* file_system = parser.file_system();
281  ASSERT_TRUE(file_system);
282  EXPECT_EQ(kFileSystemId, file_system->GetFileSystemInfo().file_system_id());
283  EXPECT_EQ(kFilePath.AsUTF8Unsafe(), parser.file_path().AsUTF8Unsafe());
284}
285
286TEST_F(FileSystemProviderMountPathUtilTest, LocalPathParser_WrongPath) {
287  {
288    const base::FilePath kFilePath = base::FilePath::FromUTF8Unsafe("/hello");
289    LocalPathParser parser(profile_, kFilePath);
290    EXPECT_FALSE(parser.Parse());
291  }
292
293  {
294    const base::FilePath kFilePath =
295        base::FilePath::FromUTF8Unsafe("/provided");
296    LocalPathParser parser(profile_, kFilePath);
297    EXPECT_FALSE(parser.Parse());
298  }
299
300  {
301    const base::FilePath kFilePath =
302        base::FilePath::FromUTF8Unsafe("provided/hello/world");
303    LocalPathParser parser(profile_, kFilePath);
304    EXPECT_FALSE(parser.Parse());
305  }
306}
307
308}  // namespace util
309}  // namespace file_system_provider
310}  // namespace chromeos
311