| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/search_provider_logos/logo_cache.h" |
| |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/run_loop.h" |
| #include "base/time/time.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace search_provider_logos { |
| |
| LogoMetadata GetExampleMetadata() { |
| LogoMetadata metadata; |
| metadata.source_url = "http://google.com/mylogo"; |
| metadata.fingerprint = "LC4JVIZ5HVITQFKH0V70"; |
| EXPECT_TRUE(base::Time::FromString("98-05-05 05:05:06 GMT", |
| &metadata.expiration_time)); |
| metadata.can_show_after_expiration = true; |
| metadata.on_click_url = "https://www.google.com/search?q=chicken"; |
| metadata.alt_text = "A logo about chickens"; |
| metadata.mime_type = "image/jpeg"; |
| return metadata; |
| } |
| |
| LogoMetadata GetExampleMetadata2() { |
| LogoMetadata metadata; |
| metadata.source_url = "https://www.example.com/thebestlogo?size=large"; |
| metadata.fingerprint = "bh4PLHdnEaQAPxNGRyMao1rOmVFTXuOdVhdrMmPV"; |
| EXPECT_TRUE(base::Time::FromString("17-04-04 07:10:58 GMT", |
| &metadata.expiration_time)); |
| metadata.can_show_after_expiration = false; |
| metadata.on_click_url = "http://www.example.co.uk/welcome.php#top"; |
| metadata.alt_text = "This is a logo"; |
| metadata.mime_type = "image/png"; |
| return metadata; |
| } |
| |
| base::RefCountedString* CreateExampleImage(size_t num_bytes) { |
| base::RefCountedString* encoded_image_str = new base::RefCountedString(); |
| std::string& str = encoded_image_str->data(); |
| str.resize(num_bytes); |
| for (size_t i = 0; i < num_bytes; ++i) |
| str[i] = static_cast<char>(i); |
| return encoded_image_str; |
| } |
| |
| EncodedLogo GetExampleLogo() { |
| EncodedLogo logo; |
| logo.encoded_image = CreateExampleImage(837); |
| logo.metadata = GetExampleMetadata(); |
| return logo; |
| } |
| |
| EncodedLogo GetExampleLogo2() { |
| EncodedLogo logo; |
| logo.encoded_image = CreateExampleImage(345); |
| logo.metadata = GetExampleMetadata2(); |
| return logo; |
| } |
| |
| void ExpectMetadataEqual(const LogoMetadata& expected_metadata, |
| const LogoMetadata& actual_metadata) { |
| EXPECT_EQ(expected_metadata.source_url, actual_metadata.source_url); |
| EXPECT_EQ(expected_metadata.fingerprint, actual_metadata.fingerprint); |
| EXPECT_EQ(expected_metadata.can_show_after_expiration, |
| actual_metadata.can_show_after_expiration); |
| EXPECT_EQ(expected_metadata.expiration_time, actual_metadata.expiration_time); |
| EXPECT_EQ(expected_metadata.on_click_url, actual_metadata.on_click_url); |
| EXPECT_EQ(expected_metadata.alt_text, actual_metadata.alt_text); |
| EXPECT_EQ(expected_metadata.mime_type, actual_metadata.mime_type); |
| } |
| |
| void ExpectLogosEqual(const EncodedLogo& expected_logo, |
| const EncodedLogo& actual_logo) { |
| ASSERT_TRUE(expected_logo.encoded_image); |
| ASSERT_TRUE(actual_logo.encoded_image); |
| EXPECT_TRUE(expected_logo.encoded_image->Equals(actual_logo.encoded_image)); |
| ExpectMetadataEqual(expected_logo.metadata, actual_logo.metadata); |
| } |
| |
| // Removes 1 byte from the end of the file at |path|. |
| void ShortenFile(base::FilePath path) { |
| base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE); |
| int64 file_length = file.GetLength(); |
| ASSERT_NE(file_length, 0); |
| file.SetLength(file_length - 1); |
| } |
| |
| class LogoCacheTest : public ::testing::Test { |
| protected: |
| virtual void SetUp() OVERRIDE { |
| ASSERT_TRUE(cache_parent_dir_.CreateUniqueTempDir()); |
| InitCache(); |
| } |
| |
| void InitCache() { |
| cache_.reset(new LogoCache( |
| cache_parent_dir_.path().Append(FILE_PATH_LITERAL("cache")))); |
| } |
| |
| void ExpectMetadata(const LogoMetadata* expected_metadata) { |
| const LogoMetadata* retrieved_metadata = cache_->GetCachedLogoMetadata(); |
| if (expected_metadata) { |
| ASSERT_TRUE(retrieved_metadata != NULL); |
| ExpectMetadataEqual(*expected_metadata, *retrieved_metadata); |
| } else { |
| ASSERT_TRUE(retrieved_metadata == NULL); |
| } |
| } |
| |
| void ExpectLogo(const EncodedLogo* expected_logo) { |
| scoped_ptr<EncodedLogo> retrieved_logo(cache_->GetCachedLogo()); |
| if (expected_logo) { |
| ASSERT_TRUE(retrieved_logo.get() != NULL); |
| ExpectLogosEqual(*expected_logo, *retrieved_logo); |
| } else { |
| ASSERT_TRUE(retrieved_logo.get() == NULL); |
| } |
| } |
| |
| // Deletes the existing LogoCache and creates a new one. This clears any |
| // logo or metadata cached in memory to simulate restarting Chrome. |
| void SimulateRestart() { |
| InitCache(); |
| } |
| |
| scoped_ptr<LogoCache> cache_; |
| base::ScopedTempDir cache_parent_dir_; |
| }; |
| |
| // Tests ----------------------------------------------------------------------- |
| |
| TEST(LogoCacheSerializationTest, SerializeMetadata) { |
| LogoMetadata metadata = GetExampleMetadata(); |
| std::string metadata_str; |
| int logo_num_bytes = 33; |
| LogoCache::LogoMetadataToString(metadata, logo_num_bytes, &metadata_str); |
| scoped_ptr<LogoMetadata> metadata2 = |
| LogoCache::LogoMetadataFromString(metadata_str, &logo_num_bytes); |
| ASSERT_TRUE(metadata2); |
| ExpectMetadataEqual(metadata, *metadata2); |
| } |
| |
| TEST(LogoCacheSerializationTest, DeserializeCorruptMetadata) { |
| int logo_num_bytes = 33; |
| scoped_ptr<LogoMetadata> metadata = |
| LogoCache::LogoMetadataFromString("", &logo_num_bytes); |
| ASSERT_TRUE(metadata.get() == NULL); |
| |
| LogoMetadata example_metadata = GetExampleMetadata2(); |
| std::string corrupt_str; |
| LogoCache::LogoMetadataToString( |
| example_metadata, logo_num_bytes, &corrupt_str); |
| corrupt_str.append("@"); |
| metadata = LogoCache::LogoMetadataFromString(corrupt_str, &logo_num_bytes); |
| ASSERT_TRUE(metadata.get() == NULL); |
| } |
| |
| TEST_F(LogoCacheTest, StoreAndRetrieveMetadata) { |
| // Expect no metadata at first. |
| ExpectMetadata(NULL); |
| |
| // Set initial metadata. |
| EncodedLogo logo = GetExampleLogo(); |
| LogoMetadata& metadata = logo.metadata; |
| cache_->SetCachedLogo(&logo); |
| ExpectMetadata(&metadata); |
| |
| // Update metadata. |
| metadata.on_click_url = "http://anotherwebsite.com"; |
| cache_->UpdateCachedLogoMetadata(metadata); |
| ExpectMetadata(&metadata); |
| |
| // Read metadata back from disk. |
| SimulateRestart(); |
| ExpectMetadata(&metadata); |
| |
| // Ensure metadata is cached in memory. |
| base::DeleteFile(cache_->GetMetadataPath(), false); |
| ExpectMetadata(&metadata); |
| } |
| |
| TEST_F(LogoCacheTest, StoreAndRetrieveLogo) { |
| // Expect no metadata at first. |
| ExpectLogo(NULL); |
| |
| // Set initial logo. |
| EncodedLogo logo = GetExampleLogo(); |
| cache_->SetCachedLogo(&logo); |
| ExpectLogo(&logo); |
| |
| // Update logo to NULL. |
| cache_->SetCachedLogo(NULL); |
| ExpectLogo(NULL); |
| |
| // Read logo back from disk. |
| SimulateRestart(); |
| ExpectLogo(NULL); |
| |
| // Update logo. |
| logo = GetExampleLogo2(); |
| cache_->SetCachedLogo(&logo); |
| ExpectLogo(&logo); |
| |
| // Read logo back from disk. |
| SimulateRestart(); |
| ExpectLogo(&logo); |
| } |
| |
| TEST_F(LogoCacheTest, RetrieveCorruptMetadata) { |
| // Set initial logo. |
| EncodedLogo logo = GetExampleLogo2(); |
| cache_->SetCachedLogo(&logo); |
| ExpectLogo(&logo); |
| |
| // Corrupt metadata and expect NULL for both logo and metadata. |
| SimulateRestart(); |
| ShortenFile(cache_->GetMetadataPath()); |
| ExpectMetadata(NULL); |
| ExpectLogo(NULL); |
| |
| // Ensure corrupt cache files are deleted. |
| EXPECT_FALSE(base::PathExists(cache_->GetMetadataPath())); |
| EXPECT_FALSE(base::PathExists(cache_->GetLogoPath())); |
| } |
| |
| TEST_F(LogoCacheTest, RetrieveCorruptLogo) { |
| // Set initial logo. |
| EncodedLogo logo = GetExampleLogo(); |
| cache_->SetCachedLogo(&logo); |
| ExpectLogo(&logo); |
| |
| // Corrupt logo and expect NULL. |
| SimulateRestart(); |
| ShortenFile(cache_->GetLogoPath()); |
| ExpectLogo(NULL); |
| // Once the logo is noticed to be NULL, the metadata should also be cleared. |
| ExpectMetadata(NULL); |
| |
| // Ensure corrupt cache files are deleted. |
| EXPECT_FALSE(base::PathExists(cache_->GetMetadataPath())); |
| EXPECT_FALSE(base::PathExists(cache_->GetLogoPath())); |
| } |
| |
| } // namespace search_provider_logos |