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 "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/safe_browsing/csd.pb.h"
17 #include "chrome/common/safe_browsing/safebrowsing_messages.h"
18 #include "chrome/renderer/safe_browsing/features.h"
19 #include "chrome/renderer/safe_browsing/phishing_classifier.h"
20 #include "chrome/renderer/safe_browsing/scorer.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "content/public/browser/browser_message_filter.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/renderer/render_view.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/test_navigation_observer.h"
30 #include "content/public/test/test_utils.h"
31 #include "net/dns/mock_host_resolver.h"
32 #include "net/test/embedded_test_server/embedded_test_server.h"
33 #include "net/test/embedded_test_server/http_request.h"
34 #include "net/test/embedded_test_server/http_response.h"
35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "third_party/WebKit/public/platform/WebURL.h"
37 #include "third_party/WebKit/public/platform/WebURLRequest.h"
38 #include "third_party/WebKit/public/web/WebFrame.h"
39 #include "third_party/WebKit/public/web/WebView.h"
42 using base::ASCIIToUTF16
;
44 using ::testing::InSequence
;
45 using ::testing::Mock
;
46 using ::testing::Pointee
;
47 using ::testing::StrictMock
;
49 namespace safe_browsing
{
53 // The RenderFrame is routing ID 1, and the RenderView is 2.
54 const int kRenderViewRoutingId
= 2;
56 class MockPhishingClassifier
: public PhishingClassifier
{
58 explicit MockPhishingClassifier(content::RenderView
* render_view
)
59 : PhishingClassifier(render_view
, NULL
/* clock */) {}
61 virtual ~MockPhishingClassifier() {}
63 MOCK_METHOD2(BeginClassification
,
64 void(const base::string16
*, const DoneCallback
&));
65 MOCK_METHOD0(CancelPendingClassification
, void());
68 DISALLOW_COPY_AND_ASSIGN(MockPhishingClassifier
);
71 class MockScorer
: public Scorer
{
73 MockScorer() : Scorer() {}
74 virtual ~MockScorer() {}
76 MOCK_CONST_METHOD1(ComputeScore
, double(const FeatureMap
&));
79 DISALLOW_COPY_AND_ASSIGN(MockScorer
);
82 class InterceptingMessageFilter
: public content::BrowserMessageFilter
{
84 InterceptingMessageFilter()
85 : BrowserMessageFilter(SafeBrowsingMsgStart
),
86 waiting_message_loop_(NULL
) {
89 const ClientPhishingRequest
* verdict() const { return verdict_
.get(); }
90 virtual bool OnMessageReceived(const IPC::Message
& message
,
91 bool* message_was_ok
) OVERRIDE
{
93 IPC_BEGIN_MESSAGE_MAP(InterceptingMessageFilter
, message
)
94 IPC_MESSAGE_HANDLER(SafeBrowsingHostMsg_PhishingDetectionDone
,
95 OnPhishingDetectionDone
)
96 IPC_MESSAGE_UNHANDLED(handled
= false);
102 run_loop_
.reset(new base::RunLoop());
103 waiting_message_loop_
= base::MessageLoop::current();
104 quit_closure_
= run_loop_
->QuitClosure();
107 void RunUntilVerdictReceived() {
108 content::RunThisRunLoop(run_loop_
.get());
110 // Clear out the synchronization state just in case.
111 waiting_message_loop_
= NULL
;
112 quit_closure_
.Reset();
116 void OnPhishingDetectionDone(const std::string
& verdict_str
) {
117 scoped_ptr
<ClientPhishingRequest
> verdict(new ClientPhishingRequest
);
118 if (verdict
->ParseFromString(verdict_str
) &&
119 verdict
->IsInitialized()) {
120 verdict_
.swap(verdict
);
122 waiting_message_loop_
->PostTask(FROM_HERE
, quit_closure_
);
126 virtual ~InterceptingMessageFilter() {}
128 scoped_ptr
<ClientPhishingRequest
> verdict_
;
129 base::MessageLoop
* waiting_message_loop_
;
130 base::Closure quit_closure_
;
131 scoped_ptr
<base::RunLoop
> run_loop_
;
135 class PhishingClassifierDelegateTest
: public InProcessBrowserTest
{
137 void CancelCalled() {
139 content::BrowserThread::PostTask(
140 content::BrowserThread::UI
, FROM_HERE
, runner_
->QuitClosure());
145 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
146 command_line
->AppendSwitch(switches::kSingleProcess
);
148 // Don't want to try to create a GPU process.
149 command_line
->AppendSwitch(switches::kDisableAcceleratedCompositing
);
153 virtual void SetUpOnMainThread() OVERRIDE
{
154 intercepting_filter_
= new InterceptingMessageFilter();
155 content::RenderView
* render_view
=
156 content::RenderView::FromRoutingID(kRenderViewRoutingId
);
158 GetWebContents()->GetRenderProcessHost()->AddFilter(
159 intercepting_filter_
.get());
160 classifier_
= new StrictMock
<MockPhishingClassifier
>(render_view
);
161 delegate_
= PhishingClassifierDelegate::Create(render_view
, classifier_
);
163 ASSERT_TRUE(StartTestServer());
164 host_resolver()->AddRule("*", "127.0.0.1");
167 // Runs the ClassificationDone callback, then waits for the
168 // PhishingDetectionDone IPC to arrive.
169 void RunClassificationDone(const ClientPhishingRequest
& verdict
) {
170 // Clear out any previous state.
171 intercepting_filter_
->Reset();
172 PostTaskToInProcessRendererAndWait(
173 base::Bind(&PhishingClassifierDelegate::ClassificationDone
,
174 base::Unretained(delegate_
),
176 intercepting_filter_
->RunUntilVerdictReceived();
179 void OnStartPhishingDetection(const GURL
& url
) {
180 PostTaskToInProcessRendererAndWait(
181 base::Bind(&PhishingClassifierDelegate::OnStartPhishingDetection
,
182 base::Unretained(delegate_
), url
));
185 void PageCaptured(base::string16
* page_text
, bool preliminary_capture
) {
186 PostTaskToInProcessRendererAndWait(
187 base::Bind(&PhishingClassifierDelegate::PageCaptured
,
188 base::Unretained(delegate_
), page_text
,
189 preliminary_capture
));
192 bool StartTestServer() {
193 CHECK(!embedded_test_server_
);
194 embedded_test_server_
.reset(new net::test_server::EmbeddedTestServer());
195 embedded_test_server_
->RegisterRequestHandler(
196 base::Bind(&PhishingClassifierDelegateTest::HandleRequest
,
197 base::Unretained(this)));
198 return embedded_test_server_
->InitializeAndWaitUntilReady();
201 scoped_ptr
<net::test_server::HttpResponse
> HandleRequest(
202 const net::test_server::HttpRequest
& request
) {
203 std::map
<std::string
, std::string
>::const_iterator host_it
=
204 request
.headers
.find("Host");
205 if (host_it
== request
.headers
.end())
206 return scoped_ptr
<net::test_server::HttpResponse
>();
209 std::string("http://") + host_it
->second
+ request
.relative_url
;
210 if (response_url_
.spec() != url
)
211 return scoped_ptr
<net::test_server::HttpResponse
>();
213 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
214 new net::test_server::BasicHttpResponse());
215 http_response
->set_code(net::HTTP_OK
);
216 http_response
->set_content_type("text/html");
217 http_response
->set_content(response_content_
);
218 return http_response
.PassAs
<net::test_server::HttpResponse
>();
221 content::WebContents
* GetWebContents() {
222 return browser()->tab_strip_model()->GetActiveWebContents();
225 // Returns the URL that was loaded.
226 GURL
LoadHtml(const std::string
& host
, const std::string
& content
) {
227 GURL::Replacements replace_host
;
228 replace_host
.SetHostStr(host
);
229 response_content_
= content
;
231 embedded_test_server_
->base_url().ReplaceComponents(replace_host
);
232 ui_test_utils::NavigateToURL(browser(), response_url_
);
233 return response_url_
;
236 void NavigateMainFrame(const GURL
& url
) {
237 PostTaskToInProcessRendererAndWait(
238 base::Bind(&PhishingClassifierDelegateTest::NavigateMainFrameInternal
,
239 base::Unretained(this), url
));
242 void NavigateMainFrameInternal(const GURL
& url
) {
243 content::RenderView
* render_view
=
244 content::RenderView::FromRoutingID(kRenderViewRoutingId
);
245 render_view
->GetWebView()->mainFrame()->firstChild()->loadRequest(
246 blink::WebURLRequest(url
));
250 GetWebContents()->GetController().GoBack();
251 content::WaitForLoadStop(GetWebContents());
255 GetWebContents()->GetController().GoForward();
256 content::WaitForLoadStop(GetWebContents());
259 scoped_refptr
<InterceptingMessageFilter
> intercepting_filter_
;
261 std::string response_content_
;
262 scoped_ptr
<net::test_server::EmbeddedTestServer
> embedded_test_server_
;
263 scoped_ptr
<ClientPhishingRequest
> verdict_
;
264 StrictMock
<MockPhishingClassifier
>* classifier_
; // Owned by |delegate_|.
265 PhishingClassifierDelegate
* delegate_
; // Owned by the RenderView.
266 scoped_refptr
<content::MessageLoopRunner
> runner_
;
269 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest
, Navigation
) {
271 delegate_
->SetPhishingScorer(&scorer
);
272 ASSERT_TRUE(classifier_
->is_ready());
274 // Test an initial load. We expect classification to happen normally.
275 EXPECT_CALL(*classifier_
, CancelPendingClassification()).Times(2);
276 std::string port
= base::IntToString(embedded_test_server_
->port());
277 std::string html
= "<html><body><iframe src=\"http://sub1.com:";
279 html
+= "/\"></iframe></body></html>";
280 GURL url
= LoadHtml("host.com", html
);
281 Mock::VerifyAndClearExpectations(classifier_
);
282 OnStartPhishingDetection(url
);
283 base::string16 page_text
= ASCIIToUTF16("dummy");
286 EXPECT_CALL(*classifier_
, CancelPendingClassification());
287 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
288 PageCaptured(&page_text
, false);
289 Mock::VerifyAndClearExpectations(classifier_
);
292 // Reloading the same page should not trigger a reclassification.
293 // However, it will cancel any pending classification since the
294 // content is being replaced.
295 EXPECT_CALL(*classifier_
, CancelPendingClassification()).Times(2);
297 content::TestNavigationObserver
observer(GetWebContents());
298 chrome::Reload(browser(), CURRENT_TAB
);
301 Mock::VerifyAndClearExpectations(classifier_
);
302 OnStartPhishingDetection(url
);
303 page_text
= ASCIIToUTF16("dummy");
304 EXPECT_CALL(*classifier_
, CancelPendingClassification());
305 PageCaptured(&page_text
, false);
306 Mock::VerifyAndClearExpectations(classifier_
);
308 // Navigating in a subframe will not change the toplevel URL. However, this
309 // should cancel pending classification since the page content is changing.
310 // Currently, we do not start a new classification after subframe loads.
311 EXPECT_CALL(*classifier_
, CancelPendingClassification())
312 .WillOnce(Invoke(this, &PhishingClassifierDelegateTest::CancelCalled
));
314 runner_
= new content::MessageLoopRunner
;
315 NavigateMainFrame(GURL(std::string("http://sub2.com:") + port
+ "/"));
320 Mock::VerifyAndClearExpectations(classifier_
);
322 OnStartPhishingDetection(url
);
323 page_text
= ASCIIToUTF16("dummy");
324 EXPECT_CALL(*classifier_
, CancelPendingClassification());
325 PageCaptured(&page_text
, false);
326 Mock::VerifyAndClearExpectations(classifier_
);
328 // Scrolling to an anchor works similarly to a subframe navigation, but
329 // see the TODO in PhishingClassifierDelegate::DidCommitProvisionalLoad.
330 EXPECT_CALL(*classifier_
, CancelPendingClassification());
331 GURL foo_url
= GURL(url
.spec() + "#foo");
332 ui_test_utils::NavigateToURL(browser(), foo_url
);
333 Mock::VerifyAndClearExpectations(classifier_
);
334 OnStartPhishingDetection(url
);
335 page_text
= ASCIIToUTF16("dummy");
336 EXPECT_CALL(*classifier_
, CancelPendingClassification());
337 PageCaptured(&page_text
, false);
338 Mock::VerifyAndClearExpectations(classifier_
);
340 // Now load a new toplevel page, which should trigger another classification.
341 EXPECT_CALL(*classifier_
, CancelPendingClassification())
342 .WillOnce(Invoke(this, &PhishingClassifierDelegateTest::CancelCalled
));
344 runner_
= new content::MessageLoopRunner
;
345 url
= LoadHtml("host2.com", "dummy2");
349 Mock::VerifyAndClearExpectations(classifier_
);
350 page_text
= ASCIIToUTF16("dummy2");
351 OnStartPhishingDetection(url
);
354 EXPECT_CALL(*classifier_
, CancelPendingClassification());
355 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
356 PageCaptured(&page_text
, false);
357 Mock::VerifyAndClearExpectations(classifier_
);
360 // No classification should happen on back/forward navigation.
361 // Note: in practice, the browser will not send a StartPhishingDetection IPC
362 // in this case. However, we want to make sure that the delegate behaves
363 // correctly regardless.
364 EXPECT_CALL(*classifier_
, CancelPendingClassification()).Times(2);
366 Mock::VerifyAndClearExpectations(classifier_
);
368 page_text
= ASCIIToUTF16("dummy");
369 OnStartPhishingDetection(url
);
370 EXPECT_CALL(*classifier_
, CancelPendingClassification());
371 PageCaptured(&page_text
, false);
372 Mock::VerifyAndClearExpectations(classifier_
);
374 EXPECT_CALL(*classifier_
, CancelPendingClassification());
376 Mock::VerifyAndClearExpectations(classifier_
);
378 page_text
= ASCIIToUTF16("dummy2");
379 OnStartPhishingDetection(url
);
380 EXPECT_CALL(*classifier_
, CancelPendingClassification());
381 PageCaptured(&page_text
, false);
382 Mock::VerifyAndClearExpectations(classifier_
);
384 // Now go back again and scroll to a different anchor.
385 // No classification should happen.
386 EXPECT_CALL(*classifier_
, CancelPendingClassification()).Times(2);
388 Mock::VerifyAndClearExpectations(classifier_
);
389 page_text
= ASCIIToUTF16("dummy");
391 OnStartPhishingDetection(url
);
392 EXPECT_CALL(*classifier_
, CancelPendingClassification());
393 PageCaptured(&page_text
, false);
394 Mock::VerifyAndClearExpectations(classifier_
);
396 EXPECT_CALL(*classifier_
, CancelPendingClassification());
397 GURL foo2_url
= GURL(foo_url
.spec() + "2");
398 ui_test_utils::NavigateToURL(browser(), foo2_url
);
399 Mock::VerifyAndClearExpectations(classifier_
);
401 OnStartPhishingDetection(url
);
402 page_text
= ASCIIToUTF16("dummy");
403 EXPECT_CALL(*classifier_
, CancelPendingClassification());
404 PageCaptured(&page_text
, false);
405 Mock::VerifyAndClearExpectations(classifier_
);
407 // The delegate will cancel pending classification on destruction.
408 EXPECT_CALL(*classifier_
, CancelPendingClassification());
411 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest
, NoScorer
) {
412 // For this test, we'll create the delegate with no scorer available yet.
413 ASSERT_FALSE(classifier_
->is_ready());
415 // Queue up a pending classification, cancel it, then queue up another one.
416 GURL url
= LoadHtml("host.com", "dummy");
417 base::string16 page_text
= ASCIIToUTF16("dummy");
418 OnStartPhishingDetection(url
);
419 PageCaptured(&page_text
, false);
421 url
= LoadHtml("host2.com", "dummy2");
422 page_text
= ASCIIToUTF16("dummy2");
423 OnStartPhishingDetection(url
);
424 PageCaptured(&page_text
, false);
426 // Now set a scorer, which should cause a classifier to be created and
427 // the classification to proceed.
428 page_text
= ASCIIToUTF16("dummy2");
429 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
431 delegate_
->SetPhishingScorer(&scorer
);
432 Mock::VerifyAndClearExpectations(classifier_
);
434 // If we set a new scorer while a classification is going on the
435 // classification should be cancelled.
436 EXPECT_CALL(*classifier_
, CancelPendingClassification());
437 delegate_
->SetPhishingScorer(&scorer
);
438 Mock::VerifyAndClearExpectations(classifier_
);
440 // The delegate will cancel pending classification on destruction.
441 EXPECT_CALL(*classifier_
, CancelPendingClassification());
444 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest
, NoScorer_Ref
) {
445 // Similar to the last test, but navigates within the page before
446 // setting the scorer.
447 ASSERT_FALSE(classifier_
->is_ready());
449 // Queue up a pending classification, cancel it, then queue up another one.
450 GURL url
= LoadHtml("host.com", "dummy");
451 base::string16 page_text
= ASCIIToUTF16("dummy");
452 OnStartPhishingDetection(url
);
453 PageCaptured(&page_text
, false);
455 OnStartPhishingDetection(url
);
456 page_text
= ASCIIToUTF16("dummy");
457 PageCaptured(&page_text
, false);
459 // Now set a scorer, which should cause a classifier to be created and
460 // the classification to proceed.
461 page_text
= ASCIIToUTF16("dummy");
462 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
464 delegate_
->SetPhishingScorer(&scorer
);
465 Mock::VerifyAndClearExpectations(classifier_
);
467 // The delegate will cancel pending classification on destruction.
468 EXPECT_CALL(*classifier_
, CancelPendingClassification());
471 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest
,
472 NoStartPhishingDetection
) {
473 // Tests the behavior when OnStartPhishingDetection has not yet been called
474 // when the page load finishes.
476 delegate_
->SetPhishingScorer(&scorer
);
477 ASSERT_TRUE(classifier_
->is_ready());
479 EXPECT_CALL(*classifier_
, CancelPendingClassification());
480 GURL url
= LoadHtml("host.com", "<html><body>phish</body></html>");
481 Mock::VerifyAndClearExpectations(classifier_
);
482 base::string16 page_text
= ASCIIToUTF16("phish");
483 EXPECT_CALL(*classifier_
, CancelPendingClassification());
484 PageCaptured(&page_text
, false);
485 Mock::VerifyAndClearExpectations(classifier_
);
486 // Now simulate the StartPhishingDetection IPC. We expect classification
488 page_text
= ASCIIToUTF16("phish");
489 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
490 OnStartPhishingDetection(url
);
491 Mock::VerifyAndClearExpectations(classifier_
);
493 // Now try again, but this time we will navigate the page away before
495 EXPECT_CALL(*classifier_
, CancelPendingClassification());
496 LoadHtml("host2.com", "<html><body>phish</body></html>");
497 Mock::VerifyAndClearExpectations(classifier_
);
498 page_text
= ASCIIToUTF16("phish");
499 EXPECT_CALL(*classifier_
, CancelPendingClassification());
500 PageCaptured(&page_text
, false);
501 Mock::VerifyAndClearExpectations(classifier_
);
503 EXPECT_CALL(*classifier_
, CancelPendingClassification());
504 LoadHtml("host3.com", "<html><body>phish</body></html>");
505 Mock::VerifyAndClearExpectations(classifier_
);
506 OnStartPhishingDetection(url
);
508 // In this test, the original page is a redirect, which we do not get a
509 // StartPhishingDetection IPC for. We use location.replace() to load a
510 // new page while reusing the original session history entry, and check that
511 // classification begins correctly for the landing page.
512 EXPECT_CALL(*classifier_
, CancelPendingClassification());
513 LoadHtml("host4.com", "<html><body>abc</body></html>");
514 Mock::VerifyAndClearExpectations(classifier_
);
515 page_text
= ASCIIToUTF16("abc");
516 EXPECT_CALL(*classifier_
, CancelPendingClassification());
517 PageCaptured(&page_text
, false);
518 Mock::VerifyAndClearExpectations(classifier_
);
519 EXPECT_CALL(*classifier_
, CancelPendingClassification());
521 ui_test_utils::NavigateToURL(
522 browser(), GURL("javascript:location.replace(\'redir\');"));
524 Mock::VerifyAndClearExpectations(classifier_
);
526 std::string url_str
= "http://host4.com:";
527 url_str
+= base::IntToString(embedded_test_server_
->port());
529 OnStartPhishingDetection(GURL(url_str
));
530 page_text
= ASCIIToUTF16("123");
533 EXPECT_CALL(*classifier_
, CancelPendingClassification());
534 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
535 PageCaptured(&page_text
, false);
536 Mock::VerifyAndClearExpectations(classifier_
);
539 // The delegate will cancel pending classification on destruction.
540 EXPECT_CALL(*classifier_
, CancelPendingClassification());
543 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest
,
544 IgnorePreliminaryCapture
) {
545 // Tests that preliminary PageCaptured notifications are ignored.
547 delegate_
->SetPhishingScorer(&scorer
);
548 ASSERT_TRUE(classifier_
->is_ready());
550 EXPECT_CALL(*classifier_
, CancelPendingClassification());
551 GURL url
= LoadHtml("host.com", "<html><body>phish</body></html>");
552 Mock::VerifyAndClearExpectations(classifier_
);
553 OnStartPhishingDetection(url
);
554 base::string16 page_text
= ASCIIToUTF16("phish");
555 PageCaptured(&page_text
, true);
557 // Once the non-preliminary capture happens, classification should begin.
558 page_text
= ASCIIToUTF16("phish");
561 EXPECT_CALL(*classifier_
, CancelPendingClassification());
562 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
563 PageCaptured(&page_text
, false);
564 Mock::VerifyAndClearExpectations(classifier_
);
567 // The delegate will cancel pending classification on destruction.
568 EXPECT_CALL(*classifier_
, CancelPendingClassification());
571 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest
, DuplicatePageCapture
) {
572 // Tests that a second PageCaptured notification causes classification to
575 delegate_
->SetPhishingScorer(&scorer
);
576 ASSERT_TRUE(classifier_
->is_ready());
578 EXPECT_CALL(*classifier_
, CancelPendingClassification());
579 GURL url
= LoadHtml("host.com", "<html><body>phish</body></html>");
580 Mock::VerifyAndClearExpectations(classifier_
);
581 OnStartPhishingDetection(url
);
582 base::string16 page_text
= ASCIIToUTF16("phish");
585 EXPECT_CALL(*classifier_
, CancelPendingClassification());
586 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
587 PageCaptured(&page_text
, false);
588 Mock::VerifyAndClearExpectations(classifier_
);
591 page_text
= ASCIIToUTF16("phish");
592 EXPECT_CALL(*classifier_
, CancelPendingClassification());
593 PageCaptured(&page_text
, false);
594 Mock::VerifyAndClearExpectations(classifier_
);
596 // The delegate will cancel pending classification on destruction.
597 EXPECT_CALL(*classifier_
, CancelPendingClassification());
600 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest
, PhishingDetectionDone
) {
601 // Tests that a PhishingDetectionDone IPC is sent to the browser
602 // whenever we finish classification.
604 delegate_
->SetPhishingScorer(&scorer
);
605 ASSERT_TRUE(classifier_
->is_ready());
607 // Start by loading a page to populate the delegate's state.
608 EXPECT_CALL(*classifier_
, CancelPendingClassification());
609 GURL url
= LoadHtml("host.com", "<html><body>phish</body></html>");
610 Mock::VerifyAndClearExpectations(classifier_
);
611 base::string16 page_text
= ASCIIToUTF16("phish");
612 OnStartPhishingDetection(url
);
615 EXPECT_CALL(*classifier_
, CancelPendingClassification());
616 EXPECT_CALL(*classifier_
, BeginClassification(Pointee(page_text
), _
));
617 PageCaptured(&page_text
, false);
618 Mock::VerifyAndClearExpectations(classifier_
);
621 // Now run the callback to simulate the classifier finishing.
622 ClientPhishingRequest verdict
;
623 verdict
.set_url(url
.spec());
624 verdict
.set_client_score(0.8f
);
625 verdict
.set_is_phishing(false); // Send IPC even if site is not phishing.
626 RunClassificationDone(verdict
);
627 ASSERT_TRUE(intercepting_filter_
->verdict());
628 EXPECT_EQ(verdict
.SerializeAsString(),
629 intercepting_filter_
->verdict()->SerializeAsString());
631 // The delegate will cancel pending classification on destruction.
632 EXPECT_CALL(*classifier_
, CancelPendingClassification());
635 } // namespace safe_browsing