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