| Index: chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
 | 
| diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
 | 
| index c490bd1534a41a41e18362df57511ef1e4553488..a1c26049c02dd53e9ae4019260c7839ec22b49c1 100644
 | 
| --- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
 | 
| +++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
 | 
| @@ -6,6 +6,7 @@
 | 
|  #include "base/memory/ref_counted.h"
 | 
|  #include "base/memory/scoped_ptr.h"
 | 
|  #include "base/task.h"
 | 
| +#include "chrome/browser/safe_browsing/browser_feature_extractor.h"
 | 
|  #include "chrome/browser/safe_browsing/client_side_detection_host.h"
 | 
|  #include "chrome/browser/safe_browsing/client_side_detection_service.h"
 | 
|  #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 | 
| @@ -48,6 +49,11 @@ MATCHER_P(EqualsProto, other, "") {
 | 
|    return other.SerializeAsString() == arg.SerializeAsString();
 | 
|  }
 | 
|  
 | 
| +ACTION(QuitUIMessageLoop) {
 | 
| +  EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
 | 
| +  MessageLoopForUI::current()->Quit();
 | 
| +}
 | 
| +
 | 
|  class MockClientSideDetectionService : public ClientSideDetectionService {
 | 
|   public:
 | 
|    MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
 | 
| @@ -95,8 +101,18 @@ class MockTestingProfile : public TestingProfile {
 | 
|    MOCK_METHOD0(IsOffTheRecord, bool());
 | 
|  };
 | 
|  
 | 
| +class MockBrowserFeatureExtractor : public BrowserFeatureExtractor {
 | 
| + public:
 | 
| +  explicit MockBrowserFeatureExtractor(TabContents* tab)
 | 
| +      : BrowserFeatureExtractor(tab) {}
 | 
| +  virtual ~MockBrowserFeatureExtractor() {}
 | 
| +
 | 
| +  MOCK_METHOD2(ExtractFeatures, void(ClientPhishingRequest*,
 | 
| +                                     BrowserFeatureExtractor::DoneCallback*));
 | 
| +};
 | 
| +
 | 
|  // Helper function which quits the UI message loop from the IO message loop.
 | 
| -void QuitUIMessageLoop() {
 | 
| +void QuitUIMessageLoopFromIO() {
 | 
|    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
 | 
|    BrowserThread::PostTask(BrowserThread::UI,
 | 
|                            FROM_HERE,
 | 
| @@ -144,7 +160,7 @@ class ClientSideDetectionHostTest : public TabContentsWrapperTestHarness {
 | 
|      // we put the quit message there.
 | 
|      BrowserThread::PostTask(BrowserThread::IO,
 | 
|                              FROM_HERE,
 | 
| -                            NewRunnableFunction(&QuitUIMessageLoop));
 | 
| +                            NewRunnableFunction(&QuitUIMessageLoopFromIO));
 | 
|      MessageLoop::current()->Run();
 | 
|    }
 | 
|  
 | 
| @@ -191,6 +207,10 @@ class ClientSideDetectionHostTest : public TabContentsWrapperTestHarness {
 | 
|      EXPECT_TRUE(Mock::VerifyAndClear(mock_profile_));
 | 
|    }
 | 
|  
 | 
| +  void SetFeatureExtractor(BrowserFeatureExtractor* extractor) {
 | 
| +    csd_host_->feature_extractor_.reset(extractor);
 | 
| +  }
 | 
| +
 | 
|   protected:
 | 
|    ClientSideDetectionHost* csd_host_;
 | 
|    scoped_ptr<StrictMock<MockClientSideDetectionService> > csd_service_;
 | 
| @@ -205,9 +225,12 @@ class ClientSideDetectionHostTest : public TabContentsWrapperTestHarness {
 | 
|  TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteInvalidVerdict) {
 | 
|    // Case 0: renderer sends an invalid verdict string that we're unable to
 | 
|    // parse.
 | 
| -  EXPECT_CALL(*csd_service_, SendClientReportPhishingRequest(_, _)).Times(0);
 | 
| +  MockBrowserFeatureExtractor* mock_extractor = new MockBrowserFeatureExtractor(
 | 
| +      contents());
 | 
| +  SetFeatureExtractor(mock_extractor);  // The host class takes ownership.
 | 
| +  EXPECT_CALL(*mock_extractor, ExtractFeatures(_, _)).Times(0);
 | 
|    OnDetectedPhishingSite("Invalid Protocol Buffer");
 | 
| -  EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 | 
| +  EXPECT_TRUE(Mock::VerifyAndClear(mock_extractor));
 | 
|  }
 | 
|  
 | 
|  TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteNotPhishing) {
 | 
| @@ -221,8 +244,9 @@ TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteNotPhishing) {
 | 
|  
 | 
|    EXPECT_CALL(*csd_service_,
 | 
|                SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
 | 
| -      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
 | 
| +      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb), QuitUIMessageLoop()));
 | 
|    OnDetectedPhishingSite(verdict.SerializeAsString());
 | 
| +  MessageLoop::current()->Run();
 | 
|    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 | 
|    ASSERT_TRUE(cb);
 | 
|  
 | 
| @@ -245,8 +269,9 @@ TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteDisabled) {
 | 
|  
 | 
|    EXPECT_CALL(*csd_service_,
 | 
|                SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
 | 
| -      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
 | 
| +      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb), QuitUIMessageLoop()));
 | 
|    OnDetectedPhishingSite(verdict.SerializeAsString());
 | 
| +  MessageLoop::current()->Run();
 | 
|    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 | 
|    ASSERT_TRUE(cb);
 | 
|  
 | 
| @@ -270,8 +295,9 @@ TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteShowInterstitial) {
 | 
|  
 | 
|    EXPECT_CALL(*csd_service_,
 | 
|                SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
 | 
| -      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
 | 
| +      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb), QuitUIMessageLoop()));
 | 
|    OnDetectedPhishingSite(verdict.SerializeAsString());
 | 
| +  MessageLoop::current()->Run();
 | 
|    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 | 
|    ASSERT_TRUE(cb);
 | 
|  
 | 
| @@ -322,8 +348,9 @@ TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteMultiplePings) {
 | 
|  
 | 
|    EXPECT_CALL(*csd_service_,
 | 
|                SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
 | 
| -      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb)));
 | 
| +      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb), QuitUIMessageLoop()));
 | 
|    OnDetectedPhishingSite(verdict.SerializeAsString());
 | 
| +  MessageLoop::current()->Run();
 | 
|    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 | 
|    ASSERT_TRUE(cb);
 | 
|    GURL other_phishing_url("http://other_phishing_url.com/bla");
 | 
| @@ -339,8 +366,11 @@ TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteMultiplePings) {
 | 
|    verdict.set_client_score(0.8f);
 | 
|    EXPECT_CALL(*csd_service_,
 | 
|                SendClientReportPhishingRequest(Pointee(EqualsProto(verdict)), _))
 | 
| -      .WillOnce(DoAll(DeleteArg<0>(), SaveArg<1>(&cb_other)));
 | 
| +      .WillOnce(DoAll(DeleteArg<0>(),
 | 
| +                      SaveArg<1>(&cb_other),
 | 
| +                      QuitUIMessageLoop()));
 | 
|    OnDetectedPhishingSite(verdict.SerializeAsString());
 | 
| +  MessageLoop::current()->Run();
 | 
|    EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get()));
 | 
|    ASSERT_TRUE(cb_other);
 | 
|  
 | 
| 
 |