1// Copyright (c) 2011 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 <deque> 6#include <limits> 7#include <string> 8 9#include "base/basictypes.h" 10#include "base/bind.h" 11#include "base/file_util.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/memory/weak_ptr.h" 14#include "base/message_loop/message_loop.h" 15#include "base/platform_file.h" 16#include "content/renderer/pepper/pepper_plugin_instance_impl.h" 17#include "content/renderer/pepper/ppapi_unittest.h" 18#include "content/renderer/pepper/quota_file_io.h" 19 20using base::MessageLoopProxy; 21using base::PlatformFile; 22using base::PlatformFileError; 23 24namespace content { 25 26namespace { 27class QuotaMockDelegate : public QuotaFileIO::Delegate { 28 public: 29 typedef QuotaFileIO::Delegate::AvailableSpaceCallback Callback; 30 31 QuotaMockDelegate() 32 : available_space_(0), 33 will_update_count_(0), 34 file_thread_(MessageLoopProxy::current()), 35 weak_factory_(this) { 36 } 37 virtual ~QuotaMockDelegate() {} 38 39 virtual void QueryAvailableSpace( 40 const GURL& origin, 41 quota::StorageType type, 42 const Callback& callback) OVERRIDE { 43 DCHECK_EQ(false, callback.is_null()); 44 MessageLoopProxy::current()->PostTask( 45 FROM_HERE, base::Bind( 46 &QuotaMockDelegate::RunAvailableSpaceCallback, 47 weak_factory_.GetWeakPtr(), callback)); 48 } 49 50 virtual void WillUpdateFile(const GURL& file_path) OVERRIDE { 51 file_path_ = file_path; 52 ++will_update_count_; 53 } 54 55 virtual void DidUpdateFile(const GURL& file_path, int64_t delta) OVERRIDE { 56 ASSERT_EQ(file_path_, file_path); 57 ASSERT_GT(will_update_count_, 0); 58 --will_update_count_; 59 available_space_ -= delta; 60 } 61 62 virtual scoped_refptr<base::MessageLoopProxy> 63 GetFileThreadMessageLoopProxy() OVERRIDE { 64 return file_thread_; 65 } 66 67 void set_available_space(int64 available) { available_space_ = available; } 68 int64_t available_space() const { return available_space_; } 69 70 private: 71 void RunAvailableSpaceCallback(const Callback& callback) { 72 callback.Run(available_space_); 73 } 74 75 int64_t available_space_; 76 int will_update_count_; 77 GURL file_path_; 78 scoped_refptr<MessageLoopProxy> file_thread_; 79 base::WeakPtrFactory<QuotaMockDelegate> weak_factory_; 80}; 81} // namespace 82 83class QuotaFileIOTest : public PpapiUnittest { 84 public: 85 QuotaFileIOTest() 86 : delegate_(NULL), 87 weak_factory_(this) {} 88 89 virtual void SetUp() OVERRIDE { 90 PpapiUnittest::SetUp(); 91 ASSERT_TRUE(dir_.CreateUniqueTempDir()); 92 base::FilePath path; 93 ASSERT_TRUE(file_util::CreateTemporaryFileInDir(dir_.path(), &path)); 94 int file_flags = base::PLATFORM_FILE_OPEN | 95 base::PLATFORM_FILE_READ | 96 base::PLATFORM_FILE_WRITE | 97 base::PLATFORM_FILE_WRITE_ATTRIBUTES; 98 bool created = false; 99 file_ = base::kInvalidPlatformFileValue; 100 PlatformFileError error = base::PLATFORM_FILE_OK; 101 file_ = base::CreatePlatformFile(path, file_flags, &created, &error); 102 ASSERT_EQ(base::PLATFORM_FILE_OK, error); 103 ASSERT_NE(base::kInvalidPlatformFileValue, file_); 104 ASSERT_FALSE(created); 105 delegate_ = new QuotaMockDelegate; // Owned by QuotaFileIO. 106 quota_file_io_.reset(new QuotaFileIO( 107 delegate_, file_, GURL(), PP_FILESYSTEMTYPE_LOCALTEMPORARY)); 108 } 109 110 virtual void TearDown() OVERRIDE { 111 quota_file_io_.reset(); 112 if (file_ != base::kInvalidPlatformFileValue) 113 base::ClosePlatformFile(file_); 114 PpapiUnittest::TearDown(); 115 } 116 117 protected: 118 void WriteTestBody(bool will_operation) { 119 // Attempt to write zero bytes. 120 EXPECT_FALSE(quota_file_io_->Write( 121 0, "data", 0, 122 base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr()))); 123 // Attempt to write negative number of bytes. 124 EXPECT_FALSE(quota_file_io_->Write( 125 0, "data", std::numeric_limits<int32_t>::min(), 126 base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr()))); 127 128 delegate()->set_available_space(100); 129 std::string read_buffer; 130 131 // Write 8 bytes at offset 0 (-> length=8). 132 std::string data("12345678"); 133 Write(0, data, will_operation); 134 base::MessageLoop::current()->RunUntilIdle(); 135 ASSERT_EQ(1U, num_results()); 136 EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front()); 137 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 138 EXPECT_EQ(100 - 8, delegate()->available_space()); 139 reset_results(); 140 141 if (will_operation) { 142 // WillWrite doesn't actually write. 143 EXPECT_EQ(0, GetPlatformFileSize()); 144 // Adjust the actual file size to 'fake' write to proceed testing. 145 SetPlatformFileSize(8); 146 } else { 147 EXPECT_EQ(8, GetPlatformFileSize()); 148 ReadPlatformFile(&read_buffer); 149 EXPECT_EQ(data, read_buffer); 150 } 151 152 // Write 5 bytes at offset 5 (-> length=10). 153 data = "55555"; 154 Write(5, data, will_operation); 155 base::MessageLoop::current()->RunUntilIdle(); 156 ASSERT_EQ(1U, num_results()); 157 EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front()); 158 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 159 EXPECT_EQ(100 - 10, delegate()->available_space()); 160 reset_results(); 161 162 if (will_operation) { 163 EXPECT_EQ(8, GetPlatformFileSize()); 164 SetPlatformFileSize(10); 165 } else { 166 EXPECT_EQ(10, GetPlatformFileSize()); 167 ReadPlatformFile(&read_buffer); 168 EXPECT_EQ("1234555555", read_buffer); 169 } 170 171 // Write 7 bytes at offset 8 (-> length=15). 172 data = "9012345"; 173 Write(8, data, will_operation); 174 base::MessageLoop::current()->RunUntilIdle(); 175 ASSERT_EQ(1U, num_results()); 176 EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front()); 177 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 178 EXPECT_EQ(100 - 15, delegate()->available_space()); 179 reset_results(); 180 181 if (will_operation) { 182 EXPECT_EQ(10, GetPlatformFileSize()); 183 SetPlatformFileSize(15); 184 } else { 185 EXPECT_EQ(15, GetPlatformFileSize()); 186 ReadPlatformFile(&read_buffer); 187 EXPECT_EQ("123455559012345", read_buffer); 188 } 189 190 // Write 2 bytes at offset 2 (-> length=15). 191 data = "33"; 192 Write(2, data, will_operation); 193 base::MessageLoop::current()->RunUntilIdle(); 194 ASSERT_EQ(1U, num_results()); 195 EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front()); 196 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 197 EXPECT_EQ(100 - 15, delegate()->available_space()); 198 reset_results(); 199 200 if (will_operation) { 201 EXPECT_EQ(15, GetPlatformFileSize()); 202 } else { 203 EXPECT_EQ(15, GetPlatformFileSize()); 204 ReadPlatformFile(&read_buffer); 205 EXPECT_EQ("123355559012345", read_buffer); 206 } 207 208 // Write 4 bytes at offset 20 (-> length=24). 209 data = "XXXX"; 210 Write(20, data, will_operation); 211 base::MessageLoop::current()->RunUntilIdle(); 212 ASSERT_EQ(1U, num_results()); 213 EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front()); 214 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 215 EXPECT_EQ(100 - 24, delegate()->available_space()); 216 reset_results(); 217 218 if (will_operation) { 219 EXPECT_EQ(15, GetPlatformFileSize()); 220 SetPlatformFileSize(24); 221 } else { 222 EXPECT_EQ(24, GetPlatformFileSize()); 223 ReadPlatformFile(&read_buffer); 224 EXPECT_EQ(std::string("123355559012345\0\0\0\0\0XXXX", 24), read_buffer); 225 } 226 227 delegate()->set_available_space(5); 228 229 // Quota error case. Write 7 bytes at offset 23 (-> length is unchanged) 230 data = "ABCDEFG"; 231 Write(23, data, will_operation); 232 base::MessageLoop::current()->RunUntilIdle(); 233 ASSERT_EQ(1U, num_results()); 234 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status().front()); 235 EXPECT_EQ(5, delegate()->available_space()); 236 reset_results(); 237 238 // Overlapping write. Write 6 bytes at offset 2 (-> length is unchanged) 239 data = "ABCDEF"; 240 Write(2, data, will_operation); 241 base::MessageLoop::current()->RunUntilIdle(); 242 ASSERT_EQ(1U, num_results()); 243 EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front()); 244 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 245 EXPECT_EQ(5, delegate()->available_space()); 246 reset_results(); 247 248 // Overlapping + extending the file size, but within the quota. 249 // Write 6 bytes at offset 23 (-> length=29). 250 Write(23, data, will_operation); 251 base::MessageLoop::current()->RunUntilIdle(); 252 ASSERT_EQ(1U, num_results()); 253 EXPECT_EQ(static_cast<int>(data.size()), bytes_written().front()); 254 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 255 EXPECT_EQ(0, delegate()->available_space()); 256 reset_results(); 257 258 if (!will_operation) { 259 EXPECT_EQ(29, GetPlatformFileSize()); 260 ReadPlatformFile(&read_buffer); 261 EXPECT_EQ(std::string("12ABCDEF9012345\0\0\0\0\0XXXABCDEF", 29), 262 read_buffer); 263 } 264 } 265 266 void SetLengthTestBody(bool will_operation) { 267 delegate()->set_available_space(100); 268 269 SetLength(0, will_operation); 270 base::MessageLoop::current()->RunUntilIdle(); 271 ASSERT_EQ(1U, num_results()); 272 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 273 EXPECT_EQ(0, GetPlatformFileSize()); 274 EXPECT_EQ(100, delegate()->available_space()); 275 reset_results(); 276 277 SetLength(8, will_operation); 278 base::MessageLoop::current()->RunUntilIdle(); 279 ASSERT_EQ(1U, num_results()); 280 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 281 EXPECT_EQ(100 - 8, delegate()->available_space()); 282 reset_results(); 283 284 if (will_operation) { 285 EXPECT_EQ(0, GetPlatformFileSize()); 286 SetPlatformFileSize(8); 287 } else { 288 EXPECT_EQ(8, GetPlatformFileSize()); 289 } 290 291 SetLength(16, will_operation); 292 base::MessageLoop::current()->RunUntilIdle(); 293 ASSERT_EQ(1U, num_results()); 294 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 295 EXPECT_EQ(100 - 16, delegate()->available_space()); 296 reset_results(); 297 298 if (will_operation) { 299 EXPECT_EQ(8, GetPlatformFileSize()); 300 SetPlatformFileSize(16); 301 } else { 302 EXPECT_EQ(16, GetPlatformFileSize()); 303 } 304 305 SetLength(4, will_operation); 306 base::MessageLoop::current()->RunUntilIdle(); 307 ASSERT_EQ(1U, num_results()); 308 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 309 EXPECT_EQ(100 - 4, delegate()->available_space()); 310 reset_results(); 311 312 if (will_operation) { 313 EXPECT_EQ(16, GetPlatformFileSize()); 314 SetPlatformFileSize(4); 315 } else { 316 EXPECT_EQ(4, GetPlatformFileSize()); 317 } 318 319 SetLength(0, will_operation); 320 base::MessageLoop::current()->RunUntilIdle(); 321 ASSERT_EQ(1U, num_results()); 322 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 323 EXPECT_EQ(100, delegate()->available_space()); 324 reset_results(); 325 326 if (will_operation) { 327 EXPECT_EQ(4, GetPlatformFileSize()); 328 SetPlatformFileSize(0); 329 } else { 330 EXPECT_EQ(0, GetPlatformFileSize()); 331 } 332 333 delegate()->set_available_space(5); 334 335 // Quota error case. 336 SetLength(7, will_operation); 337 base::MessageLoop::current()->RunUntilIdle(); 338 ASSERT_EQ(1U, num_results()); 339 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status().front()); 340 EXPECT_EQ(5, delegate()->available_space()); 341 reset_results(); 342 } 343 344 QuotaMockDelegate* delegate() { 345 return delegate_; 346 } 347 348 void Write(int64_t offset, const std::string& data, bool will_operation) { 349 if (will_operation) { 350 ASSERT_TRUE(quota_file_io_->WillWrite( 351 offset, data.size(), 352 base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr()))); 353 } else { 354 ASSERT_TRUE(quota_file_io_->Write( 355 offset, data.c_str(), data.size(), 356 base::Bind(&QuotaFileIOTest::DidWrite, weak_factory_.GetWeakPtr()))); 357 } 358 } 359 360 void SetLength(int64_t length, bool will_operation) { 361 if (will_operation) { 362 ASSERT_TRUE(quota_file_io_->WillSetLength( 363 length, 364 base::Bind(&QuotaFileIOTest::DidSetLength, 365 weak_factory_.GetWeakPtr()))); 366 } else { 367 ASSERT_TRUE(quota_file_io_->SetLength( 368 length, 369 base::Bind(&QuotaFileIOTest::DidSetLength, 370 weak_factory_.GetWeakPtr()))); 371 } 372 } 373 374 void DidWrite(PlatformFileError status, int bytes_written) { 375 status_.push_back(status); 376 bytes_written_.push_back(bytes_written); 377 } 378 379 void DidSetLength(PlatformFileError status) { 380 status_.push_back(status); 381 } 382 383 size_t num_results() const { return status_.size(); } 384 const std::deque<int>& bytes_written() const { return bytes_written_; } 385 const std::deque<PlatformFileError>& status() const { return status_; } 386 387 void reset_results() { 388 bytes_written_.clear(); 389 status_.clear(); 390 } 391 392 void pop_result() { 393 bytes_written_.pop_front(); 394 status_.pop_front(); 395 } 396 397 void ReadPlatformFile(std::string* data) { 398 data->clear(); 399 char buf[256]; 400 int32_t read_offset = 0; 401 for (;;) { 402 int rv = base::ReadPlatformFile(file_, read_offset, buf, sizeof(buf)); 403 ASSERT_GE(rv, 0); 404 if (rv == 0) 405 break; 406 read_offset += rv; 407 data->append(buf, rv); 408 } 409 } 410 411 int64_t GetPlatformFileSize() { 412 base::PlatformFileInfo info; 413 EXPECT_TRUE(base::GetPlatformFileInfo(file_, &info)); 414 return info.size; 415 } 416 417 void SetPlatformFileSize(int64_t length) { 418 EXPECT_TRUE(base::TruncatePlatformFile(file_, length)); 419 } 420 421 private: 422 base::ScopedTempDir dir_; 423 PlatformFile file_; 424 scoped_ptr<QuotaFileIO> quota_file_io_; 425 std::deque<int> bytes_written_; 426 std::deque<PlatformFileError> status_; 427 QuotaMockDelegate* delegate_; 428 base::WeakPtrFactory<QuotaFileIOTest> weak_factory_; 429}; 430 431TEST_F(QuotaFileIOTest, Write) { 432 WriteTestBody(false); 433} 434 435TEST_F(QuotaFileIOTest, WillWrite) { 436 WriteTestBody(true); 437} 438 439TEST_F(QuotaFileIOTest, SetLength) { 440 SetLengthTestBody(false); 441} 442 443TEST_F(QuotaFileIOTest, WillSetLength) { 444 SetLengthTestBody(true); 445} 446 447TEST_F(QuotaFileIOTest, ParallelWrites) { 448 delegate()->set_available_space(22); 449 std::string read_buffer; 450 451 const std::string data1[] = { 452 std::string("12345678"), 453 std::string("55555"), 454 std::string("9012345"), 455 }; 456 Write(0, data1[0], false); 457 Write(5, data1[1], false); 458 Write(8, data1[2], false); 459 base::MessageLoop::current()->RunUntilIdle(); 460 461 ASSERT_EQ(ARRAYSIZE_UNSAFE(data1), num_results()); 462 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data1); ++i) { 463 EXPECT_EQ(static_cast<int>(data1[i].size()), bytes_written().front()); 464 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 465 pop_result(); 466 } 467 468 EXPECT_EQ(22 - 15, delegate()->available_space()); 469 EXPECT_EQ(15, GetPlatformFileSize()); 470 ReadPlatformFile(&read_buffer); 471 EXPECT_EQ("123455559012345", read_buffer); 472 473 // The second write will fail for quota error. 474 const std::string data2[] = { 475 std::string("33"), 476 std::string("XXXX"), 477 }; 478 Write(2, data2[0], false); 479 Write(20, data2[1], false); 480 base::MessageLoop::current()->RunUntilIdle(); 481 482 ASSERT_EQ(ARRAYSIZE_UNSAFE(data2), num_results()); 483 EXPECT_EQ(static_cast<int>(data2[0].size()), bytes_written().front()); 484 EXPECT_EQ(base::PLATFORM_FILE_OK, status().front()); 485 pop_result(); 486 EXPECT_EQ(0, bytes_written().front()); 487 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status().front()); 488 pop_result(); 489 490 EXPECT_EQ(22 - 15, delegate()->available_space()); 491 EXPECT_EQ(15, GetPlatformFileSize()); 492 ReadPlatformFile(&read_buffer); 493 EXPECT_EQ("123355559012345", read_buffer); 494} 495 496} // namespace content 497