OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // Note that although this is not a "browser" test, it runs as part of | 5 // Note that although this is not a "browser" test, it runs as part of |
6 // browser_tests. This is because WebKit does not work properly if it is | 6 // browser_tests. This is because WebKit does not work properly if it is |
7 // shutdown and re-initialized. Since browser_tests runs each test in a | 7 // shutdown and re-initialized. Since browser_tests runs each test in a |
8 // new process, this avoids the problem. | 8 // new process, this avoids the problem. |
9 | 9 |
10 #include "chrome/renderer/safe_browsing/phishing_dom_feature_extractor.h" | 10 #include "chrome/renderer/safe_browsing/phishing_dom_feature_extractor.h" |
11 | 11 |
12 #include <string.h> // for memcpy() | 12 #include <string.h> // for memcpy() |
13 #include <map> | 13 #include <map> |
14 #include <string> | 14 #include <string> |
15 | 15 |
16 #include "base/callback.h" | 16 #include "base/callback.h" |
17 #include "base/command_line.h" | 17 #include "base/command_line.h" |
18 #include "base/message_loop.h" | 18 #include "base/message_loop.h" |
19 #include "base/process.h" | 19 #include "base/process.h" |
20 #include "base/string_util.h" | 20 #include "base/string_util.h" |
| 21 #include "base/time.h" |
21 #include "chrome/common/main_function_params.h" | 22 #include "chrome/common/main_function_params.h" |
22 #include "chrome/common/render_messages.h" | 23 #include "chrome/common/render_messages.h" |
23 #include "chrome/common/sandbox_init_wrapper.h" | 24 #include "chrome/common/sandbox_init_wrapper.h" |
24 #include "chrome/renderer/mock_render_process.h" | 25 #include "chrome/renderer/mock_render_process.h" |
25 #include "chrome/renderer/render_thread.h" | 26 #include "chrome/renderer/render_thread.h" |
26 #include "chrome/renderer/render_view.h" | 27 #include "chrome/renderer/render_view.h" |
27 #include "chrome/renderer/render_view_visitor.h" | 28 #include "chrome/renderer/render_view_visitor.h" |
28 #include "chrome/renderer/renderer_main_platform_delegate.h" | 29 #include "chrome/renderer/renderer_main_platform_delegate.h" |
| 30 #include "chrome/renderer/safe_browsing/feature_extractor_clock.h" |
29 #include "chrome/renderer/safe_browsing/features.h" | 31 #include "chrome/renderer/safe_browsing/features.h" |
30 #include "googleurl/src/gurl.h" | 32 #include "googleurl/src/gurl.h" |
31 #include "ipc/ipc_channel.h" | 33 #include "ipc/ipc_channel.h" |
32 #include "net/http/http_response_headers.h" | 34 #include "net/http/http_response_headers.h" |
33 #include "testing/gmock/include/gmock/gmock.h" | 35 #include "testing/gmock/include/gmock/gmock.h" |
34 #include "testing/gtest/include/gtest/gtest.h" | 36 #include "testing/gtest/include/gtest/gtest.h" |
35 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" | 37 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" |
36 #include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" | 38 #include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" |
37 #include "third_party/WebKit/WebKit/chromium/public/WebView.h" | 39 #include "third_party/WebKit/WebKit/chromium/public/WebView.h" |
38 #include "webkit/glue/webkit_glue.h" | 40 #include "webkit/glue/webkit_glue.h" |
39 | 41 |
40 using ::testing::ContainerEq; | 42 using ::testing::ContainerEq; |
| 43 using ::testing::Return; |
41 | 44 |
42 namespace safe_browsing { | 45 namespace safe_browsing { |
43 | 46 |
44 class PhishingDOMFeatureExtractorTest : public ::testing::Test, | 47 class PhishingDOMFeatureExtractorTest : public ::testing::Test, |
45 public IPC::Channel::Listener, | 48 public IPC::Channel::Listener, |
46 public RenderViewVisitor { | 49 public RenderViewVisitor { |
47 public: | 50 public: |
48 // IPC::Channel::Listener implementation. | 51 // IPC::Channel::Listener implementation. |
49 virtual void OnMessageReceived(const IPC::Message& message) { | 52 virtual void OnMessageReceived(const IPC::Message& message) { |
50 IPC_BEGIN_MESSAGE_MAP(PhishingDOMFeatureExtractorTest, message) | 53 IPC_BEGIN_MESSAGE_MAP(PhishingDOMFeatureExtractorTest, message) |
51 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnRenderViewReady) | 54 IPC_MESSAGE_HANDLER(ViewHostMsg_RenderViewReady, OnRenderViewReady) |
52 IPC_MESSAGE_HANDLER(ViewHostMsg_DidStopLoading, OnDidStopLoading) | 55 IPC_MESSAGE_HANDLER(ViewHostMsg_DidStopLoading, OnDidStopLoading) |
53 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestResource, OnRequestResource) | 56 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestResource, OnRequestResource) |
54 IPC_END_MESSAGE_MAP() | 57 IPC_END_MESSAGE_MAP() |
55 } | 58 } |
56 | 59 |
57 // RenderViewVisitor implementation. | 60 // RenderViewVisitor implementation. |
58 virtual bool Visit(RenderView* render_view) { | 61 virtual bool Visit(RenderView* render_view) { |
59 view_ = render_view; | 62 view_ = render_view; |
60 return false; | 63 return false; |
61 } | 64 } |
62 | 65 |
63 protected: | 66 protected: |
| 67 class MockClock : public FeatureExtractorClock { |
| 68 public: |
| 69 MOCK_METHOD0(Now, base::TimeTicks()); |
| 70 }; |
| 71 |
64 virtual void SetUp() { | 72 virtual void SetUp() { |
65 // Set up the renderer. This code is largely adapted from | 73 // Set up the renderer. This code is largely adapted from |
66 // render_view_test.cc and renderer_main.cc. Note that we use a | 74 // render_view_test.cc and renderer_main.cc. Note that we use a |
67 // MockRenderProcess (because we don't need to use IPC for painting), | 75 // MockRenderProcess (because we don't need to use IPC for painting), |
68 // but we use a real RenderThread so that we can use the ResourceDispatcher | 76 // but we use a real RenderThread so that we can use the ResourceDispatcher |
69 // to fetch network resources. These are then served canned content | 77 // to fetch network resources. These are then served canned content |
70 // in OnRequestResource(). | 78 // in OnRequestResource(). |
71 sandbox_init_wrapper_.reset(new SandboxInitWrapper); | 79 sandbox_init_wrapper_.reset(new SandboxInitWrapper); |
72 command_line_.reset(new CommandLine(CommandLine::ARGUMENTS_ONLY)); | 80 command_line_.reset(new CommandLine(CommandLine::ARGUMENTS_ONLY)); |
73 params_.reset(new MainFunctionParams(*command_line_, | 81 params_.reset(new MainFunctionParams(*command_line_, |
(...skipping 15 matching lines...) Expand all Loading... |
89 // We can't call View::Create() directly here or else we won't get | 97 // We can't call View::Create() directly here or else we won't get |
90 // RenderProcess's lazy initialization of WebKit. | 98 // RenderProcess's lazy initialization of WebKit. |
91 view_ = NULL; | 99 view_ = NULL; |
92 ViewMsg_New_Params params; | 100 ViewMsg_New_Params params; |
93 params.parent_window = 0; | 101 params.parent_window = 0; |
94 params.view_id = kViewId; | 102 params.view_id = kViewId; |
95 params.session_storage_namespace_id = kInvalidSessionStorageNamespaceId; | 103 params.session_storage_namespace_id = kInvalidSessionStorageNamespaceId; |
96 ASSERT_TRUE(channel_->Send(new ViewMsg_New(params))); | 104 ASSERT_TRUE(channel_->Send(new ViewMsg_New(params))); |
97 msg_loop_.Run(); | 105 msg_loop_.Run(); |
98 | 106 |
99 extractor_.reset(new PhishingDOMFeatureExtractor(view_)); | 107 clock_ = new MockClock(); |
| 108 extractor_.reset(new PhishingDOMFeatureExtractor(view_, clock_)); |
100 } | 109 } |
101 | 110 |
102 virtual void TearDown() { | 111 virtual void TearDown() { |
103 // Try very hard to collect garbage before shutting down. | 112 // Try very hard to collect garbage before shutting down. |
104 GetMainFrame()->collectGarbage(); | 113 GetMainFrame()->collectGarbage(); |
105 GetMainFrame()->collectGarbage(); | 114 GetMainFrame()->collectGarbage(); |
106 | 115 |
107 ASSERT_TRUE(channel_->Send(new ViewMsg_Close(kViewId))); | 116 ASSERT_TRUE(channel_->Send(new ViewMsg_Close(kViewId))); |
108 do { | 117 do { |
109 msg_loop_.RunAllPending(); | 118 msg_loop_.RunAllPending(); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 scoped_ptr<IPC::Channel> channel_; | 234 scoped_ptr<IPC::Channel> channel_; |
226 RenderThread* render_thread_; // owned by mock_process_ | 235 RenderThread* render_thread_; // owned by mock_process_ |
227 scoped_ptr<MockRenderProcess> mock_process_; | 236 scoped_ptr<MockRenderProcess> mock_process_; |
228 RenderView* view_; // not owned, deletes itself on close | 237 RenderView* view_; // not owned, deletes itself on close |
229 scoped_ptr<RendererMainPlatformDelegate> platform_; | 238 scoped_ptr<RendererMainPlatformDelegate> platform_; |
230 scoped_ptr<MainFunctionParams> params_; | 239 scoped_ptr<MainFunctionParams> params_; |
231 scoped_ptr<CommandLine> command_line_; | 240 scoped_ptr<CommandLine> command_line_; |
232 scoped_ptr<SandboxInitWrapper> sandbox_init_wrapper_; | 241 scoped_ptr<SandboxInitWrapper> sandbox_init_wrapper_; |
233 | 242 |
234 scoped_ptr<PhishingDOMFeatureExtractor> extractor_; | 243 scoped_ptr<PhishingDOMFeatureExtractor> extractor_; |
| 244 MockClock* clock_; // owned by extractor_ |
235 // Map of URL -> response body for network requests from the renderer. | 245 // Map of URL -> response body for network requests from the renderer. |
236 // Any URLs not in this map are served a 404 error. | 246 // Any URLs not in this map are served a 404 error. |
237 std::map<std::string, std::string> responses_; | 247 std::map<std::string, std::string> responses_; |
238 bool success_; // holds the success value from ExtractFeatures | 248 bool success_; // holds the success value from ExtractFeatures |
239 }; | 249 }; |
240 | 250 |
241 int PhishingDOMFeatureExtractorTest::next_thread_id_ = 0; | 251 int PhishingDOMFeatureExtractorTest::next_thread_id_ = 0; |
242 | 252 |
243 TEST_F(PhishingDOMFeatureExtractorTest, FormFeatures) { | 253 TEST_F(PhishingDOMFeatureExtractorTest, FormFeatures) { |
| 254 // This test doesn't exercise the extraction timing. |
| 255 EXPECT_CALL(*clock_, Now()).WillRepeatedly(Return(base::TimeTicks::Now())); |
244 responses_["http://host.com/"] = | 256 responses_["http://host.com/"] = |
245 "<html><head><body>" | 257 "<html><head><body>" |
246 "<form action=\"query\"><input type=text><input type=checkbox></form>" | 258 "<form action=\"query\"><input type=text><input type=checkbox></form>" |
247 "<form action=\"http://cgi.host.com/submit\"></form>" | 259 "<form action=\"http://cgi.host.com/submit\"></form>" |
248 "<form action=\"http://other.com/\"></form>" | 260 "<form action=\"http://other.com/\"></form>" |
249 "<form action=\"query\"></form>" | 261 "<form action=\"query\"></form>" |
250 "<form></form></body></html>"; | 262 "<form></form></body></html>"; |
251 | 263 |
252 FeatureMap expected_features; | 264 FeatureMap expected_features; |
253 expected_features.AddBooleanFeature(features::kPageHasForms); | 265 expected_features.AddBooleanFeature(features::kPageHasForms); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 expected_features.Clear(); | 302 expected_features.Clear(); |
291 expected_features.AddBooleanFeature(features::kPageHasTextInputs); | 303 expected_features.AddBooleanFeature(features::kPageHasTextInputs); |
292 | 304 |
293 features.Clear(); | 305 features.Clear(); |
294 LoadURL("http://host.com/"); | 306 LoadURL("http://host.com/"); |
295 ASSERT_TRUE(ExtractFeatures(&features)); | 307 ASSERT_TRUE(ExtractFeatures(&features)); |
296 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); | 308 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); |
297 } | 309 } |
298 | 310 |
299 TEST_F(PhishingDOMFeatureExtractorTest, LinkFeatures) { | 311 TEST_F(PhishingDOMFeatureExtractorTest, LinkFeatures) { |
| 312 // This test doesn't exercise the extraction timing. |
| 313 EXPECT_CALL(*clock_, Now()).WillRepeatedly(Return(base::TimeTicks::Now())); |
300 responses_["http://www.host.com/"] = | 314 responses_["http://www.host.com/"] = |
301 "<html><head><body>" | 315 "<html><head><body>" |
302 "<a href=\"http://www2.host.com/abc\">link</a>" | 316 "<a href=\"http://www2.host.com/abc\">link</a>" |
303 "<a name=page_anchor></a>" | 317 "<a name=page_anchor></a>" |
304 "<a href=\"http://www.chromium.org/\">chromium</a>" | 318 "<a href=\"http://www.chromium.org/\">chromium</a>" |
305 "</body></html"; | 319 "</body></html"; |
306 | 320 |
307 FeatureMap expected_features; | 321 FeatureMap expected_features; |
308 expected_features.AddRealFeature(features::kPageExternalLinksFreq, 0.5); | 322 expected_features.AddRealFeature(features::kPageExternalLinksFreq, 0.5); |
309 expected_features.AddRealFeature(features::kPageSecureLinksFreq, 0.0); | 323 expected_features.AddRealFeature(features::kPageSecureLinksFreq, 0.0); |
(...skipping 20 matching lines...) Expand all Loading... |
330 expected_features.AddBooleanFeature(features::kPageLinkDomain + | 344 expected_features.AddBooleanFeature(features::kPageLinkDomain + |
331 std::string("chromium.org")); | 345 std::string("chromium.org")); |
332 | 346 |
333 features.Clear(); | 347 features.Clear(); |
334 LoadURL("https://www.host.com/"); | 348 LoadURL("https://www.host.com/"); |
335 ASSERT_TRUE(ExtractFeatures(&features)); | 349 ASSERT_TRUE(ExtractFeatures(&features)); |
336 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); | 350 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); |
337 } | 351 } |
338 | 352 |
339 TEST_F(PhishingDOMFeatureExtractorTest, ScriptAndImageFeatures) { | 353 TEST_F(PhishingDOMFeatureExtractorTest, ScriptAndImageFeatures) { |
| 354 // This test doesn't exercise the extraction timing. |
| 355 EXPECT_CALL(*clock_, Now()).WillRepeatedly(Return(base::TimeTicks::Now())); |
340 responses_["http://host.com/"] = | 356 responses_["http://host.com/"] = |
341 "<html><head><script></script><script></script></head></html>"; | 357 "<html><head><script></script><script></script></head></html>"; |
342 | 358 |
343 FeatureMap expected_features; | 359 FeatureMap expected_features; |
344 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTOne); | 360 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTOne); |
345 | 361 |
346 FeatureMap features; | 362 FeatureMap features; |
347 LoadURL("http://host.com/"); | 363 LoadURL("http://host.com/"); |
348 ASSERT_TRUE(ExtractFeatures(&features)); | 364 ASSERT_TRUE(ExtractFeatures(&features)); |
349 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); | 365 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); |
350 | 366 |
351 responses_["http://host.com/"] = | 367 responses_["http://host.com/"] = |
352 "<html><head><script></script><script></script><script></script>" | 368 "<html><head><script></script><script></script><script></script>" |
353 "<script></script><script></script><script></script><script></script>" | 369 "<script></script><script></script><script></script><script></script>" |
354 "</head><body><img src=\"blah.gif\">" | 370 "</head><body><img src=\"blah.gif\">" |
355 "<img src=\"http://host2.com/blah.gif\"></body></html>"; | 371 "<img src=\"http://host2.com/blah.gif\"></body></html>"; |
356 | 372 |
357 expected_features.Clear(); | 373 expected_features.Clear(); |
358 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTOne); | 374 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTOne); |
359 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTSix); | 375 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTSix); |
360 expected_features.AddRealFeature(features::kPageImgOtherDomainFreq, 0.5); | 376 expected_features.AddRealFeature(features::kPageImgOtherDomainFreq, 0.5); |
361 | 377 |
362 features.Clear(); | 378 features.Clear(); |
363 LoadURL("http://host.com/"); | 379 LoadURL("http://host.com/"); |
364 ASSERT_TRUE(ExtractFeatures(&features)); | 380 ASSERT_TRUE(ExtractFeatures(&features)); |
365 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); | 381 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); |
366 } | 382 } |
367 | 383 |
368 TEST_F(PhishingDOMFeatureExtractorTest, SubFrames) { | 384 TEST_F(PhishingDOMFeatureExtractorTest, SubFrames) { |
| 385 // This test doesn't exercise the extraction timing. |
| 386 EXPECT_CALL(*clock_, Now()).WillRepeatedly(Return(base::TimeTicks::Now())); |
| 387 |
369 // Test that features are aggregated across all frames. | 388 // Test that features are aggregated across all frames. |
370 responses_["http://host.com/"] = | 389 responses_["http://host.com/"] = |
371 "<html><body><input type=text><a href=\"info.html\">link</a>" | 390 "<html><body><input type=text><a href=\"info.html\">link</a>" |
372 "<iframe src=\"http://host2.com/\"></iframe>" | 391 "<iframe src=\"http://host2.com/\"></iframe>" |
373 "<iframe src=\"http://host3.com/\"></iframe>" | 392 "<iframe src=\"http://host3.com/\"></iframe>" |
374 "</body></html>"; | 393 "</body></html>"; |
375 | 394 |
376 responses_["http://host2.com/"] = | 395 responses_["http://host2.com/"] = |
377 "<html><head><script></script><body>" | 396 "<html><head><script></script><body>" |
378 "<form action=\"http://host4.com/\"><input type=checkbox></form>" | 397 "<form action=\"http://host4.com/\"><input type=checkbox></form>" |
(...skipping 28 matching lines...) Expand all Loading... |
407 expected_features.AddRealFeature(features::kPageSecureLinksFreq, 0.25); | 426 expected_features.AddRealFeature(features::kPageSecureLinksFreq, 0.25); |
408 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTOne); | 427 expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTOne); |
409 expected_features.AddRealFeature(features::kPageImgOtherDomainFreq, 1.0); | 428 expected_features.AddRealFeature(features::kPageImgOtherDomainFreq, 1.0); |
410 | 429 |
411 FeatureMap features; | 430 FeatureMap features; |
412 LoadURL("http://host.com/"); | 431 LoadURL("http://host.com/"); |
413 ASSERT_TRUE(ExtractFeatures(&features)); | 432 ASSERT_TRUE(ExtractFeatures(&features)); |
414 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); | 433 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); |
415 } | 434 } |
416 | 435 |
417 // TODO(bryner): Test extraction with multiple passes, including the case where | 436 TEST_F(PhishingDOMFeatureExtractorTest, Continuation) { |
418 // the node we stopped on is removed from the document. | 437 // For this test, we'll cause the feature extraction to run multiple |
| 438 // iterations by incrementing the clock. |
| 439 |
| 440 // This page has a total of 50 elements. For the external forms feature to |
| 441 // be computed correctly, the extractor has to examine the whole document. |
| 442 // Note: the empty HEAD is important -- WebKit will synthesize a HEAD if |
| 443 // there isn't one present, which can be confusing for the element counts. |
| 444 std::string response = "<html><head></head><body>" |
| 445 "<form action=\"ondomain\"></form>"; |
| 446 for (int i = 0; i < 45; ++i) { |
| 447 response.append("<p>"); |
| 448 } |
| 449 response.append("<form action=\"http://host2.com/\"></form></body></html>"); |
| 450 responses_["http://host.com/"] = response; |
| 451 |
| 452 // Advance the clock 30 ms every 10 elements processed, 10 ms between chunks. |
| 453 // Note that this assumes kClockCheckGranularity = 10 and |
| 454 // kMaxTimePerChunkMs = 50. |
| 455 base::TimeTicks now = base::TimeTicks::Now(); |
| 456 EXPECT_CALL(*clock_, Now()) |
| 457 // Time check at the start of extraction. |
| 458 .WillOnce(Return(now)) |
| 459 // Time check at the start of the first chunk of work. |
| 460 .WillOnce(Return(now)) |
| 461 // Time check after the first 10 elements. |
| 462 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(30))) |
| 463 // Time check after the next 10 elements. This is over the chunk |
| 464 // time limit, so a continuation task will be posted. |
| 465 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(60))) |
| 466 // Time check at the start of the second chunk of work. |
| 467 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(70))) |
| 468 // Time check after resuming iteration for the second chunk. |
| 469 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(72))) |
| 470 // Time check after the next 10 elements. |
| 471 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(100))) |
| 472 // Time check after the next 10 elements. This will trigger another |
| 473 // continuation task. |
| 474 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(130))) |
| 475 // Time check at the start of the third chunk of work. |
| 476 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(140))) |
| 477 // Time check after resuming iteration for the third chunk. |
| 478 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(142))) |
| 479 // Time check after the last 10 elements. |
| 480 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(170))) |
| 481 // A final time check for the histograms. |
| 482 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(180))); |
| 483 |
| 484 FeatureMap expected_features; |
| 485 expected_features.AddBooleanFeature(features::kPageHasForms); |
| 486 expected_features.AddRealFeature(features::kPageActionOtherDomainFreq, 0.5); |
| 487 |
| 488 FeatureMap features; |
| 489 LoadURL("http://host.com/"); |
| 490 ASSERT_TRUE(ExtractFeatures(&features)); |
| 491 EXPECT_THAT(features.features(), ContainerEq(expected_features.features())); |
| 492 // Make sure none of the mock expectations carry over to the next test. |
| 493 ::testing::Mock::VerifyAndClearExpectations(clock_); |
| 494 |
| 495 // Now repeat the test with the same page, but advance the clock faster so |
| 496 // that the extraction time exceeds the maximum total time for the feature |
| 497 // extractor. Extraction should fail. Note that this assumes |
| 498 // kMaxTotalTimeMs = 500. |
| 499 EXPECT_CALL(*clock_, Now()) |
| 500 // Time check at the start of extraction. |
| 501 .WillOnce(Return(now)) |
| 502 // Time check at the start of the first chunk of work. |
| 503 .WillOnce(Return(now)) |
| 504 // Time check after the first 10 elements. |
| 505 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(300))) |
| 506 // Time check at the start of the second chunk of work. |
| 507 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(350))) |
| 508 // Time check after resuming iteration for the second chunk. |
| 509 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(360))) |
| 510 // Time check after the next 10 elements. This is over the limit. |
| 511 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(600))) |
| 512 // A final time check for the histograms. |
| 513 .WillOnce(Return(now + base::TimeDelta::FromMilliseconds(620))); |
| 514 |
| 515 features.Clear(); |
| 516 EXPECT_FALSE(ExtractFeatures(&features)); |
| 517 } |
419 | 518 |
420 } // namespace safe_browsing | 519 } // namespace safe_browsing |
OLD | NEW |