Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / client_side_detection_service_unittest.cc
blobb5f64d5eb348415588d83fa4d98107cf7127c53d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <map>
6 #include <queue>
7 #include <string>
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
16 #include "chrome/common/safe_browsing/client_model.pb.h"
17 #include "chrome/common/safe_browsing/csd.pb.h"
18 #include "content/public/test/test_browser_thread.h"
19 #include "crypto/sha2.h"
20 #include "net/http/http_status_code.h"
21 #include "net/url_request/test_url_fetcher_factory.h"
22 #include "net/url_request/url_request_status.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "url/gurl.h"
27 using ::testing::Invoke;
28 using ::testing::Mock;
29 using ::testing::StrictMock;
30 using ::testing::_;
31 using content::BrowserThread;
33 namespace safe_browsing {
34 namespace {
35 class MockClientSideDetectionService : public ClientSideDetectionService {
36 public:
37 MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
38 virtual ~MockClientSideDetectionService() {}
40 MOCK_METHOD1(EndFetchModel, void(ClientModelStatus));
41 MOCK_METHOD1(ScheduleFetchModel, void(int64));
43 void Schedule(int64) {
44 // Ignore the delay when testing.
45 StartFetchModel();
48 void Disable(int) {
49 // Ignore the status.
50 SetEnabledAndRefreshState(false);
53 private:
54 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
57 ACTION(QuitCurrentMessageLoop) {
58 base::MessageLoop::current()->Quit();
61 } // namespace
63 class ClientSideDetectionServiceTest : public testing::Test {
64 protected:
65 virtual void SetUp() {
66 file_thread_.reset(new content::TestBrowserThread(BrowserThread::FILE,
67 &msg_loop_));
69 factory_.reset(new net::FakeURLFetcherFactory(NULL));
71 browser_thread_.reset(new content::TestBrowserThread(BrowserThread::UI,
72 &msg_loop_));
75 virtual void TearDown() {
76 msg_loop_.RunUntilIdle();
77 csd_service_.reset();
78 file_thread_.reset();
79 browser_thread_.reset();
82 bool SendClientReportPhishingRequest(const GURL& phishing_url,
83 float score) {
84 ClientPhishingRequest* request = new ClientPhishingRequest();
85 request->set_url(phishing_url.spec());
86 request->set_client_score(score);
87 request->set_is_phishing(true); // client thinks the URL is phishing.
88 csd_service_->SendClientReportPhishingRequest(
89 request,
90 base::Bind(&ClientSideDetectionServiceTest::SendRequestDone,
91 base::Unretained(this)));
92 phishing_url_ = phishing_url;
93 msg_loop_.Run(); // Waits until callback is called.
94 return is_phishing_;
97 bool SendClientReportMalwareRequest(const GURL& url) {
98 scoped_ptr<ClientMalwareRequest> request(new ClientMalwareRequest());
99 request->set_url(url.spec());
100 csd_service_->SendClientReportMalwareRequest(
101 request.release(),
102 base::Bind(&ClientSideDetectionServiceTest::SendMalwareRequestDone,
103 base::Unretained(this)));
104 phishing_url_ = url;
105 msg_loop_.Run(); // Waits until callback is called.
106 return is_malware_;
109 void SetModelFetchResponse(std::string response_data,
110 net::HttpStatusCode response_code,
111 net::URLRequestStatus::Status status) {
112 factory_->SetFakeResponse(GURL(ClientSideDetectionService::kClientModelUrl),
113 response_data, response_code, status);
116 void SetClientReportPhishingResponse(std::string response_data,
117 net::HttpStatusCode response_code,
118 net::URLRequestStatus::Status status) {
119 factory_->SetFakeResponse(
120 ClientSideDetectionService::GetClientReportUrl(
121 ClientSideDetectionService::kClientReportPhishingUrl),
122 response_data, response_code, status);
125 void SetClientReportMalwareResponse(std::string response_data,
126 net::HttpStatusCode response_code,
127 net::URLRequestStatus::Status status) {
128 factory_->SetFakeResponse(
129 ClientSideDetectionService::GetClientReportUrl(
130 ClientSideDetectionService::kClientReportMalwareUrl),
131 response_data, response_code, status);
134 int GetNumReports(std::queue<base::Time>* report_times) {
135 return csd_service_->GetNumReports(report_times);
138 std::queue<base::Time>& GetPhishingReportTimes() {
139 return csd_service_->phishing_report_times_;
142 std::queue<base::Time>& GetMalwareReportTimes() {
143 return csd_service_->malware_report_times_;
146 void SetCache(const GURL& gurl, bool is_phishing, base::Time time) {
147 csd_service_->cache_[gurl] =
148 make_linked_ptr(new ClientSideDetectionService::CacheState(is_phishing,
149 time));
152 void TestCache() {
153 ClientSideDetectionService::PhishingCache& cache = csd_service_->cache_;
154 base::Time now = base::Time::Now();
155 base::Time time =
156 now - base::TimeDelta::FromDays(
157 ClientSideDetectionService::kNegativeCacheIntervalDays) +
158 base::TimeDelta::FromMinutes(5);
159 cache[GURL("http://first.url.com/")] =
160 make_linked_ptr(new ClientSideDetectionService::CacheState(false,
161 time));
163 time =
164 now - base::TimeDelta::FromDays(
165 ClientSideDetectionService::kNegativeCacheIntervalDays) -
166 base::TimeDelta::FromHours(1);
167 cache[GURL("http://second.url.com/")] =
168 make_linked_ptr(new ClientSideDetectionService::CacheState(false,
169 time));
171 time =
172 now - base::TimeDelta::FromMinutes(
173 ClientSideDetectionService::kPositiveCacheIntervalMinutes) -
174 base::TimeDelta::FromMinutes(5);
175 cache[GURL("http://third.url.com/")] =
176 make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
178 time =
179 now - base::TimeDelta::FromMinutes(
180 ClientSideDetectionService::kPositiveCacheIntervalMinutes) +
181 base::TimeDelta::FromMinutes(5);
182 cache[GURL("http://fourth.url.com/")] =
183 make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
185 csd_service_->UpdateCache();
187 // 3 elements should be in the cache, the first, third, and fourth.
188 EXPECT_EQ(3U, cache.size());
189 EXPECT_TRUE(cache.find(GURL("http://first.url.com/")) != cache.end());
190 EXPECT_TRUE(cache.find(GURL("http://third.url.com/")) != cache.end());
191 EXPECT_TRUE(cache.find(GURL("http://fourth.url.com/")) != cache.end());
193 // While 3 elements remain, only the first and the fourth are actually
194 // valid.
195 bool is_phishing;
196 EXPECT_TRUE(csd_service_->GetValidCachedResult(
197 GURL("http://first.url.com"), &is_phishing));
198 EXPECT_FALSE(is_phishing);
199 EXPECT_FALSE(csd_service_->GetValidCachedResult(
200 GURL("http://third.url.com"), &is_phishing));
201 EXPECT_TRUE(csd_service_->GetValidCachedResult(
202 GURL("http://fourth.url.com"), &is_phishing));
203 EXPECT_TRUE(is_phishing);
206 void AddFeature(const std::string& name, double value,
207 ClientPhishingRequest* request) {
208 ClientPhishingRequest_Feature* feature = request->add_feature_map();
209 feature->set_name(name);
210 feature->set_value(value);
213 void AddNonModelFeature(const std::string& name, double value,
214 ClientPhishingRequest* request) {
215 ClientPhishingRequest_Feature* feature =
216 request->add_non_model_feature_map();
217 feature->set_name(name);
218 feature->set_value(value);
221 void CheckConfirmedMalwareUrl(GURL url) {
222 ASSERT_EQ(confirmed_malware_url_, url);
225 protected:
226 scoped_ptr<ClientSideDetectionService> csd_service_;
227 scoped_ptr<net::FakeURLFetcherFactory> factory_;
228 base::MessageLoop msg_loop_;
230 private:
231 void SendRequestDone(GURL phishing_url, bool is_phishing) {
232 ASSERT_EQ(phishing_url, phishing_url_);
233 is_phishing_ = is_phishing;
234 msg_loop_.Quit();
237 void SendMalwareRequestDone(GURL original_url, GURL malware_url,
238 bool is_malware) {
239 ASSERT_EQ(phishing_url_, original_url);
240 confirmed_malware_url_ = malware_url;
241 is_malware_ = is_malware;
242 msg_loop_.Quit();
245 scoped_ptr<content::TestBrowserThread> browser_thread_;
246 scoped_ptr<content::TestBrowserThread> file_thread_;
248 GURL phishing_url_;
249 GURL confirmed_malware_url_;
250 bool is_phishing_;
251 bool is_malware_;
254 TEST_F(ClientSideDetectionServiceTest, FetchModelTest) {
255 // We don't want to use a real service class here because we can't call
256 // the real EndFetchModel. It would reschedule a reload which might
257 // make the test flaky.
258 MockClientSideDetectionService service;
259 EXPECT_CALL(service, ScheduleFetchModel(_)).Times(1);
260 service.SetEnabledAndRefreshState(true);
262 // The model fetch failed.
263 SetModelFetchResponse("blamodel", net::HTTP_INTERNAL_SERVER_ERROR,
264 net::URLRequestStatus::FAILED);
265 EXPECT_CALL(service, EndFetchModel(
266 ClientSideDetectionService::MODEL_FETCH_FAILED))
267 .WillOnce(QuitCurrentMessageLoop());
268 service.StartFetchModel();
269 msg_loop_.Run(); // EndFetchModel will quit the message loop.
270 Mock::VerifyAndClearExpectations(&service);
272 // Empty model file.
273 SetModelFetchResponse(std::string(), net::HTTP_OK,
274 net::URLRequestStatus::SUCCESS);
275 EXPECT_CALL(service, EndFetchModel(ClientSideDetectionService::MODEL_EMPTY))
276 .WillOnce(QuitCurrentMessageLoop());
277 service.StartFetchModel();
278 msg_loop_.Run(); // EndFetchModel will quit the message loop.
279 Mock::VerifyAndClearExpectations(&service);
281 // Model is too large.
282 SetModelFetchResponse(
283 std::string(ClientSideDetectionService::kMaxModelSizeBytes + 1, 'x'),
284 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
285 EXPECT_CALL(service, EndFetchModel(
286 ClientSideDetectionService::MODEL_TOO_LARGE))
287 .WillOnce(QuitCurrentMessageLoop());
288 service.StartFetchModel();
289 msg_loop_.Run(); // EndFetchModel will quit the message loop.
290 Mock::VerifyAndClearExpectations(&service);
292 // Unable to parse the model file.
293 SetModelFetchResponse("Invalid model file", net::HTTP_OK,
294 net::URLRequestStatus::SUCCESS);
295 EXPECT_CALL(service, EndFetchModel(
296 ClientSideDetectionService::MODEL_PARSE_ERROR))
297 .WillOnce(QuitCurrentMessageLoop());
298 service.StartFetchModel();
299 msg_loop_.Run(); // EndFetchModel will quit the message loop.
300 Mock::VerifyAndClearExpectations(&service);
302 // Model that is missing some required fields (missing the version field).
303 ClientSideModel model;
304 model.set_max_words_per_term(4);
305 SetModelFetchResponse(model.SerializePartialAsString(), net::HTTP_OK,
306 net::URLRequestStatus::SUCCESS);
307 EXPECT_CALL(service, EndFetchModel(
308 ClientSideDetectionService::MODEL_MISSING_FIELDS))
309 .WillOnce(QuitCurrentMessageLoop());
310 service.StartFetchModel();
311 msg_loop_.Run(); // EndFetchModel will quit the message loop.
312 Mock::VerifyAndClearExpectations(&service);
314 // Model that points to hashes that don't exist.
315 model.set_version(10);
316 model.add_hashes("bla");
317 model.add_page_term(1); // Should be 0 instead of 1.
318 SetModelFetchResponse(model.SerializePartialAsString(), net::HTTP_OK,
319 net::URLRequestStatus::SUCCESS);
320 EXPECT_CALL(service, EndFetchModel(
321 ClientSideDetectionService::MODEL_BAD_HASH_IDS))
322 .WillOnce(QuitCurrentMessageLoop());
323 service.StartFetchModel();
324 msg_loop_.Run(); // EndFetchModel will quit the message loop.
325 Mock::VerifyAndClearExpectations(&service);
326 model.set_page_term(0, 0);
328 // Model version number is wrong.
329 model.set_version(-1);
330 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
331 net::URLRequestStatus::SUCCESS);
332 EXPECT_CALL(service, EndFetchModel(
333 ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
334 .WillOnce(QuitCurrentMessageLoop());
335 service.StartFetchModel();
336 msg_loop_.Run(); // EndFetchModel will quit the message loop.
337 Mock::VerifyAndClearExpectations(&service);
339 // Normal model.
340 model.set_version(10);
341 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
342 net::URLRequestStatus::SUCCESS);
343 EXPECT_CALL(service, EndFetchModel(
344 ClientSideDetectionService::MODEL_SUCCESS))
345 .WillOnce(QuitCurrentMessageLoop());
346 service.StartFetchModel();
347 msg_loop_.Run(); // EndFetchModel will quit the message loop.
348 Mock::VerifyAndClearExpectations(&service);
350 // Model version number is decreasing. Set the model version number of the
351 // model that is currently loaded in the service object to 11.
352 service.model_.reset(new ClientSideModel(model));
353 service.model_->set_version(11);
354 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
355 net::URLRequestStatus::SUCCESS);
356 EXPECT_CALL(service, EndFetchModel(
357 ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
358 .WillOnce(QuitCurrentMessageLoop());
359 service.StartFetchModel();
360 msg_loop_.Run(); // EndFetchModel will quit the message loop.
361 Mock::VerifyAndClearExpectations(&service);
363 // Model version hasn't changed since the last reload.
364 service.model_->set_version(10);
365 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
366 net::URLRequestStatus::SUCCESS);
367 EXPECT_CALL(service, EndFetchModel(
368 ClientSideDetectionService::MODEL_NOT_CHANGED))
369 .WillOnce(QuitCurrentMessageLoop());
370 service.StartFetchModel();
371 msg_loop_.Run(); // EndFetchModel will quit the message loop.
372 Mock::VerifyAndClearExpectations(&service);
375 TEST_F(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) {
376 SetModelFetchResponse("bogus model", net::HTTP_OK,
377 net::URLRequestStatus::SUCCESS);
378 csd_service_.reset(ClientSideDetectionService::Create(NULL));
379 csd_service_->SetEnabledAndRefreshState(true);
380 EXPECT_TRUE(csd_service_.get() != NULL);
381 // We delete the client-side detection service class even though the callbacks
382 // haven't run yet.
383 csd_service_.reset();
384 // Waiting for the callbacks to run should not crash even if the service
385 // object is gone.
386 msg_loop_.RunUntilIdle();
389 TEST_F(ClientSideDetectionServiceTest, SendClientReportPhishingRequest) {
390 SetModelFetchResponse("bogus model", net::HTTP_OK,
391 net::URLRequestStatus::SUCCESS);
392 csd_service_.reset(ClientSideDetectionService::Create(NULL));
393 csd_service_->SetEnabledAndRefreshState(true);
395 GURL url("http://a.com/");
396 float score = 0.4f; // Some random client score.
398 base::Time before = base::Time::Now();
400 // Invalid response body from the server.
401 SetClientReportPhishingResponse("invalid proto response", net::HTTP_OK,
402 net::URLRequestStatus::SUCCESS);
403 EXPECT_FALSE(SendClientReportPhishingRequest(url, score));
405 // Normal behavior.
406 ClientPhishingResponse response;
407 response.set_phishy(true);
408 SetClientReportPhishingResponse(response.SerializeAsString(), net::HTTP_OK,
409 net::URLRequestStatus::SUCCESS);
410 EXPECT_TRUE(SendClientReportPhishingRequest(url, score));
412 // This request will fail
413 GURL second_url("http://b.com/");
414 response.set_phishy(false);
415 SetClientReportPhishingResponse(response.SerializeAsString(),
416 net::HTTP_INTERNAL_SERVER_ERROR,
417 net::URLRequestStatus::FAILED);
418 EXPECT_FALSE(SendClientReportPhishingRequest(second_url, score));
420 base::Time after = base::Time::Now();
422 // Check that we have recorded all 3 requests within the correct time range.
423 std::queue<base::Time>& report_times = GetPhishingReportTimes();
424 EXPECT_EQ(3U, report_times.size());
425 while (!report_times.empty()) {
426 base::Time time = report_times.back();
427 report_times.pop();
428 EXPECT_LE(before, time);
429 EXPECT_GE(after, time);
432 // Only the first url should be in the cache.
433 bool is_phishing;
434 EXPECT_TRUE(csd_service_->IsInCache(url));
435 EXPECT_TRUE(csd_service_->GetValidCachedResult(url, &is_phishing));
436 EXPECT_TRUE(is_phishing);
437 EXPECT_FALSE(csd_service_->IsInCache(second_url));
440 TEST_F(ClientSideDetectionServiceTest, SendClientReportMalwareRequest) {
441 SetModelFetchResponse("bogus model", net::HTTP_OK,
442 net::URLRequestStatus::SUCCESS);
443 csd_service_.reset(ClientSideDetectionService::Create(NULL));
444 csd_service_->SetEnabledAndRefreshState(true);
445 GURL url("http://a.com/");
447 base::Time before = base::Time::Now();
448 // Invalid response body from the server.
449 SetClientReportMalwareResponse("invalid proto response", net::HTTP_OK,
450 net::URLRequestStatus::SUCCESS);
451 EXPECT_FALSE(SendClientReportMalwareRequest(url));
453 // Missing bad_url.
454 ClientMalwareResponse response;
455 response.set_blacklist(true);
456 SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
457 net::URLRequestStatus::SUCCESS);
458 EXPECT_FALSE(SendClientReportMalwareRequest(url));
460 // Normal behavior.
461 response.set_blacklist(true);
462 response.set_bad_url("http://response-bad.com/");
463 SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
464 net::URLRequestStatus::SUCCESS);
465 EXPECT_TRUE(SendClientReportMalwareRequest(url));
466 CheckConfirmedMalwareUrl(GURL("http://response-bad.com/"));
468 // This request will fail
469 response.set_blacklist(false);
470 SetClientReportMalwareResponse(response.SerializeAsString(),
471 net::HTTP_INTERNAL_SERVER_ERROR,
472 net::URLRequestStatus::FAILED);
473 EXPECT_FALSE(SendClientReportMalwareRequest(url));
475 // server blacklist decision is false, and response is succesful
476 response.set_blacklist(false);
477 SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
478 net::URLRequestStatus::SUCCESS);
479 EXPECT_FALSE(SendClientReportMalwareRequest(url));
481 // Check that we have recorded all 4 requests within the correct time range.
482 base::Time after = base::Time::Now();
483 std::queue<base::Time>& report_times = GetMalwareReportTimes();
484 EXPECT_EQ(4U, report_times.size());
486 // Another normal behavior will fail because of the limit is hit
487 response.set_blacklist(true);
488 SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
489 net::URLRequestStatus::SUCCESS);
490 EXPECT_FALSE(SendClientReportMalwareRequest(url));
492 report_times = GetMalwareReportTimes();
493 EXPECT_EQ(4U, report_times.size());
494 while (!report_times.empty()) {
495 base::Time time = report_times.back();
496 report_times.pop();
497 EXPECT_LE(before, time);
498 EXPECT_GE(after, time);
502 TEST_F(ClientSideDetectionServiceTest, GetNumReportTest) {
503 SetModelFetchResponse("bogus model", net::HTTP_OK,
504 net::URLRequestStatus::SUCCESS);
505 csd_service_.reset(ClientSideDetectionService::Create(NULL));
507 std::queue<base::Time>& report_times = GetPhishingReportTimes();
508 base::Time now = base::Time::Now();
509 base::TimeDelta twenty_five_hours = base::TimeDelta::FromHours(25);
510 report_times.push(now - twenty_five_hours);
511 report_times.push(now - twenty_five_hours);
512 report_times.push(now);
513 report_times.push(now);
515 EXPECT_EQ(2, GetNumReports(&report_times));
518 TEST_F(ClientSideDetectionServiceTest, CacheTest) {
519 SetModelFetchResponse("bogus model", net::HTTP_OK,
520 net::URLRequestStatus::SUCCESS);
521 csd_service_.reset(ClientSideDetectionService::Create(NULL));
523 TestCache();
526 TEST_F(ClientSideDetectionServiceTest, IsPrivateIPAddress) {
527 SetModelFetchResponse("bogus model", net::HTTP_OK,
528 net::URLRequestStatus::SUCCESS);
529 csd_service_.reset(ClientSideDetectionService::Create(NULL));
531 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("10.1.2.3"));
532 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("127.0.0.1"));
533 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("172.24.3.4"));
534 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("192.168.1.1"));
535 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fc00::"));
536 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0::"));
537 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0:1:2::3"));
538 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("::1"));
540 EXPECT_FALSE(csd_service_->IsPrivateIPAddress("1.2.3.4"));
541 EXPECT_FALSE(csd_service_->IsPrivateIPAddress("200.1.1.1"));
542 EXPECT_FALSE(csd_service_->IsPrivateIPAddress("2001:0db8:ac10:fe01::"));
544 // If the address can't be parsed, the default is true.
545 EXPECT_TRUE(csd_service_->IsPrivateIPAddress("blah"));
548 TEST_F(ClientSideDetectionServiceTest, SetBadSubnets) {
549 ClientSideModel model;
550 ClientSideDetectionService::BadSubnetMap bad_subnets;
551 ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
552 EXPECT_EQ(0U, bad_subnets.size());
554 // Bad subnets are skipped.
555 ClientSideModel::IPSubnet* subnet = model.add_bad_subnet();
556 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
557 subnet->set_size(130); // Invalid size.
559 subnet = model.add_bad_subnet();
560 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
561 subnet->set_size(-1); // Invalid size.
563 subnet = model.add_bad_subnet();
564 subnet->set_prefix(std::string(16, '.')); // Invalid len.
565 subnet->set_size(64);
567 ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
568 EXPECT_EQ(0U, bad_subnets.size());
570 subnet = model.add_bad_subnet();
571 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
572 subnet->set_size(64);
574 subnet = model.add_bad_subnet();
575 subnet->set_prefix(std::string(crypto::kSHA256Length, ','));
576 subnet->set_size(64);
578 subnet = model.add_bad_subnet();
579 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
580 subnet->set_size(128);
582 subnet = model.add_bad_subnet();
583 subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
584 subnet->set_size(100);
586 ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
587 EXPECT_EQ(3U, bad_subnets.size());
588 ClientSideDetectionService::BadSubnetMap::const_iterator it;
589 std::string mask = std::string(8, '\xFF') + std::string(8, '\x00');
590 EXPECT_TRUE(bad_subnets.count(mask));
591 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
592 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, ',')));
594 mask = std::string(16, '\xFF');
595 EXPECT_TRUE(bad_subnets.count(mask));
596 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
598 mask = std::string(12, '\xFF') + "\xF0" + std::string(3, '\x00');
599 EXPECT_TRUE(bad_subnets.count(mask));
600 EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
603 TEST_F(ClientSideDetectionServiceTest, ModelHasValidHashIds) {
604 ClientSideModel model;
605 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
606 model.add_hashes("bla");
607 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
608 model.add_page_term(0);
609 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
611 model.add_page_term(-1);
612 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
613 model.set_page_term(1, 1);
614 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
615 model.set_page_term(1, 0);
616 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
618 // Test bad rules.
619 model.add_hashes("blu");
620 ClientSideModel::Rule* rule = model.add_rule();
621 rule->add_feature(0);
622 rule->add_feature(1);
623 rule->set_weight(0.1f);
624 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
626 rule = model.add_rule();
627 rule->add_feature(0);
628 rule->add_feature(1);
629 rule->add_feature(-1);
630 rule->set_weight(0.2f);
631 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
633 rule->set_feature(2, 2);
634 EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
636 rule->set_feature(2, 1);
637 EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
640 TEST_F(ClientSideDetectionServiceTest, SetEnabledAndRefreshState) {
641 // Check that the model isn't downloaded until the service is enabled.
642 csd_service_.reset(ClientSideDetectionService::Create(NULL));
643 EXPECT_FALSE(csd_service_->enabled());
644 EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
646 // Use a MockClientSideDetectionService for the rest of the test, to avoid
647 // the scheduling delay.
648 MockClientSideDetectionService* service =
649 new StrictMock<MockClientSideDetectionService>();
650 csd_service_.reset(service);
651 EXPECT_FALSE(csd_service_->enabled());
652 EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
653 // No calls expected yet.
654 Mock::VerifyAndClearExpectations(service);
656 ClientSideModel model;
657 model.set_version(10);
658 model.set_max_words_per_term(4);
659 SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
660 net::URLRequestStatus::SUCCESS);
661 EXPECT_CALL(*service, ScheduleFetchModel(_))
662 .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
663 EXPECT_CALL(*service, EndFetchModel(
664 ClientSideDetectionService::MODEL_SUCCESS))
665 .WillOnce(QuitCurrentMessageLoop());
666 csd_service_->SetEnabledAndRefreshState(true);
667 EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
668 msg_loop_.Run(); // EndFetchModel will quit the message loop.
669 Mock::VerifyAndClearExpectations(service);
671 // Check that enabling again doesn't request the model.
672 csd_service_->SetEnabledAndRefreshState(true);
673 // No calls expected.
674 Mock::VerifyAndClearExpectations(service);
676 // Check that disabling the service cancels pending requests.
677 EXPECT_CALL(*service, ScheduleFetchModel(_))
678 .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
679 csd_service_->SetEnabledAndRefreshState(false);
680 csd_service_->SetEnabledAndRefreshState(true);
681 Mock::VerifyAndClearExpectations(service);
682 EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
683 csd_service_->SetEnabledAndRefreshState(false);
684 EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
685 msg_loop_.RunUntilIdle();
686 // No calls expected.
687 Mock::VerifyAndClearExpectations(service);
689 // Requests always return false when the service is disabled.
690 ClientPhishingResponse response;
691 response.set_phishy(true);
692 SetClientReportPhishingResponse(response.SerializeAsString(), net::HTTP_OK,
693 net::URLRequestStatus::SUCCESS);
694 EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
696 // Pending requests also return false if the service is disabled before they
697 // report back.
698 EXPECT_CALL(*service, ScheduleFetchModel(_))
699 .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
700 EXPECT_CALL(*service, EndFetchModel(
701 ClientSideDetectionService::MODEL_NOT_CHANGED))
702 .WillOnce(Invoke(service, &MockClientSideDetectionService::Disable));
703 csd_service_->SetEnabledAndRefreshState(true);
704 EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
705 Mock::VerifyAndClearExpectations(service);
707 } // namespace safe_browsing