Home | History | Annotate | Download | only in fileapi
      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 "base/files/file_path.h"
      6 #include "base/memory/ref_counted.h"
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/run_loop.h"
     10 #include "base/time/time.h"
     11 #include "content/browser/fileapi/blob_storage_host.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 #include "webkit/browser/blob/blob_data_handle.h"
     14 #include "webkit/browser/blob/blob_storage_context.h"
     15 
     16 using webkit_blob::BlobDataHandle;
     17 
     18 namespace content {
     19 
     20 namespace {
     21 void SetupBasicBlob(BlobStorageHost* host, const std::string& id) {
     22   EXPECT_TRUE(host->StartBuildingBlob(id));
     23   BlobData::Item item;
     24   item.SetToBytes("1", 1);
     25   EXPECT_TRUE(host->AppendBlobDataItem(id, item));
     26   EXPECT_TRUE(host->FinishBuildingBlob(id, "text/plain"));
     27   EXPECT_FALSE(host->StartBuildingBlob(id));
     28 }
     29 }  // namespace
     30 
     31 TEST(BlobStorageContextTest, IncrementDecrementRef) {
     32   BlobStorageContext context;
     33   BlobStorageHost host(&context);
     34   base::MessageLoop fake_io_message_loop;
     35 
     36   // Build up a basic blob.
     37   const std::string kId("id");
     38   SetupBasicBlob(&host, kId);
     39 
     40   // Make sure it's there, finish building implies a ref of one.
     41   scoped_ptr<BlobDataHandle> blob_data_handle;
     42   blob_data_handle = context.GetBlobDataFromUUID(kId);
     43   EXPECT_TRUE(blob_data_handle);
     44   blob_data_handle.reset();
     45   {  // Clean up for ASAN
     46     base::RunLoop run_loop;
     47     run_loop.RunUntilIdle();
     48   }
     49 
     50   // Make sure its still there after inc/dec.
     51   EXPECT_TRUE(host.IncrementBlobRefCount(kId));
     52   EXPECT_TRUE(host.DecrementBlobRefCount(kId));
     53   blob_data_handle = context.GetBlobDataFromUUID(kId);
     54   EXPECT_TRUE(blob_data_handle);
     55   blob_data_handle.reset();
     56   {  // Clean up for ASAN
     57     base::RunLoop run_loop;
     58     run_loop.RunUntilIdle();
     59   }
     60 
     61   // Make sure it goes away in the end.
     62   EXPECT_TRUE(host.DecrementBlobRefCount(kId));
     63   blob_data_handle = context.GetBlobDataFromUUID(kId);
     64   EXPECT_FALSE(blob_data_handle);
     65   EXPECT_FALSE(host.DecrementBlobRefCount(kId));
     66   EXPECT_FALSE(host.IncrementBlobRefCount(kId));
     67 }
     68 
     69 TEST(BlobStorageContextTest, BlobDataHandle) {
     70   BlobStorageContext context;
     71   BlobStorageHost host(&context);
     72   base::MessageLoop fake_io_message_loop;
     73 
     74   // Build up a basic blob.
     75   const std::string kId("id");
     76   SetupBasicBlob(&host, kId);
     77 
     78   // Get a handle to it.
     79   scoped_ptr<BlobDataHandle> blob_data_handle =
     80       context.GetBlobDataFromUUID(kId);
     81   EXPECT_TRUE(blob_data_handle);
     82 
     83   // Drop the host's ref to it.
     84   EXPECT_TRUE(host.DecrementBlobRefCount(kId));
     85 
     86   // Should still be there due to the handle.
     87   scoped_ptr<BlobDataHandle> another_handle =
     88       context.GetBlobDataFromUUID(kId);
     89   EXPECT_TRUE(another_handle);
     90 
     91   // Should disappear after dropping both handles.
     92   blob_data_handle.reset();
     93   another_handle.reset();
     94   {  // Clean up for ASAN
     95     base::RunLoop run_loop;
     96     run_loop.RunUntilIdle();
     97   }
     98   blob_data_handle = context.GetBlobDataFromUUID(kId);
     99   EXPECT_FALSE(blob_data_handle);
    100 }
    101 
    102 TEST(BlobStorageContextTest, CompoundBlobs) {
    103   const std::string kId1("id1");
    104   const std::string kId2("id2");
    105   const std::string kId2Prime("id2.prime");
    106 
    107   base::MessageLoop fake_io_message_loop;
    108 
    109   // Setup a set of blob data for testing.
    110   base::Time time1, time2;
    111   base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1);
    112   base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2);
    113 
    114   scoped_refptr<BlobData> blob_data1(new BlobData(kId1));
    115   blob_data1->AppendData("Data1");
    116   blob_data1->AppendData("Data2");
    117   blob_data1->AppendFile(base::FilePath(FILE_PATH_LITERAL("File1.txt")),
    118     10, 1024, time1);
    119 
    120   scoped_refptr<BlobData> blob_data2(new BlobData(kId2));
    121   blob_data2->AppendData("Data3");
    122   blob_data2->AppendBlob(kId1, 8, 100);
    123   blob_data2->AppendFile(base::FilePath(FILE_PATH_LITERAL("File2.txt")),
    124       0, 20, time2);
    125 
    126   scoped_refptr<BlobData> canonicalized_blob_data2(new BlobData(kId2Prime));
    127   canonicalized_blob_data2->AppendData("Data3");
    128   canonicalized_blob_data2->AppendData("a2___", 2);
    129   canonicalized_blob_data2->AppendFile(
    130       base::FilePath(FILE_PATH_LITERAL("File1.txt")),
    131       10, 98, time1);
    132   canonicalized_blob_data2->AppendFile(
    133       base::FilePath(FILE_PATH_LITERAL("File2.txt")), 0, 20, time2);
    134 
    135   BlobStorageContext context;
    136   scoped_ptr<BlobDataHandle> blob_data_handle;
    137 
    138   // Test a blob referring to only data and a file.
    139   blob_data_handle = context.AddFinishedBlob(blob_data1.get());
    140   ASSERT_TRUE(blob_data_handle.get());
    141   EXPECT_TRUE(*(blob_data_handle->data()) == *blob_data1.get());
    142 
    143   // Test a blob composed in part with another blob.
    144   blob_data_handle = context.AddFinishedBlob(blob_data2.get());
    145   ASSERT_TRUE(blob_data_handle.get());
    146   EXPECT_TRUE(*(blob_data_handle->data()) == *canonicalized_blob_data2.get());
    147 
    148   blob_data_handle.reset();
    149   {  // Clean up for ASAN
    150     base::RunLoop run_loop;
    151     run_loop.RunUntilIdle();
    152   }
    153 }
    154 
    155 TEST(BlobStorageContextTest, PublicBlobUrls) {
    156   BlobStorageContext context;
    157   BlobStorageHost host(&context);
    158   base::MessageLoop fake_io_message_loop;
    159 
    160   // Build up a basic blob.
    161   const std::string kId("id");
    162   SetupBasicBlob(&host, kId);
    163 
    164   // Now register a url for that blob.
    165   GURL kUrl("blob:id");
    166   EXPECT_TRUE(host.RegisterPublicBlobURL(kUrl, kId));
    167   scoped_ptr<BlobDataHandle> blob_data_handle =
    168       context.GetBlobDataFromPublicURL(kUrl);
    169   ASSERT_TRUE(blob_data_handle.get());
    170   EXPECT_EQ(kId, blob_data_handle->data()->uuid());
    171   blob_data_handle.reset();
    172   {  // Clean up for ASAN
    173     base::RunLoop run_loop;
    174     run_loop.RunUntilIdle();
    175   }
    176 
    177   // The url registration should keep the blob alive even after
    178   // explicit references are dropped.
    179   EXPECT_TRUE(host.DecrementBlobRefCount(kId));
    180   blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
    181   EXPECT_TRUE(blob_data_handle);
    182   blob_data_handle.reset();
    183   {  // Clean up for ASAN
    184     base::RunLoop run_loop;
    185     run_loop.RunUntilIdle();
    186   }
    187 
    188   // Finally get rid of the url registration and the blob.
    189   EXPECT_TRUE(host.RevokePublicBlobURL(kUrl));
    190   blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
    191   EXPECT_TRUE(!blob_data_handle.get());
    192   EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
    193 }
    194 
    195 TEST(BlobStorageContextTest, HostCleanup) {
    196   BlobStorageContext context;
    197   scoped_ptr<BlobStorageHost> host(new BlobStorageHost(&context));
    198   base::MessageLoop fake_io_message_loop;
    199 
    200   // Build up a basic blob and register a url
    201   const std::string kId("id");
    202   GURL kUrl("blob:id");
    203   SetupBasicBlob(host.get(), kId);
    204   EXPECT_TRUE(host->RegisterPublicBlobURL(kUrl, kId));
    205 
    206   // All should disappear upon host deletion.
    207   host.reset();
    208   scoped_ptr<BlobDataHandle> handle = context.GetBlobDataFromPublicURL(kUrl);
    209   EXPECT_TRUE(!handle.get());
    210   handle = context.GetBlobDataFromUUID(kId);
    211   EXPECT_TRUE(!handle.get());
    212 }
    213 
    214 TEST(BlobStorageContextTest, EarlyContextDeletion) {
    215   scoped_ptr<BlobStorageContext> context(new BlobStorageContext);
    216   BlobStorageHost host(context.get());
    217   base::MessageLoop fake_io_message_loop;
    218 
    219   // Deleting the context should not induce crashes.
    220   context.reset();
    221 
    222   const std::string kId("id");
    223   GURL kUrl("blob:id");
    224   EXPECT_FALSE(host.StartBuildingBlob(kId));
    225   BlobData::Item item;
    226   item.SetToBytes("1", 1);
    227   EXPECT_FALSE(host.AppendBlobDataItem(kId, item));
    228   EXPECT_FALSE(host.FinishBuildingBlob(kId, "text/plain"));
    229   EXPECT_FALSE(host.RegisterPublicBlobURL(kUrl, kId));
    230   EXPECT_FALSE(host.IncrementBlobRefCount(kId));
    231   EXPECT_FALSE(host.DecrementBlobRefCount(kId));
    232   EXPECT_FALSE(host.RevokePublicBlobURL(kUrl));
    233 }
    234 
    235 // TODO(michaeln): tests for the depcrecated url stuff
    236 
    237 }  // namespace content
    238