client_side_detection_service_unittest.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <queue>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/safe_browsing/client_side_detection_service.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/safe_browsing/client_model.pb.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/safe_browsing/csd.pb.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/test/test_browser_thread.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/sha2.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "googleurl/src/gurl.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/test_url_fetcher_factory.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_status.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::_;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::Invoke;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::Mock;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using ::testing::StrictMock;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace safe_browsing {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockClientSideDetectionService : public ClientSideDetectionService {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~MockClientSideDetectionService() {}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MOCK_METHOD1(EndFetchModel, void(ClientModelStatus));
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MOCK_METHOD1(ScheduleFetchModel, void(int64));
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Schedule(int64) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ignore the delay when testing.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartFetchModel();
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Disable(int) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ignore the status.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetEnabledAndRefreshState(false);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ACTION(QuitCurrentMessageLoop) {
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->Quit();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ClientSideDetectionServiceTest : public testing::Test {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_thread_.reset(new content::TestBrowserThread(BrowserThread::FILE,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                      &msg_loop_));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    factory_.reset(new net::FakeURLFetcherFactory(NULL));
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_thread_.reset(new content::TestBrowserThread(BrowserThread::UI,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                         &msg_loop_));
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TearDown() {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    msg_loop_.RunUntilIdle();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    csd_service_.reset();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_thread_.reset();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    browser_thread_.reset();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool SendClientReportPhishingRequest(const GURL& phishing_url,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       float score) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientPhishingRequest* request = new ClientPhishingRequest();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->set_url(phishing_url.spec());
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->set_client_score(score);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request->set_is_phishing(true);  // client thinks the URL is phishing.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    csd_service_->SendClientReportPhishingRequest(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ClientSideDetectionServiceTest::SendRequestDone,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   base::Unretained(this)));
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    phishing_url_ = phishing_url;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg_loop_.Run();  // Waits until callback is called.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return is_phishing_;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool SendClientReportMalwareRequest(const GURL& url) {
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<ClientMalwareRequest> request(new ClientMalwareRequest());
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request->set_url(url.spec());
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    csd_service_->SendClientReportMalwareRequest(
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.release(),
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&ClientSideDetectionServiceTest::SendMalwareRequestDone,
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this)));
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    phishing_url_ = url;
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    msg_loop_.Run();  // Waits until callback is called.
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return is_malware_;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetModelFetchResponse(std::string response_data, bool success) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    factory_->SetFakeResponse(ClientSideDetectionService::kClientModelUrl,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              response_data, success);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetClientReportPhishingResponse(std::string response_data,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       bool success) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    factory_->SetFakeResponse(
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ClientSideDetectionService::GetClientReportUrl(
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ClientSideDetectionService::kClientReportPhishingUrl),
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        response_data, success);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SetClientReportMalwareResponse(std::string response_data,
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      bool success) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    factory_->SetFakeResponse(
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ClientSideDetectionService::GetClientReportUrl(
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            ClientSideDetectionService::kClientReportMalwareUrl),
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        response_data, success);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int GetNumReports(std::queue<base::Time>* report_times) {
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return csd_service_->GetNumReports(report_times);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::queue<base::Time>& GetPhishingReportTimes() {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return csd_service_->phishing_report_times_;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::queue<base::Time>& GetMalwareReportTimes() {
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return csd_service_->malware_report_times_;
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetCache(const GURL& gurl, bool is_phishing, base::Time time) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    csd_service_->cache_[gurl] =
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        make_linked_ptr(new ClientSideDetectionService::CacheState(is_phishing,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                   time));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void TestCache() {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientSideDetectionService::PhishingCache& cache = csd_service_->cache_;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time now = base::Time::Now();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time time =
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        now - base::TimeDelta::FromDays(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ClientSideDetectionService::kNegativeCacheIntervalDays) +
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMinutes(5);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache[GURL("http://first.url.com/")] =
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        make_linked_ptr(new ClientSideDetectionService::CacheState(false,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                   time));
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time =
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        now - base::TimeDelta::FromDays(
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ClientSideDetectionService::kNegativeCacheIntervalDays) -
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromHours(1);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache[GURL("http://second.url.com/")] =
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        make_linked_ptr(new ClientSideDetectionService::CacheState(false,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                   time));
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time =
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        now - base::TimeDelta::FromMinutes(
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ClientSideDetectionService::kPositiveCacheIntervalMinutes) -
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMinutes(5);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache[GURL("http://third.url.com/")] =
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time =
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        now - base::TimeDelta::FromMinutes(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            ClientSideDetectionService::kPositiveCacheIntervalMinutes) +
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMinutes(5);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache[GURL("http://fourth.url.com/")] =
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    csd_service_->UpdateCache();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // 3 elements should be in the cache, the first, third, and fourth.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(3U, cache.size());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(cache.find(GURL("http://first.url.com/")) != cache.end());
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(cache.find(GURL("http://third.url.com/")) != cache.end());
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(cache.find(GURL("http://fourth.url.com/")) != cache.end());
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // While 3 elements remain, only the first and the fourth are actually
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // valid.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_phishing;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(csd_service_->GetValidCachedResult(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GURL("http://first.url.com"), &is_phishing));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_FALSE(is_phishing);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_FALSE(csd_service_->GetValidCachedResult(
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GURL("http://third.url.com"), &is_phishing));
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(csd_service_->GetValidCachedResult(
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GURL("http://fourth.url.com"), &is_phishing));
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(is_phishing);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddFeature(const std::string& name, double value,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  ClientPhishingRequest* request) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientPhishingRequest_Feature* feature = request->add_feature_map();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    feature->set_name(name);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    feature->set_value(value);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddNonModelFeature(const std::string& name, double value,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          ClientPhishingRequest* request) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClientPhishingRequest_Feature* feature =
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        request->add_non_model_feature_map();
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    feature->set_name(name);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    feature->set_value(value);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ClientSideDetectionService> csd_service_;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::FakeURLFetcherFactory> factory_;
21990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop msg_loop_;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SendRequestDone(GURL phishing_url, bool is_phishing) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_EQ(phishing_url, phishing_url_);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_phishing_ = is_phishing;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg_loop_.Quit();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void SendMalwareRequestDone(GURL url, bool is_malware) {
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_EQ(phishing_url_, url);
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    is_malware_ = is_malware;
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    msg_loop_.Quit();
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<content::TestBrowserThread> browser_thread_;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<content::TestBrowserThread> file_thread_;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL phishing_url_;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_phishing_;
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_malware_;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, FetchModelTest) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't want to use a real service class here because we can't call
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the real EndFetchModel.  It would reschedule a reload which might
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // make the test flaky.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockClientSideDetectionService service;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, ScheduleFetchModel(_)).Times(1);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.SetEnabledAndRefreshState(true);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The model fetch failed.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse("blamodel", false /* failure */);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_FETCH_FAILED))
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Empty model file.
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetModelFetchResponse(std::string(), true /* success */);
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(ClientSideDetectionService::MODEL_EMPTY))
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Model is too large.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string(ClientSideDetectionService::kMaxModelSizeBytes + 1, 'x'),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      true /* success */);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_TOO_LARGE))
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unable to parse the model file.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse("Invalid model file", true /* success */);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_PARSE_ERROR))
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Model that is missing some required fields (missing the version field).
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel model;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_max_words_per_term(4);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(model.SerializePartialAsString(), true /* success */);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_MISSING_FIELDS))
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Model that points to hashes that don't exist.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_version(10);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.add_hashes("bla");
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.add_page_term(1);  // Should be 0 instead of 1.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(model.SerializePartialAsString(), true /* success */);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_BAD_HASH_IDS))
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_page_term(0, 0);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Model version number is wrong.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_version(-1);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Normal model.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_version(10);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_SUCCESS))
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Model version number is decreasing.  Set the model version number of the
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // model that is currently loaded in the service object to 11.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.model_.reset(new ClientSideModel(model));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.model_->set_version(11);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Model version hasn't changed since the last reload.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.model_->set_version(10);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(service, EndFetchModel(
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_NOT_CHANGED))
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service.StartFetchModel();
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&service);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse("bogus model", true /* success */);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(true);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_.get() != NULL);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We delete the client-side detection service class even though the callbacks
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // haven't run yet.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset();
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Waiting for the callbacks to run should not crash even if the service
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // object is gone.
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  msg_loop_.RunUntilIdle();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, SendClientReportPhishingRequest) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse("bogus model", true /* success */);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(true);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url("http://a.com/");
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  float score = 0.4f;  // Some random client score.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time before = base::Time::Now();
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invalid response body from the server.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetClientReportPhishingResponse("invalid proto response", true /* success */);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(SendClientReportPhishingRequest(url, score));
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Normal behavior.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientPhishingResponse response;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.set_phishy(true);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetClientReportPhishingResponse(response.SerializeAsString(),
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  true /* success */);
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(SendClientReportPhishingRequest(url, score));
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This request will fail
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL second_url("http://b.com/");
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.set_phishy(false);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetClientReportPhishingResponse(response.SerializeAsString(),
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  false /* success */);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(SendClientReportPhishingRequest(second_url, score));
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time after = base::Time::Now();
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that we have recorded all 3 requests within the correct time range.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::queue<base::Time>& report_times = GetPhishingReportTimes();
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(3U, report_times.size());
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!report_times.empty()) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time time = report_times.back();
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    report_times.pop();
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_LE(before, time);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_GE(after, time);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only the first url should be in the cache.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_phishing;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsInCache(url));
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->GetValidCachedResult(url, &is_phishing));
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(is_phishing);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsInCache(second_url));
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, SendClientReportMalwareRequest) {
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetModelFetchResponse("bogus model", true /* success */);
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(true);
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL url("http://a.com/");
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
42090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::Time before = base::Time::Now();
42190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Invalid response body from the server.
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetClientReportMalwareResponse("invalid proto response", true /* success */);
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_FALSE(SendClientReportMalwareRequest(url));
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Normal behavior.
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientMalwareResponse response;
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  response.set_blacklist(true);
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetClientReportMalwareResponse(response.SerializeAsString(), true);
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(SendClientReportMalwareRequest(url));
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This request will fail
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  response.set_blacklist(false);
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetClientReportMalwareResponse(response.SerializeAsString(),
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 false /* success */);
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_FALSE(SendClientReportMalwareRequest(url));
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // server blacklist decision is false, and response is succesful
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  response.set_blacklist(false);
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetClientReportMalwareResponse(response.SerializeAsString(), true);
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_FALSE(SendClientReportMalwareRequest(url));
44290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
44390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Check that we have recorded all 4 requests within the correct time range.
44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::Time after = base::Time::Now();
44590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::queue<base::Time>& report_times = GetMalwareReportTimes();
44690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_EQ(4U, report_times.size());
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
44890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Another normal behavior will fail because of the limit is hit
44990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  response.set_blacklist(true);
45090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SetClientReportMalwareResponse(response.SerializeAsString(), true);
45190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_FALSE(SendClientReportMalwareRequest(url));
45290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
45390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  report_times = GetMalwareReportTimes();
45490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_EQ(4U, report_times.size());
45590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  while (!report_times.empty()) {
45690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::Time time = report_times.back();
45790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    report_times.pop();
45890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_LE(before, time);
45990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_GE(after, time);
46090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, GetNumReportTest) {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse("bogus model", true /* success */);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::queue<base::Time>& report_times = GetPhishingReportTimes();
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time now = base::Time::Now();
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta twenty_five_hours = base::TimeDelta::FromHours(25);
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  report_times.push(now - twenty_five_hours);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  report_times.push(now - twenty_five_hours);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  report_times.push(now);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  report_times.push(now);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
47590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_EQ(2, GetNumReports(&report_times));
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, CacheTest) {
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse("bogus model", true /* success */);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TestCache();
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, IsPrivateIPAddress) {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse("bogus model", true /* success */);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("10.1.2.3"));
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("127.0.0.1"));
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("172.24.3.4"));
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("192.168.1.1"));
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fc00::"));
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0::"));
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0:1:2::3"));
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("::1"));
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsPrivateIPAddress("1.2.3.4"));
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsPrivateIPAddress("200.1.1.1"));
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsPrivateIPAddress("2001:0db8:ac10:fe01::"));
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the address can't be parsed, the default is true.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsPrivateIPAddress("blah"));
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, SetBadSubnets) {
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel model;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideDetectionService::BadSubnetMap bad_subnets;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, bad_subnets.size());
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bad subnets are skipped.
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel::IPSubnet* subnet = model.add_bad_subnet();
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(130);  // Invalid size.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(-1);  // Invalid size.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(std::string(16, '.'));  // Invalid len.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(64);
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, bad_subnets.size());
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(64);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(std::string(crypto::kSHA256Length, ','));
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(64);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(128);
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(100);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(3U, bad_subnets.size());
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideDetectionService::BadSubnetMap::const_iterator it;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string mask = std::string(8, '\xFF') + std::string(8, '\x00');
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(bad_subnets.count(mask));
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, ',')));
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mask = std::string(16, '\xFF');
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(bad_subnets.count(mask));
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mask = std::string(12, '\xFF') + "\xF0" + std::string(3, '\x00');
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(bad_subnets.count(mask));
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, IsBadIpAddress) {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel model;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IPv6 exact match for: 2620:0:1000:3103:21a:a0ff:fe10:786e.
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel::IPSubnet* subnet = model.add_bad_subnet();
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(crypto::SHA256HashString(std::string(
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "\x26\x20\x00\x00\x10\x00\x31\x03\x02\x1a\xa0\xff\xfe\x10\x78\x6e", 16)));
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(128);
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IPv6 prefix match for: fe80::21a:a0ff:fe10:786e/64.
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(crypto::SHA256HashString(std::string(
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)));
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(64);
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IPv4 exact match for ::ffff:192.0.2.128.
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(crypto::SHA256HashString(std::string(
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x00\x02\x80", 16)));
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(128);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IPv4 prefix match (/8) for ::ffff:192.1.1.0.
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(crypto::SHA256HashString(std::string(
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x01\x01\x00", 16)));
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(120);
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IPv4 prefix match (/9) for ::ffff:192.1.122.0.
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(crypto::SHA256HashString(std::string(
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x01\x7a\x00", 16)));
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(119);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IPv4 prefix match (/15) for ::ffff:192.1.128.0.
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet = model.add_bad_subnet();
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_prefix(crypto::SHA256HashString(std::string(
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xc0\x01\x80\x00", 16)));
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  subnet->set_size(113);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideDetectionService::SetBadSubnets(
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model, &(csd_service_->bad_subnets_));
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress("blabla"));
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress(std::string()));
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress(
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "2620:0:1000:3103:21a:a0ff:fe10:786e"));
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress(
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "2620:0:1000:3103:21a:a0ff:fe10:786f"));
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("fe80::21a:a0ff:fe10:786e"));
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("fe80::31a:a0ff:fe10:786e"));
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("fe80::21a:a0ff:fe10:786f"));
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress("fe81::21a:a0ff:fe10:786e"));
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.0.2.128"));
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.0.2.128"));
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.0.2.129"));
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.1.0"));
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.1.255"));
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.1.10"));
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.1.1.2"));
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.1.121.255"));
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.122.0"));
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.1.122.1"));
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.122.255"));
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.123.0"));
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.123.255"));
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.1.124.0"));
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.1.127.255"));
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.128.0"));
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("::ffff:192.1.128.1"));
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.128.255"));
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.255.0"));
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->IsBadIpAddress("192.1.255.255"));
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->IsBadIpAddress("192.2.0.0"));
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, ModelHasValidHashIds) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel model;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.add_hashes("bla");
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.add_page_term(0);
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.add_page_term(-1);
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_page_term(1, 1);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_page_term(1, 0);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test bad rules.
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.add_hashes("blu");
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel::Rule* rule = model.add_rule();
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->add_feature(0);
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->add_feature(1);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->set_weight(0.1f);
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule = model.add_rule();
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->add_feature(0);
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->add_feature(1);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->add_feature(-1);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->set_weight(0.2f);
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->set_feature(2, 2);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rule->set_feature(2, 1);
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ClientSideDetectionServiceTest, SetEnabledAndRefreshState) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that the model isn't downloaded until the service is enabled.
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(ClientSideDetectionService::Create(NULL));
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->enabled());
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use a MockClientSideDetectionService for the rest of the test, to avoid
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the scheduling delay.
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockClientSideDetectionService* service =
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new StrictMock<MockClientSideDetectionService>();
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_.reset(service);
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(csd_service_->enabled());
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No calls expected yet.
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(service);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientSideModel model;
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_version(10);
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model.set_max_words_per_term(4);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetModelFetchResponse(model.SerializeAsString(), true /* success */);
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(*service, ScheduleFetchModel(_))
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(*service, EndFetchModel(
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_SUCCESS))
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(QuitCurrentMessageLoop());
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(true);
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg_loop_.Run();  // EndFetchModel will quit the message loop.
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(service);
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that enabling again doesn't request the model.
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(true);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No calls expected.
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(service);
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that disabling the service cancels pending requests.
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(*service, ScheduleFetchModel(_))
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(false);
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(true);
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(service);
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(false);
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  msg_loop_.RunUntilIdle();
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No calls expected.
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(service);
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Requests always return false when the service is disabled.
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientPhishingResponse response;
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.set_phishy(true);
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetClientReportPhishingResponse(response.SerializeAsString(),
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  true /* success */);
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pending requests also return false if the service is disabled before they
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // report back.
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(*service, ScheduleFetchModel(_))
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(*service, EndFetchModel(
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ClientSideDetectionService::MODEL_NOT_CHANGED))
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .WillOnce(Invoke(service, &MockClientSideDetectionService::Disable));
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  csd_service_->SetEnabledAndRefreshState(true);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mock::VerifyAndClearExpectations(service);
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace safe_browsing
745