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 <string> 6#include <vector> 7 8#include "base/files/file.h" 9#include "base/files/file_path.h" 10#include "base/files/scoped_temp_dir.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/memory/weak_ptr.h" 13#include "base/platform_file.h" 14#include "base/run_loop.h" 15#include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h" 16#include "chrome/browser/chromeos/file_system_provider/fileapi/file_stream_reader.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 "testing/gtest/include/gtest/gtest.h" 28#include "webkit/browser/fileapi/async_file_util.h" 29#include "webkit/browser/fileapi/external_mount_points.h" 30#include "webkit/browser/fileapi/file_system_url.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. 62fileapi::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 fileapi::ExternalMountPoints* const mount_points = 66 fileapi::ExternalMountPoints::GetSystemInstance(); 67 return mount_points->CreateCrackedFileSystemURL( 68 GURL(origin), 69 fileapi::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() {} 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( 100 kExtensionId, kFileSystemId, "Testing File System"); 101 ASSERT_TRUE(result); 102 const ProvidedFileSystemInfo& file_system_info = 103 service->GetProvidedFileSystem(kExtensionId, kFileSystemId) 104 ->GetFileSystemInfo(); 105 const std::string mount_point_name = 106 file_system_info.mount_path().BaseName().AsUTF8Unsafe(); 107 108 file_url_ = CreateFileSystemURL( 109 mount_point_name, base::FilePath::FromUTF8Unsafe(kFakeFilePath + 1)); 110 ASSERT_TRUE(file_url_.is_valid()); 111 wrong_file_url_ = CreateFileSystemURL( 112 mount_point_name, base::FilePath::FromUTF8Unsafe("im-not-here.txt")); 113 ASSERT_TRUE(wrong_file_url_.is_valid()); 114 } 115 116 virtual void TearDown() OVERRIDE { 117 // Setting the testing factory to NULL will destroy the created service 118 // associated with the testing profile. 119 ServiceFactory::GetInstance()->SetTestingFactory(profile_, NULL); 120 } 121 122 content::TestBrowserThreadBundle thread_bundle_; 123 base::ScopedTempDir data_dir_; 124 scoped_ptr<TestingProfileManager> profile_manager_; 125 TestingProfile* profile_; // Owned by TestingProfileManager. 126 fileapi::FileSystemURL file_url_; 127 fileapi::FileSystemURL wrong_file_url_; 128}; 129 130TEST_F(FileSystemProviderFileStreamReader, Read_AllAtOnce) { 131 EventLogger logger; 132 133 const int64 initial_offset = 0; 134 FileStreamReader reader(NULL, 135 file_url_, 136 initial_offset, 137 base::Time::Now()); // Not used yet. 138 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(kFakeFileSize)); 139 140 const int result = 141 reader.Read(io_buffer.get(), 142 kFakeFileSize, 143 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 144 EXPECT_EQ(net::ERR_IO_PENDING, result); 145 base::RunLoop().RunUntilIdle(); 146 147 ASSERT_EQ(1u, logger.results().size()); 148 EXPECT_LT(0, logger.results()[0]); 149 EXPECT_EQ(kFakeFileSize, static_cast<size_t>(logger.results()[0])); 150 151 std::string buffer_as_string(io_buffer->data(), kFakeFileSize); 152 EXPECT_EQ(kFakeFileText, buffer_as_string); 153} 154 155TEST_F(FileSystemProviderFileStreamReader, Read_WrongFile) { 156 EventLogger logger; 157 158 const int64 initial_offset = 0; 159 FileStreamReader reader(NULL, 160 wrong_file_url_, 161 initial_offset, 162 base::Time::Now()); // Not used yet. 163 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(kFakeFileSize)); 164 165 const int result = 166 reader.Read(io_buffer.get(), 167 kFakeFileSize, 168 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 169 EXPECT_EQ(net::ERR_IO_PENDING, result); 170 base::RunLoop().RunUntilIdle(); 171 172 ASSERT_EQ(1u, logger.results().size()); 173 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, logger.results()[0]); 174} 175 176TEST_F(FileSystemProviderFileStreamReader, Read_InChunks) { 177 EventLogger logger; 178 179 const int64 initial_offset = 0; 180 FileStreamReader reader(NULL, 181 file_url_, 182 initial_offset, 183 base::Time::Now()); // Not used yet. 184 185 for (size_t offset = 0; offset < kFakeFileSize; ++offset) { 186 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(1)); 187 const int result = 188 reader.Read(io_buffer.get(), 189 1, 190 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 191 EXPECT_EQ(net::ERR_IO_PENDING, result); 192 base::RunLoop().RunUntilIdle(); 193 ASSERT_EQ(offset + 1u, logger.results().size()); 194 EXPECT_EQ(1, logger.results()[offset]); 195 EXPECT_EQ(kFakeFileText[offset], io_buffer->data()[0]); 196 } 197} 198 199TEST_F(FileSystemProviderFileStreamReader, Read_Slice) { 200 EventLogger logger; 201 202 // Trim first 3 and last 3 characters. 203 const int64 initial_offset = 3; 204 const int length = static_cast<int>(kFakeFileSize) - initial_offset - 3; 205 ASSERT_GT(kFakeFileSize, static_cast<size_t>(initial_offset)); 206 ASSERT_LT(0, length); 207 208 FileStreamReader reader(NULL, 209 file_url_, 210 initial_offset, 211 base::Time::Now()); // Not used yet. 212 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length)); 213 214 const int result = 215 reader.Read(io_buffer.get(), 216 length, 217 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 218 EXPECT_EQ(net::ERR_IO_PENDING, result); 219 base::RunLoop().RunUntilIdle(); 220 221 ASSERT_EQ(1u, logger.results().size()); 222 EXPECT_EQ(length, logger.results()[0]); 223 224 std::string buffer_as_string(io_buffer->data(), length); 225 std::string expected_buffer(kFakeFileText + initial_offset, length); 226 EXPECT_EQ(expected_buffer, buffer_as_string); 227} 228 229TEST_F(FileSystemProviderFileStreamReader, Read_Beyond) { 230 EventLogger logger; 231 232 // Request reading 1KB more than available. 233 const int64 initial_offset = 0; 234 const int length = static_cast<int>(kFakeFileSize) + 1024; 235 236 FileStreamReader reader(NULL, 237 file_url_, 238 initial_offset, 239 base::Time::Now()); // Not used yet. 240 scoped_refptr<net::IOBuffer> io_buffer(new net::IOBuffer(length)); 241 242 const int result = 243 reader.Read(io_buffer.get(), 244 length, 245 base::Bind(&EventLogger::OnRead, logger.GetWeakPtr())); 246 EXPECT_EQ(net::ERR_IO_PENDING, result); 247 base::RunLoop().RunUntilIdle(); 248 249 ASSERT_EQ(1u, logger.results().size()); 250 EXPECT_LT(0, logger.results()[0]); 251 EXPECT_EQ(kFakeFileSize, static_cast<size_t>(logger.results()[0])); 252 253 std::string buffer_as_string(io_buffer->data(), kFakeFileSize); 254 EXPECT_EQ(kFakeFileText, buffer_as_string); 255} 256 257TEST_F(FileSystemProviderFileStreamReader, GetLength) { 258 EventLogger logger; 259 260 const int64 initial_offset = 0; 261 FileStreamReader reader(NULL, 262 file_url_, 263 initial_offset, 264 base::Time::Now()); // Not used yet. 265 266 const int result = reader.GetLength( 267 base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr())); 268 EXPECT_EQ(net::ERR_IO_PENDING, result); 269 base::RunLoop().RunUntilIdle(); 270 271 ASSERT_EQ(1u, logger.results().size()); 272 EXPECT_LT(0, logger.results()[0]); 273 EXPECT_EQ(kFakeFileSize, static_cast<size_t>(logger.results()[0])); 274} 275 276TEST_F(FileSystemProviderFileStreamReader, GetLength_WrongFile) { 277 EventLogger logger; 278 279 const int64 initial_offset = 0; 280 FileStreamReader reader(NULL, 281 wrong_file_url_, 282 initial_offset, 283 base::Time::Now()); // Not used yet. 284 285 const int result = reader.GetLength( 286 base::Bind(&EventLogger::OnGetLength, logger.GetWeakPtr())); 287 EXPECT_EQ(net::ERR_IO_PENDING, result); 288 base::RunLoop().RunUntilIdle(); 289 290 ASSERT_EQ(1u, logger.results().size()); 291 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, logger.results()[0]); 292} 293 294} // namespace file_system_provider 295} // namespace chromeos 296