• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 
GetExampleMetadata()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 
GetExampleMetadata2()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 
CreateExampleImage(size_t num_bytes)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 
GetExampleLogo()54 EncodedLogo GetExampleLogo() {
55   EncodedLogo logo;
56   logo.encoded_image = CreateExampleImage(837);
57   logo.metadata = GetExampleMetadata();
58   return logo;
59 }
60 
GetExampleLogo2()61 EncodedLogo GetExampleLogo2() {
62   EncodedLogo logo;
63   logo.encoded_image = CreateExampleImage(345);
64   logo.metadata = GetExampleMetadata2();
65   return logo;
66 }
67 
ExpectMetadataEqual(const LogoMetadata & expected_metadata,const LogoMetadata & actual_metadata)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 
ExpectLogosEqual(const EncodedLogo & expected_logo,const EncodedLogo & actual_logo)80 void ExpectLogosEqual(const EncodedLogo& expected_logo,
81                       const EncodedLogo& actual_logo) {
82   ASSERT_TRUE(expected_logo.encoded_image);
83   ASSERT_TRUE(actual_logo.encoded_image);
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|.
ShortenFile(base::FilePath 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:
SetUp()98   virtual void SetUp() OVERRIDE {
99     ASSERT_TRUE(cache_parent_dir_.CreateUniqueTempDir());
100     InitCache();
101   }
102 
InitCache()103   void InitCache() {
104     cache_.reset(new LogoCache(
105         cache_parent_dir_.path().Append(FILE_PATH_LITERAL("cache"))));
106   }
107 
ExpectMetadata(const LogoMetadata * expected_metadata)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 
ExpectLogo(const EncodedLogo * expected_logo)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.
SimulateRestart()130   void SimulateRestart() {
131     InitCache();
132   }
133 
134   scoped_ptr<LogoCache> cache_;
135   base::ScopedTempDir cache_parent_dir_;
136 };
137 
138 // Tests -----------------------------------------------------------------------
139 
TEST(LogoCacheSerializationTest,SerializeMetadata)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 
TEST(LogoCacheSerializationTest,DeserializeCorruptMetadata)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 
TEST_F(LogoCacheTest,StoreAndRetrieveMetadata)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 
TEST_F(LogoCacheTest,StoreAndRetrieveLogo)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 
TEST_F(LogoCacheTest,RetrieveCorruptMetadata)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 
TEST_F(LogoCacheTest,RetrieveCorruptLogo)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