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_reader.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 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 file stream reader. 40class EventLogger { 41 public: 42 EventLogger() : weak_ptr_factory_(this) {} 43 virtual ~EventLogger() {} 44 45 void OnRead(int result) { results_.push_back(result); } 46 void OnGetLength(int64 result) { results_.push_back(result); } 47 48 base::WeakPtr<EventLogger> GetWeakPtr() { 49 return weak_ptr_factory_.GetWeakPtr(); 50 } 51 52 const std::vector<int64>& results() const { return results_; } 53 54 private: 55 std::vector<int64> results_; 56 base::WeakPtrFactory<EventLogger> weak_ptr_factory_; 57 58 DISALLOW_COPY_AND_ASSIGN(EventLogger); 59}; 60 61// Creates a cracked FileSystemURL for tests. 62storage::FileSystemURL CreateFileSystemURL(const std::string& mount_point_name, 63 const base::FilePath& file_path) { 64 const std::string origin = std::string("chrome-extension://") + kExtensionId; 65 const storage::ExternalMountPoints* const mount_points = 66 storage::ExternalMountPoints::GetSystemInstance(); 67 return mount_points->CreateCrackedFileSystemURL( 68 GURL(origin), 69 storage::kFileSystemTypeExternal, 70 base::FilePath::FromUTF8Unsafe(mount_point_name).Append(file_path)); 71} 72 73// Creates a Service instance. Used to be able to destroy the service in 74// TearDown(). 75KeyedService* CreateService(content::BrowserContext* context) { 76 return new Service(Profile::FromBrowserContext(context), 77 extensions::ExtensionRegistry::Get(context)); 78} 79 80} // namespace 81 82class FileSystemProviderFileStreamReader : public testing::Test { 83 protected: 84 FileSystemProviderFileStreamReader() : profile_(NULL), fake_file_(NULL) {} 85 virtual ~FileSystemProviderFileStreamReader() {} 86 87 virtual void SetUp() OVERRIDE { 88 ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); 89 profile_manager_.reset( 90 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); 91 ASSERT_TRUE(profile_manager_->SetUp()); 92 profile_ = profile_manager_->CreateTestingProfile("testing-profile"); 93 94 ServiceFactory::GetInstance()->SetTestingFactory(profile_, &CreateService); 95 Service* service = Service::Get(profile_); // Owned by its factory. 96 service->SetFileSystemFactoryForTesting( 97 base::Bind(&FakeProvidedFileSystem::Create)); 98 99 const bool result = service->MountFileSystem(kExtensionId, 100 kFileSystemId, 101 "Testing File System", 102 false /* writable */); 103 ASSERT_TRUE(result); 104 FakeProvidedFileSystem* provided_file_system = 105 static_cast<FakeProvidedFileSystem*>( 106 service->GetProvidedFileSystem(kExtensionId, kFileSystemId)); 107 ASSERT_TRUE(provided_file_system); 108 fake_file_ = provided_file_system->GetEntry( 109 base::FilePath::FromUTF8Unsafe(kFakeFilePath)); 110 ASSERT_TRUE(fake_file_); 111 const ProvidedFileSystemInfo& file_system_info = 112 service->GetProvidedFileSystem(kExtensionId, kFileSystemId) 113 ->GetFileSystemInfo(); 114 const std::string mount_point_name = 115 file_system_info.mount_path().BaseName().AsUTF8Unsafe(); 116 117 file_url_ = CreateFileSystemURL( 118 mount_point_name, base::FilePath::FromUTF8Unsafe(kFakeFilePath + 1)); 119 ASSERT_TRUE(file_url_.is_valid()); 120 wrong_file_url_ = CreateFileSystemURL( 121 mount_point_name, base::FilePath::FromUTF8Unsafe("im-not-here.txt")); 122 ASSERT_TRUE(wrong_file_url_.is_valid()); 123 } 124 125 virtual void TearDown() OVERRIDE { 126 // Setting the testing factory to NULL will destroy the created service 127 // associated with the testing profile. 128 ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL); 129 } 130 131 content::TestBrowserThreadBundle thread_bundle_; 132 base::ScopedTempDir data_dir_; 133 scoped_ptr<TestingProfileManager> profile_manager_; 134 TestingProfile* profile_; // Owned by TestingProfileManager. 135 const FakeEntry* fake_file_; // Owned by FakePRovidedFileSystem. 136 storage::FileSystemURL file_url_; 137 storage::FileSystemURL wrong_file_url_; 138}; 139 140TEST_F(FileSystemProviderFileStreamReader, Read_AllAtOnce) { 141 EventLogger logger; 142 143 const int64 initial_offset = 0; 144 FileStreamReader reader( 145 NULL, file_url_, initial_offset, fake_file_->metadata->modification_time); 146 scoped_refptr<net::IOBuffer> io_buffer( 147 new net::IOBuffer(fake_file_->metadata->size)); 148 149 const int result = 150 reader.Read(io_buffer.get(), 151 fake_file_->metadata->size, 152 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 153 EXPECT_EQ(net::ERR_IO_PENDING, result); 154 base::RunLoop().RunUntilIdle(); 155 156 ASSERT_EQ(1u, logger.results().size()); 157 EXPECT_LT(0, logger.results()[0]); 158 EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]); 159 160 std::string buffer_as_string(io_buffer->data(), fake_file_->metadata->size); 161 EXPECT_EQ(fake_file_->contents, buffer_as_string); 162} 163 164TEST_F(FileSystemProviderFileStreamReader, Read_WrongFile) { 165 EventLogger logger; 166 167 const int64 initial_offset = 0; 168 FileStreamReader reader(NULL, 169 wrong_file_url_, 170 initial_offset, 171 fake_file_->metadata->modification_time); 172 scoped_refptr<net::IOBuffer> io_buffer( 173 new net::IOBuffer(fake_file_->metadata->size)); 174 175 const int result = 176 reader.Read(io_buffer.get(), 177 fake_file_->metadata->size, 178 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 179 EXPECT_EQ(net::ERR_IO_PENDING, result); 180 base::RunLoop().RunUntilIdle(); 181 182 ASSERT_EQ(1u, logger.results().size()); 183 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, logger.results()[0]); 184} 185 186TEST_F(FileSystemProviderFileStreamReader, Read_InChunks) { 187 EventLogger logger; 188 189 const int64 initial_offset = 0; 190 FileStreamReader reader( 191 NULL, file_url_, initial_offset, fake_file_->metadata->modification_time); 192 193 for (int64 offset = 0; offset < fake_file_->metadata->size; ++offset) { 194 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(1)); 195 const int result = 196 reader.Read(io_buffer.get(), 197 1, 198 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 199 EXPECT_EQ(net::ERR_IO_PENDING, result); 200 base::RunLoop().RunUntilIdle(); 201 ASSERT_EQ(offset + 1, static_cast<int64>(logger.results().size())); 202 EXPECT_EQ(1, logger.results()[offset]); 203 EXPECT_EQ(fake_file_->contents[offset], io_buffer->data()[0]); 204 } 205} 206 207TEST_F(FileSystemProviderFileStreamReader, Read_Slice) { 208 EventLogger logger; 209 210 // Trim first 3 and last 3 characters. 211 const int64 initial_offset = 3; 212 const int length = fake_file_->metadata->size - initial_offset - 3; 213 ASSERT_GT(fake_file_->metadata->size, initial_offset); 214 ASSERT_LT(0, length); 215 216 FileStreamReader reader( 217 NULL, file_url_, initial_offset, fake_file_->metadata->modification_time); 218 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length)); 219 220 const int result = 221 reader.Read(io_buffer.get(), 222 length, 223 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 224 EXPECT_EQ(net::ERR_IO_PENDING, result); 225 base::RunLoop().RunUntilIdle(); 226 227 ASSERT_EQ(1u, logger.results().size()); 228 EXPECT_EQ(length, logger.results()[0]); 229 230 std::string buffer_as_string(io_buffer->data(), length); 231 std::string expected_buffer(fake_file_->contents.data() + initial_offset, 232 length); 233 EXPECT_EQ(expected_buffer, buffer_as_string); 234} 235 236TEST_F(FileSystemProviderFileStreamReader, Read_Beyond) { 237 EventLogger logger; 238 239 // Request reading 1KB more than available. 240 const int64 initial_offset = 0; 241 const int length = fake_file_->metadata->size + 1024; 242 243 FileStreamReader reader( 244 NULL, file_url_, initial_offset, fake_file_->metadata->modification_time); 245 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length)); 246 247 const int result = 248 reader.Read(io_buffer.get(), 249 length, 250 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 251 EXPECT_EQ(net::ERR_IO_PENDING, result); 252 base::RunLoop().RunUntilIdle(); 253 254 ASSERT_EQ(1u, logger.results().size()); 255 EXPECT_LT(0, logger.results()[0]); 256 EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]); 257 258 std::string buffer_as_string(io_buffer->data(), fake_file_->metadata->size); 259 EXPECT_EQ(fake_file_->contents, buffer_as_string); 260} 261 262TEST_F(FileSystemProviderFileStreamReader, Read_ModifiedFile) { 263 EventLogger logger; 264 265 const int64 initial_offset = 0; 266 FileStreamReader reader(NULL, file_url_, initial_offset, base::Time::Max()); 267 268 scoped_refptr<net::IOBuffer> io_buffer( 269 new net::IOBuffer(fake_file_->metadata->size)); 270 const int result = 271 reader.Read(io_buffer.get(), 272 fake_file_->metadata->size, 273 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 274 275 EXPECT_EQ(net::ERR_IO_PENDING, result); 276 base::RunLoop().RunUntilIdle(); 277 278 ASSERT_EQ(1u, logger.results().size()); 279 EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, logger.results()[0]); 280} 281 282TEST_F(FileSystemProviderFileStreamReader, Read_ExpectedModificationTimeNull) { 283 EventLogger logger; 284 285 const int64 initial_offset = 0; 286 FileStreamReader reader(NULL, file_url_, initial_offset, base::Time()); 287 288 scoped_refptr<net::IOBuffer> io_buffer( 289 new net::IOBuffer(fake_file_->metadata->size)); 290 const int result = 291 reader.Read(io_buffer.get(), 292 fake_file_->metadata->size, 293 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 294 295 EXPECT_EQ(net::ERR_IO_PENDING, result); 296 base::RunLoop().RunUntilIdle(); 297 298 ASSERT_EQ(1u, logger.results().size()); 299 EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]); 300 301 std::string buffer_as_string(io_buffer->data(), fake_file_->metadata->size); 302 EXPECT_EQ(fake_file_->contents, buffer_as_string); 303} 304 305TEST_F(FileSystemProviderFileStreamReader, GetLength) { 306 EventLogger logger; 307 308 const int64 initial_offset = 0; 309 FileStreamReader reader( 310 NULL, file_url_, initial_offset, fake_file_->metadata->modification_time); 311 312 const int result = reader.GetLength( 313 base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr())); 314 EXPECT_EQ(net::ERR_IO_PENDING, result); 315 base::RunLoop().RunUntilIdle(); 316 317 ASSERT_EQ(1u, logger.results().size()); 318 EXPECT_LT(0, logger.results()[0]); 319 EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]); 320} 321 322TEST_F(FileSystemProviderFileStreamReader, GetLength_WrongFile) { 323 EventLogger logger; 324 325 const int64 initial_offset = 0; 326 FileStreamReader reader(NULL, 327 wrong_file_url_, 328 initial_offset, 329 fake_file_->metadata->modification_time); 330 331 const int result = reader.GetLength( 332 base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr())); 333 EXPECT_EQ(net::ERR_IO_PENDING, result); 334 base::RunLoop().RunUntilIdle(); 335 336 ASSERT_EQ(1u, logger.results().size()); 337 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, logger.results()[0]); 338} 339 340TEST_F(FileSystemProviderFileStreamReader, GetLength_ModifiedFile) { 341 EventLogger logger; 342 343 const int64 initial_offset = 0; 344 FileStreamReader reader(NULL, file_url_, initial_offset, base::Time::Max()); 345 346 const int result = reader.GetLength( 347 base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr())); 348 EXPECT_EQ(net::ERR_IO_PENDING, result); 349 base::RunLoop().RunUntilIdle(); 350 351 ASSERT_EQ(1u, logger.results().size()); 352 EXPECT_EQ(net::ERR_UPLOAD_FILE_CHANGED, logger.results()[0]); 353} 354 355TEST_F(FileSystemProviderFileStreamReader, 356 GetLength_ExpectedModificationTimeNull) { 357 EventLogger logger; 358 359 const int64 initial_offset = 0; 360 FileStreamReader reader(NULL, file_url_, initial_offset, base::Time()); 361 362 const int result = reader.GetLength( 363 base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr())); 364 EXPECT_EQ(net::ERR_IO_PENDING, result); 365 base::RunLoop().RunUntilIdle(); 366 367 ASSERT_EQ(1u, logger.results().size()); 368 EXPECT_LT(0, logger.results()[0]); 369 EXPECT_EQ(fake_file_->metadata->size, logger.results()[0]); 370} 371 372} // namespace file_system_provider 373} // namespace chromeos 374