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