Home | History | Annotate | Download | only in pepper
      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 
     20 using base::MessageLoopProxy;
     21 using base::PlatformFile;
     22 using base::PlatformFileError;
     23 
     24 namespace content {
     25 
     26 namespace {
     27 class 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 
     83 class 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 
    431 TEST_F(QuotaFileIOTest, Write) {
    432   WriteTestBody(false);
    433 }
    434 
    435 TEST_F(QuotaFileIOTest, WillWrite) {
    436   WriteTestBody(true);
    437 }
    438 
    439 TEST_F(QuotaFileIOTest, SetLength) {
    440   SetLengthTestBody(false);
    441 }
    442 
    443 TEST_F(QuotaFileIOTest, WillSetLength) {
    444   SetLengthTestBody(true);
    445 }
    446 
    447 TEST_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