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 |