Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / renderer / safe_browsing / phishing_classifier_delegate_browsertest.cc
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.
4
5 #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
6
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"
40 #include "url/gurl.h"
41
42 using base::ASCIIToUTF16;
43 using ::testing::_;
44 using ::testing::InSequence;
45 using ::testing::Mock;
46 using ::testing::Pointee;
47 using ::testing::StrictMock;
48
49 namespace safe_browsing {
50
51 namespace {
52
53 // The RenderFrame is routing ID 1, and the RenderView is 2.
54 const int kRenderViewRoutingId = 2;
55
56 class MockPhishingClassifier : public PhishingClassifier {
57  public:
58   explicit MockPhishingClassifier(content::RenderView* render_view)
59       : PhishingClassifier(render_view, NULL /* clock */) {}
60
61   virtual ~MockPhishingClassifier() {}
62
63   MOCK_METHOD2(BeginClassification,
64                void(const base::string16*, const DoneCallback&));
65   MOCK_METHOD0(CancelPendingClassification, void());
66
67  private:
68   DISALLOW_COPY_AND_ASSIGN(MockPhishingClassifier);
69 };
70
71 class MockScorer : public Scorer {
72  public:
73   MockScorer() : Scorer() {}
74   virtual ~MockScorer() {}
75
76   MOCK_CONST_METHOD1(ComputeScore, double(const FeatureMap&));
77
78  private:
79   DISALLOW_COPY_AND_ASSIGN(MockScorer);
80 };
81
82 class InterceptingMessageFilter : public content::BrowserMessageFilter {
83  public:
84   InterceptingMessageFilter()
85       : BrowserMessageFilter(SafeBrowsingMsgStart),
86         waiting_message_loop_(NULL) {
87   }
88
89   const ClientPhishingRequest* verdict() const { return verdict_.get(); }
90   virtual bool OnMessageReceived(const IPC::Message& message,
91                                  bool* message_was_ok) OVERRIDE {
92     bool handled = true;
93     IPC_BEGIN_MESSAGE_MAP(InterceptingMessageFilter, message)
94         IPC_MESSAGE_HANDLER(SafeBrowsingHostMsg_PhishingDetectionDone,
95                             OnPhishingDetectionDone)
96         IPC_MESSAGE_UNHANDLED(handled = false);
97     IPC_END_MESSAGE_MAP()
98     return handled;
99   }
100
101   void Reset() {
102     run_loop_.reset(new base::RunLoop());
103     waiting_message_loop_ = base::MessageLoop::current();
104     quit_closure_ = run_loop_->QuitClosure();
105   }
106
107   void RunUntilVerdictReceived() {
108     content::RunThisRunLoop(run_loop_.get());
109
110     // Clear out the synchronization state just in case.
111     waiting_message_loop_ = NULL;
112     quit_closure_.Reset();
113     run_loop_.reset();
114   }
115
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);
121     }
122     waiting_message_loop_->PostTask(FROM_HERE, quit_closure_);
123   }
124
125  private:
126   virtual ~InterceptingMessageFilter() {}
127
128   scoped_ptr<ClientPhishingRequest> verdict_;
129   base::MessageLoop* waiting_message_loop_;
130   base::Closure quit_closure_;
131   scoped_ptr<base::RunLoop> run_loop_;
132 };
133 }  // namespace
134
135 class PhishingClassifierDelegateTest : public InProcessBrowserTest {
136  public:
137   void CancelCalled() {
138     if (runner_.get()) {
139       content::BrowserThread::PostTask(
140           content::BrowserThread::UI, FROM_HERE, runner_->QuitClosure());
141     }
142   }
143
144  protected:
145   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
146     command_line->AppendSwitch(switches::kSingleProcess);
147 #if defined(OS_WIN)
148     // Don't want to try to create a GPU process.
149     command_line->AppendSwitch(switches::kDisableGpu);
150 #endif
151   }
152
153   virtual void SetUpOnMainThread() OVERRIDE {
154     intercepting_filter_ = new InterceptingMessageFilter();
155     content::RenderView* render_view =
156         content::RenderView::FromRoutingID(kRenderViewRoutingId);
157
158     GetWebContents()->GetRenderProcessHost()->AddFilter(
159         intercepting_filter_.get());
160     classifier_ = new StrictMock<MockPhishingClassifier>(render_view);
161     delegate_ = PhishingClassifierDelegate::Create(render_view, classifier_);
162
163     ASSERT_TRUE(StartTestServer());
164     host_resolver()->AddRule("*", "127.0.0.1");
165   }
166
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_),
175         verdict));
176     intercepting_filter_->RunUntilVerdictReceived();
177   }
178
179   void OnStartPhishingDetection(const GURL& url) {
180     PostTaskToInProcessRendererAndWait(
181         base::Bind(&PhishingClassifierDelegate::OnStartPhishingDetection,
182                    base::Unretained(delegate_), url));
183   }
184
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));
190   }
191
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();
199   }
200
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>();
207
208     std::string url =
209         std::string("http://") + host_it->second + request.relative_url;
210     if (response_url_.spec() != url)
211       return scoped_ptr<net::test_server::HttpResponse>();
212
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>();
219   }
220
221   content::WebContents* GetWebContents() {
222     return browser()->tab_strip_model()->GetActiveWebContents();
223   }
224
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;
230     response_url_ =
231         embedded_test_server_->base_url().ReplaceComponents(replace_host);
232     ui_test_utils::NavigateToURL(browser(), response_url_);
233     return response_url_;
234   }
235
236   void NavigateMainFrame(const GURL& url) {
237     PostTaskToInProcessRendererAndWait(
238         base::Bind(&PhishingClassifierDelegateTest::NavigateMainFrameInternal,
239                    base::Unretained(this), url));
240   }
241
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));
247   }
248
249   void GoBack() {
250     GetWebContents()->GetController().GoBack();
251     content::WaitForLoadStop(GetWebContents());
252   }
253
254   void GoForward() {
255     GetWebContents()->GetController().GoForward();
256     content::WaitForLoadStop(GetWebContents());
257   }
258
259   scoped_refptr<InterceptingMessageFilter> intercepting_filter_;
260   GURL response_url_;
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_;
267 };
268
269 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest, Navigation) {
270   MockScorer scorer;
271   delegate_->SetPhishingScorer(&scorer);
272   ASSERT_TRUE(classifier_->is_ready());
273
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:";
278   html += port;
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");
284   {
285     InSequence s;
286     EXPECT_CALL(*classifier_, CancelPendingClassification());
287     EXPECT_CALL(*classifier_, BeginClassification(Pointee(page_text), _));
288     PageCaptured(&page_text, false);
289     Mock::VerifyAndClearExpectations(classifier_);
290   }
291
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);
296
297   content::TestNavigationObserver observer(GetWebContents());
298   chrome::Reload(browser(), CURRENT_TAB);
299   observer.Wait();
300
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_);
307
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));
313
314   runner_ = new content::MessageLoopRunner;
315   NavigateMainFrame(GURL(std::string("http://sub2.com:") + port + "/"));
316
317   runner_->Run();
318   runner_ = NULL;
319
320   Mock::VerifyAndClearExpectations(classifier_);
321
322   OnStartPhishingDetection(url);
323   page_text = ASCIIToUTF16("dummy");
324   EXPECT_CALL(*classifier_, CancelPendingClassification());
325   PageCaptured(&page_text, false);
326   Mock::VerifyAndClearExpectations(classifier_);
327
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_);
339
340   // Now load a new toplevel page, which should trigger another classification.
341   EXPECT_CALL(*classifier_, CancelPendingClassification())
342       .WillOnce(Invoke(this, &PhishingClassifierDelegateTest::CancelCalled));
343
344   runner_ = new content::MessageLoopRunner;
345   url = LoadHtml("host2.com", "dummy2");
346   runner_->Run();
347   runner_ = NULL;
348
349   Mock::VerifyAndClearExpectations(classifier_);
350   page_text = ASCIIToUTF16("dummy2");
351   OnStartPhishingDetection(url);
352   {
353     InSequence s;
354     EXPECT_CALL(*classifier_, CancelPendingClassification());
355     EXPECT_CALL(*classifier_, BeginClassification(Pointee(page_text), _));
356     PageCaptured(&page_text, false);
357     Mock::VerifyAndClearExpectations(classifier_);
358   }
359
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);
365   GoBack();
366   Mock::VerifyAndClearExpectations(classifier_);
367
368   page_text = ASCIIToUTF16("dummy");
369   OnStartPhishingDetection(url);
370   EXPECT_CALL(*classifier_, CancelPendingClassification());
371   PageCaptured(&page_text, false);
372   Mock::VerifyAndClearExpectations(classifier_);
373
374   EXPECT_CALL(*classifier_, CancelPendingClassification());
375   GoForward();
376   Mock::VerifyAndClearExpectations(classifier_);
377
378   page_text = ASCIIToUTF16("dummy2");
379   OnStartPhishingDetection(url);
380   EXPECT_CALL(*classifier_, CancelPendingClassification());
381   PageCaptured(&page_text, false);
382   Mock::VerifyAndClearExpectations(classifier_);
383
384   // Now go back again and scroll to a different anchor.
385   // No classification should happen.
386   EXPECT_CALL(*classifier_, CancelPendingClassification()).Times(2);
387   GoBack();
388   Mock::VerifyAndClearExpectations(classifier_);
389   page_text = ASCIIToUTF16("dummy");
390
391   OnStartPhishingDetection(url);
392   EXPECT_CALL(*classifier_, CancelPendingClassification());
393   PageCaptured(&page_text, false);
394   Mock::VerifyAndClearExpectations(classifier_);
395
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_);
400
401   OnStartPhishingDetection(url);
402   page_text = ASCIIToUTF16("dummy");
403   EXPECT_CALL(*classifier_, CancelPendingClassification());
404   PageCaptured(&page_text, false);
405   Mock::VerifyAndClearExpectations(classifier_);
406
407   // The delegate will cancel pending classification on destruction.
408   EXPECT_CALL(*classifier_, CancelPendingClassification());
409 }
410
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());
414
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);
420
421   url = LoadHtml("host2.com", "dummy2");
422   page_text = ASCIIToUTF16("dummy2");
423   OnStartPhishingDetection(url);
424   PageCaptured(&page_text, false);
425
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), _));
430   MockScorer scorer;
431   delegate_->SetPhishingScorer(&scorer);
432   Mock::VerifyAndClearExpectations(classifier_);
433
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_);
439
440   // The delegate will cancel pending classification on destruction.
441   EXPECT_CALL(*classifier_, CancelPendingClassification());
442 }
443
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());
448
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);
454
455   OnStartPhishingDetection(url);
456   page_text = ASCIIToUTF16("dummy");
457   PageCaptured(&page_text, false);
458
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), _));
463   MockScorer scorer;
464   delegate_->SetPhishingScorer(&scorer);
465   Mock::VerifyAndClearExpectations(classifier_);
466
467   // The delegate will cancel pending classification on destruction.
468   EXPECT_CALL(*classifier_, CancelPendingClassification());
469 }
470
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.
475   MockScorer scorer;
476   delegate_->SetPhishingScorer(&scorer);
477   ASSERT_TRUE(classifier_->is_ready());
478
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
487   // to begin.
488   page_text = ASCIIToUTF16("phish");
489   EXPECT_CALL(*classifier_, BeginClassification(Pointee(page_text), _));
490   OnStartPhishingDetection(url);
491   Mock::VerifyAndClearExpectations(classifier_);
492
493   // Now try again, but this time we will navigate the page away before
494   // the IPC is sent.
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_);
502
503   EXPECT_CALL(*classifier_, CancelPendingClassification());
504   LoadHtml("host3.com", "<html><body>phish</body></html>");
505   Mock::VerifyAndClearExpectations(classifier_);
506   OnStartPhishingDetection(url);
507
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());
520
521   ui_test_utils::NavigateToURL(
522       browser(), GURL("javascript:location.replace(\'redir\');"));
523
524   Mock::VerifyAndClearExpectations(classifier_);
525
526   std::string url_str = "http://host4.com:";
527   url_str += base::IntToString(embedded_test_server_->port());
528   url_str += "/redir";
529   OnStartPhishingDetection(GURL(url_str));
530   page_text = ASCIIToUTF16("123");
531   {
532     InSequence s;
533     EXPECT_CALL(*classifier_, CancelPendingClassification());
534     EXPECT_CALL(*classifier_, BeginClassification(Pointee(page_text), _));
535     PageCaptured(&page_text, false);
536     Mock::VerifyAndClearExpectations(classifier_);
537   }
538
539   // The delegate will cancel pending classification on destruction.
540   EXPECT_CALL(*classifier_, CancelPendingClassification());
541 }
542
543 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest,
544                        IgnorePreliminaryCapture) {
545   // Tests that preliminary PageCaptured notifications are ignored.
546   MockScorer scorer;
547   delegate_->SetPhishingScorer(&scorer);
548   ASSERT_TRUE(classifier_->is_ready());
549
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);
556
557   // Once the non-preliminary capture happens, classification should begin.
558   page_text = ASCIIToUTF16("phish");
559   {
560     InSequence s;
561     EXPECT_CALL(*classifier_, CancelPendingClassification());
562     EXPECT_CALL(*classifier_, BeginClassification(Pointee(page_text), _));
563     PageCaptured(&page_text, false);
564     Mock::VerifyAndClearExpectations(classifier_);
565   }
566
567   // The delegate will cancel pending classification on destruction.
568   EXPECT_CALL(*classifier_, CancelPendingClassification());
569 }
570
571 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest, DuplicatePageCapture) {
572   // Tests that a second PageCaptured notification causes classification to
573   // be cancelled.
574   MockScorer scorer;
575   delegate_->SetPhishingScorer(&scorer);
576   ASSERT_TRUE(classifier_->is_ready());
577
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");
583   {
584     InSequence s;
585     EXPECT_CALL(*classifier_, CancelPendingClassification());
586     EXPECT_CALL(*classifier_, BeginClassification(Pointee(page_text), _));
587     PageCaptured(&page_text, false);
588     Mock::VerifyAndClearExpectations(classifier_);
589   }
590
591   page_text = ASCIIToUTF16("phish");
592   EXPECT_CALL(*classifier_, CancelPendingClassification());
593   PageCaptured(&page_text, false);
594   Mock::VerifyAndClearExpectations(classifier_);
595
596   // The delegate will cancel pending classification on destruction.
597   EXPECT_CALL(*classifier_, CancelPendingClassification());
598 }
599
600 IN_PROC_BROWSER_TEST_F(PhishingClassifierDelegateTest, PhishingDetectionDone) {
601   // Tests that a PhishingDetectionDone IPC is sent to the browser
602   // whenever we finish classification.
603   MockScorer scorer;
604   delegate_->SetPhishingScorer(&scorer);
605   ASSERT_TRUE(classifier_->is_ready());
606
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);
613   {
614     InSequence s;
615     EXPECT_CALL(*classifier_, CancelPendingClassification());
616     EXPECT_CALL(*classifier_, BeginClassification(Pointee(page_text), _));
617     PageCaptured(&page_text, false);
618     Mock::VerifyAndClearExpectations(classifier_);
619   }
620
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());
630
631   // The delegate will cancel pending classification on destruction.
632   EXPECT_CALL(*classifier_, CancelPendingClassification());
633 }
634
635 }  // namespace safe_browsing