Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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 "base/command_line.h" | |
| 6 #include "base/file_path.h" | |
| 7 #include "base/ref_counted.h" | |
| 8 #include "base/scoped_ptr.h" | |
| 9 #include "base/scoped_temp_dir.h" | |
| 10 #include "base/task.h" | |
| 11 #include "chrome/browser/browser_thread.h" | |
| 12 #include "chrome/browser/renderer_host/test/test_render_view_host.h" | |
| 13 #include "chrome/browser/safe_browsing/client_side_detection_host.h" | |
| 14 #include "chrome/browser/safe_browsing/client_side_detection_service.h" | |
| 15 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | |
| 16 #include "chrome/browser/tab_contents/test_tab_contents.h" | |
| 17 #include "chrome/common/chrome_switches.h" | |
| 18 #include "chrome/test/ui_test_utils.h" | |
| 19 #include "googleurl/src/gurl.h" | |
| 20 #include "testing/gmock/include/gmock/gmock.h" | |
| 21 #include "testing/gmock/include/gmock/gmock-spec-builders.h" | |
| 22 | |
| 23 using ::testing::_; | |
| 24 using ::testing::DoAll; | |
| 25 using ::testing::Mock; | |
| 26 using ::testing::SaveArg; | |
| 27 | |
| 28 namespace safe_browsing { | |
| 29 | |
| 30 class MockClientSideDetectionService : public ClientSideDetectionService { | |
| 31 public: | |
| 32 MockClientSideDetectionService(const FilePath& model_path) | |
| 33 : ClientSideDetectionService(model_path, NULL) {} | |
| 34 virtual ~MockClientSideDetectionService() {}; | |
| 35 | |
| 36 MOCK_METHOD3(SendClientReportPhishingRequest, | |
| 37 void(const GURL&, double, ClientReportPhishingRequestCallback*)); | |
| 38 | |
| 39 private: | |
| 40 DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService); | |
| 41 }; | |
| 42 | |
| 43 class MockSafeBrowsingService : public SafeBrowsingService { | |
| 44 public: | |
| 45 MockSafeBrowsingService() {} | |
| 46 virtual ~MockSafeBrowsingService() {} | |
| 47 | |
| 48 MOCK_METHOD8(DisplayBlockingPage, | |
| 49 void(const GURL&, const GURL&, const std::vector<GURL>&, | |
| 50 ResourceType::Type, UrlCheckResult, Client*, int, int)); | |
| 51 | |
| 52 // Helper function which calls OnBlockingPageComplete for this client | |
| 53 // object. | |
| 54 void InvokeOnBlockingPageComplete(SafeBrowsingService::Client* client) { | |
| 55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 56 DCHECK(client); | |
| 57 // Note: this will delete the client object in the case of the CsdClient | |
| 58 // implementation. | |
| 59 client->OnBlockingPageComplete(false); | |
| 60 } | |
| 61 | |
| 62 private: | |
| 63 DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService); | |
| 64 }; | |
| 65 | |
| 66 // Helper function which quits the UI message loop from the IO message loop. | |
| 67 void QuitUIMessageLoop() { | |
| 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 69 BrowserThread::PostTask(BrowserThread::UI, | |
| 70 FROM_HERE, | |
| 71 new MessageLoop::QuitTask()); | |
| 72 } | |
| 73 | |
| 74 class ClientSideDetectionHostTest : public RenderViewHostTestHarness { | |
| 75 public: | |
| 76 virtual void SetUp() { | |
| 77 RenderViewHostTestHarness::SetUp(); | |
| 78 ui_thread_.reset(new BrowserThread(BrowserThread::UI, &message_loop_)); | |
| 79 // Note: we're starting a real IO thread to make sure our DCHECKs that | |
| 80 // verify which thread is running are actually tested. | |
| 81 io_thread_.reset(new BrowserThread(BrowserThread::IO)); | |
| 82 CHECK(io_thread_->Start()); | |
|
Brian Ryner
2011/02/16 22:37:10
I've been told in the past to prefer ASSERT_TRUE o
noelutz
2011/02/16 23:22:36
Done.
| |
| 83 | |
| 84 // Inject service classes. | |
| 85 ScopedTempDir tmp_dir; | |
| 86 ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); | |
| 87 FilePath model_path = tmp_dir.path().AppendASCII("model"); | |
| 88 | |
| 89 csd_service_.reset(new MockClientSideDetectionService(model_path)); | |
| 90 sb_service_ = new MockSafeBrowsingService(); | |
| 91 csd_host_ = contents()->safebrowsing_detection_host(); | |
| 92 csd_host_->set_client_side_detection_service(csd_service_.get()); | |
| 93 csd_host_->set_safe_browsing_service(sb_service_.get()); | |
| 94 } | |
| 95 | |
| 96 virtual void TearDown() { | |
| 97 io_thread_->Stop(); | |
|
Brian Ryner
2011/02/16 22:37:10
I think the thread stops automatically when it is
noelutz
2011/02/16 23:22:36
Done.
| |
| 98 io_thread_.reset(); | |
| 99 ui_thread_.reset(); | |
| 100 RenderViewHostTestHarness::TearDown(); | |
| 101 } | |
| 102 | |
| 103 void OnDetectedPhishingSite(const GURL& phishing_url, double phishing_score) { | |
| 104 csd_host_->OnDetectedPhishingSite(phishing_url, phishing_score); | |
| 105 } | |
| 106 | |
| 107 protected: | |
| 108 ClientSideDetectionHost* csd_host_; | |
| 109 scoped_ptr<MockClientSideDetectionService> csd_service_; | |
| 110 scoped_refptr<MockSafeBrowsingService> sb_service_; | |
| 111 | |
| 112 private: | |
| 113 scoped_ptr<BrowserThread> ui_thread_; | |
| 114 scoped_ptr<BrowserThread> io_thread_; | |
| 115 }; | |
| 116 | |
| 117 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteNotPhishing) { | |
| 118 // Case 1: client thinks the page is phishing. The server does not agree. | |
| 119 // No interstitial is shown. | |
| 120 ClientSideDetectionService::ClientReportPhishingRequestCallback* cb; | |
| 121 GURL phishing_url("http://phishingurl.com/"); | |
| 122 | |
| 123 EXPECT_CALL(*csd_service_, | |
| 124 SendClientReportPhishingRequest(phishing_url, 1.0, _)) | |
| 125 .WillOnce(SaveArg<2>(&cb)); | |
| 126 OnDetectedPhishingSite(phishing_url, 1.0); | |
| 127 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get())); | |
| 128 ASSERT_TRUE(cb != NULL); | |
| 129 | |
| 130 // Make sure DisplayBlockingPage is not going to be called. | |
| 131 EXPECT_CALL(*sb_service_, | |
| 132 DisplayBlockingPage(_, _, _, _, _, _, _, _)).Times(0); | |
| 133 cb->Run(phishing_url, false); | |
| 134 delete cb; | |
| 135 // If there was a message posted on the IO thread to display the | |
| 136 // interstitial page we know that it would have been posted before | |
| 137 // we put the quit message there. | |
| 138 BrowserThread::PostTask(BrowserThread::IO, | |
| 139 FROM_HERE, | |
| 140 NewRunnableFunction(&QuitUIMessageLoop)); | |
| 141 MessageLoop::current()->Run(); | |
| 142 EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get())); | |
| 143 } | |
| 144 | |
| 145 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteDisabled) { | |
| 146 // Case 2: client thinks the page is phishing and so does the server but | |
| 147 // showing the interstitial is disabled => no interstitial is shown. | |
| 148 ClientSideDetectionService::ClientReportPhishingRequestCallback* cb; | |
| 149 GURL phishing_url("http://phishingurl.com/"); | |
| 150 | |
| 151 EXPECT_CALL(*csd_service_, | |
| 152 SendClientReportPhishingRequest(phishing_url, 1.0, _)) | |
| 153 .WillOnce(SaveArg<2>(&cb)); | |
| 154 OnDetectedPhishingSite(phishing_url, 1.0); | |
| 155 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get())); | |
| 156 ASSERT_TRUE(cb != NULL); | |
| 157 | |
| 158 // Make sure DisplayBlockingPage is not going to be called. | |
| 159 EXPECT_CALL(*sb_service_, | |
| 160 DisplayBlockingPage(_, _, _, _, _, _, _, _)).Times(0); | |
| 161 cb->Run(phishing_url, false); | |
| 162 delete cb; | |
| 163 | |
| 164 // If there was a message posted on the IO thread to display the | |
|
Brian Ryner
2011/02/16 22:37:10
You could factor this out into a helper method, th
noelutz
2011/02/16 23:22:36
Done.
noelutz
2011/02/16 23:22:36
Done.
| |
| 165 // interstitial page we know that it would have been posted before | |
| 166 // we put the quit message there. | |
| 167 BrowserThread::PostTask(BrowserThread::IO, | |
| 168 FROM_HERE, | |
| 169 NewRunnableFunction(&QuitUIMessageLoop)); | |
| 170 MessageLoop::current()->Run(); | |
| 171 EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get())); | |
| 172 } | |
| 173 | |
| 174 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteShowInterstitial) { | |
| 175 // Case 3: client thinks the page is phishing and so does the server. | |
| 176 // We show an interstitial. | |
| 177 ClientSideDetectionService::ClientReportPhishingRequestCallback* cb; | |
| 178 GURL phishing_url("http://phishingurl.com/"); | |
| 179 | |
| 180 CommandLine::ForCurrentProcess()->AppendSwitch( | |
| 181 switches::kEnableClientSidePhishingInterstitial); | |
| 182 | |
| 183 EXPECT_CALL(*csd_service_, | |
| 184 SendClientReportPhishingRequest(phishing_url, 1.0, _)) | |
| 185 .WillOnce(SaveArg<2>(&cb)); | |
| 186 OnDetectedPhishingSite(phishing_url, 1.0); | |
| 187 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get())); | |
| 188 ASSERT_TRUE(cb != NULL); | |
| 189 | |
| 190 SafeBrowsingService::Client* client; | |
| 191 EXPECT_CALL(*sb_service_, | |
| 192 DisplayBlockingPage( | |
| 193 phishing_url, | |
| 194 phishing_url, | |
| 195 _, | |
| 196 ResourceType::MAIN_FRAME, | |
| 197 SafeBrowsingService::URL_PHISHING, | |
| 198 _ /* a CsdClient object */, | |
| 199 contents()->GetRenderProcessHost()->id(), | |
| 200 contents()->render_view_host()->routing_id())) | |
| 201 .WillOnce(SaveArg<5>(&client)); | |
| 202 | |
| 203 cb->Run(phishing_url, true); | |
| 204 delete cb; | |
| 205 | |
| 206 BrowserThread::PostTask(BrowserThread::IO, | |
| 207 FROM_HERE, | |
| 208 NewRunnableFunction(&QuitUIMessageLoop)); | |
| 209 MessageLoop::current()->Run(); | |
| 210 EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get())); | |
| 211 | |
| 212 // Make sure the client object will be deleted. | |
| 213 BrowserThread::PostTask( | |
| 214 BrowserThread::IO, | |
| 215 FROM_HERE, | |
| 216 NewRunnableMethod( | |
| 217 sb_service_.get(), | |
| 218 &MockSafeBrowsingService::InvokeOnBlockingPageComplete, | |
| 219 client)); | |
| 220 // Since the CsdClient object will be deleted on the UI thread I need | |
| 221 // to run the UI message loop. Post a task to stop the UI message loop | |
| 222 // after the client object destructor is called. | |
| 223 BrowserThread::PostTask(BrowserThread::IO, | |
| 224 FROM_HERE, | |
| 225 NewRunnableFunction(&QuitUIMessageLoop)); | |
| 226 MessageLoop::current()->Run(); | |
| 227 } | |
| 228 | |
| 229 TEST_F(ClientSideDetectionHostTest, OnDetectedPhishingSiteMultiplePings) { | |
| 230 // Case 4 & 5: client thinks a page is phishing then navigates to | |
| 231 // another page which is also considered phishing by the client | |
| 232 // before the server responds with a verdict. After a while the | |
| 233 // server responds for both requests with a phishing verdict. Only | |
| 234 // a single interstitial is shown for the second URL. | |
| 235 ClientSideDetectionService::ClientReportPhishingRequestCallback* cb; | |
| 236 GURL phishing_url("http://phishingurl.com/"); | |
| 237 | |
| 238 CommandLine::ForCurrentProcess()->AppendSwitch( | |
| 239 switches::kEnableClientSidePhishingInterstitial); | |
| 240 | |
| 241 EXPECT_CALL(*csd_service_, | |
| 242 SendClientReportPhishingRequest(phishing_url, 1.0, _)) | |
| 243 .WillOnce(SaveArg<2>(&cb)); | |
| 244 OnDetectedPhishingSite(phishing_url, 1.0); | |
| 245 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get())); | |
| 246 ASSERT_TRUE(cb != NULL); | |
| 247 GURL other_phishing_url("http://other_phishing_url.com/bla"); | |
| 248 // We navigate away. The callback cb should be revoked. | |
| 249 NavigateAndCommit(other_phishing_url); | |
| 250 | |
| 251 ClientSideDetectionService::ClientReportPhishingRequestCallback* cb_other; | |
| 252 EXPECT_CALL(*csd_service_, | |
| 253 SendClientReportPhishingRequest(other_phishing_url, 0.8, _)) | |
| 254 .WillOnce(SaveArg<2>(&cb_other)); | |
| 255 OnDetectedPhishingSite(other_phishing_url, 0.8); | |
| 256 EXPECT_TRUE(Mock::VerifyAndClear(csd_service_.get())); | |
| 257 ASSERT_TRUE(cb_other); | |
| 258 | |
| 259 // We expect that the interstitial is shown for the second phishing URL. | |
|
Brian Ryner
2011/02/16 22:37:10
Do you want to add an EXPECT_CALL for the first ur
| |
| 260 SafeBrowsingService::Client* client; | |
| 261 EXPECT_CALL(*sb_service_, | |
| 262 DisplayBlockingPage( | |
| 263 other_phishing_url, | |
| 264 other_phishing_url, | |
| 265 _, | |
| 266 ResourceType::MAIN_FRAME, | |
| 267 SafeBrowsingService::URL_PHISHING, | |
| 268 _ /* a CsdClient object */, | |
| 269 contents()->GetRenderProcessHost()->id(), | |
| 270 contents()->render_view_host()->routing_id())) | |
| 271 .WillOnce(SaveArg<5>(&client)); | |
| 272 | |
| 273 cb->Run(phishing_url, true); // Should have no effect. | |
| 274 delete cb; | |
| 275 cb_other->Run(other_phishing_url, true); // Should show interstitial. | |
| 276 delete cb_other; | |
| 277 | |
| 278 BrowserThread::PostTask(BrowserThread::IO, | |
| 279 FROM_HERE, | |
| 280 NewRunnableFunction(&QuitUIMessageLoop)); | |
| 281 MessageLoop::current()->Run(); | |
| 282 EXPECT_TRUE(Mock::VerifyAndClear(sb_service_.get())); | |
| 283 | |
| 284 // Make sure the client object will be deleted. | |
| 285 BrowserThread::PostTask( | |
| 286 BrowserThread::IO, | |
| 287 FROM_HERE, | |
| 288 NewRunnableMethod( | |
| 289 sb_service_.get(), | |
| 290 &MockSafeBrowsingService::InvokeOnBlockingPageComplete, | |
| 291 client)); | |
| 292 // Since the CsdClient object will be deleted on the UI thread I need | |
| 293 // to run the UI message loop. Post a task to stop the UI message loop | |
| 294 // after the client object destructor is called. | |
| 295 BrowserThread::PostTask(BrowserThread::IO, | |
| 296 FROM_HERE, | |
| 297 NewRunnableFunction(&QuitUIMessageLoop)); | |
| 298 MessageLoop::current()->Run(); | |
| 299 } | |
| 300 | |
| 301 } // namespace safe_browsing | |
| OLD | NEW |