Index: components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc |
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc b/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc |
index edf130ac9dc24a607fddf176e6e960b100cdfe42..e558fc5ae03eeddf7678f467ab26aaa53e5afeab 100644 |
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc |
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc |
@@ -9,6 +9,7 @@ |
#include "base/base64.h" |
#include "base/memory/ptr_util.h" |
+#include "base/run_loop.h" |
#include "base/strings/stringprintf.h" |
#include "base/test/simple_test_clock.h" |
#include "base/time/time.h" |
@@ -34,7 +35,7 @@ const char kKeyParam[] = "test_key_param"; |
namespace safe_browsing { |
-class SafeBrowsingV4GetHashProtocolManagerTest : public testing::Test { |
+class V4GetHashProtocolManagerTest : public testing::Test { |
protected: |
std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager() { |
V4ProtocolConfig config; |
@@ -89,9 +90,10 @@ void ValidateGetV4HashResults( |
EXPECT_EQ(expected.metadata, actual.metadata); |
EXPECT_EQ(expected.cache_expire_after, actual.cache_expire_after); |
} |
+ |
} |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
+TEST_F(V4GetHashProtocolManagerTest, |
TestGetHashErrorHandlingNetwork) { |
net::TestURLFetcherFactory factory; |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
@@ -118,7 +120,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
EXPECT_EQ(1ul, pm->gethash_back_off_mult_); |
} |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
+TEST_F(V4GetHashProtocolManagerTest, |
TestGetHashErrorHandlingResponseCode) { |
net::TestURLFetcherFactory factory; |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
@@ -144,14 +146,14 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
EXPECT_EQ(1ul, pm->gethash_back_off_mult_); |
} |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK) { |
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK) { |
net::TestURLFetcherFactory factory; |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
base::Time now = base::Time::UnixEpoch(); |
SetTestClock(now, pm.get()); |
- std::vector<SBPrefix> prefixes; |
+ std::vector<SBPrefix> prefixes = {2877448190}; |
std::vector<SBFullHashResult> expected_full_hashes; |
SBFullHashResult hash_result; |
hash_result.hash = SBFullHashForString("Everything's shiny, Cap'n."); |
@@ -174,9 +176,19 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK) { |
// No error, back off multiplier is unchanged. |
EXPECT_EQ(0ul, pm->gethash_error_count_); |
EXPECT_EQ(1ul, pm->gethash_back_off_mult_); |
+ |
+ // Verify the state of the cache. |
+ const V4GetHashProtocolManager::PrefixToFullHashResultsMap& cache = |
+ pm->v4_full_hash_cache()->at(SB_THREAT_TYPE_API_ABUSE); |
+ // Check the cache. |
+ EXPECT_EQ(1u, cache.size()); |
+ EXPECT_EQ(1u, cache.count(prefixes[0])); |
+ const SBCachedFullHashResult& cached_result = cache.at(prefixes[0]); |
+ EXPECT_EQ(1u, cached_result.full_hashes.size()); |
+ EXPECT_TRUE(SBFullHashEqual(SBFullHashForString("Everything's shiny, Cap'n."), cached_result.full_hashes[0].hash)); |
} |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashRequest) { |
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashRequest) { |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
FindFullHashesRequest req; |
@@ -211,7 +223,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashRequest) { |
EXPECT_EQ(req_base64, pm->GetHashRequest(prefixes, platform, API_ABUSE)); |
} |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) { |
+TEST_F(V4GetHashProtocolManagerTest, TestParseHashResponse) { |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
base::Time now = base::Time::UnixEpoch(); |
@@ -253,7 +265,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) { |
} |
// Adds an entry with an ignored ThreatEntryType. |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
+TEST_F(V4GetHashProtocolManagerTest, |
TestParseHashResponseWrongThreatEntryType) { |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
@@ -278,7 +290,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
} |
// Adds entries with a ThreatPatternType metadata. |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
+TEST_F(V4GetHashProtocolManagerTest, |
TestParseHashThreatPatternType) { |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
@@ -357,7 +369,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
} |
// Adds metadata with a key value that is not "permission". |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
+TEST_F(V4GetHashProtocolManagerTest, |
TestParseHashResponseNonPermissionMetadata) { |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
@@ -389,7 +401,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
EXPECT_EQ(0ul, full_hashes.size()); |
} |
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
+TEST_F(V4GetHashProtocolManagerTest, |
TestParseHashResponseInconsistentThreatTypes) { |
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
@@ -417,4 +429,204 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, |
EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire)); |
} |
+// Checks that results are looked up correctly in the cache. |
+TEST_F(V4GetHashProtocolManagerTest, GetCachedResults) { |
+ base::Time now = base::Time::UnixEpoch(); |
+ std::vector<SBFullHash> full_hashes; |
+ SBFullHash full_hash = SBFullHashForString("example.com/"); |
+ full_hashes.push_back(full_hash); |
+ std::vector<SBFullHashResult> cached_results; |
+ std::vector<SBPrefix> prefixes; |
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
+ pm->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
+ full_hashes, now, &prefixes, &cached_results); |
+ |
+ // The cache is empty. |
+ EXPECT_TRUE(cached_results.empty()); |
+ EXPECT_EQ(1ul, prefixes.size()); |
+ EXPECT_EQ(full_hash.prefix, prefixes[0]); |
+ |
+ // Prefix has a cache entry but full hash is not there. |
+ SBCachedFullHashResult& entry = pm-> |
+ v4_full_hash_cache()->at(SB_THREAT_TYPE_API_ABUSE)[full_hash.prefix] = |
+ SBCachedFullHashResult(now + base::TimeDelta::FromMinutes(5)); |
+ pm->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
+ full_hashes, now, &prefixes, &cached_results); |
+ |
+ EXPECT_TRUE(prefixes.empty()); |
+ EXPECT_TRUE(cached_results.empty()); |
+ |
+ // Expired negative cache entry. |
+ entry.expire_after = now - base::TimeDelta::FromMinutes(5); |
+ pm->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
+ full_hashes, now, &prefixes, &cached_results); |
+ |
+ EXPECT_TRUE(cached_results.empty()); |
+ EXPECT_EQ(1ul, prefixes.size()); |
+ EXPECT_EQ(full_hash.prefix, prefixes[0]); |
+ |
+ // Now put the full hash in the cache. |
+ SBFullHashResult full_hash_result; |
+ full_hash_result.hash = full_hash; |
+ full_hash_result.cache_expire_after = now + base::TimeDelta::FromMinutes(3); |
+ entry.full_hashes.push_back(full_hash_result); |
+ pm->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
+ full_hashes, now, &prefixes, &cached_results); |
+ |
+ EXPECT_TRUE(prefixes.empty()); |
+ EXPECT_EQ(1ul, cached_results.size()); |
+ EXPECT_TRUE(SBFullHashEqual(full_hash, cached_results[0].hash)); |
+ |
+ // Expired full hash in cache. |
+ entry.full_hashes.clear(); |
+ full_hash_result.cache_expire_after = now - base::TimeDelta::FromMinutes(3); |
+ entry.full_hashes.push_back(full_hash_result); |
+ pm->GetFullHashCachedResults(SB_THREAT_TYPE_API_ABUSE, |
+ full_hashes, now, &prefixes, &cached_results); |
+ |
+ EXPECT_TRUE(cached_results.empty()); |
+ EXPECT_EQ(1ul, prefixes.size()); |
+ EXPECT_EQ(full_hash.prefix, prefixes[0]); |
+} |
+/* |
+// Checks that the cached results and request results are merged. |
+TEST_F(V4GetHashProtocolManagerTest, CachedResultsMerged) { |
+ //TestClient client; |
+ const GURL url("https://www.example.com/more"); |
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
+ // Set now to max time so the cache expire times are in the future. |
+ SBFullHash full_hash = SBFullHashForString("example.com/"); |
+ SBFullHashResult full_hash_result; |
+ full_hash_result.hash = full_hash; |
+ full_hash_result.metadata.api_permissions.insert("GEOLOCATION"); |
+ full_hash_result.cache_expire_after = base::Time::Max(); |
+ //pm->AddGetFullHashResponse(full_hash_result); |
+ //pm->SetNegativeCacheDurationMins(base::Time::Max(), 0); |
+ |
+ EXPECT_TRUE(pm->v4_full_hash_cache()->empty()); |
+ EXPECT_FALSE(pm->CheckApiBlacklistUrl(url, &client)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_TRUE(client.callback_invoked()); |
+ const std::set<std::string>& permissions = client.GetBlockedPermissions(); |
+ EXPECT_EQ(1ul, permissions.size()); |
+ EXPECT_EQ(1ul, permissions.count("GEOLOCATION")); |
+ |
+ // The results should be cached, so remove them from the protocol manager |
+ // response. |
+ //TestClient client2; |
+ //pm->ClearFullHashResponse(); |
+ //pm->SetNegativeCacheDurationMins(base::Time(), 0); |
+ EXPECT_FALSE(pm->CheckApiBlacklistUrl(url, &client2)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_TRUE(client2.callback_invoked()); |
+ const std::set<std::string>& permissions2 = |
+ client2.GetBlockedPermissions(); |
+ EXPECT_EQ(1ul, permissions2.size()); |
+ EXPECT_EQ(1ul, permissions2.count("GEOLOCATION")); |
+ |
+ // Add a different result to the protocol manager response and ensure it is |
+ // merged with the cached result in the metadata. |
+ //TestClient client3; |
+ const GURL url2("https://m.example.com/more"); |
+ full_hash_result.hash = SBFullHashForString("m.example.com/"); |
+ full_hash_result.metadata.api_permissions.insert("NOTIFICATIONS"); |
+ //pm->AddGetFullHashResponse(full_hash_result); |
+ //pm->SetNegativeCacheDurationMins(base::Time::Max(), 0); |
+ EXPECT_FALSE(pm->CheckApiBlacklistUrl(url2, &client3)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ EXPECT_TRUE(client3.callback_invoked()); |
+ const std::set<std::string>& permissions3 = |
+ client3.GetBlockedPermissions(); |
+ EXPECT_EQ(2ul, permissions3.size()); |
+ EXPECT_EQ(1ul, permissions3.count("GEOLOCATION")); |
+ EXPECT_EQ(1ul, permissions3.count("NOTIFICATIONS")); |
+} |
+ |
+TEST_F(V4GetHashProtocolManagerTest, CachedResultsAreEvicted) { |
+ base::Time epoch = base::Time::UnixEpoch(); |
+ SBFullHashResult full_hash_result; |
+ full_hash_result.hash = SBFullHashForString("example.com/"); |
+ full_hash_result.cache_expire_after = epoch; |
+ |
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager()); |
+ V4GetHashProtocolManager::PrefixToFullHashResultsMap& cache = |
+ pm->v4_full_hash_cache()->at(SB_THREAT_TYPE_API_ABUSE); |
+ |
+ // Fill the cache with some expired entries. |
+ // Both negative cache and full hash expired. |
+ cache[full_hash_result.hash.prefix] = SBCachedFullHashResult(epoch); |
+ cache[full_hash_result.hash.prefix].full_hashes.push_back(full_hash_result); |
+ |
+ TestClient client; |
+ const GURL url("https://www.example.com/more"); |
+ |
+ EXPECT_EQ(1ul, cache.size()); |
+ EXPECT_FALSE(pm->CheckApiBlacklistUrl(url, &client)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Cache should be empty. |
+ EXPECT_TRUE(client.callback_invoked()); |
+ EXPECT_TRUE(cache.empty()); |
+ |
+ // Negative cache still valid and full hash expired. |
+ cache[full_hash_result.hash.prefix] = |
+ SBCachedFullHashResult(base::Time::Max()); |
+ cache[full_hash_result.hash.prefix].full_hashes.push_back(full_hash_result); |
+ |
+ EXPECT_EQ(1ul, cache.size()); |
+ EXPECT_FALSE(pm->CheckApiBlacklistUrl(url, &client)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Cache entry should still be there. |
+ EXPECT_EQ(1ul, cache.size()); |
+ auto entry = cache.find(full_hash_result.hash.prefix); |
+ EXPECT_NE(cache.end(), entry); |
+ EXPECT_EQ(base::Time::Max(), entry->second.expire_after); |
+ EXPECT_EQ(1ul, entry->second.full_hashes.size()); |
+ EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash, |
+ entry->second.full_hashes[0].hash)); |
+ EXPECT_EQ(full_hash_result.cache_expire_after, |
+ entry->second.full_hashes[0].cache_expire_after); |
+ |
+ // Negative cache still valid and full hash still valid. |
+ cache[full_hash_result.hash.prefix].full_hashes[0]. |
+ cache_expire_after = base::Time::Max(); |
+ |
+ EXPECT_EQ(1ul, cache.size()); |
+ EXPECT_FALSE(pm->CheckApiBlacklistUrl(url, &client)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Cache entry should still be there. |
+ EXPECT_EQ(1ul, cache.size()); |
+ entry = cache.find(full_hash_result.hash.prefix); |
+ EXPECT_NE(cache.end(), entry); |
+ EXPECT_EQ(base::Time::Max(), entry->second.expire_after); |
+ EXPECT_EQ(1ul, entry->second.full_hashes.size()); |
+ EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash, |
+ entry->second.full_hashes[0].hash)); |
+ EXPECT_EQ(base::Time::Max(), |
+ entry->second.full_hashes[0].cache_expire_after); |
+ |
+ // Negative cache expired and full hash still valid. |
+ cache[full_hash_result.hash.prefix].expire_after = epoch; |
+ |
+ EXPECT_EQ(1ul, cache.size()); |
+ EXPECT_FALSE(pm->CheckApiBlacklistUrl(url, &client)); |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // Cache entry should still be there. |
+ EXPECT_EQ(1ul, cache.size()); |
+ entry = cache.find(full_hash_result.hash.prefix); |
+ EXPECT_NE(cache.end(), entry); |
+ EXPECT_EQ(epoch, entry->second.expire_after); |
+ EXPECT_EQ(1ul, entry->second.full_hashes.size()); |
+ EXPECT_TRUE(SBFullHashEqual(full_hash_result.hash, |
+ entry->second.full_hashes[0].hash)); |
+ EXPECT_EQ(base::Time::Max(), |
+ entry->second.full_hashes[0].cache_expire_after); |
+} |
+*/ |
} // namespace safe_browsing |