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/fileapi/provider_async_file_util.h" 6 7#include <string> 8#include <vector> 9 10#include "base/files/file.h" 11#include "base/files/file_path.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/memory/scoped_ptr.h" 14#include "base/memory/weak_ptr.h" 15#include "base/run_loop.h" 16#include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h" 17#include "chrome/browser/chromeos/file_system_provider/service.h" 18#include "chrome/browser/chromeos/file_system_provider/service_factory.h" 19#include "chrome/test/base/testing_browser_process.h" 20#include "chrome/test/base/testing_profile.h" 21#include "chrome/test/base/testing_profile_manager.h" 22#include "content/public/test/test_browser_thread_bundle.h" 23#include "content/public/test/test_file_system_context.h" 24#include "extensions/browser/extension_registry.h" 25#include "storage/browser/fileapi/async_file_util.h" 26#include "storage/browser/fileapi/external_mount_points.h" 27#include "storage/browser/fileapi/file_system_context.h" 28#include "storage/browser/fileapi/file_system_url.h" 29#include "storage/common/blob/shareable_file_reference.h" 30#include "testing/gtest/include/gtest/gtest.h" 31 32namespace chromeos { 33namespace file_system_provider { 34namespace { 35 36const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj"; 37const char kFileSystemId[] = "testing-file-system"; 38 39// Logs callbacks invocations on the tested operations. 40// TODO(mtomasz): Store and verify more arguments, once the operations return 41// anything else than just an error. 42class EventLogger { 43 public: 44 EventLogger() {} 45 virtual ~EventLogger() {} 46 47 void OnStatus(base::File::Error error) { 48 result_.reset(new base::File::Error(error)); 49 } 50 51 void OnCreateOrOpen(base::File file, 52 const base::Closure& on_close_callback) { 53 if (file.IsValid()) 54 result_.reset(new base::File::Error(base::File::FILE_OK)); 55 56 result_.reset(new base::File::Error(file.error_details())); 57 } 58 59 void OnEnsureFileExists(base::File::Error error, bool created) { 60 result_.reset(new base::File::Error(error)); 61 } 62 63 void OnGetFileInfo(base::File::Error error, 64 const base::File::Info& file_info) { 65 result_.reset(new base::File::Error(error)); 66 } 67 68 void OnReadDirectory(base::File::Error error, 69 const storage::AsyncFileUtil::EntryList& file_list, 70 bool has_more) { 71 result_.reset(new base::File::Error(error)); 72 } 73 74 void OnCreateSnapshotFile( 75 base::File::Error error, 76 const base::File::Info& file_info, 77 const base::FilePath& platform_path, 78 const scoped_refptr<storage::ShareableFileReference>& file_ref) { 79 result_.reset(new base::File::Error(error)); 80 } 81 82 void OnCopyFileProgress(int64 size) {} 83 84 base::File::Error* result() { return result_.get(); } 85 86 private: 87 scoped_ptr<base::File::Error> result_; 88 DISALLOW_COPY_AND_ASSIGN(EventLogger); 89}; 90 91// Creates a cracked FileSystemURL for tests. 92storage::FileSystemURL CreateFileSystemURL(const std::string& mount_point_name, 93 const base::FilePath& file_path) { 94 const std::string origin = std::string("chrome-extension://") + kExtensionId; 95 const storage::ExternalMountPoints* const mount_points = 96 storage::ExternalMountPoints::GetSystemInstance(); 97 return mount_points->CreateCrackedFileSystemURL( 98 GURL(origin), 99 storage::kFileSystemTypeExternal, 100 base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path)); 101} 102 103// Creates a Service instance. Used to be able to destroy the service in 104// TearDown(). 105KeyedService* CreateService(content::BrowserContext* context) { 106 return new Service(Profile::FromBrowserContext(context), 107 extensions::ExtensionRegistry::Get(context)); 108} 109 110} // namespace 111 112// Tests in this file are very lightweight and just test integration between 113// AsyncFileUtil and ProvideFileSystemInterface. Currently it tests if not 114// implemented operations return a correct error code. For not allowed 115// operations it is FILE_ERROR_ACCESS_DENIED, and for not implemented the error 116// is FILE_ERROR_INVALID_OPERATION. 117class FileSystemProviderProviderAsyncFileUtilTest : public testing::Test { 118 protected: 119 FileSystemProviderProviderAsyncFileUtilTest() {} 120 virtual ~FileSystemProviderProviderAsyncFileUtilTest() {} 121 122 virtual void SetUp() OVERRIDE { 123 ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); 124 profile_manager_.reset( 125 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); 126 ASSERT_TRUE(profile_manager_->SetUp()); 127 profile_ = profile_manager_->CreateTestingProfile("testing-profile"); 128 async_file_util_.reset(new internal::ProviderAsyncFileUtil); 129 130 file_system_context_ = 131 content::CreateFileSystemContextForTesting(NULL, data_dir_.path()); 132 133 ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService); 134 Service* service = Service::Get(profile_); // Owned by its factory. 135 service->SetFileSystemFactoryForTesting( 136 base::Bind(&FakeProvidedFileSystem::Create)); 137 138 const bool result = service->MountFileSystem(kExtensionId, 139 kFileSystemId, 140 "Testing File System", 141 false /* writable */); 142 ASSERT_TRUE(result); 143 const ProvidedFileSystemInfo& file_system_info = 144 service->GetProvidedFileSystem(kExtensionId, kFileSystemId) 145 ->GetFileSystemInfo(); 146 const std::string mount_point_name = 147 file_system_info.mount_path().BaseName().AsUTF8Unsafe(); 148 149 file_url_ = 150 CreateFileSystemURL(mount_point_name, 151 base::FilePath::FromUTF8Unsafe( 152 kFakeFilePath + 1 /* No leading slash. */)); 153 ASSERT_TRUE(file_url_.is_valid()); 154 directory_url_ = CreateFileSystemURL( 155 mount_point_name, base::FilePath::FromUTF8Unsafe("hello")); 156 ASSERT_TRUE(directory_url_.is_valid()); 157 root_url_ = CreateFileSystemURL(mount_point_name, base::FilePath()); 158 ASSERT_TRUE(root_url_.is_valid()); 159 } 160 161 virtual void TearDown() OVERRIDE { 162 // Setting the testing factory to NULL will destroy the created service 163 // associated with the testing profile. 164 ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL); 165 } 166 167 scoped_ptr<storage::FileSystemOperationContext> CreateOperationContext() { 168 return make_scoped_ptr( 169 new storage::FileSystemOperationContext(file_system_context_.get())); 170 } 171 172 content::TestBrowserThreadBundle thread_bundle_; 173 base::ScopedTempDir data_dir_; 174 scoped_ptr<TestingProfileManager> profile_manager_; 175 TestingProfile* profile_; // Owned by TestingProfileManager. 176 scoped_ptr<storage::AsyncFileUtil> async_file_util_; 177 scoped_refptr<storage::FileSystemContext> file_system_context_; 178 storage::FileSystemURL file_url_; 179 storage::FileSystemURL directory_url_; 180 storage::FileSystemURL root_url_; 181}; 182 183TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_Create) { 184 EventLogger logger; 185 186 async_file_util_->CreateOrOpen( 187 CreateOperationContext(), 188 file_url_, 189 base::File::FLAG_CREATE, 190 base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger))); 191 192 ASSERT_TRUE(logger.result()); 193 EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result()); 194} 195 196TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_CreateAlways) { 197 EventLogger logger; 198 199 async_file_util_->CreateOrOpen( 200 CreateOperationContext(), 201 file_url_, 202 base::File::FLAG_CREATE_ALWAYS, 203 base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger))); 204 205 ASSERT_TRUE(logger.result()); 206 EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result()); 207} 208 209TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_OpenAlways) { 210 EventLogger logger; 211 212 async_file_util_->CreateOrOpen( 213 CreateOperationContext(), 214 file_url_, 215 base::File::FLAG_OPEN_ALWAYS, 216 base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger))); 217 218 ASSERT_TRUE(logger.result()); 219 EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result()); 220} 221 222TEST_F(FileSystemProviderProviderAsyncFileUtilTest, 223 CreateOrOpen_OpenTruncated) { 224 EventLogger logger; 225 226 async_file_util_->CreateOrOpen( 227 CreateOperationContext(), 228 file_url_, 229 base::File::FLAG_OPEN_TRUNCATED, 230 base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger))); 231 232 ASSERT_TRUE(logger.result()); 233 EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result()); 234} 235 236TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateOrOpen_Open) { 237 EventLogger logger; 238 239 async_file_util_->CreateOrOpen( 240 CreateOperationContext(), 241 file_url_, 242 base::File::FLAG_OPEN, 243 base::Bind(&EventLogger::OnCreateOrOpen, base::Unretained(&logger))); 244 245 ASSERT_TRUE(logger.result()); 246 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, *logger.result()); 247} 248 249TEST_F(FileSystemProviderProviderAsyncFileUtilTest, EnsureFileExists) { 250 EventLogger logger; 251 252 async_file_util_->EnsureFileExists( 253 CreateOperationContext(), 254 file_url_, 255 base::Bind(&EventLogger::OnEnsureFileExists, base::Unretained(&logger))); 256 base::RunLoop().RunUntilIdle(); 257 258 ASSERT_TRUE(logger.result()); 259 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 260} 261 262TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateDirectory) { 263 EventLogger logger; 264 265 async_file_util_->CreateDirectory( 266 CreateOperationContext(), 267 directory_url_, 268 false, // exclusive 269 false, // recursive 270 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 271 base::RunLoop().RunUntilIdle(); 272 273 ASSERT_TRUE(logger.result()); 274 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 275} 276 277TEST_F(FileSystemProviderProviderAsyncFileUtilTest, GetFileInfo) { 278 EventLogger logger; 279 280 async_file_util_->GetFileInfo( 281 CreateOperationContext(), 282 root_url_, 283 base::Bind(&EventLogger::OnGetFileInfo, base::Unretained(&logger))); 284 base::RunLoop().RunUntilIdle(); 285 286 ASSERT_TRUE(logger.result()); 287 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 288} 289 290TEST_F(FileSystemProviderProviderAsyncFileUtilTest, ReadDirectory) { 291 EventLogger logger; 292 293 async_file_util_->ReadDirectory( 294 CreateOperationContext(), 295 root_url_, 296 base::Bind(&EventLogger::OnReadDirectory, base::Unretained(&logger))); 297 base::RunLoop().RunUntilIdle(); 298 299 ASSERT_TRUE(logger.result()); 300 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 301} 302 303TEST_F(FileSystemProviderProviderAsyncFileUtilTest, Touch) { 304 EventLogger logger; 305 306 async_file_util_->Touch( 307 CreateOperationContext(), 308 file_url_, 309 base::Time(), // last_modified_time 310 base::Time(), // last_access_time 311 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 312 313 ASSERT_TRUE(logger.result()); 314 EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result()); 315} 316 317TEST_F(FileSystemProviderProviderAsyncFileUtilTest, Truncate) { 318 EventLogger logger; 319 320 async_file_util_->Truncate( 321 CreateOperationContext(), 322 file_url_, 323 0, // length 324 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 325 base::RunLoop().RunUntilIdle(); 326 327 ASSERT_TRUE(logger.result()); 328 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 329} 330 331TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CopyFileLocal) { 332 EventLogger logger; 333 334 async_file_util_->CopyFileLocal( 335 CreateOperationContext(), 336 file_url_, // src_url 337 file_url_, // dst_url 338 storage::FileSystemOperation::OPTION_NONE, 339 base::Bind(&EventLogger::OnCopyFileProgress, base::Unretained(&logger)), 340 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 341 base::RunLoop().RunUntilIdle(); 342 343 ASSERT_TRUE(logger.result()); 344 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 345} 346 347TEST_F(FileSystemProviderProviderAsyncFileUtilTest, MoveFileLocal) { 348 EventLogger logger; 349 350 async_file_util_->MoveFileLocal( 351 CreateOperationContext(), 352 file_url_, // src_url 353 file_url_, // dst_url 354 storage::FileSystemOperation::OPTION_NONE, 355 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 356 base::RunLoop().RunUntilIdle(); 357 358 ASSERT_TRUE(logger.result()); 359 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 360} 361 362TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CopyInForeignFile) { 363 EventLogger logger; 364 365 async_file_util_->CopyInForeignFile( 366 CreateOperationContext(), 367 base::FilePath(), // src_file_path 368 file_url_, // dst_url 369 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 370 371 ASSERT_TRUE(logger.result()); 372 EXPECT_EQ(base::File::FILE_ERROR_ACCESS_DENIED, *logger.result()); 373} 374 375TEST_F(FileSystemProviderProviderAsyncFileUtilTest, DeleteFile) { 376 EventLogger logger; 377 378 async_file_util_->DeleteFile( 379 CreateOperationContext(), 380 file_url_, 381 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 382 base::RunLoop().RunUntilIdle(); 383 384 ASSERT_TRUE(logger.result()); 385 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 386} 387 388TEST_F(FileSystemProviderProviderAsyncFileUtilTest, DeleteDirectory) { 389 EventLogger logger; 390 391 async_file_util_->DeleteDirectory( 392 CreateOperationContext(), 393 directory_url_, 394 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 395 base::RunLoop().RunUntilIdle(); 396 397 ASSERT_TRUE(logger.result()); 398 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 399} 400 401TEST_F(FileSystemProviderProviderAsyncFileUtilTest, DeleteRecursively) { 402 EventLogger logger; 403 404 async_file_util_->DeleteRecursively( 405 CreateOperationContext(), 406 directory_url_, 407 base::Bind(&EventLogger::OnStatus, base::Unretained(&logger))); 408 base::RunLoop().RunUntilIdle(); 409 410 ASSERT_TRUE(logger.result()); 411 EXPECT_EQ(base::File::FILE_OK, *logger.result()); 412} 413 414TEST_F(FileSystemProviderProviderAsyncFileUtilTest, CreateSnapshotFile) { 415 EventLogger logger; 416 417 async_file_util_->CreateSnapshotFile( 418 CreateOperationContext(), 419 file_url_, 420 base::Bind(&EventLogger::OnCreateSnapshotFile, 421 base::Unretained(&logger))); 422 423 ASSERT_TRUE(logger.result()); 424 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, *logger.result()); 425} 426 427} // namespace file_system_provider 428} // namespace chromeos 429