1// Copyright (c) 2012 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 "webkit/browser/fileapi/sandbox_file_system_backend.h"
6
7#include <set>
8
9#include "base/basictypes.h"
10#include "base/file_util.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/message_loop/message_loop.h"
14#include "base/message_loop/message_loop_proxy.h"
15#include "testing/gtest/include/gtest/gtest.h"
16#include "url/gurl.h"
17#include "webkit/browser/fileapi/file_system_backend.h"
18#include "webkit/browser/fileapi/file_system_url.h"
19#include "webkit/browser/fileapi/mock_file_system_options.h"
20#include "webkit/browser/fileapi/sandbox_context.h"
21#include "webkit/common/fileapi/file_system_util.h"
22
23// PS stands for path separator.
24#if defined(FILE_PATH_USES_WIN_SEPARATORS)
25#define PS  "\\"
26#else
27#define PS  "/"
28#endif
29
30namespace fileapi {
31
32namespace {
33
34const struct RootPathTest {
35  fileapi::FileSystemType type;
36  const char* origin_url;
37  const char* expected_path;
38} kRootPathTestCases[] = {
39  { fileapi::kFileSystemTypeTemporary, "http://foo:1/",
40    "000" PS "t" },
41  { fileapi::kFileSystemTypePersistent, "http://foo:1/",
42    "000" PS "p" },
43  { fileapi::kFileSystemTypeTemporary, "http://bar.com/",
44    "001" PS "t" },
45  { fileapi::kFileSystemTypePersistent, "http://bar.com/",
46    "001" PS "p" },
47  { fileapi::kFileSystemTypeTemporary, "https://foo:2/",
48    "002" PS "t" },
49  { fileapi::kFileSystemTypePersistent, "https://foo:2/",
50    "002" PS "p" },
51  { fileapi::kFileSystemTypeTemporary, "https://bar.com/",
52    "003" PS "t" },
53  { fileapi::kFileSystemTypePersistent, "https://bar.com/",
54    "003" PS "p" },
55};
56
57const struct RootPathFileURITest {
58  fileapi::FileSystemType type;
59  const char* origin_url;
60  const char* expected_path;
61  const char* virtual_path;
62} kRootPathFileURITestCases[] = {
63  { fileapi::kFileSystemTypeTemporary, "file:///",
64    "000" PS "t", NULL },
65  { fileapi::kFileSystemTypePersistent, "file:///",
66    "000" PS "p", NULL },
67};
68
69FileSystemURL CreateFileSystemURL(const char* path) {
70  const GURL kOrigin("http://foo/");
71  return FileSystemURL::CreateForTest(
72      kOrigin, kFileSystemTypeTemporary, base::FilePath::FromUTF8Unsafe(path));
73}
74
75void DidOpenFileSystem(base::PlatformFileError* error_out,
76                       const GURL& origin_url,
77                       const std::string& name,
78                       base::PlatformFileError error) {
79  *error_out = error;
80}
81
82}  // namespace
83
84class SandboxFileSystemBackendTest : public testing::Test {
85 protected:
86  virtual void SetUp() {
87    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
88    SetUpNewSandboxContext(CreateAllowFileAccessOptions());
89  }
90
91  void SetUpNewSandboxContext(const FileSystemOptions& options) {
92    context_.reset(new SandboxContext(
93        NULL /* quota_manager_proxy */,
94        base::MessageLoopProxy::current().get(),
95        data_dir_.path(),
96        NULL /* special_storage_policy */,
97        options));
98  }
99
100  void SetUpNewBackend(const FileSystemOptions& options) {
101    SetUpNewSandboxContext(options);
102    backend_.reset(new SandboxFileSystemBackend(context_.get()));
103  }
104
105  SandboxContext::OriginEnumerator* CreateOriginEnumerator() const {
106    return backend_->CreateOriginEnumerator();
107  }
108
109  void CreateOriginTypeDirectory(const GURL& origin,
110                                 fileapi::FileSystemType type) {
111    base::FilePath target = context_->
112        GetBaseDirectoryForOriginAndType(origin, type, true);
113    ASSERT_TRUE(!target.empty());
114    ASSERT_TRUE(base::DirectoryExists(target));
115  }
116
117  bool GetRootPath(const GURL& origin_url,
118                   fileapi::FileSystemType type,
119                   OpenFileSystemMode mode,
120                   base::FilePath* root_path) {
121    base::PlatformFileError error = base::PLATFORM_FILE_OK;
122    backend_->OpenFileSystem(
123        origin_url, type, mode,
124        base::Bind(&DidOpenFileSystem, &error));
125    base::MessageLoop::current()->RunUntilIdle();
126    if (error != base::PLATFORM_FILE_OK)
127      return false;
128    base::FilePath returned_root_path =
129        context_->GetBaseDirectoryForOriginAndType(
130            origin_url, type, false /* create */);
131    if (root_path)
132      *root_path = returned_root_path;
133    return !returned_root_path.empty();
134  }
135
136  base::FilePath file_system_path() const {
137    return data_dir_.path().Append(SandboxContext::kFileSystemDirectory);
138  }
139
140  base::ScopedTempDir data_dir_;
141  base::MessageLoop message_loop_;
142  scoped_ptr<SandboxContext> context_;
143  scoped_ptr<SandboxFileSystemBackend> backend_;
144};
145
146TEST_F(SandboxFileSystemBackendTest, Empty) {
147  SetUpNewBackend(CreateAllowFileAccessOptions());
148  scoped_ptr<SandboxContext::OriginEnumerator> enumerator(
149      CreateOriginEnumerator());
150  ASSERT_TRUE(enumerator->Next().is_empty());
151}
152
153TEST_F(SandboxFileSystemBackendTest, EnumerateOrigins) {
154  SetUpNewBackend(CreateAllowFileAccessOptions());
155  const char* temporary_origins[] = {
156    "http://www.bar.com/",
157    "http://www.foo.com/",
158    "http://www.foo.com:1/",
159    "http://www.example.com:8080/",
160    "http://www.google.com:80/",
161  };
162  const char* persistent_origins[] = {
163    "http://www.bar.com/",
164    "http://www.foo.com:8080/",
165    "http://www.foo.com:80/",
166  };
167  size_t temporary_size = ARRAYSIZE_UNSAFE(temporary_origins);
168  size_t persistent_size = ARRAYSIZE_UNSAFE(persistent_origins);
169  std::set<GURL> temporary_set, persistent_set;
170  for (size_t i = 0; i < temporary_size; ++i) {
171    CreateOriginTypeDirectory(GURL(temporary_origins[i]),
172        fileapi::kFileSystemTypeTemporary);
173    temporary_set.insert(GURL(temporary_origins[i]));
174  }
175  for (size_t i = 0; i < persistent_size; ++i) {
176    CreateOriginTypeDirectory(GURL(persistent_origins[i]),
177        kFileSystemTypePersistent);
178    persistent_set.insert(GURL(persistent_origins[i]));
179  }
180
181  scoped_ptr<SandboxContext::OriginEnumerator> enumerator(
182      CreateOriginEnumerator());
183  size_t temporary_actual_size = 0;
184  size_t persistent_actual_size = 0;
185  GURL current;
186  while (!(current = enumerator->Next()).is_empty()) {
187    SCOPED_TRACE(testing::Message() << "EnumerateOrigin " << current.spec());
188    if (enumerator->HasFileSystemType(kFileSystemTypeTemporary)) {
189      ASSERT_TRUE(temporary_set.find(current) != temporary_set.end());
190      ++temporary_actual_size;
191    }
192    if (enumerator->HasFileSystemType(kFileSystemTypePersistent)) {
193      ASSERT_TRUE(persistent_set.find(current) != persistent_set.end());
194      ++persistent_actual_size;
195    }
196  }
197
198  EXPECT_EQ(temporary_size, temporary_actual_size);
199  EXPECT_EQ(persistent_size, persistent_actual_size);
200}
201
202TEST_F(SandboxFileSystemBackendTest, GetRootPathCreateAndExamine) {
203  std::vector<base::FilePath> returned_root_path(
204      ARRAYSIZE_UNSAFE(kRootPathTestCases));
205  SetUpNewBackend(CreateAllowFileAccessOptions());
206
207  // Create a new root directory.
208  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
209    SCOPED_TRACE(testing::Message() << "RootPath (create) #" << i << " "
210                 << kRootPathTestCases[i].expected_path);
211
212    base::FilePath root_path;
213    EXPECT_TRUE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
214                            kRootPathTestCases[i].type,
215                            OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
216                            &root_path));
217
218    base::FilePath expected = file_system_path().AppendASCII(
219        kRootPathTestCases[i].expected_path);
220    EXPECT_EQ(expected.value(), root_path.value());
221    EXPECT_TRUE(base::DirectoryExists(root_path));
222    ASSERT_TRUE(returned_root_path.size() > i);
223    returned_root_path[i] = root_path;
224  }
225
226  // Get the root directory with create=false and see if we get the
227  // same directory.
228  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
229    SCOPED_TRACE(testing::Message() << "RootPath (get) #" << i << " "
230                 << kRootPathTestCases[i].expected_path);
231
232    base::FilePath root_path;
233    EXPECT_TRUE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
234                            kRootPathTestCases[i].type,
235                            OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
236                            &root_path));
237    ASSERT_TRUE(returned_root_path.size() > i);
238    EXPECT_EQ(returned_root_path[i].value(), root_path.value());
239  }
240}
241
242TEST_F(SandboxFileSystemBackendTest,
243       GetRootPathCreateAndExamineWithNewBackend) {
244  std::vector<base::FilePath> returned_root_path(
245      ARRAYSIZE_UNSAFE(kRootPathTestCases));
246  SetUpNewBackend(CreateAllowFileAccessOptions());
247
248  GURL origin_url("http://foo.com:1/");
249
250  base::FilePath root_path1;
251  EXPECT_TRUE(GetRootPath(origin_url, kFileSystemTypeTemporary,
252                          OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
253                          &root_path1));
254
255  SetUpNewBackend(CreateDisallowFileAccessOptions());
256  base::FilePath root_path2;
257  EXPECT_TRUE(GetRootPath(origin_url, kFileSystemTypeTemporary,
258                          OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
259                          &root_path2));
260
261  EXPECT_EQ(root_path1.value(), root_path2.value());
262}
263
264TEST_F(SandboxFileSystemBackendTest, GetRootPathGetWithoutCreate) {
265  SetUpNewBackend(CreateDisallowFileAccessOptions());
266
267  // Try to get a root directory without creating.
268  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
269    SCOPED_TRACE(testing::Message() << "RootPath (create=false) #" << i << " "
270                 << kRootPathTestCases[i].expected_path);
271    EXPECT_FALSE(GetRootPath(GURL(kRootPathTestCases[i].origin_url),
272                             kRootPathTestCases[i].type,
273                             OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
274                             NULL));
275  }
276}
277
278TEST_F(SandboxFileSystemBackendTest, GetRootPathInIncognito) {
279  SetUpNewBackend(CreateIncognitoFileSystemOptions());
280
281  // Try to get a root directory.
282  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathTestCases); ++i) {
283    SCOPED_TRACE(testing::Message() << "RootPath (incognito) #" << i << " "
284                 << kRootPathTestCases[i].expected_path);
285    EXPECT_FALSE(
286        GetRootPath(GURL(kRootPathTestCases[i].origin_url),
287                    kRootPathTestCases[i].type,
288                    OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
289                    NULL));
290  }
291}
292
293TEST_F(SandboxFileSystemBackendTest, GetRootPathFileURI) {
294  SetUpNewBackend(CreateDisallowFileAccessOptions());
295  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathFileURITestCases); ++i) {
296    SCOPED_TRACE(testing::Message() << "RootPathFileURI (disallow) #"
297                 << i << " " << kRootPathFileURITestCases[i].expected_path);
298    EXPECT_FALSE(
299        GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url),
300                    kRootPathFileURITestCases[i].type,
301                    OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
302                    NULL));
303  }
304}
305
306TEST_F(SandboxFileSystemBackendTest, GetRootPathFileURIWithAllowFlag) {
307  SetUpNewBackend(CreateAllowFileAccessOptions());
308  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRootPathFileURITestCases); ++i) {
309    SCOPED_TRACE(testing::Message() << "RootPathFileURI (allow) #"
310                 << i << " " << kRootPathFileURITestCases[i].expected_path);
311    base::FilePath root_path;
312    EXPECT_TRUE(GetRootPath(GURL(kRootPathFileURITestCases[i].origin_url),
313                            kRootPathFileURITestCases[i].type,
314                            OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
315                            &root_path));
316    base::FilePath expected = file_system_path().AppendASCII(
317        kRootPathFileURITestCases[i].expected_path);
318    EXPECT_EQ(expected.value(), root_path.value());
319    EXPECT_TRUE(base::DirectoryExists(root_path));
320  }
321}
322
323}  // namespace fileapi
324