Home | History | Annotate | Download | only in search_provider_logos
      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 "components/search_provider_logos/logo_cache.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/callback.h"
     11 #include "base/files/file_util.h"
     12 #include "base/files/scoped_temp_dir.h"
     13 #include "base/run_loop.h"
     14 #include "base/time/time.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace search_provider_logos {
     18 
     19 LogoMetadata GetExampleMetadata() {
     20   LogoMetadata metadata;
     21   metadata.source_url = "http://google.com/mylogo";
     22   metadata.fingerprint = "LC4JVIZ5HVITQFKH0V70";
     23   EXPECT_TRUE(base::Time::FromString("98-05-05 05:05:06 GMT",
     24                                      &metadata.expiration_time));
     25   metadata.can_show_after_expiration = true;
     26   metadata.on_click_url = "https://www.google.com/search?q=chicken";
     27   metadata.alt_text = "A logo about chickens";
     28   metadata.mime_type = "image/jpeg";
     29   return metadata;
     30 }
     31 
     32 LogoMetadata GetExampleMetadata2() {
     33   LogoMetadata metadata;
     34   metadata.source_url = "https://www.example.com/thebestlogo?size=large";
     35   metadata.fingerprint = "bh4PLHdnEaQAPxNGRyMao1rOmVFTXuOdVhdrMmPV";
     36   EXPECT_TRUE(base::Time::FromString("17-04-04 07:10:58 GMT",
     37                                      &metadata.expiration_time));
     38   metadata.can_show_after_expiration = false;
     39   metadata.on_click_url = "http://www.example.co.uk/welcome.php#top";
     40   metadata.alt_text = "This is a logo";
     41   metadata.mime_type = "image/png";
     42   return metadata;
     43 }
     44 
     45 base::RefCountedString* CreateExampleImage(size_t num_bytes) {
     46   base::RefCountedString* encoded_image_str = new base::RefCountedString();
     47   std::string& str = encoded_image_str->data();
     48   str.resize(num_bytes);
     49   for (size_t i = 0; i < num_bytes; ++i)
     50     str[i] = static_cast<char>(i);
     51   return encoded_image_str;
     52 }
     53 
     54 EncodedLogo GetExampleLogo() {
     55   EncodedLogo logo;
     56   logo.encoded_image = CreateExampleImage(837);
     57   logo.metadata = GetExampleMetadata();
     58   return logo;
     59 }
     60 
     61 EncodedLogo GetExampleLogo2() {
     62   EncodedLogo logo;
     63   logo.encoded_image = CreateExampleImage(345);
     64   logo.metadata = GetExampleMetadata2();
     65   return logo;
     66 }
     67 
     68 void ExpectMetadataEqual(const LogoMetadata& expected_metadata,
     69                          const LogoMetadata& actual_metadata) {
     70   EXPECT_EQ(expected_metadata.source_url, actual_metadata.source_url);
     71   EXPECT_EQ(expected_metadata.fingerprint, actual_metadata.fingerprint);
     72   EXPECT_EQ(expected_metadata.can_show_after_expiration,
     73             actual_metadata.can_show_after_expiration);
     74   EXPECT_EQ(expected_metadata.expiration_time, actual_metadata.expiration_time);
     75   EXPECT_EQ(expected_metadata.on_click_url, actual_metadata.on_click_url);
     76   EXPECT_EQ(expected_metadata.alt_text, actual_metadata.alt_text);
     77   EXPECT_EQ(expected_metadata.mime_type, actual_metadata.mime_type);
     78 }
     79 
     80 void ExpectLogosEqual(const EncodedLogo& expected_logo,
     81                       const EncodedLogo& actual_logo) {
     82   ASSERT_TRUE(expected_logo.encoded_image.get());
     83   ASSERT_TRUE(actual_logo.encoded_image.get());
     84   EXPECT_TRUE(expected_logo.encoded_image->Equals(actual_logo.encoded_image));
     85   ExpectMetadataEqual(expected_logo.metadata, actual_logo.metadata);
     86 }
     87 
     88 // Removes 1 byte from the end of the file at |path|.
     89 void ShortenFile(base::FilePath path) {
     90   base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE);
     91   int64 file_length = file.GetLength();
     92   ASSERT_NE(file_length, 0);
     93   file.SetLength(file_length - 1);
     94 }
     95 
     96 class LogoCacheTest : public ::testing::Test {
     97  protected:
     98   virtual void SetUp() OVERRIDE {
     99     ASSERT_TRUE(cache_parent_dir_.CreateUniqueTempDir());
    100     InitCache();
    101   }
    102 
    103   void InitCache() {
    104     cache_.reset(new LogoCache(
    105         cache_parent_dir_.path().Append(FILE_PATH_LITERAL("cache"))));
    106   }
    107 
    108   void ExpectMetadata(const LogoMetadata* expected_metadata) {
    109     const LogoMetadata* retrieved_metadata = cache_->GetCachedLogoMetadata();
    110     if (expected_metadata) {
    111       ASSERT_TRUE(retrieved_metadata != NULL);
    112       ExpectMetadataEqual(*expected_metadata, *retrieved_metadata);
    113     } else {
    114       ASSERT_TRUE(retrieved_metadata == NULL);
    115     }
    116   }
    117 
    118   void ExpectLogo(const EncodedLogo* expected_logo) {
    119     scoped_ptr<EncodedLogo> retrieved_logo(cache_->GetCachedLogo());
    120     if (expected_logo) {
    121       ASSERT_TRUE(retrieved_logo.get() != NULL);
    122       ExpectLogosEqual(*expected_logo, *retrieved_logo);
    123     } else {
    124       ASSERT_TRUE(retrieved_logo.get() == NULL);
    125     }
    126   }
    127 
    128   // Deletes the existing LogoCache and creates a new one. This clears any
    129   // logo or metadata cached in memory to simulate restarting Chrome.
    130   void SimulateRestart() {
    131     InitCache();
    132   }
    133 
    134   scoped_ptr<LogoCache> cache_;
    135   base::ScopedTempDir cache_parent_dir_;
    136 };
    137 
    138 // Tests -----------------------------------------------------------------------
    139 
    140 TEST(LogoCacheSerializationTest, SerializeMetadata) {
    141   LogoMetadata metadata = GetExampleMetadata();
    142   std::string metadata_str;
    143   int logo_num_bytes = 33;
    144   LogoCache::LogoMetadataToString(metadata, logo_num_bytes, &metadata_str);
    145   scoped_ptr<LogoMetadata> metadata2 =
    146       LogoCache::LogoMetadataFromString(metadata_str, &logo_num_bytes);
    147   ASSERT_TRUE(metadata2);
    148   ExpectMetadataEqual(metadata, *metadata2);
    149 }
    150 
    151 TEST(LogoCacheSerializationTest, DeserializeCorruptMetadata) {
    152   int logo_num_bytes = 33;
    153   scoped_ptr<LogoMetadata> metadata =
    154       LogoCache::LogoMetadataFromString("", &logo_num_bytes);
    155   ASSERT_TRUE(metadata.get() == NULL);
    156 
    157   LogoMetadata example_metadata = GetExampleMetadata2();
    158   std::string corrupt_str;
    159   LogoCache::LogoMetadataToString(
    160       example_metadata, logo_num_bytes, &corrupt_str);
    161   corrupt_str.append("@");
    162   metadata = LogoCache::LogoMetadataFromString(corrupt_str, &logo_num_bytes);
    163   ASSERT_TRUE(metadata.get() == NULL);
    164 }
    165 
    166 TEST_F(LogoCacheTest, StoreAndRetrieveMetadata) {
    167   // Expect no metadata at first.
    168   ExpectMetadata(NULL);
    169 
    170   // Set initial metadata.
    171   EncodedLogo logo = GetExampleLogo();
    172   LogoMetadata& metadata = logo.metadata;
    173   cache_->SetCachedLogo(&logo);
    174   ExpectMetadata(&metadata);
    175 
    176   // Update metadata.
    177   metadata.on_click_url = "http://anotherwebsite.com";
    178   cache_->UpdateCachedLogoMetadata(metadata);
    179   ExpectMetadata(&metadata);
    180 
    181   // Read metadata back from disk.
    182   SimulateRestart();
    183   ExpectMetadata(&metadata);
    184 
    185   // Ensure metadata is cached in memory.
    186   base::DeleteFile(cache_->GetMetadataPath(), false);
    187   ExpectMetadata(&metadata);
    188 }
    189 
    190 TEST_F(LogoCacheTest, StoreAndRetrieveLogo) {
    191   // Expect no metadata at first.
    192   ExpectLogo(NULL);
    193 
    194   // Set initial logo.
    195   EncodedLogo logo = GetExampleLogo();
    196   cache_->SetCachedLogo(&logo);
    197   ExpectLogo(&logo);
    198 
    199   // Update logo to NULL.
    200   cache_->SetCachedLogo(NULL);
    201   ExpectLogo(NULL);
    202 
    203   // Read logo back from disk.
    204   SimulateRestart();
    205   ExpectLogo(NULL);
    206 
    207   // Update logo.
    208   logo = GetExampleLogo2();
    209   cache_->SetCachedLogo(&logo);
    210   ExpectLogo(&logo);
    211 
    212   // Read logo back from disk.
    213   SimulateRestart();
    214   ExpectLogo(&logo);
    215 }
    216 
    217 TEST_F(LogoCacheTest, RetrieveCorruptMetadata) {
    218   // Set initial logo.
    219   EncodedLogo logo = GetExampleLogo2();
    220   cache_->SetCachedLogo(&logo);
    221   ExpectLogo(&logo);
    222 
    223   // Corrupt metadata and expect NULL for both logo and metadata.
    224   SimulateRestart();
    225   ShortenFile(cache_->GetMetadataPath());
    226   ExpectMetadata(NULL);
    227   ExpectLogo(NULL);
    228 
    229   // Ensure corrupt cache files are deleted.
    230   EXPECT_FALSE(base::PathExists(cache_->GetMetadataPath()));
    231   EXPECT_FALSE(base::PathExists(cache_->GetLogoPath()));
    232 }
    233 
    234 TEST_F(LogoCacheTest, RetrieveCorruptLogo) {
    235   // Set initial logo.
    236   EncodedLogo logo = GetExampleLogo();
    237   cache_->SetCachedLogo(&logo);
    238   ExpectLogo(&logo);
    239 
    240   // Corrupt logo and expect NULL.
    241   SimulateRestart();
    242   ShortenFile(cache_->GetLogoPath());
    243   ExpectLogo(NULL);
    244   // Once the logo is noticed to be NULL, the metadata should also be cleared.
    245   ExpectMetadata(NULL);
    246 
    247   // Ensure corrupt cache files are deleted.
    248   EXPECT_FALSE(base::PathExists(cache_->GetMetadataPath()));
    249   EXPECT_FALSE(base::PathExists(cache_->GetLogoPath()));
    250 }
    251 
    252 }  // namespace search_provider_logos
    253