Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(637)

Side by Side Diff: chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win_unittest.cc

Issue 2906103002: Post-cleanup settings reset. (Closed)
Patch Set: Use base::DoNothing Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 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 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_ win.h" 5 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_ win.h"
6 6
7 #include <string> 7 #include <string>
8 #include <tuple> 8 #include <tuple>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/callback_helpers.h"
11 #include "base/command_line.h" 12 #include "base/command_line.h"
12 #include "base/run_loop.h" 13 #include "base/run_loop.h"
13 #include "base/task_scheduler/post_task.h" 14 #include "base/task_scheduler/post_task.h"
14 #include "base/test/multiprocess_test.h" 15 #include "base/test/multiprocess_test.h"
15 #include "base/test/scoped_feature_list.h" 16 #include "base/test/scoped_feature_list.h"
16 #include "base/threading/thread_task_runner_handle.h" 17 #include "base/threading/thread_task_runner_handle.h"
17 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" 18 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_proces s_win.h" 21 #include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_proces s_win.h"
19 #include "chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h" 22 #include "chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h"
20 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h" 23 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
24 #include "chrome/test/base/testing_browser_process.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "chrome/test/base/testing_profile_manager.h"
21 #include "components/chrome_cleaner/public/constants/constants.h" 27 #include "components/chrome_cleaner/public/constants/constants.h"
22 #include "content/public/browser/browser_thread.h" 28 #include "content/public/browser/browser_thread.h"
23 #include "content/public/test/test_browser_thread_bundle.h" 29 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "testing/gmock/include/gmock/gmock.h" 30 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h" 31 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/multiprocess_func_list.h" 32 #include "testing/multiprocess_func_list.h"
27 33
28 namespace safe_browsing { 34 namespace safe_browsing {
29 namespace { 35 namespace {
30 36
31 using ::testing::Combine; 37 using ::testing::Combine;
32 using ::testing::DoAll; 38 using ::testing::DoAll;
33 using ::testing::InvokeWithoutArgs; 39 using ::testing::InvokeWithoutArgs;
34 using ::testing::SaveArg; 40 using ::testing::SaveArg;
35 using ::testing::StrictMock; 41 using ::testing::StrictMock;
42 using ::testing::UnorderedElementsAreArray;
36 using ::testing::Values; 43 using ::testing::Values;
37 using ::testing::_; 44 using ::testing::_;
38 using CrashPoint = MockChromeCleanerProcess::CrashPoint; 45 using CrashPoint = MockChromeCleanerProcess::CrashPoint;
39 using IdleReason = ChromeCleanerController::IdleReason; 46 using IdleReason = ChromeCleanerController::IdleReason;
40 using State = ChromeCleanerController::State; 47 using State = ChromeCleanerController::State;
41 using UserResponse = ChromeCleanerController::UserResponse; 48 using UserResponse = ChromeCleanerController::UserResponse;
42 49
43 class MockChromeCleanerControllerObserver 50 class MockChromeCleanerControllerObserver
44 : public ChromeCleanerController::Observer { 51 : public ChromeCleanerController::Observer {
45 public: 52 public:
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 std::move(fetched_callback) 112 std::move(fetched_callback)
106 .Run(base::FilePath(FILE_PATH_LITERAL("chrome_cleaner.exe"))); 113 .Run(base::FilePath(FILE_PATH_LITERAL("chrome_cleaner.exe")));
107 } 114 }
108 115
109 bool SafeBrowsingExtendedReportingScoutEnabled() override { 116 bool SafeBrowsingExtendedReportingScoutEnabled() override {
110 return scout_enabled_; 117 return scout_enabled_;
111 } 118 }
112 119
113 bool IsMetricsAndCrashReportingEnabled() override { return metrics_enabled_; } 120 bool IsMetricsAndCrashReportingEnabled() override { return metrics_enabled_; }
114 121
122 void TagForResetting(Profile* profile) override {
123 // This function should never be called by these tests.
124 FAIL();
125 }
126
127 void ResetTaggedProfiles(std::vector<Profile*> profiles,
128 base::OnceClosure continuation) override {
129 // This function should never be called by these tests.
130 FAIL();
131 }
132
115 // ChromeCleanerRunnerTestDelegate overrides. 133 // ChromeCleanerRunnerTestDelegate overrides.
116 134
117 base::Process LaunchTestProcess( 135 base::Process LaunchTestProcess(
118 const base::CommandLine& command_line, 136 const base::CommandLine& command_line,
119 const base::LaunchOptions& launch_options) override { 137 const base::LaunchOptions& launch_options) override {
120 command_line_ = command_line; 138 command_line_ = command_line;
121 // Return an invalid process. 139 // Return an invalid process.
122 return base::Process(); 140 return base::Process();
123 } 141 }
124 142
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 // configurations and mocks the user's response. 214 // configurations and mocks the user's response.
197 class ChromeCleanerControllerTest 215 class ChromeCleanerControllerTest
198 : public testing::TestWithParam< 216 : public testing::TestWithParam<
199 std::tuple<CleanerProcessStatus, 217 std::tuple<CleanerProcessStatus,
200 MockChromeCleanerProcess::CrashPoint, 218 MockChromeCleanerProcess::CrashPoint,
201 UwsFoundStatus, 219 UwsFoundStatus,
202 ChromeCleanerController::UserResponse>>, 220 ChromeCleanerController::UserResponse>>,
203 public ChromeCleanerRunnerTestDelegate, 221 public ChromeCleanerRunnerTestDelegate,
204 public ChromeCleanerControllerDelegate { 222 public ChromeCleanerControllerDelegate {
205 public: 223 public:
224 ChromeCleanerControllerTest() = default;
206 ~ChromeCleanerControllerTest() override {} 225 ~ChromeCleanerControllerTest() override {}
207 226
208 void SetUp() override { 227 void SetUp() override {
209 std::tie(process_status_, crash_point_, uws_found_status_, user_response_) = 228 std::tie(process_status_, crash_point_, uws_found_status_, user_response_) =
210 GetParam(); 229 GetParam();
211 230
212 cleaner_process_options_.SetDoFindUws(uws_found_status_ != 231 cleaner_process_options_.SetDoFindUws(uws_found_status_ !=
213 UwsFoundStatus::kNoUwsFound); 232 UwsFoundStatus::kNoUwsFound);
214 cleaner_process_options_.set_reboot_required( 233 cleaner_process_options_.set_reboot_required(
215 uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired); 234 uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 // fixture. 267 // fixture.
249 return false; 268 return false;
250 } 269 }
251 270
252 bool IsMetricsAndCrashReportingEnabled() override { 271 bool IsMetricsAndCrashReportingEnabled() override {
253 // Returning an arbitrary value since this is not being tested in this 272 // Returning an arbitrary value since this is not being tested in this
254 // fixture. 273 // fixture.
255 return false; 274 return false;
256 } 275 }
257 276
277 void TagForResetting(Profile* profile) override {
278 profiles_tagged_.push_back(profile);
279 }
280
281 void ResetTaggedProfiles(std::vector<Profile*> profiles,
282 base::OnceClosure continuation) override {
283 for (Profile* profile : profiles)
284 profiles_to_reset_if_tagged_.push_back(profile);
285 std::move(continuation).Run();
286 }
287
258 // ChromeCleanerRunnerTestDelegate overrides. 288 // ChromeCleanerRunnerTestDelegate overrides.
259 289
260 base::Process LaunchTestProcess( 290 base::Process LaunchTestProcess(
261 const base::CommandLine& command_line, 291 const base::CommandLine& command_line,
262 const base::LaunchOptions& launch_options) override { 292 const base::LaunchOptions& launch_options) override {
263 if (process_status_ != CleanerProcessStatus::kFetchSuccessValidProcess) 293 if (process_status_ != CleanerProcessStatus::kFetchSuccessValidProcess)
264 return base::Process(); 294 return base::Process();
265 295
266 // Add switches and program name that the test process needs for the multi 296 // Add switches and program name that the test process needs for the multi
267 // process tests. 297 // process tests.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 crash_point_ != CrashPoint::kAfterRequestSent && 335 crash_point_ != CrashPoint::kAfterRequestSent &&
306 user_response_ == UserResponse::kAccepted; 336 user_response_ == UserResponse::kAccepted;
307 } 337 }
308 338
309 bool ExpectedOnRebootRequiredCalled() { 339 bool ExpectedOnRebootRequiredCalled() {
310 return ExpectedFinalState() == State::kRebootRequired; 340 return ExpectedFinalState() == State::kRebootRequired;
311 } 341 }
312 342
313 bool ExpectedUwsFound() { return ExpectedOnInfectedCalled(); } 343 bool ExpectedUwsFound() { return ExpectedOnInfectedCalled(); }
314 344
345 bool ExpectedToTagProfile() {
346 return process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess &&
347 (crash_point_ == CrashPoint::kNone ||
348 crash_point_ == CrashPoint::kAfterResponseReceived) &&
349 (uws_found_status_ == UwsFoundStatus::kUwsFoundNoRebootRequired ||
350 uws_found_status_ == UwsFoundStatus::kUwsFoundRebootRequired) &&
351 user_response_ == UserResponse::kAccepted;
352 }
353
354 bool ExpectedToResetSettings() {
355 return process_status_ == CleanerProcessStatus::kFetchSuccessValidProcess &&
356 crash_point_ == CrashPoint::kNone &&
357 uws_found_status_ == UwsFoundStatus::kUwsFoundNoRebootRequired &&
358 user_response_ == UserResponse::kAccepted;
359 }
360
315 ChromeCleanerController::IdleReason ExpectedIdleReason() { 361 ChromeCleanerController::IdleReason ExpectedIdleReason() {
316 EXPECT_EQ(ExpectedFinalState(), State::kIdle); 362 EXPECT_EQ(ExpectedFinalState(), State::kIdle);
317 363
318 if (process_status_ != CleanerProcessStatus::kFetchSuccessValidProcess || 364 if (process_status_ != CleanerProcessStatus::kFetchSuccessValidProcess ||
319 crash_point_ == CrashPoint::kOnStartup || 365 crash_point_ == CrashPoint::kOnStartup ||
320 crash_point_ == CrashPoint::kAfterConnection) { 366 crash_point_ == CrashPoint::kAfterConnection) {
321 return IdleReason::kScanningFailed; 367 return IdleReason::kScanningFailed;
322 } 368 }
323 369
324 if (uws_found_status_ == UwsFoundStatus::kNoUwsFound) 370 if (uws_found_status_ == UwsFoundStatus::kNoUwsFound)
(...skipping 23 matching lines...) Expand all
348 394
349 CleanerProcessStatus process_status_; 395 CleanerProcessStatus process_status_;
350 MockChromeCleanerProcess::CrashPoint crash_point_; 396 MockChromeCleanerProcess::CrashPoint crash_point_;
351 UwsFoundStatus uws_found_status_; 397 UwsFoundStatus uws_found_status_;
352 ChromeCleanerController::UserResponse user_response_; 398 ChromeCleanerController::UserResponse user_response_;
353 399
354 MockChromeCleanerProcess::Options cleaner_process_options_; 400 MockChromeCleanerProcess::Options cleaner_process_options_;
355 401
356 StrictMock<MockChromeCleanerControllerObserver> mock_observer_; 402 StrictMock<MockChromeCleanerControllerObserver> mock_observer_;
357 ChromeCleanerController* controller_; 403 ChromeCleanerController* controller_;
404
405 std::vector<Profile*> profiles_tagged_;
406 std::vector<Profile*> profiles_to_reset_if_tagged_;
358 }; 407 };
359 408
360 MULTIPROCESS_TEST_MAIN(MockChromeCleanerProcessMain) { 409 MULTIPROCESS_TEST_MAIN(MockChromeCleanerProcessMain) {
361 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 410 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
362 MockChromeCleanerProcess::Options options; 411 MockChromeCleanerProcess::Options options;
363 EXPECT_TRUE(MockChromeCleanerProcess::Options::FromCommandLine(*command_line, 412 EXPECT_TRUE(MockChromeCleanerProcess::Options::FromCommandLine(*command_line,
364 &options)); 413 &options));
365 414
366 std::string chrome_mojo_pipe_token = command_line->GetSwitchValueASCII( 415 std::string chrome_mojo_pipe_token = command_line->GetSwitchValueASCII(
367 chrome_cleaner::kChromeMojoPipeTokenSwitch); 416 chrome_cleaner::kChromeMojoPipeTokenSwitch);
368 EXPECT_FALSE(chrome_mojo_pipe_token.empty()); 417 EXPECT_FALSE(chrome_mojo_pipe_token.empty());
369 418
370 // Since failures in any of the above calls to EXPECT_*() do not actually fail 419 // Since failures in any of the above calls to EXPECT_*() do not actually fail
371 // the test, we need to ensure that we return an exit code to indicate test 420 // the test, we need to ensure that we return an exit code to indicate test
372 // failure in such cases. 421 // failure in such cases.
373 if (::testing::Test::HasFailure()) 422 if (::testing::Test::HasFailure())
374 return MockChromeCleanerProcess::kInternalTestFailureExitCode; 423 return MockChromeCleanerProcess::kInternalTestFailureExitCode;
375 424
376 MockChromeCleanerProcess mock_cleaner_process(options, 425 MockChromeCleanerProcess mock_cleaner_process(options,
377 chrome_mojo_pipe_token); 426 chrome_mojo_pipe_token);
378 return mock_cleaner_process.Run(); 427 return mock_cleaner_process.Run();
379 } 428 }
380 429
381 TEST_P(ChromeCleanerControllerTest, WithMockCleanerProcess) { 430 TEST_P(ChromeCleanerControllerTest, WithMockCleanerProcess) {
431 TestingProfileManager profile_manager(TestingBrowserProcess::GetGlobal());
432 ASSERT_TRUE(profile_manager.SetUp());
433
434 constexpr char kTestProfileName1[] = "Test 1";
435 constexpr char kTestProfileName2[] = "Test 2";
436
437 Profile* profile1 = profile_manager.CreateTestingProfile(kTestProfileName1);
438 ASSERT_TRUE(profile1);
439 Profile* profile2 = profile_manager.CreateTestingProfile(kTestProfileName2);
440 ASSERT_TRUE(profile2);
441
442 const int num_profiles =
443 profile_manager.profile_manager()->GetNumberOfProfiles();
444 ASSERT_EQ(2, num_profiles);
445
382 EXPECT_CALL(mock_observer_, OnIdle(_)).Times(1); 446 EXPECT_CALL(mock_observer_, OnIdle(_)).Times(1);
383 controller_->AddObserver(&mock_observer_); 447 controller_->AddObserver(&mock_observer_);
384 EXPECT_EQ(controller_->state(), State::kIdle); 448 EXPECT_EQ(controller_->state(), State::kIdle);
385 449
386 EXPECT_CALL(mock_observer_, OnScanning()).Times(1); 450 EXPECT_CALL(mock_observer_, OnScanning()).Times(1);
387 controller_->Scan(GetInvocationWithPromptTrigger()); 451 controller_->Scan(GetInvocationWithPromptTrigger());
388 EXPECT_EQ(controller_->state(), State::kScanning); 452 EXPECT_EQ(controller_->state(), State::kScanning);
389 453
390 base::RunLoop run_loop; 454 base::RunLoop run_loop;
391 455
392 std::set<base::FilePath> files_to_delete_on_infected; 456 std::set<base::FilePath> files_to_delete_on_infected;
393 std::set<base::FilePath> files_to_delete_on_cleaning; 457 std::set<base::FilePath> files_to_delete_on_cleaning;
394 458
395 if (ExpectedOnIdleCalled()) { 459 if (ExpectedOnIdleCalled()) {
396 EXPECT_CALL(mock_observer_, OnIdle(ExpectedIdleReason())) 460 EXPECT_CALL(mock_observer_, OnIdle(ExpectedIdleReason()))
397 .WillOnce( 461 .WillOnce(
398 InvokeWithoutArgs([&run_loop]() { run_loop.QuitWhenIdle(); })); 462 InvokeWithoutArgs([&run_loop]() { run_loop.QuitWhenIdle(); }));
399 } 463 }
400 464
401 if (ExpectedOnInfectedCalled()) { 465 if (ExpectedOnInfectedCalled()) {
402 EXPECT_CALL(mock_observer_, OnInfected(_)) 466 EXPECT_CALL(mock_observer_, OnInfected(_))
403 .WillOnce(DoAll(SaveArg<0>(&files_to_delete_on_infected), 467 .WillOnce(DoAll(SaveArg<0>(&files_to_delete_on_infected),
404 InvokeWithoutArgs([this]() { 468 InvokeWithoutArgs([this, profile1]() {
405 controller_->ReplyWithUserResponse(user_response_); 469 controller_->ReplyWithUserResponse(profile1,
470 user_response_);
406 }))); 471 })));
407 } 472 }
408 473
409 if (ExpectedOnCleaningCalled()) { 474 if (ExpectedOnCleaningCalled()) {
410 EXPECT_CALL(mock_observer_, OnCleaning(_)) 475 EXPECT_CALL(mock_observer_, OnCleaning(_))
411 .WillOnce(SaveArg<0>(&files_to_delete_on_cleaning)); 476 .WillOnce(SaveArg<0>(&files_to_delete_on_cleaning));
412 } 477 }
413 478
414 if (ExpectedOnRebootRequiredCalled()) { 479 if (ExpectedOnRebootRequiredCalled()) {
415 EXPECT_CALL(mock_observer_, OnRebootRequired()) 480 EXPECT_CALL(mock_observer_, OnRebootRequired())
416 .WillOnce( 481 .WillOnce(
417 InvokeWithoutArgs([&run_loop]() { run_loop.QuitWhenIdle(); })); 482 InvokeWithoutArgs([&run_loop]() { run_loop.QuitWhenIdle(); }));
418 } 483 }
419 484
420 // Assert here that we expect at least one of OnIdle or OnRebootRequired to be 485 // Assert here that we expect at least one of OnIdle or OnRebootRequired to be
421 // called, since otherwise, the test is set up incorrectly and is expected to 486 // called, since otherwise, the test is set up incorrectly and is expected to
422 // never stop. 487 // never stop.
423 ASSERT_TRUE(ExpectedOnIdleCalled() || ExpectedOnRebootRequiredCalled()); 488 ASSERT_TRUE(ExpectedOnIdleCalled() || ExpectedOnRebootRequiredCalled());
424 run_loop.Run(); 489 run_loop.Run();
425 490
426 EXPECT_EQ(controller_->state(), ExpectedFinalState()); 491 EXPECT_EQ(controller_->state(), ExpectedFinalState());
427 EXPECT_EQ(!files_to_delete_on_infected.empty(), ExpectedUwsFound()); 492 EXPECT_EQ(!files_to_delete_on_infected.empty(), ExpectedUwsFound());
428 EXPECT_EQ(!files_to_delete_on_cleaning.empty(), 493 EXPECT_EQ(!files_to_delete_on_cleaning.empty(),
429 ExpectedUwsFound() && ExpectedOnCleaningCalled()); 494 ExpectedUwsFound() && ExpectedOnCleaningCalled());
430 if (!files_to_delete_on_infected.empty() && 495 if (!files_to_delete_on_infected.empty() &&
431 !files_to_delete_on_cleaning.empty()) { 496 !files_to_delete_on_cleaning.empty()) {
432 EXPECT_EQ(files_to_delete_on_infected, files_to_delete_on_cleaning); 497 EXPECT_EQ(files_to_delete_on_infected, files_to_delete_on_cleaning);
433 } 498 }
434 499
500 std::vector<Profile*> expected_tagged;
501 if (ExpectedToTagProfile())
502 expected_tagged.push_back(profile1);
503 EXPECT_THAT(expected_tagged, UnorderedElementsAreArray(profiles_tagged_));
504
505 std::vector<Profile*> expected_reset_if_tagged;
506 if (ExpectedToResetSettings()) {
507 expected_reset_if_tagged.push_back(profile1);
508 expected_reset_if_tagged.push_back(profile2);
509 }
510 EXPECT_THAT(expected_reset_if_tagged,
511 UnorderedElementsAreArray(profiles_to_reset_if_tagged_));
512
435 controller_->RemoveObserver(&mock_observer_); 513 controller_->RemoveObserver(&mock_observer_);
436 } 514 }
437 515
438 INSTANTIATE_TEST_CASE_P( 516 INSTANTIATE_TEST_CASE_P(
439 All, 517 All,
440 ChromeCleanerControllerTest, 518 ChromeCleanerControllerTest,
441 Combine(Values(CleanerProcessStatus::kFetchFailure, 519 Combine(Values(CleanerProcessStatus::kFetchFailure,
442 CleanerProcessStatus::kFetchSuccessInvalidProcess, 520 CleanerProcessStatus::kFetchSuccessInvalidProcess,
443 CleanerProcessStatus::kFetchSuccessValidProcess), 521 CleanerProcessStatus::kFetchSuccessValidProcess),
444 Values(CrashPoint::kNone, 522 Values(CrashPoint::kNone,
445 CrashPoint::kOnStartup, 523 CrashPoint::kOnStartup,
446 CrashPoint::kAfterConnection, 524 CrashPoint::kAfterConnection,
447 // CrashPoint::kAfterRequestSent is not used because we 525 // CrashPoint::kAfterRequestSent is not used because we
448 // cannot ensure the order between the Mojo request being 526 // cannot ensure the order between the Mojo request being
449 // received by Chrome and the connection being lost. 527 // received by Chrome and the connection being lost.
450 CrashPoint::kAfterResponseReceived), 528 CrashPoint::kAfterResponseReceived),
451 Values(UwsFoundStatus::kNoUwsFound, 529 Values(UwsFoundStatus::kNoUwsFound,
452 UwsFoundStatus::kUwsFoundRebootRequired, 530 UwsFoundStatus::kUwsFoundRebootRequired,
453 UwsFoundStatus::kUwsFoundNoRebootRequired), 531 UwsFoundStatus::kUwsFoundNoRebootRequired),
454 Values(UserResponse::kAccepted, 532 Values(UserResponse::kAccepted,
455 UserResponse::kDenied, 533 UserResponse::kDenied,
456 UserResponse::kDismissed))); 534 UserResponse::kDismissed)));
457 535
458 } // namespace 536 } // namespace
459 } // namespace safe_browsing 537 } // namespace safe_browsing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698