Home | History | Annotate | Download | only in fileapi
      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/file_stream_writer.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 "net/base/io_buffer.h"
     26 #include "net/base/net_errors.h"
     27 #include "storage/browser/fileapi/async_file_util.h"
     28 #include "storage/browser/fileapi/external_mount_points.h"
     29 #include "storage/browser/fileapi/file_system_url.h"
     30 #include "testing/gtest/include/gtest/gtest.h"
     31 
     32 namespace chromeos {
     33 namespace file_system_provider {
     34 namespace {
     35 
     36 const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
     37 const char kFileSystemId[] = "testing-file-system";
     38 const char kTextToWrite[] = "This is a test of FileStreamWriter.";
     39 
     40 // Pushes a value to the passed log vector.
     41 void LogValue(std::vector<int>* log, int value) {
     42   log->push_back(value);
     43 }
     44 
     45 // Creates a cracked FileSystemURL for tests.
     46 storage::FileSystemURL CreateFileSystemURL(const std::string& mount_point_name,
     47                                            const base::FilePath& file_path) {
     48   const std::string origin = std::string("chrome-extension://") + kExtensionId;
     49   const storage::ExternalMountPoints* const mount_points =
     50       storage::ExternalMountPoints::GetSystemInstance();
     51   return mount_points->CreateCrackedFileSystemURL(
     52       GURL(origin),
     53       storage::kFileSystemTypeExternal,
     54       base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path));
     55 }
     56 
     57 // Creates a Service instance. Used to be able to destroy the service in
     58 // TearDown().
     59 KeyedService* CreateService(content::BrowserContext* context) {
     60   return new Service(Profile::FromBrowserContext(context),
     61                      extensions::ExtensionRegistry::Get(context));
     62 }
     63 
     64 }  // namespace
     65 
     66 class FileSystemProviderFileStreamWriter : public testing::Test {
     67  protected:
     68   FileSystemProviderFileStreamWriter() {}
     69   virtual ~FileSystemProviderFileStreamWriter() {}
     70 
     71   virtual void SetUp() OVERRIDE {
     72     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     73     profile_manager_.reset(
     74         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
     75     ASSERT_TRUE(profile_manager_->SetUp());
     76     profile_ = profile_manager_->CreateTestingProfile("testing-profile");
     77 
     78     ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService);
     79     Service* service = Service::Get(profile_);  // Owned by its factory.
     80     service->SetFileSystemFactoryForTesting(
     81         base::Bind(&FakeProvidedFileSystem::Create));
     82 
     83     const bool result = service->MountFileSystem(kExtensionId,
     84                                                  kFileSystemId,
     85                                                  "Testing File System",
     86                                                  false /* writable */);
     87     ASSERT_TRUE(result);
     88     provided_file_system_ = static_cast<FakeProvidedFileSystem*>(
     89         service->GetProvidedFileSystem(kExtensionId, kFileSystemId));
     90     ASSERT_TRUE(provided_file_system_);
     91     const ProvidedFileSystemInfo& file_system_info =
     92         provided_file_system_->GetFileSystemInfo();
     93     const std::string mount_point_name =
     94         file_system_info.mount_path().BaseName().AsUTF8Unsafe();
     95 
     96     file_url_ = CreateFileSystemURL(
     97         mount_point_name, base::FilePath::FromUTF8Unsafe(kFakeFilePath + 1));
     98     ASSERT_TRUE(file_url_.is_valid());
     99     wrong_file_url_ = CreateFileSystemURL(
    100         mount_point_name, base::FilePath::FromUTF8Unsafe("im-not-here.txt"));
    101     ASSERT_TRUE(wrong_file_url_.is_valid());
    102   }
    103 
    104   virtual void TearDown() OVERRIDE {
    105     // Setting the testing factory to NULL will destroy the created service
    106     // associated with the testing profile.
    107     ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL);
    108   }
    109 
    110   content::TestBrowserThreadBundle thread_bundle_;
    111   base::ScopedTempDir data_dir_;
    112   scoped_ptr<TestingProfileManager> profile_manager_;
    113   TestingProfile* profile_;  // Owned by TestingProfileManager.
    114   FakeProvidedFileSystem* provided_file_system_;  // Owned by Service.
    115   storage::FileSystemURL file_url_;
    116   storage::FileSystemURL wrong_file_url_;
    117 };
    118 
    119 TEST_F(FileSystemProviderFileStreamWriter, Write) {
    120   std::vector<int> write_log;
    121 
    122   const int64 initial_offset = 0;
    123   FileStreamWriter writer(file_url_, initial_offset);
    124   scoped_refptr<net::IOBuffer> io_buffer(new net::StringIOBuffer(kTextToWrite));
    125 
    126   {
    127     const int result = writer.Write(io_buffer.get(),
    128                                     sizeof(kTextToWrite) - 1,
    129                                     base::Bind(&LogValue, &write_log));
    130     EXPECT_EQ(net::ERR_IO_PENDING, result);
    131     base::RunLoop().RunUntilIdle();
    132 
    133     ASSERT_EQ(1u, write_log.size());
    134     EXPECT_LT(0, write_log[0]);
    135     EXPECT_EQ(sizeof(kTextToWrite) - 1, static_cast<size_t>(write_log[0]));
    136 
    137     const FakeEntry* const entry = provided_file_system_->GetEntry(
    138         base::FilePath::FromUTF8Unsafe(kFakeFilePath));
    139     ASSERT_TRUE(entry);
    140 
    141     EXPECT_EQ(kTextToWrite,
    142               entry->contents.substr(0, sizeof(kTextToWrite) - 1));
    143   }
    144 
    145   // Write additional data to be sure, that the writer's offset is shifted
    146   // properly.
    147   {
    148     const int result = writer.Write(io_buffer.get(),
    149                                     sizeof(kTextToWrite) - 1,
    150                                     base::Bind(&LogValue, &write_log));
    151     EXPECT_EQ(net::ERR_IO_PENDING, result);
    152     base::RunLoop().RunUntilIdle();
    153 
    154     ASSERT_EQ(2u, write_log.size());
    155     EXPECT_LT(0, write_log[0]);
    156     EXPECT_EQ(sizeof(kTextToWrite) - 1, static_cast<size_t>(write_log[0]));
    157 
    158     const FakeEntry* const entry = provided_file_system_->GetEntry(
    159         base::FilePath::FromUTF8Unsafe(kFakeFilePath));
    160     ASSERT_TRUE(entry);
    161 
    162     // The testing text is written twice.
    163     const std::string expected_contents =
    164         std::string(kTextToWrite) + kTextToWrite;
    165     EXPECT_EQ(expected_contents,
    166               entry->contents.substr(0, expected_contents.size()));
    167   }
    168 }
    169 
    170 TEST_F(FileSystemProviderFileStreamWriter, Cancel) {
    171   std::vector<int> write_log;
    172 
    173   const int64 initial_offset = 0;
    174   FileStreamWriter writer(file_url_, initial_offset);
    175   scoped_refptr<net::IOBuffer> io_buffer(new net::StringIOBuffer(kTextToWrite));
    176 
    177   const int write_result = writer.Write(io_buffer.get(),
    178                                         sizeof(kTextToWrite) - 1,
    179                                         base::Bind(&LogValue, &write_log));
    180   EXPECT_EQ(net::ERR_IO_PENDING, write_result);
    181 
    182   std::vector<int> cancel_log;
    183   const int cancel_result = writer.Cancel(base::Bind(&LogValue, &cancel_log));
    184   EXPECT_EQ(net::ERR_IO_PENDING, cancel_result);
    185   base::RunLoop().RunUntilIdle();
    186 
    187   EXPECT_EQ(0u, write_log.size());
    188   ASSERT_EQ(1u, cancel_log.size());
    189   EXPECT_EQ(net::OK, cancel_log[0]);
    190 }
    191 
    192 TEST_F(FileSystemProviderFileStreamWriter, Write_WrongFile) {
    193   std::vector<int> write_log;
    194 
    195   const int64 initial_offset = 0;
    196   FileStreamWriter writer(wrong_file_url_, initial_offset);
    197   scoped_refptr<net::IOBuffer> io_buffer(new net::StringIOBuffer(kTextToWrite));
    198 
    199   const int result = writer.Write(io_buffer.get(),
    200                                   sizeof(kTextToWrite) - 1,
    201                                   base::Bind(&LogValue, &write_log));
    202   EXPECT_EQ(net::ERR_IO_PENDING, result);
    203   base::RunLoop().RunUntilIdle();
    204 
    205   ASSERT_EQ(1u, write_log.size());
    206   EXPECT_EQ(net::ERR_FILE_NOT_FOUND, write_log[0]);
    207 }
    208 
    209 TEST_F(FileSystemProviderFileStreamWriter, Write_Append) {
    210   std::vector<int> write_log;
    211 
    212   const FakeEntry* const entry = provided_file_system_->GetEntry(
    213       base::FilePath::FromUTF8Unsafe(kFakeFilePath));
    214   ASSERT_TRUE(entry);
    215 
    216   const std::string original_contents = entry->contents;
    217   const int64 initial_offset = entry->metadata->size;
    218   ASSERT_LT(0, initial_offset);
    219 
    220   FileStreamWriter writer(file_url_, initial_offset);
    221   scoped_refptr<net::IOBuffer> io_buffer(new net::StringIOBuffer(kTextToWrite));
    222 
    223   const int result = writer.Write(io_buffer.get(),
    224                                   sizeof(kTextToWrite) - 1,
    225                                   base::Bind(&LogValue, &write_log));
    226   EXPECT_EQ(net::ERR_IO_PENDING, result);
    227   base::RunLoop().RunUntilIdle();
    228 
    229   ASSERT_EQ(1u, write_log.size());
    230   EXPECT_EQ(sizeof(kTextToWrite) - 1, static_cast<size_t>(write_log[0]));
    231 
    232   const std::string expected_contents = original_contents + kTextToWrite;
    233   EXPECT_EQ(expected_contents, entry->contents);
    234 }
    235 
    236 }  // namespace file_system_provider
    237 }  // namespace chromeos
    238