16cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com// Copyright 2013 The Chromium Authors. All rights reserved.
26cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com// Use of this source code is governed by a BSD-style license that can be
36cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com// found in the LICENSE file.
46cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com
56cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include "storage/browser/fileapi/file_system_dir_url_request_job.h"
66cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com
76cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include <string>
86cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com
96cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include "base/files/file_path.h"
103f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org#include "base/files/file_util.h"
113f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org#include "base/files/scoped_temp_dir.h"
123f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org#include "base/format_macros.h"
136cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include "base/memory/scoped_vector.h"
146cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include "base/memory/weak_ptr.h"
153f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org#include "base/message_loop/message_loop.h"
166cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include "base/run_loop.h"
176cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include "base/strings/string_piece.h"
189299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "base/strings/utf_string_conversions.h"
199299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "content/public/test/mock_special_storage_policy.h"
200689d7b12e7c427a077b003d3d8ae759d86f798freed#include "content/public/test/test_file_system_backend.h"
210689d7b12e7c427a077b003d3d8ae759d86f798freed#include "content/public/test/test_file_system_context.h"
229299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "net/base/net_errors.h"
239299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "net/base/net_util.h"
249299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "net/base/request_priority.h"
259299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "net/http/http_request_headers.h"
269299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "net/url_request/url_request.h"
279299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "net/url_request/url_request_context.h"
289299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "net/url_request/url_request_test_util.h"
299299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "storage/browser/fileapi/external_mount_points.h"
309299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "storage/browser/fileapi/file_system_context.h"
319299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "storage/browser/fileapi/file_system_file_util.h"
326cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com#include "storage/browser/fileapi/file_system_operation_context.h"
3324c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org#include "storage/browser/fileapi/file_system_url.h"
3424c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org#include "testing/gtest/include/gtest/gtest.h"
3524c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org#include "third_party/icu/source/i18n/unicode/regex.h"
3624c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org
3724c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.orgusing storage::FileSystemContext;
3824c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.orgusing storage::FileSystemOperationContext;
3924c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.orgusing storage::FileSystemURL;
4024c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org
4124c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.orgnamespace content {
4224c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.orgnamespace {
4324c568c1597de9f54df8cea3b46f2e93028a5aeccommit-bot@chromium.org
4458b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com// We always use the TEMPORARY FileSystem in this test.
45163b56734fe01c088581895a8e0b65ddf1cb4fa5keyar@chromium.orgconst char kFileSystemURLPrefix[] = "filesystem:http://remote/temporary/";
46163b56734fe01c088581895a8e0b65ddf1cb4fa5keyar@chromium.org
47163b56734fe01c088581895a8e0b65ddf1cb4fa5keyar@chromium.orgconst char kValidExternalMountPoint[] = "mnt_name";
48163b56734fe01c088581895a8e0b65ddf1cb4fa5keyar@chromium.org
496cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com// An auto mounter that will try to mount anything for |storage_domain| =
506c22573edb234ad14df947278cfed010669a39a7reed// "automount", but will only succeed for the mount point "mnt_name".
51dbfac8a72393eaf01670aeb3244de0e18d8faf98junov@google.combool TestAutoMountForURLRequest(
526cf5303b93e2afbabefc8123b6e2efac8e27a603twiz@google.com    const net::URLRequest* /*url_request*/,
533f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org    const storage::FileSystemURL& filesystem_url,
543f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org    const std::string& storage_domain,
553f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org    const base::Callback<void(base::File::Error result)>& callback) {
563f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org  if (storage_domain != "automount")
573f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org    return false;
583f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org
593f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org  std::vector<base::FilePath::StringType> components;
603f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org  filesystem_url.path().GetComponents(&components);
613f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org  std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe();
623f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org
633f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org  if (mount_point == kValidExternalMountPoint) {
643f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org    storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
653f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org        kValidExternalMountPoint,
663f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org        storage::kFileSystemTypeTest,
673f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org        storage::FileSystemMountOption(),
683f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org        base::FilePath());
693f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org    callback.Run(base::File::FILE_OK);
703f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org  } else {
713f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org    callback.Run(base::File::FILE_ERROR_NOT_FOUND);
723f0451772109959fcb79bacf2c9a03e0eb39ff27commit-bot@chromium.org  }
73  return true;
74}
75
76class FileSystemDirURLRequestJobFactory : public net::URLRequestJobFactory {
77 public:
78  FileSystemDirURLRequestJobFactory(const std::string& storage_domain,
79                                    FileSystemContext* context)
80      : storage_domain_(storage_domain), file_system_context_(context) {
81  }
82
83  virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
84      const std::string& scheme,
85      net::URLRequest* request,
86      net::NetworkDelegate* network_delegate) const OVERRIDE {
87    return new storage::FileSystemDirURLRequestJob(
88        request, network_delegate, storage_domain_, file_system_context_);
89  }
90
91  virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
92    return true;
93  }
94
95  virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
96    return true;
97  }
98
99  virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
100    return false;
101  }
102
103 private:
104  std::string storage_domain_;
105  FileSystemContext* file_system_context_;
106};
107
108
109}  // namespace
110
111class FileSystemDirURLRequestJobTest : public testing::Test {
112 protected:
113  FileSystemDirURLRequestJobTest()
114    : weak_factory_(this) {
115  }
116
117  virtual void SetUp() OVERRIDE {
118    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
119
120    special_storage_policy_ = new MockSpecialStoragePolicy;
121    file_system_context_ = CreateFileSystemContextForTesting(
122        NULL, temp_dir_.path());
123
124    file_system_context_->OpenFileSystem(
125        GURL("http://remote/"),
126        storage::kFileSystemTypeTemporary,
127        storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
128        base::Bind(&FileSystemDirURLRequestJobTest::OnOpenFileSystem,
129                   weak_factory_.GetWeakPtr()));
130    base::RunLoop().RunUntilIdle();
131  }
132
133  virtual void TearDown() OVERRIDE {
134    // NOTE: order matters, request must die before delegate
135    request_.reset(NULL);
136    delegate_.reset(NULL);
137  }
138
139  void SetUpAutoMountContext(base::FilePath* mnt_point) {
140    *mnt_point = temp_dir_.path().AppendASCII("auto_mount_dir");
141    ASSERT_TRUE(base::CreateDirectory(*mnt_point));
142
143    ScopedVector<storage::FileSystemBackend> additional_providers;
144    additional_providers.push_back(new TestFileSystemBackend(
145        base::MessageLoopProxy::current().get(), *mnt_point));
146
147    std::vector<storage::URLRequestAutoMountHandler> handlers;
148    handlers.push_back(base::Bind(&TestAutoMountForURLRequest));
149
150    file_system_context_ = CreateFileSystemContextWithAutoMountersForTesting(
151        NULL, additional_providers.Pass(), handlers, temp_dir_.path());
152  }
153
154  void OnOpenFileSystem(const GURL& root_url,
155                        const std::string& name,
156                        base::File::Error result) {
157    ASSERT_EQ(base::File::FILE_OK, result);
158  }
159
160  void TestRequestHelper(const GURL& url, bool run_to_completion,
161                         FileSystemContext* file_system_context) {
162    delegate_.reset(new net::TestDelegate());
163    delegate_->set_quit_on_redirect(true);
164    job_factory_.reset(new FileSystemDirURLRequestJobFactory(
165        url.GetOrigin().host(), file_system_context));
166    empty_context_.set_job_factory(job_factory_.get());
167
168    request_ = empty_context_.CreateRequest(
169        url, net::DEFAULT_PRIORITY, delegate_.get(), NULL);
170    request_->Start();
171    ASSERT_TRUE(request_->is_pending());  // verify that we're starting async
172    if (run_to_completion)
173      base::MessageLoop::current()->Run();
174  }
175
176  void TestRequest(const GURL& url) {
177    TestRequestHelper(url, true, file_system_context_.get());
178  }
179
180  void TestRequestWithContext(const GURL& url,
181                              FileSystemContext* file_system_context) {
182    TestRequestHelper(url, true, file_system_context);
183  }
184
185  void TestRequestNoRun(const GURL& url) {
186    TestRequestHelper(url, false, file_system_context_.get());
187  }
188
189  FileSystemURL CreateURL(const base::FilePath& file_path) {
190    return file_system_context_->CreateCrackedFileSystemURL(
191        GURL("http://remote"), storage::kFileSystemTypeTemporary, file_path);
192  }
193
194  FileSystemOperationContext* NewOperationContext() {
195    FileSystemOperationContext* context(
196        new FileSystemOperationContext(file_system_context_.get()));
197    context->set_allowed_bytes_growth(1024);
198    return context;
199  }
200
201  void CreateDirectory(const base::StringPiece& dir_name) {
202    base::FilePath path = base::FilePath().AppendASCII(dir_name);
203    scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
204    ASSERT_EQ(base::File::FILE_OK, file_util()->CreateDirectory(
205        context.get(),
206        CreateURL(path),
207        false /* exclusive */,
208        false /* recursive */));
209  }
210
211  void EnsureFileExists(const base::StringPiece file_name) {
212    base::FilePath path = base::FilePath().AppendASCII(file_name);
213    scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
214    ASSERT_EQ(base::File::FILE_OK, file_util()->EnsureFileExists(
215        context.get(), CreateURL(path), NULL));
216  }
217
218  void TruncateFile(const base::StringPiece file_name, int64 length) {
219    base::FilePath path = base::FilePath().AppendASCII(file_name);
220    scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
221    ASSERT_EQ(base::File::FILE_OK, file_util()->Truncate(
222        context.get(), CreateURL(path), length));
223  }
224
225  base::File::Error GetFileInfo(const base::FilePath& path,
226                                base::File::Info* file_info,
227                                base::FilePath* platform_file_path) {
228    scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
229    return file_util()->GetFileInfo(context.get(),
230                                    CreateURL(path),
231                                    file_info, platform_file_path);
232  }
233
234  // If |size| is negative, the reported size is ignored.
235  void VerifyListingEntry(const std::string& entry_line,
236                          const std::string& name,
237                          const std::string& url,
238                          bool is_directory,
239                          int64 size) {
240#define STR "([^\"]*)"
241    icu::UnicodeString pattern("^<script>addRow\\(\"" STR "\",\"" STR
242                               "\",(0|1),\"" STR "\",\"" STR "\"\\);</script>");
243#undef STR
244    icu::UnicodeString input(entry_line.c_str());
245
246    UErrorCode status = U_ZERO_ERROR;
247    icu::RegexMatcher match(pattern, input, 0, status);
248
249    EXPECT_TRUE(match.find());
250    EXPECT_EQ(5, match.groupCount());
251    EXPECT_EQ(icu::UnicodeString(name.c_str()), match.group(1, status));
252    EXPECT_EQ(icu::UnicodeString(url.c_str()), match.group(2, status));
253    EXPECT_EQ(icu::UnicodeString(is_directory ? "1" : "0"),
254              match.group(3, status));
255    if (size >= 0) {
256      icu::UnicodeString size_string(FormatBytesUnlocalized(size).c_str());
257      EXPECT_EQ(size_string, match.group(4, status));
258    }
259
260    base::Time date;
261    icu::UnicodeString date_ustr(match.group(5, status));
262    std::string date_str;
263    base::UTF16ToUTF8(date_ustr.getBuffer(), date_ustr.length(), &date_str);
264    EXPECT_TRUE(base::Time::FromString(date_str.c_str(), &date));
265    EXPECT_FALSE(date.is_null());
266  }
267
268  GURL CreateFileSystemURL(const std::string path) {
269    return GURL(kFileSystemURLPrefix + path);
270  }
271
272  storage::FileSystemFileUtil* file_util() {
273    return file_system_context_->sandbox_delegate()->sync_file_util();
274  }
275
276  // Put the message loop at the top, so that it's the last thing deleted.
277  // Delete all MessageLoopProxy objects before the MessageLoop, to help prevent
278  // leaks caused by tasks posted during shutdown.
279  base::MessageLoopForIO message_loop_;
280
281  base::ScopedTempDir temp_dir_;
282  net::URLRequestContext empty_context_;
283  scoped_ptr<net::TestDelegate> delegate_;
284  scoped_ptr<net::URLRequest> request_;
285  scoped_ptr<FileSystemDirURLRequestJobFactory> job_factory_;
286  scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
287  scoped_refptr<FileSystemContext> file_system_context_;
288  base::WeakPtrFactory<FileSystemDirURLRequestJobTest> weak_factory_;
289};
290
291namespace {
292
293TEST_F(FileSystemDirURLRequestJobTest, DirectoryListing) {
294  CreateDirectory("foo");
295  CreateDirectory("foo/bar");
296  CreateDirectory("foo/bar/baz");
297
298  EnsureFileExists("foo/bar/hoge");
299  TruncateFile("foo/bar/hoge", 10);
300
301  TestRequest(CreateFileSystemURL("foo/bar/"));
302
303  ASSERT_FALSE(request_->is_pending());
304  EXPECT_EQ(1, delegate_->response_started_count());
305  EXPECT_FALSE(delegate_->received_data_before_response());
306  EXPECT_GT(delegate_->bytes_received(), 0);
307
308  std::istringstream in(delegate_->data_received());
309  std::string line;
310  EXPECT_TRUE(!!std::getline(in, line));
311
312#if defined(OS_WIN)
313  EXPECT_EQ("<script>start(\"foo\\\\bar\");</script>", line);
314#elif defined(OS_POSIX)
315  EXPECT_EQ("<script>start(\"/foo/bar\");</script>", line);
316#endif
317
318  EXPECT_TRUE(!!std::getline(in, line));
319  VerifyListingEntry(line, "hoge", "hoge", false, 10);
320
321  EXPECT_TRUE(!!std::getline(in, line));
322  VerifyListingEntry(line, "baz", "baz", true, 0);
323  EXPECT_FALSE(!!std::getline(in, line));
324}
325
326TEST_F(FileSystemDirURLRequestJobTest, InvalidURL) {
327  TestRequest(GURL("filesystem:/foo/bar/baz"));
328  ASSERT_FALSE(request_->is_pending());
329  EXPECT_TRUE(delegate_->request_failed());
330  ASSERT_FALSE(request_->status().is_success());
331  EXPECT_EQ(net::ERR_INVALID_URL, request_->status().error());
332}
333
334TEST_F(FileSystemDirURLRequestJobTest, NoSuchRoot) {
335  TestRequest(GURL("filesystem:http://remote/persistent/somedir/"));
336  ASSERT_FALSE(request_->is_pending());
337  ASSERT_FALSE(request_->status().is_success());
338  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
339}
340
341TEST_F(FileSystemDirURLRequestJobTest, NoSuchDirectory) {
342  TestRequest(CreateFileSystemURL("somedir/"));
343  ASSERT_FALSE(request_->is_pending());
344  ASSERT_FALSE(request_->status().is_success());
345  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
346}
347
348TEST_F(FileSystemDirURLRequestJobTest, Cancel) {
349  CreateDirectory("foo");
350  TestRequestNoRun(CreateFileSystemURL("foo/"));
351  // Run StartAsync() and only StartAsync().
352  base::MessageLoop::current()->DeleteSoon(FROM_HERE, request_.release());
353  base::RunLoop().RunUntilIdle();
354  // If we get here, success! we didn't crash!
355}
356
357TEST_F(FileSystemDirURLRequestJobTest, Incognito) {
358  CreateDirectory("foo");
359
360  scoped_refptr<FileSystemContext> file_system_context =
361      CreateIncognitoFileSystemContextForTesting(NULL, temp_dir_.path());
362
363  TestRequestWithContext(CreateFileSystemURL("/"),
364                         file_system_context.get());
365  ASSERT_FALSE(request_->is_pending());
366  ASSERT_TRUE(request_->status().is_success());
367
368  std::istringstream in(delegate_->data_received());
369  std::string line;
370  EXPECT_TRUE(!!std::getline(in, line));
371  EXPECT_FALSE(!!std::getline(in, line));
372
373  TestRequestWithContext(CreateFileSystemURL("foo"),
374                         file_system_context.get());
375  ASSERT_FALSE(request_->is_pending());
376  ASSERT_FALSE(request_->status().is_success());
377  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
378}
379
380TEST_F(FileSystemDirURLRequestJobTest, AutoMountDirectoryListing) {
381  base::FilePath mnt_point;
382  SetUpAutoMountContext(&mnt_point);
383  ASSERT_TRUE(base::CreateDirectory(mnt_point));
384  ASSERT_TRUE(base::CreateDirectory(mnt_point.AppendASCII("foo")));
385  ASSERT_EQ(10,
386            base::WriteFile(mnt_point.AppendASCII("bar"), "1234567890", 10));
387
388  TestRequest(GURL("filesystem:http://automount/external/mnt_name"));
389
390  ASSERT_FALSE(request_->is_pending());
391  EXPECT_EQ(1, delegate_->response_started_count());
392  EXPECT_FALSE(delegate_->received_data_before_response());
393  EXPECT_GT(delegate_->bytes_received(), 0);
394
395  std::istringstream in(delegate_->data_received());
396  std::string line;
397  EXPECT_TRUE(!!std::getline(in, line));  // |line| contains the temp dir path.
398
399  // Result order is not guaranteed, so sort the results.
400  std::vector<std::string> listing_entries;
401  while (!!std::getline(in, line))
402    listing_entries.push_back(line);
403
404  ASSERT_EQ(2U, listing_entries.size());
405  std::sort(listing_entries.begin(), listing_entries.end());
406  VerifyListingEntry(listing_entries[0], "bar", "bar", false, 10);
407  VerifyListingEntry(listing_entries[1], "foo", "foo", true, -1);
408
409  ASSERT_TRUE(
410      storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
411          kValidExternalMountPoint));
412}
413
414TEST_F(FileSystemDirURLRequestJobTest, AutoMountInvalidRoot) {
415  base::FilePath mnt_point;
416  SetUpAutoMountContext(&mnt_point);
417  TestRequest(GURL("filesystem:http://automount/external/invalid"));
418
419  ASSERT_FALSE(request_->is_pending());
420  ASSERT_FALSE(request_->status().is_success());
421  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
422
423  ASSERT_FALSE(
424      storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
425          "invalid"));
426}
427
428TEST_F(FileSystemDirURLRequestJobTest, AutoMountNoHandler) {
429  base::FilePath mnt_point;
430  SetUpAutoMountContext(&mnt_point);
431  TestRequest(GURL("filesystem:http://noauto/external/mnt_name"));
432
433  ASSERT_FALSE(request_->is_pending());
434  ASSERT_FALSE(request_->status().is_success());
435  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
436
437  ASSERT_FALSE(
438      storage::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
439          kValidExternalMountPoint));
440}
441
442}  // namespace (anonymous)
443}  // namespace content
444