Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(598)

Unified Diff: components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc

Issue 2233103002: Move full hash caching logic to v4_get_hash_protocol_manager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: shess@ feedback - part 2. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..faf1916d01e6cc24633dfa76be3f551329d2b8b0 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"
@@ -19,7 +20,7 @@
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/url_request/test_url_fetcher_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
using base::Time;
using base::TimeDelta;
@@ -34,37 +35,77 @@ const char kKeyParam[] = "test_key_param";
namespace safe_browsing {
-class SafeBrowsingV4GetHashProtocolManagerTest : public testing::Test {
- protected:
+namespace {
+
+struct KeyValue {
+ std::string key;
+ std::string value;
+
+ explicit KeyValue(const std::string key, const std::string value)
+ : key(key), value(value){};
+ explicit KeyValue(const KeyValue& other) = default;
+
+ private:
+ KeyValue();
+};
+
+struct ResponseInfo {
+ FullHash full_hash;
+ UpdateListIdentifier list_id;
+ std::vector<KeyValue> key_values;
+
+ explicit ResponseInfo(FullHash full_hash, UpdateListIdentifier list_id)
+ : full_hash(full_hash), list_id(list_id){};
+ explicit ResponseInfo(const ResponseInfo& other)
+ : full_hash(other.full_hash),
+ list_id(other.list_id),
+ key_values(other.key_values){};
+
+ private:
+ ResponseInfo();
+};
+
+} // namespace
+
+class V4GetHashProtocolManagerTest : public PlatformTest {
+ public:
+ void SetUp() override {
+ PlatformTest::SetUp();
+ callback_called_ = false;
+ }
+
std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager() {
V4ProtocolConfig config;
config.client_name = kClient;
config.version = kAppVer;
config.key_param = kKeyParam;
- return std::unique_ptr<V4GetHashProtocolManager>(
- V4GetHashProtocolManager::Create(NULL, config));
+ base::hash_set<UpdateListIdentifier> stores_to_look(
+ {GetUrlMalwareId(), GetChromeUrlApiId()});
+ return V4GetHashProtocolManager::Create(NULL, stores_to_look, config);
}
- std::string GetStockV4HashResponse() {
- FindFullHashesResponse res;
- res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* m = res.add_matches();
- m->set_threat_type(API_ABUSE);
- m->set_platform_type(CHROME_PLATFORM);
- m->set_threat_entry_type(URL);
- m->mutable_cache_duration()->set_seconds(300);
- m->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n.")));
- ThreatEntryMetadata::MetadataEntry* e =
- m->mutable_threat_entry_metadata()->add_entries();
- e->set_key("permission");
- e->set_value("NOTIFICATIONS");
+ static void SetupFetcherToReturnOKResponse(
+ const net::TestURLFetcherFactory& factory,
+ const std::vector<ResponseInfo>& infos) {
+ net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
+ DCHECK(fetcher);
+ fetcher->set_status(net::URLRequestStatus());
+ fetcher->set_response_code(200);
+ fetcher->SetResponseString(GetV4HashResponse(infos));
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ }
- // Serialize.
- std::string res_data;
- res.SerializeToString(&res_data);
+ static std::vector<ResponseInfo> GetStockV4HashResponseInfos() {
+ ResponseInfo info(FullHash("Everything's shiny, Cap'n."),
+ GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "NOTIFICATIONS");
+ std::vector<ResponseInfo> infos;
+ infos.push_back(info);
+ return infos;
+ }
- return res_data;
+ static std::string GetStockV4HashResponse() {
+ return GetV4HashResponse(GetStockV4HashResponseInfos());
}
void SetTestClock(base::Time now, V4GetHashProtocolManager* pm) {
@@ -72,37 +113,68 @@ class SafeBrowsingV4GetHashProtocolManagerTest : public testing::Test {
clock->SetNow(now);
pm->SetClockForTests(base::WrapUnique(clock));
}
-};
-void ValidateGetV4HashResults(
- const std::vector<SBFullHashResult>& expected_full_hashes,
- const base::Time& expected_cache_expire,
- const std::vector<SBFullHashResult>& full_hashes,
- const base::Time& cache_expire) {
- EXPECT_EQ(expected_cache_expire, cache_expire);
- ASSERT_EQ(expected_full_hashes.size(), full_hashes.size());
-
- for (unsigned int i = 0; i < expected_full_hashes.size(); ++i) {
- const SBFullHashResult& expected = expected_full_hashes[i];
- const SBFullHashResult& actual = full_hashes[i];
- EXPECT_TRUE(SBFullHashEqual(expected.hash, actual.hash));
- EXPECT_EQ(expected.metadata, actual.metadata);
- EXPECT_EQ(expected.cache_expire_after, actual.cache_expire_after);
+ void ValidateGetV4ApiResults(const ThreatMetadata& expected_md,
+ const ThreatMetadata& actual_md) {
+ EXPECT_EQ(expected_md, actual_md);
+ callback_called_ = true;
+ }
+
+ void ValidateGetV4HashResults(
+ const std::vector<FullHashInfo>& expected_results,
+ const std::vector<FullHashInfo>& actual_results) {
+ EXPECT_EQ(expected_results.size(), actual_results.size());
+ for (size_t i = 0; i < actual_results.size(); i++) {
+ EXPECT_TRUE(expected_results[i] == actual_results[i]);
+ }
+ callback_called_ = true;
}
-}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
- TestGetHashErrorHandlingNetwork) {
+ bool callback_called() { return callback_called_; }
+
+ private:
+ static std::string GetV4HashResponse(
+ std::vector<ResponseInfo> response_infos) {
+ FindFullHashesResponse res;
+ res.mutable_negative_cache_duration()->set_seconds(600);
+ for (const ResponseInfo& info : response_infos) {
+ ThreatMatch* m = res.add_matches();
+ m->set_platform_type(info.list_id.platform_type);
+ m->set_threat_entry_type(info.list_id.threat_entry_type);
+ m->set_threat_type(info.list_id.threat_type);
+ m->mutable_cache_duration()->set_seconds(300);
+ m->mutable_threat()->set_hash(info.full_hash);
+
+ for (const KeyValue& key_value : info.key_values) {
+ ThreatEntryMetadata::MetadataEntry* e =
+ m->mutable_threat_entry_metadata()->add_entries();
+ e->set_key(key_value.key);
+ e->set_value(key_value.value);
+ }
+ }
+
+ // Serialize.
+ std::string res_data;
+ res.SerializeToString(&res_data);
+
+ return res_data;
+ }
+
+ bool callback_called_;
+};
+
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingNetwork) {
net::TestURLFetcherFactory factory;
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
- std::vector<SBPrefix> prefixes;
- std::vector<SBFullHashResult> expected_full_hashes;
- base::Time expected_cache_expire;
-
- pm->GetFullHashesWithApis(
- prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes,
- expected_cache_expire));
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[FullHash("AHashFull")].emplace_back(GetUrlSocEngId(),
+ HashPrefix("AHash"));
+ std::vector<FullHashInfo> expected_results;
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
DCHECK(fetcher);
@@ -116,20 +188,21 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
// Should have recorded one error, but back off multiplier is unchanged.
EXPECT_EQ(1ul, pm->gethash_error_count_);
EXPECT_EQ(1ul, pm->gethash_back_off_mult_);
+ EXPECT_TRUE(callback_called());
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
- TestGetHashErrorHandlingResponseCode) {
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashErrorHandlingResponseCode) {
net::TestURLFetcherFactory factory;
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
- std::vector<SBPrefix> prefixes;
- std::vector<SBFullHashResult> expected_full_hashes;
- base::Time expected_cache_expire;
-
- pm->GetFullHashesWithApis(
- prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes,
- expected_cache_expire));
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[FullHash("AHashFull")].emplace_back(GetUrlSocEngId(),
+ HashPrefix("AHash"));
+ std::vector<FullHashInfo> expected_results;
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
DCHECK(fetcher);
@@ -142,81 +215,106 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
// Should have recorded one error, but back off multiplier is unchanged.
EXPECT_EQ(1ul, pm->gethash_error_count_);
EXPECT_EQ(1ul, pm->gethash_back_off_mult_);
+ EXPECT_TRUE(callback_called());
}
-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<SBFullHashResult> expected_full_hashes;
- SBFullHashResult hash_result;
- hash_result.hash = SBFullHashForString("Everything's shiny, Cap'n.");
- hash_result.metadata.api_permissions.insert("NOTIFICATIONS");
- hash_result.cache_expire_after = now + base::TimeDelta::FromSeconds(300);
- expected_full_hashes.push_back(hash_result);
- base::Time expected_cache_expire = now + base::TimeDelta::FromSeconds(600);
+ HashPrefix prefix("Everything");
+ FullHash full_hash("Everything's shiny, Cap'n.");
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[full_hash].push_back(
+ StoreAndHashPrefix(GetChromeUrlApiId(), prefix));
+ std::vector<FullHashInfo> expected_results;
+ FullHashInfo fhi(full_hash, GetChromeUrlApiId(),
+ now + base::TimeDelta::FromSeconds(300));
+ fhi.metadata.api_permissions.insert("NOTIFICATIONS");
+ expected_results.push_back(fhi);
- pm->GetFullHashesWithApis(
- prefixes, base::Bind(&ValidateGetV4HashResults, expected_full_hashes,
- expected_cache_expire));
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
- net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
- DCHECK(fetcher);
- fetcher->set_status(net::URLRequestStatus());
- fetcher->set_response_code(200);
- fetcher->SetResponseString(GetStockV4HashResponse());
- fetcher->delegate()->OnURLFetchComplete(fetcher);
+ SetupFetcherToReturnOKResponse(factory, GetStockV4HashResponseInfos());
// 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 FullHashCache* cache = pm->full_hash_cache_for_tests();
+ // Check the cache.
+ ASSERT_EQ(1u, cache->size());
+ EXPECT_EQ(1u, cache->count(prefix));
+ const CachedHashPrefixInfo& cached_result = cache->at(prefix);
+ EXPECT_EQ(cached_result.negative_expiry,
+ now + base::TimeDelta::FromSeconds(600));
+ ASSERT_EQ(1u, cached_result.full_hash_infos.size());
+ EXPECT_EQ(FullHash("Everything's shiny, Cap'n."),
+ cached_result.full_hash_infos[0].full_hash);
+ EXPECT_TRUE(callback_called());
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashRequest) {
+TEST_F(V4GetHashProtocolManagerTest,
+ TestResultsNotCachedForNegativeCacheDuration) {
+ net::TestURLFetcherFactory factory;
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ HashPrefix prefix("Everything");
+ std::vector<HashPrefix> prefixes_requested({prefix});
+ base::Time negative_cache_expire;
+ FullHash full_hash("Everything's shiny, Cap'n.");
+ std::vector<FullHashInfo> fhis;
+ fhis.emplace_back(full_hash, GetChromeUrlApiId(), base::Time::UnixEpoch());
+
+ pm->UpdateCache(prefixes_requested, fhis, negative_cache_expire);
+
+ // Verify the state of the cache.
+ const FullHashCache* cache = pm->full_hash_cache_for_tests();
+ // Check the cache.
+ EXPECT_EQ(0u, cache->size());
+}
+
+TEST_F(V4GetHashProtocolManagerTest, TestGetHashRequest) {
+ HashPrefix one = "hashone";
+ HashPrefix two = "hashtwo";
+ std::vector<HashPrefix> prefixes_to_request = {one, two};
+
FindFullHashesRequest req;
ThreatInfo* info = req.mutable_threat_info();
+ info->add_threat_types(MALWARE_THREAT);
info->add_threat_types(API_ABUSE);
+
+ info->add_platform_types(GetCurrentPlatformType());
info->add_platform_types(CHROME_PLATFORM);
+
info->add_threat_entry_types(URL);
- SBPrefix one = 1u;
- SBPrefix two = 2u;
- SBPrefix three = 3u;
- std::string hash(reinterpret_cast<const char*>(&one), sizeof(SBPrefix));
- info->add_threat_entries()->set_hash(hash);
- hash.clear();
- hash.append(reinterpret_cast<const char*>(&two), sizeof(SBPrefix));
- info->add_threat_entries()->set_hash(hash);
- hash.clear();
- hash.append(reinterpret_cast<const char*>(&three), sizeof(SBPrefix));
- info->add_threat_entries()->set_hash(hash);
+ info->add_threat_entries()->set_hash(one);
+ info->add_threat_entries()->set_hash(two);
// Serialize and Base64 encode.
std::string req_data, req_base64;
req.SerializeToString(&req_data);
base::Base64Encode(req_data, &req_base64);
- std::vector<PlatformType> platform;
- platform.push_back(CHROME_PLATFORM);
- std::vector<SBPrefix> prefixes;
- prefixes.push_back(one);
- prefixes.push_back(two);
- prefixes.push_back(three);
- EXPECT_EQ(req_base64, pm->GetHashRequest(prefixes, platform, API_ABUSE));
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ EXPECT_EQ(req_base64, pm->GetHashRequest(prefixes_to_request));
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) {
+TEST_F(V4GetHashProtocolManagerTest, TestParseHashResponse) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
base::Time now = base::Time::UnixEpoch();
SetTestClock(now, pm.get());
+ FullHash full_hash("Everything's shiny, Cap'n.");
FindFullHashesResponse res;
res.mutable_negative_cache_duration()->set_seconds(600);
res.mutable_minimum_wait_duration()->set_seconds(400);
@@ -225,8 +323,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) {
m->set_platform_type(CHROME_PLATFORM);
m->set_threat_entry_type(URL);
m->mutable_cache_duration()->set_seconds(300);
- m->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n.")));
+ m->mutable_threat()->set_hash(full_hash);
ThreatEntryMetadata::MetadataEntry* e =
m->mutable_threat_entry_metadata()->add_entries();
e->set_key("permission");
@@ -236,24 +333,23 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse) {
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_TRUE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_TRUE(pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
- EXPECT_EQ(1ul, full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(SBFullHashForString("Everything's shiny, Cap'n."),
- full_hashes[0].hash));
- EXPECT_EQ(1ul, full_hashes[0].metadata.api_permissions.size());
- EXPECT_EQ(1ul,
- full_hashes[0].metadata.api_permissions.count("NOTIFICATIONS"));
- EXPECT_EQ(now +
- base::TimeDelta::FromSeconds(300), full_hashes[0].cache_expire_after);
+ ASSERT_EQ(1ul, full_hash_infos.size());
+ const FullHashInfo& fhi = full_hash_infos[0];
+ EXPECT_EQ(full_hash, fhi.full_hash);
+ EXPECT_EQ(GetChromeUrlApiId(), fhi.list_id);
+ EXPECT_EQ(1ul, fhi.metadata.api_permissions.size());
+ EXPECT_EQ(1ul, fhi.metadata.api_permissions.count("NOTIFICATIONS"));
+ EXPECT_EQ(now + base::TimeDelta::FromSeconds(300), fhi.positive_expiry);
EXPECT_EQ(now + base::TimeDelta::FromSeconds(400), pm->next_gethash_time_);
}
// Adds an entry with an ignored ThreatEntryType.
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
+TEST_F(V4GetHashProtocolManagerTest,
TestParseHashResponseWrongThreatEntryType) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
@@ -268,96 +364,117 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_FALSE(
+ pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
// There should be no hash results.
- EXPECT_EQ(0ul, full_hashes.size());
+ EXPECT_EQ(0ul, full_hash_infos.size());
}
// Adds entries with a ThreatPatternType metadata.
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
- TestParseHashThreatPatternType) {
+TEST_F(V4GetHashProtocolManagerTest, TestParseHashThreatPatternType) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
base::Time now = base::Time::UnixEpoch();
SetTestClock(now, pm.get());
- // Test social engineering pattern type.
- FindFullHashesResponse se_res;
- se_res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* se = se_res.add_matches();
- se->set_threat_type(SOCIAL_ENGINEERING_PUBLIC);
- se->set_platform_type(CHROME_PLATFORM);
- se->set_threat_entry_type(URL);
- SBFullHash hash_string = SBFullHashForString("Everything's shiny, Cap'n.");
- se->mutable_threat()->set_hash(SBFullHashToString(hash_string));
- ThreatEntryMetadata::MetadataEntry* se_meta =
- se->mutable_threat_entry_metadata()->add_entries();
- se_meta->set_key("se_pattern_type");
- se_meta->set_value("SOCIAL_ENGINEERING_LANDING");
-
- std::string se_data;
- se_res.SerializeToString(&se_data);
-
- std::vector<SBFullHashResult> full_hashes;
- base::Time cache_expire;
- EXPECT_TRUE(pm->ParseHashResponse(se_data, &full_hashes, &cache_expire));
+ {
+ // Test social engineering pattern type.
+ FindFullHashesResponse se_res;
+ se_res.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* se = se_res.add_matches();
+ se->set_threat_type(SOCIAL_ENGINEERING_PUBLIC);
+ se->set_platform_type(CHROME_PLATFORM);
+ se->set_threat_entry_type(URL);
+ FullHash full_hash("Everything's shiny, Cap'n.");
+ se->mutable_threat()->set_hash(full_hash);
+ ThreatEntryMetadata::MetadataEntry* se_meta =
+ se->mutable_threat_entry_metadata()->add_entries();
+ se_meta->set_key("se_pattern_type");
+ se_meta->set_value("SOCIAL_ENGINEERING_LANDING");
+
+ std::string se_data;
+ se_res.SerializeToString(&se_data);
+
+ std::vector<FullHashInfo> full_hash_infos;
+ base::Time cache_expire;
+ EXPECT_TRUE(
+ pm->ParseHashResponse(se_data, &full_hash_infos, &cache_expire));
+ EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
+
+ ASSERT_EQ(1ul, full_hash_infos.size());
+ const FullHashInfo& fhi = full_hash_infos[0];
+ EXPECT_EQ(full_hash, fhi.full_hash);
+ const UpdateListIdentifier list_id(CHROME_PLATFORM, URL,
+ SOCIAL_ENGINEERING_PUBLIC);
+ EXPECT_EQ(list_id, fhi.list_id);
+ EXPECT_EQ(ThreatPatternType::SOCIAL_ENGINEERING_LANDING,
+ fhi.metadata.threat_pattern_type);
+ }
- EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
- EXPECT_EQ(1ul, full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(hash_string, full_hashes[0].hash));
- EXPECT_EQ(ThreatPatternType::SOCIAL_ENGINEERING_LANDING,
- full_hashes[0].metadata.threat_pattern_type);
-
- // Test potentially harmful application pattern type.
- FindFullHashesResponse pha_res;
- pha_res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* pha = pha_res.add_matches();
- pha->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
- pha->set_threat_entry_type(URL);
- pha->set_platform_type(CHROME_PLATFORM);
- hash_string = SBFullHashForString("Not to fret.");
- pha->mutable_threat()->set_hash(SBFullHashToString(hash_string));
- ThreatEntryMetadata::MetadataEntry* pha_meta =
- pha->mutable_threat_entry_metadata()->add_entries();
- pha_meta->set_key("pha_pattern_type");
- pha_meta->set_value("LANDING");
-
- std::string pha_data;
- pha_res.SerializeToString(&pha_data);
- full_hashes.clear();
- EXPECT_TRUE(pm->ParseHashResponse(pha_data, &full_hashes, &cache_expire));
- EXPECT_EQ(1ul, full_hashes.size());
- EXPECT_TRUE(SBFullHashEqual(hash_string, full_hashes[0].hash));
- EXPECT_EQ(ThreatPatternType::MALWARE_LANDING,
- full_hashes[0].metadata.threat_pattern_type);
-
- // Test invalid pattern type.
- FindFullHashesResponse invalid_res;
- invalid_res.mutable_negative_cache_duration()->set_seconds(600);
- ThreatMatch* invalid = invalid_res.add_matches();
- invalid->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
- invalid->set_threat_entry_type(URL);
- invalid->set_platform_type(CHROME_PLATFORM);
- invalid->mutable_threat()->set_hash(SBFullHashToString(hash_string));
- ThreatEntryMetadata::MetadataEntry* invalid_meta =
- invalid->mutable_threat_entry_metadata()->add_entries();
- invalid_meta->set_key("pha_pattern_type");
- invalid_meta->set_value("INVALIDE_VALUE");
-
- std::string invalid_data;
- invalid_res.SerializeToString(&invalid_data);
- full_hashes.clear();
- EXPECT_FALSE(
- pm->ParseHashResponse(invalid_data, &full_hashes, &cache_expire));
- EXPECT_EQ(0ul, full_hashes.size());
+ {
+ // Test potentially harmful application pattern type.
+ FindFullHashesResponse pha_res;
+ pha_res.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* pha = pha_res.add_matches();
+ pha->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
+ pha->set_threat_entry_type(URL);
+ pha->set_platform_type(CHROME_PLATFORM);
+ FullHash full_hash("Not to fret.");
+ pha->mutable_threat()->set_hash(full_hash);
+ ThreatEntryMetadata::MetadataEntry* pha_meta =
+ pha->mutable_threat_entry_metadata()->add_entries();
+ pha_meta->set_key("pha_pattern_type");
+ pha_meta->set_value("LANDING");
+
+ std::string pha_data;
+ pha_res.SerializeToString(&pha_data);
+ std::vector<FullHashInfo> full_hash_infos;
+ base::Time cache_expire;
+ EXPECT_TRUE(
+ pm->ParseHashResponse(pha_data, &full_hash_infos, &cache_expire));
+ EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
+
+ ASSERT_EQ(1ul, full_hash_infos.size());
+ const FullHashInfo& fhi = full_hash_infos[0];
+ EXPECT_EQ(full_hash, fhi.full_hash);
+ const UpdateListIdentifier list_id(CHROME_PLATFORM, URL,
+ POTENTIALLY_HARMFUL_APPLICATION);
+ EXPECT_EQ(list_id, fhi.list_id);
+ EXPECT_EQ(ThreatPatternType::MALWARE_LANDING,
+ fhi.metadata.threat_pattern_type);
+ }
+
+ {
+ // Test invalid pattern type.
+ FullHash full_hash("Not to fret.");
+ FindFullHashesResponse invalid_res;
+ invalid_res.mutable_negative_cache_duration()->set_seconds(600);
+ ThreatMatch* invalid = invalid_res.add_matches();
+ invalid->set_threat_type(POTENTIALLY_HARMFUL_APPLICATION);
+ invalid->set_threat_entry_type(URL);
+ invalid->set_platform_type(CHROME_PLATFORM);
+ invalid->mutable_threat()->set_hash(full_hash);
+ ThreatEntryMetadata::MetadataEntry* invalid_meta =
+ invalid->mutable_threat_entry_metadata()->add_entries();
+ invalid_meta->set_key("pha_pattern_type");
+ invalid_meta->set_value("INVALIDE_VALUE");
+
+ std::string invalid_data;
+ invalid_res.SerializeToString(&invalid_data);
+ std::vector<FullHashInfo> full_hash_infos;
+ base::Time cache_expire;
+ EXPECT_FALSE(
+ pm->ParseHashResponse(invalid_data, &full_hash_infos, &cache_expire));
+ EXPECT_EQ(0ul, full_hash_infos.size());
+ }
}
// Adds metadata with a key value that is not "permission".
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
+TEST_F(V4GetHashProtocolManagerTest,
TestParseHashResponseNonPermissionMetadata) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
@@ -370,8 +487,7 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
m->set_threat_type(API_ABUSE);
m->set_platform_type(CHROME_PLATFORM);
m->set_threat_entry_type(URL);
- m->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Not to fret.")));
+ m->mutable_threat()->set_hash(FullHash("Not to fret."));
ThreatEntryMetadata::MetadataEntry* e =
m->mutable_threat_entry_metadata()->add_entries();
e->set_key("notpermission");
@@ -381,15 +497,16 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_FALSE(
+ pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
EXPECT_EQ(now + base::TimeDelta::FromSeconds(600), cache_expire);
- EXPECT_EQ(0ul, full_hashes.size());
+ EXPECT_EQ(0ul, full_hash_infos.size());
}
-TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
+TEST_F(V4GetHashProtocolManagerTest,
TestParseHashResponseInconsistentThreatTypes) {
std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
@@ -399,22 +516,217 @@ TEST_F(SafeBrowsingV4GetHashProtocolManagerTest,
m1->set_threat_type(API_ABUSE);
m1->set_platform_type(CHROME_PLATFORM);
m1->set_threat_entry_type(URL);
- m1->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Everything's shiny, Cap'n.")));
+ m1->mutable_threat()->set_hash(FullHash("Everything's shiny, Cap'n."));
m1->mutable_threat_entry_metadata()->add_entries();
ThreatMatch* m2 = res.add_matches();
m2->set_threat_type(MALWARE_THREAT);
m2->set_threat_entry_type(URL);
- m2->mutable_threat()->set_hash(
- SBFullHashToString(SBFullHashForString("Not to fret.")));
+ m2->mutable_threat()->set_hash(FullHash("Not to fret."));
// Serialize.
std::string res_data;
res.SerializeToString(&res_data);
- std::vector<SBFullHashResult> full_hashes;
+ std::vector<FullHashInfo> full_hash_infos;
base::Time cache_expire;
- EXPECT_FALSE(pm->ParseHashResponse(res_data, &full_hashes, &cache_expire));
+ EXPECT_FALSE(
+ pm->ParseHashResponse(res_data, &full_hash_infos, &cache_expire));
+}
+
+// Checks that results are looked up correctly in the cache.
+TEST_F(V4GetHashProtocolManagerTest, GetCachedResults) {
+ base::Time now = base::Time::UnixEpoch();
+ FullHash full_hash("example");
+ HashPrefix prefix("exam");
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[full_hash].emplace_back(GetUrlMalwareId(), prefix);
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ FullHashCache* cache = pm->full_hash_cache_for_tests();
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Test with an empty cache. (Case: 2)
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ EXPECT_TRUE(cache->empty());
+ ASSERT_EQ(1ul, prefixes_to_request.size());
+ EXPECT_EQ(prefix, prefixes_to_request[0]);
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Prefix has a cache entry but full hash is not there. (Case: 1-b-i)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(5);
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ EXPECT_TRUE(prefixes_to_request.empty());
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Expired negative cache entry. (Case: 1-b-ii)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now - base::TimeDelta::FromMinutes(5);
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ ASSERT_EQ(1ul, prefixes_to_request.size());
+ EXPECT_EQ(prefix, prefixes_to_request[0]);
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Now put unexpired full hash in the cache. (Case: 1-a-i)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(5);
+ entry->full_hash_infos.emplace_back(full_hash, GetUrlMalwareId(),
+ now + base::TimeDelta::FromMinutes(3));
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ EXPECT_TRUE(prefixes_to_request.empty());
+ ASSERT_EQ(1ul, cached_full_hash_infos.size());
+ EXPECT_EQ(full_hash, cached_full_hash_infos[0].full_hash);
+ }
+
+ {
+ std::vector<HashPrefix> prefixes_to_request;
+ std::vector<FullHashInfo> cached_full_hash_infos;
+ cache->clear();
+
+ // Expire the full hash in the cache. (Case: 1-a-ii)
+ CachedHashPrefixInfo* entry = &(*cache)[prefix];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(5);
+ entry->full_hash_infos.emplace_back(full_hash, GetUrlMalwareId(),
+ now - base::TimeDelta::FromMinutes(3));
+ pm->GetFullHashCachedResults(matched_locally, now, &prefixes_to_request,
+ &cached_full_hash_infos);
+ ASSERT_EQ(1ul, prefixes_to_request.size());
+ EXPECT_EQ(prefix, prefixes_to_request[0]);
+ EXPECT_TRUE(cached_full_hash_infos.empty());
+ }
+}
+
+TEST_F(V4GetHashProtocolManagerTest, TestUpdatesAreMerged) {
+ // We'll add one of the requested FullHashInfo objects into the cache, and
+ // inject the other one as a response from the server. The result should
+ // include both FullHashInfo objects.
+
+ net::TestURLFetcherFactory factory;
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ HashPrefix prefix_1("exam");
+ FullHash full_hash_1("example");
+ HashPrefix prefix_2("Everything");
+ FullHash full_hash_2("Everything's shiny, Cap'n.");
+
+ base::Time now = Time::Now();
+ SetTestClock(now, pm.get());
+
+ FullHashCache* cache = pm->full_hash_cache_for_tests();
+ CachedHashPrefixInfo* entry = &(*cache)[prefix_1];
+ entry->negative_expiry = now + base::TimeDelta::FromMinutes(100);
+ // Put one unexpired full hash in the cache for a store we'll look in.
+ entry->full_hash_infos.emplace_back(full_hash_1, GetUrlMalwareId(),
+ now + base::TimeDelta::FromSeconds(200));
+ // Put one unexpired full hash in the cache for a store we'll not look in.
+ entry->full_hash_infos.emplace_back(full_hash_1, GetUrlSocEngId(),
+ now + base::TimeDelta::FromSeconds(200));
+
+ // Request full hash information from two stores.
+ FullHashToStoreAndHashPrefixesMap matched_locally;
+ matched_locally[full_hash_1].push_back(
+ StoreAndHashPrefix(GetUrlMalwareId(), prefix_1));
+ matched_locally[full_hash_2].push_back(
+ StoreAndHashPrefix(GetChromeUrlApiId(), prefix_2));
+
+ // Expect full hash information from both stores.
+ std::vector<FullHashInfo> expected_results;
+ expected_results.emplace_back(full_hash_1, GetUrlMalwareId(),
+ now + base::TimeDelta::FromSeconds(200));
+ expected_results.emplace_back(full_hash_2, GetChromeUrlApiId(),
+ now + base::TimeDelta::FromSeconds(300));
+ expected_results[1].metadata.api_permissions.insert("NOTIFICATIONS");
+
+ pm->GetFullHashes(
+ matched_locally,
+ base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4HashResults,
+ base::Unretained(this), expected_results));
+
+ SetupFetcherToReturnOKResponse(factory, GetStockV4HashResponseInfos());
+
+ // 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.
+ ASSERT_EQ(2u, cache->size());
+ const CachedHashPrefixInfo& cached_result_1 = cache->at(prefix_1);
+ EXPECT_EQ(cached_result_1.negative_expiry,
+ now + base::TimeDelta::FromMinutes(100));
+ ASSERT_EQ(2u, cached_result_1.full_hash_infos.size());
+ EXPECT_EQ(full_hash_1, cached_result_1.full_hash_infos[0].full_hash);
+ EXPECT_EQ(GetUrlMalwareId(), cached_result_1.full_hash_infos[0].list_id);
+
+ const CachedHashPrefixInfo& cached_result_2 = cache->at(prefix_2);
+ EXPECT_EQ(cached_result_2.negative_expiry,
+ now + base::TimeDelta::FromSeconds(600));
+ ASSERT_EQ(1u, cached_result_2.full_hash_infos.size());
+ EXPECT_EQ(full_hash_2, cached_result_2.full_hash_infos[0].full_hash);
+ EXPECT_EQ(GetChromeUrlApiId(), cached_result_2.full_hash_infos[0].list_id);
+ EXPECT_TRUE(callback_called());
+}
+
+// The server responds back with full hash information containing metadata
+// information for one of the full hashes for the URL in test.
+TEST_F(V4GetHashProtocolManagerTest, TestGetFullHashesWithApisMergesMetadata) {
+ net::TestURLFetcherFactory factory;
+ const GURL url("https://www.example.com/more");
+ ThreatMetadata expected_md;
+ expected_md.api_permissions.insert("NOTIFICATIONS");
+ expected_md.api_permissions.insert("AUDIO_CAPTURE");
+ std::unique_ptr<V4GetHashProtocolManager> pm(CreateProtocolManager());
+ pm->GetFullHashesWithApis(
+ url, base::Bind(&V4GetHashProtocolManagerTest::ValidateGetV4ApiResults,
+ base::Unretained(this), expected_md));
+
+ // The following two random looking strings value are two of the full hashes
+ // produced by UrlToFullHashes in v4_protocol_manager_util.h for the URL:
+ // "https://www.example.com/more"
+ std::vector<ResponseInfo> infos;
+ FullHash full_hash;
+ base::Base64Decode("1ZzJ0/7NjPkg6t0DAS8L5Jf7jA48Pn7opQcP4UXYeXc=",
+ &full_hash);
+ ResponseInfo info(full_hash, GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "NOTIFICATIONS");
+ infos.push_back(info);
+
+ base::Base64Decode("4rPDSdcei1BiCOPnj9kgsy2O6Ua6X3iFBakqphB3ZfA=",
+ &full_hash);
+ info = ResponseInfo(full_hash, GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "AUDIO_CAPTURE");
+ infos.push_back(info);
+
+ full_hash = FullHash("Everything's shiny, Cap'n.");
+ info = ResponseInfo(full_hash, GetChromeUrlApiId());
+ info.key_values.emplace_back("permission", "GEOLOCATION");
+ infos.push_back(info);
+ SetupFetcherToReturnOKResponse(factory, infos);
+
+ EXPECT_TRUE(callback_called());
}
} // namespace safe_browsing
« no previous file with comments | « components/safe_browsing_db/v4_get_hash_protocol_manager.cc ('k') | components/safe_browsing_db/v4_local_database_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698