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.
4
5#include "base/basictypes.h"
6#include "base/files/file_util.h"
7#include "base/files/scoped_temp_dir.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/message_loop/message_loop.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "base/run_loop.h"
12#include "content/public/test/async_file_test_helper.h"
13#include "content/public/test/test_file_system_context.h"
14#include "content/public/test/test_file_system_options.h"
15#include "storage/browser/fileapi/file_system_context.h"
16#include "storage/browser/fileapi/isolated_context.h"
17#include "storage/browser/fileapi/obfuscated_file_util.h"
18#include "storage/browser/fileapi/plugin_private_file_system_backend.h"
19#include "storage/common/fileapi/file_system_util.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22using content::AsyncFileTestHelper;
23using storage::FileSystemContext;
24using storage::FileSystemURL;
25using storage::IsolatedContext;
26
27namespace content {
28
29namespace {
30
31const GURL kOrigin("http://www.example.com");
32const std::string kPlugin1("plugin1");
33const std::string kPlugin2("plugin2");
34const storage::FileSystemType kType = storage::kFileSystemTypePluginPrivate;
35const std::string kRootName = "pluginprivate";
36
37void DidOpenFileSystem(base::File::Error* error_out,
38                       base::File::Error error) {
39  *error_out = error;
40}
41
42std::string RegisterFileSystem() {
43  return IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
44      kType, kRootName, base::FilePath());
45}
46
47}  // namespace
48
49class PluginPrivateFileSystemBackendTest : public testing::Test {
50 protected:
51  virtual void SetUp() OVERRIDE {
52    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
53    context_ = CreateFileSystemContextForTesting(
54        NULL /* quota_manager_proxy */,
55        data_dir_.path());
56  }
57
58  FileSystemURL CreateURL(const GURL& root_url, const std::string& relative) {
59    FileSystemURL root = context_->CrackURL(root_url);
60    return context_->CreateCrackedFileSystemURL(
61        root.origin(),
62        root.mount_type(),
63        root.virtual_path().AppendASCII(relative));
64  }
65
66  storage::PluginPrivateFileSystemBackend* backend() const {
67    return context_->plugin_private_backend();
68  }
69
70  const base::FilePath& base_path() const { return backend()->base_path(); }
71
72  base::ScopedTempDir data_dir_;
73  base::MessageLoop message_loop_;
74  scoped_refptr<FileSystemContext> context_;
75  std::string filesystem_id_;
76};
77
78TEST_F(PluginPrivateFileSystemBackendTest, OpenFileSystemBasic) {
79  const std::string filesystem_id1 = RegisterFileSystem();
80  base::File::Error error = base::File::FILE_ERROR_FAILED;
81  backend()->OpenPrivateFileSystem(
82      kOrigin,
83      kType,
84      filesystem_id1,
85      kPlugin1,
86      storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
87      base::Bind(&DidOpenFileSystem, &error));
88  base::RunLoop().RunUntilIdle();
89  ASSERT_EQ(base::File::FILE_OK, error);
90
91  // Run this again with FAIL_IF_NONEXISTENT to see if it succeeds.
92  const std::string filesystem_id2 = RegisterFileSystem();
93  error = base::File::FILE_ERROR_FAILED;
94  backend()->OpenPrivateFileSystem(
95      kOrigin,
96      kType,
97      filesystem_id2,
98      kPlugin1,
99      storage::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT,
100      base::Bind(&DidOpenFileSystem, &error));
101  base::RunLoop().RunUntilIdle();
102  ASSERT_EQ(base::File::FILE_OK, error);
103
104  const GURL root_url(storage::GetIsolatedFileSystemRootURIString(
105      kOrigin, filesystem_id1, kRootName));
106  FileSystemURL file = CreateURL(root_url, "foo");
107  base::FilePath platform_path;
108  EXPECT_EQ(base::File::FILE_OK,
109            AsyncFileTestHelper::CreateFile(context_.get(), file));
110  EXPECT_EQ(base::File::FILE_OK,
111            AsyncFileTestHelper::GetPlatformPath(context_.get(), file,
112                                                 &platform_path));
113  EXPECT_TRUE(base_path().AppendASCII("000").AppendASCII(kPlugin1).IsParent(
114      platform_path));
115}
116
117TEST_F(PluginPrivateFileSystemBackendTest, PluginIsolation) {
118  // Open filesystem for kPlugin1 and kPlugin2.
119  const std::string filesystem_id1 = RegisterFileSystem();
120  base::File::Error error = base::File::FILE_ERROR_FAILED;
121  backend()->OpenPrivateFileSystem(
122      kOrigin,
123      kType,
124      filesystem_id1,
125      kPlugin1,
126      storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
127      base::Bind(&DidOpenFileSystem, &error));
128  base::RunLoop().RunUntilIdle();
129  ASSERT_EQ(base::File::FILE_OK, error);
130
131  const std::string filesystem_id2 = RegisterFileSystem();
132  error = base::File::FILE_ERROR_FAILED;
133  backend()->OpenPrivateFileSystem(
134      kOrigin,
135      kType,
136      filesystem_id2,
137      kPlugin2,
138      storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
139      base::Bind(&DidOpenFileSystem, &error));
140  base::RunLoop().RunUntilIdle();
141  ASSERT_EQ(base::File::FILE_OK, error);
142
143  // Create 'foo' in kPlugin1.
144  const GURL root_url1(storage::GetIsolatedFileSystemRootURIString(
145      kOrigin, filesystem_id1, kRootName));
146  FileSystemURL file1 = CreateURL(root_url1, "foo");
147  base::FilePath platform_path;
148  EXPECT_EQ(base::File::FILE_OK,
149            AsyncFileTestHelper::CreateFile(context_.get(), file1));
150  EXPECT_TRUE(AsyncFileTestHelper::FileExists(
151      context_.get(), file1, AsyncFileTestHelper::kDontCheckSize));
152
153  // See the same path is not available in kPlugin2.
154  const GURL root_url2(storage::GetIsolatedFileSystemRootURIString(
155      kOrigin, filesystem_id2, kRootName));
156  FileSystemURL file2 = CreateURL(root_url2, "foo");
157  EXPECT_FALSE(AsyncFileTestHelper::FileExists(
158      context_.get(), file2, AsyncFileTestHelper::kDontCheckSize));
159}
160
161// TODO(kinuko,nhiroki): also test if DeleteOriginDataOnFileThread
162// works fine when there's multiple plugin partitions.
163
164}  // namespace content
165