Index: chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc |
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..449de3883db3e21dfe4fbb38046e236b77be6138 |
--- /dev/null |
+++ b/chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.cc |
@@ -0,0 +1,242 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/safe_browsing/chrome_cleaner/mock_chrome_cleaner_process_win.h" |
+ |
+#include <utility> |
+ |
+#include "base/bind_helpers.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/run_loop.h" |
+#include "base/sequenced_task_runner.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "base/threading/sequenced_task_runner_handle.h" |
+#include "base/threading/thread.h" |
+#include "mojo/edk/embedder/connection_params.h" |
+#include "mojo/edk/embedder/embedder.h" |
+#include "mojo/edk/embedder/incoming_broker_client_invitation.h" |
+#include "mojo/edk/embedder/outgoing_broker_client_invitation.h" |
+#include "mojo/edk/embedder/platform_channel_pair.h" |
+#include "mojo/edk/embedder/scoped_ipc_support.h" |
+#include "mojo/edk/embedder/transport_protocol.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace safe_browsing { |
+ |
+namespace { |
+ |
+using ::chrome_cleaner::mojom::ChromePrompt; |
+using ::chrome_cleaner::mojom::ChromePromptPtr; |
+using ::chrome_cleaner::mojom::ChromePromptPtrInfo; |
+using ::chrome_cleaner::mojom::ElevationStatus; |
+using ::chrome_cleaner::mojom::PromptAcceptance; |
+using ::chrome_cleaner::mojom::UwSPtr; |
+ |
+constexpr char kCrashPointSwitch[] = "mock-crash-point"; |
+constexpr char kExitCodeSwitch[] = "mock-exit-code"; |
+constexpr char kUwsFoundSwitch[] = "mock-uws-found"; |
+constexpr char kRebootRequiredSwitch[] = "mock-reboot-required"; |
+ |
+} // namespace |
+ |
+// static |
+bool MockChromeCleanerProcess::Options::FromCommandLine( |
+ const base::CommandLine& command_line, |
+ Options* options) { |
+ options->SetDoFindUws(command_line.HasSwitch(kUwsFoundSwitch)); |
+ options->set_reboot_required(command_line.HasSwitch(kRebootRequiredSwitch)); |
+ |
+ if (command_line.HasSwitch(kCrashPointSwitch)) { |
+ int crash_point_int = 0; |
+ if (base::StringToInt(command_line.GetSwitchValueASCII(kCrashPointSwitch), |
+ &crash_point_int) && |
+ crash_point_int >= 0 && |
+ crash_point_int < static_cast<int>(CrashPoint::kNumCrashPoints)) { |
+ options->set_crash_point(static_cast<CrashPoint>(crash_point_int)); |
+ } else { |
+ return false; |
+ } |
+ } |
+ |
+ return true; |
+} |
+ |
+MockChromeCleanerProcess::Options::Options(bool do_find_uws, |
+ bool reboot_required, |
+ CrashPoint crash_point) |
Joe Mason
2017/05/23 15:39:36
Nit: This constructor's never actually used. Might
alito
2017/05/23 18:58:57
Done. Now only a default constructor without argum
|
+ : reboot_required_(reboot_required), crash_point_(crash_point) { |
+ SetDoFindUws(do_find_uws); |
+} |
+ |
+MockChromeCleanerProcess::Options::Options(const Options& other) |
+ : files_to_delete_(other.files_to_delete_), |
+ reboot_required_(other.reboot_required_), |
+ crash_point_(other.crash_point_) { |
+ for (const UwSPtr& uws_ptr : other.found_uws()) |
+ found_uws_.push_back(uws_ptr->Clone()); |
+} |
+ |
+void MockChromeCleanerProcess::Options::AddSwitchesToCommandLine( |
+ base::CommandLine* command_line) const { |
+ if (!found_uws_.empty()) |
+ command_line->AppendSwitch(kUwsFoundSwitch); |
+ |
+ if (reboot_required()) |
+ command_line->AppendSwitch(kRebootRequiredSwitch); |
+ |
+ if (crash_point() != CrashPoint::kNone) { |
+ command_line->AppendSwitchASCII( |
+ kCrashPointSwitch, base::IntToString(static_cast<int>(crash_point()))); |
+ } |
+} |
+ |
+void MockChromeCleanerProcess::Options::SetDoFindUws(bool do_find_uws) { |
+ found_uws_.clear(); |
+ files_to_delete_.clear(); |
+ if (!do_find_uws) |
+ return; |
+ |
+ UwSPtr uws1 = chrome_cleaner::mojom::UwS::New(); |
+ uws1->id = 1; |
+ uws1->name = "Some UwS"; |
+ uws1->observed_behaviours = chrome_cleaner::mojom::ObservedBehaviours::New(); |
+ uws1->files_to_delete.push_back( |
+ base::FilePath((FILE_PATH_LITERAL("/path/to/file1.exe")))); |
+ uws1->files_to_delete.push_back( |
+ base::FilePath((FILE_PATH_LITERAL("/path/to/other/file2.exe")))); |
+ found_uws_.push_back(std::move(uws1)); |
+ |
+ UwSPtr uws2 = chrome_cleaner::mojom::UwS::New(); |
+ uws2->id = 2; |
+ uws2->name = "Other UwS"; |
+ uws2->observed_behaviours = chrome_cleaner::mojom::ObservedBehaviours::New(); |
+ uws2->files_to_delete.push_back( |
+ base::FilePath((FILE_PATH_LITERAL("/path/to/some file.dll")))); |
+ found_uws_.push_back(std::move(uws2)); |
+ |
+ for (const UwSPtr& uws_ptr : found_uws_) { |
+ for (const base::FilePath& filepath : uws_ptr->files_to_delete) |
+ files_to_delete_.insert(filepath); |
+ } |
+} |
+ |
+int MockChromeCleanerProcess::Options::ExpectedExitCode( |
+ PromptAcceptance received_prompt_acceptance) const { |
+ if (crash_point() != CrashPoint::kNone) |
+ return kDeliberateCrashExitCode; |
+ |
+ if (found_uws_.empty()) |
+ return kNothingFoundExitCode; |
+ |
+ if (received_prompt_acceptance == PromptAcceptance::ACCEPTED_WITH_LOGS || |
+ received_prompt_acceptance == PromptAcceptance::ACCEPTED_WITHOUT_LOGS) { |
+ return reboot_required() ? kRebootRequiredExitCode |
+ : kRebootNotRequiredExitCode; |
+ } |
+ |
+ return kCanceledExitCode; |
+} |
+ |
+MockChromeCleanerProcess::MockChromeCleanerProcess( |
+ const Options& options, |
+ const std::string& chrome_mojo_pipe_token) |
+ : options_(options), chrome_mojo_pipe_token_(chrome_mojo_pipe_token) {} |
+ |
+int MockChromeCleanerProcess::Run() { |
+ EXPECT_FALSE(chrome_mojo_pipe_token_.empty()); |
+ if (::testing::Test::HasFailure()) |
Joe Mason
2017/05/23 15:39:36
Can you comment on what this pattern means?
alito
2017/05/23 18:58:57
Done.
|
+ return kInternalTestFailureExitCode; |
+ |
+ if (options_.crash_point() == CrashPoint::kOnStartup) |
+ exit(kDeliberateCrashExitCode); |
+ |
+ mojo::edk::Init(); |
+ base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0); |
+ base::Thread io_thread("IPCThread"); |
+ EXPECT_TRUE(io_thread.StartWithOptions(thread_options)); |
+ if (::testing::Test::HasFailure()) |
+ return kInternalTestFailureExitCode; |
+ |
+ mojo::edk::ScopedIPCSupport ipc_support( |
+ io_thread.task_runner(), |
+ mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN); |
+ |
+ auto invitation = |
+ mojo::edk::IncomingBrokerClientInvitation::AcceptFromCommandLine( |
+ mojo::edk::TransportProtocol::kLegacy); |
+ ChromePromptPtrInfo prompt_ptr_info( |
+ invitation->ExtractMessagePipe(chrome_mojo_pipe_token_), 0); |
+ |
+ if (options_.crash_point() == CrashPoint::kAfterConnection) |
+ exit(kDeliberateCrashExitCode); |
+ |
+ base::MessageLoop message_loop; |
+ base::RunLoop run_loop; |
+ // After the response from the parent process is received, this will post a |
+ // task to unblock the child process's main thread. |
+ auto quit_closure = base::BindOnce( |
+ [](scoped_refptr<base::SequencedTaskRunner> main_runner, |
+ base::Closure quit_closure) { |
+ main_runner->PostTask(FROM_HERE, std::move(quit_closure)); |
+ }, |
+ base::SequencedTaskRunnerHandle::Get(), |
+ base::Passed(run_loop.QuitClosure())); |
+ |
+ io_thread.task_runner()->PostTask( |
+ FROM_HERE, |
+ base::BindOnce(&MockChromeCleanerProcess::SendScanResults, |
+ base::Unretained(this), std::move(prompt_ptr_info), |
+ base::Passed(&quit_closure))); |
+ |
+ run_loop.Run(); |
+ |
+ EXPECT_NE(received_prompt_acceptance_, PromptAcceptance::UNSPECIFIED); |
+ if (::testing::Test::HasFailure()) |
+ return kInternalTestFailureExitCode; |
+ return options_.ExpectedExitCode(received_prompt_acceptance_); |
+} |
+ |
+void MockChromeCleanerProcess::SendScanResults( |
+ ChromePromptPtrInfo prompt_ptr_info, |
+ base::OnceClosure quit_closure) { |
+ // This pointer will be deleted by PromptUserCallback. |
+ chrome_prompt_ptr_ = new ChromePromptPtr(); |
+ chrome_prompt_ptr_->Bind(std::move(prompt_ptr_info)); |
+ |
+ if (options_.crash_point() == CrashPoint::kAfterRequestSent) { |
+ // This task is posted to the IPC thread so that it will happen after the |
+ // request is sent to the parent process and before the response gets |
+ // handled on the IPC thread. |
+ base::SequencedTaskRunnerHandle::Get()->PostTask( |
+ FROM_HERE, base::Bind([]() { exit(kDeliberateCrashExitCode); })); |
Joe Mason
2017/05/23 15:39:36
Nit: could avoid the lambda with "base::Bind(&exit
alito
2017/05/23 18:58:57
Done.
alito
2017/05/24 00:42:47
Turns out, the clang compiler does not like bindin
|
+ } |
+ |
+ std::vector<UwSPtr> uws_found; |
+ for (const UwSPtr& uws_ptr : options_.found_uws()) |
+ uws_found.push_back(uws_ptr->Clone()); |
+ |
+ (*chrome_prompt_ptr_) |
+ ->PromptUser( |
+ std::move(uws_found), ElevationStatus::REQUIRED, |
+ base::BindOnce(&MockChromeCleanerProcess::PromptUserCallback, |
+ base::Unretained(this), std::move(quit_closure))); |
+} |
+ |
+void MockChromeCleanerProcess::PromptUserCallback( |
+ base::OnceClosure quit_closure, |
+ PromptAcceptance prompt_acceptance) { |
+ delete chrome_prompt_ptr_; |
+ chrome_prompt_ptr_ = nullptr; |
+ |
+ received_prompt_acceptance_ = prompt_acceptance; |
+ |
+ if (options_.crash_point() == CrashPoint::kAfterResponseReceived) |
+ exit(kDeliberateCrashExitCode); |
+ |
+ std::move(quit_closure).Run(); |
+} |
+ |
+} // namespace safe_browsing |