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