Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/reporter_runner_win.h" | 5 #include "chrome/browser/safe_browsing/chrome_cleaner/reporter_runner_win.h" |
| 6 | 6 |
| 7 #include <initializer_list> | 7 #include <initializer_list> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <tuple> | |
| 10 #include <utility> | 9 #include <utility> |
| 11 #include <vector> | 10 #include <vector> |
| 12 | 11 |
| 13 #include "base/bind.h" | 12 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
| 15 #include "base/callback.h" | 14 #include "base/callback.h" |
| 16 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
| 17 #include "base/files/file_path.h" | 16 #include "base/files/file_path.h" |
| 18 #include "base/macros.h" | 17 #include "base/macros.h" |
| 19 #include "base/memory/ref_counted.h" | 18 #include "base/memory/ref_counted.h" |
| 20 #include "base/message_loop/message_loop.h" | 19 #include "base/message_loop/message_loop.h" |
| 21 #include "base/run_loop.h" | 20 #include "base/run_loop.h" |
| 22 #include "base/strings/string_number_conversions.h" | |
| 23 #include "base/test/multiprocess_test.h" | |
| 24 #include "base/test/scoped_feature_list.h" | 21 #include "base/test/scoped_feature_list.h" |
| 25 #include "base/test/test_mock_time_task_runner.h" | 22 #include "base/test/test_mock_time_task_runner.h" |
| 26 #include "base/threading/sequenced_task_runner_handle.h" | 23 #include "base/threading/sequenced_task_runner_handle.h" |
| 27 #include "base/threading/thread_task_runner_handle.h" | 24 #include "base/threading/thread_task_runner_handle.h" |
| 28 #include "base/time/time.h" | 25 #include "base/time/time.h" |
| 29 #include "base/version.h" | 26 #include "base/version.h" |
| 30 #include "chrome/browser/browser_process.h" | 27 #include "chrome/browser/browser_process.h" |
| 31 #include "chrome/browser/lifetime/keep_alive_types.h" | 28 #include "chrome/browser/lifetime/keep_alive_types.h" |
| 32 #include "chrome/browser/lifetime/scoped_keep_alive.h" | 29 #include "chrome/browser/lifetime/scoped_keep_alive.h" |
| 33 #include "chrome/browser/profiles/profile.h" | 30 #include "chrome/browser/profiles/profile.h" |
| 34 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_chrome_prompt_impl.h" | |
| 35 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.h" | 31 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_client_info_win.h" |
| 36 #include "chrome/browser/ui/browser.h" | 32 #include "chrome/browser/ui/browser.h" |
| 37 #include "chrome/browser/ui/browser_finder.h" | 33 #include "chrome/browser/ui/browser_finder.h" |
| 38 #include "chrome/browser/ui/test/test_browser_dialog.h" | 34 #include "chrome/browser/ui/test/test_browser_dialog.h" |
| 39 #include "chrome/common/pref_names.h" | 35 #include "chrome/common/pref_names.h" |
| 40 #include "chrome/test/base/in_process_browser_test.h" | 36 #include "chrome/test/base/in_process_browser_test.h" |
| 41 #include "components/chrome_cleaner/public/constants/constants.h" | 37 #include "components/chrome_cleaner/public/constants/constants.h" |
| 42 #include "components/component_updater/pref_names.h" | 38 #include "components/component_updater/pref_names.h" |
| 43 #include "components/prefs/pref_service.h" | 39 #include "components/prefs/pref_service.h" |
| 44 #include "components/safe_browsing/common/safe_browsing_prefs.h" | 40 #include "components/safe_browsing_db/safe_browsing_prefs.h" |
|
ftirelo
2017/05/18 13:43:07
Shouldn't this be common/safe_browsing_prefs.h ?
alito
2017/05/18 16:09:40
That file was moved in this cl: https://codereview
| |
| 45 #include "mojo/edk/embedder/embedder.h" | |
| 46 #include "mojo/edk/embedder/incoming_broker_client_invitation.h" | |
| 47 #include "mojo/edk/embedder/scoped_ipc_support.h" | |
| 48 #include "mojo/edk/system/core.h" | |
| 49 #include "testing/multiprocess_func_list.h" | |
| 50 | 41 |
| 51 namespace safe_browsing { | 42 namespace safe_browsing { |
| 52 | 43 |
| 53 namespace { | 44 namespace { |
| 54 | 45 |
| 55 using chrome_cleaner::mojom::ElevationStatus; | 46 // Parameter for this test: |
| 56 using chrome_cleaner::mojom::PromptAcceptance; | 47 // - bool in_browser_cleaner_ui: indicates if InBrowserCleanerUI feature |
| 57 | 48 // is enabled; |
| 58 // Special switches passed by the parent process (test case) to the reporter | 49 // |
| 59 // child process to indicate the behavior that should be mocked. | 50 // We expect that the reporter's logic should remain unchanged even when the |
| 60 constexpr char kExitCodeToReturnSwitch[] = "exit-code-to-return"; | 51 // InBrowserCleanerUI feature is enabled with one exception: the reporter is |
| 61 constexpr char kReportUwSFoundSwitch[] = "report-uws-found"; | 52 // not run daily because with the new feature enabled there is no concept of |
| 62 constexpr char kReportElevationRequiredSwitch[] = "report-elevation-required"; | 53 // a pending prompt. See the RunDaily and InBrowserUINoRunDaily tests. |
| 63 constexpr char kExpectedPromptAcceptanceSwitch[] = "expected-prompt-acceptance"; | 54 class ReporterRunnerTest : public InProcessBrowserTest, |
| 64 constexpr char kExpectedReporterFailureSwitch[] = "expected-reporter-crash"; | 55 public SwReporterTestingDelegate, |
| 65 | 56 public ::testing::WithParamInterface<bool> { |
| 66 // The exit code to be returned in case of failure in the child process. | |
| 67 // This should never be passed as the expected exit code to be reported by | |
| 68 // tests. | |
| 69 constexpr int kFailureExitCode = -1; | |
| 70 | |
| 71 // Pass the |prompt_acceptance| to the mock child process in command line | |
| 72 // switch kExpectedPromptAcceptanceSwitch. | |
| 73 void AddPromptAcceptanceToCommandLine(PromptAcceptance prompt_acceptance, | |
| 74 base::CommandLine* command_line) { | |
| 75 command_line->AppendSwitchASCII( | |
| 76 kExpectedPromptAcceptanceSwitch, | |
| 77 base::IntToString(static_cast<int>(prompt_acceptance))); | |
| 78 } | |
| 79 | |
| 80 // Parses and returns the prompt acceptance value passed by the parent process | |
| 81 // in command line switch kExpectedPromptAcceptanceSwitch. Returns | |
| 82 // PromptAcceptance::UNSPECIFIED if the switch doesn't exist or can't be | |
| 83 // parsed to a valid PromptAcceptance enumerator. | |
| 84 PromptAcceptance PromptAcceptanceFromCommandLine( | |
| 85 const base::CommandLine& command_line) { | |
| 86 const std::string& prompt_acceptance_str = | |
| 87 command_line.GetSwitchValueASCII(kExpectedPromptAcceptanceSwitch); | |
| 88 int val = -1; | |
| 89 if (base::StringToInt(prompt_acceptance_str, &val)) { | |
| 90 PromptAcceptance prompt_acceptance = static_cast<PromptAcceptance>(val); | |
| 91 if (chrome_cleaner::mojom::IsKnownEnumValue(prompt_acceptance)) | |
| 92 return prompt_acceptance; | |
| 93 } | |
| 94 return PromptAcceptance::UNSPECIFIED; | |
| 95 } | |
| 96 | |
| 97 // Pointer to ChromePromptPtr object to be used by the child process. The | |
| 98 // object must be created, deleted, and accessed on the IPC thread only. | |
| 99 chrome_cleaner::mojom::ChromePromptPtr* g_chrome_prompt_ptr = nullptr; | |
| 100 | |
| 101 // Potential failures in the reporter process that should be handled by the | |
| 102 // parent process. | |
| 103 enum class MockedReporterFailure { | |
| 104 kNone = 0, | |
| 105 // Crashes at specific moments in the reporter when connected to the IPC. | |
| 106 kCrashOnStartup = 1, | |
| 107 kCrashAfterConnectedToParentProcess = 2, | |
| 108 kCrashWhileWaitingForResponse = 3, | |
| 109 kCrashAfterReceivedResponse = 4, | |
| 110 // Once an IPC message is sent by the reporter, the parent process will | |
| 111 // report a bad message that will lead to an invocation of OnConnectionError. | |
| 112 kBadMessageReported = 5, | |
| 113 }; | |
| 114 | |
| 115 void AddExpectedCrashToCommandLine(MockedReporterFailure reporter_failure, | |
| 116 base::CommandLine* command_line) { | |
| 117 command_line->AppendSwitchASCII( | |
| 118 kExpectedReporterFailureSwitch, | |
| 119 base::IntToString(static_cast<int>(reporter_failure))); | |
| 120 } | |
| 121 | |
| 122 void CrashIf(MockedReporterFailure reporter_failure) { | |
| 123 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
| 124 const std::string& expected_str = | |
| 125 command_line->GetSwitchValueASCII(kExpectedReporterFailureSwitch); | |
| 126 int val = -1; | |
| 127 if (base::StringToInt(expected_str, &val) && | |
| 128 static_cast<MockedReporterFailure>(val) == reporter_failure) { | |
| 129 exit(kFailureExitCode); | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 // The callback function to be passed to ChromePrompt::PromptUser to check if | |
| 134 // the prompt accepted returned by the parent process is equal to | |
| 135 // |expected_prompt_acceptance|. Will set |expected_value_received| with the | |
| 136 // comparison result, so that the main thread can report failure. Will invoke | |
| 137 // |done| callback when done. | |
| 138 void PromptUserCallback(const base::Closure& done, | |
| 139 PromptAcceptance expected_prompt_acceptance, | |
| 140 bool* expected_value_received, | |
| 141 PromptAcceptance prompt_acceptance) { | |
| 142 *expected_value_received = prompt_acceptance == expected_prompt_acceptance; | |
| 143 // It's safe to delete the ChromePromptPtr object here, since it will not be | |
| 144 // used anymore by the child process. | |
| 145 delete g_chrome_prompt_ptr; | |
| 146 g_chrome_prompt_ptr = nullptr; | |
| 147 CrashIf(MockedReporterFailure::kCrashAfterReceivedResponse); | |
| 148 done.Run(); | |
| 149 } | |
| 150 | |
| 151 // Mocks the sending of scan results from the child process to the parent | |
| 152 // process. Obtains the behavior to be mocked from special switches in | |
| 153 // |command_line|. Sets |expected_value_received| as true if the parent | |
| 154 // process replies with the expected prompt acceptance value. | |
| 155 void SendScanResults(chrome_cleaner::mojom::ChromePromptPtrInfo prompt_ptr_info, | |
| 156 const base::CommandLine& command_line, | |
| 157 const base::Closure& done, | |
| 158 bool* expected_value_received) { | |
| 159 constexpr int kDefaultUwSId = 10; | |
| 160 constexpr char kDefaultUwSName[] = "RemovedUwS"; | |
| 161 | |
| 162 // This pointer will be deleted by PromptUserCallback. | |
| 163 g_chrome_prompt_ptr = new chrome_cleaner::mojom::ChromePromptPtr(); | |
| 164 g_chrome_prompt_ptr->Bind(std::move(prompt_ptr_info)); | |
| 165 | |
| 166 std::vector<chrome_cleaner::mojom::UwSPtr> removable_uws_found; | |
| 167 if (command_line.HasSwitch(kReportUwSFoundSwitch)) { | |
| 168 chrome_cleaner::mojom::UwSPtr uws = chrome_cleaner::mojom::UwS::New(); | |
| 169 uws->id = kDefaultUwSId; | |
| 170 uws->name = kDefaultUwSName; | |
| 171 uws->observed_behaviours = chrome_cleaner::mojom::ObservedBehaviours::New(); | |
| 172 removable_uws_found.push_back(std::move(uws)); | |
| 173 } | |
| 174 const ElevationStatus elevation_status = | |
| 175 command_line.HasSwitch(kReportElevationRequiredSwitch) | |
| 176 ? ElevationStatus::REQUIRED | |
| 177 : ElevationStatus::NOT_REQUIRED; | |
| 178 const PromptAcceptance expected_prompt_acceptance = | |
| 179 PromptAcceptanceFromCommandLine(command_line); | |
| 180 | |
| 181 // This task is posted to the IPC thread so that it will happen after the | |
| 182 // request is sent to the parent process and before the response gets | |
| 183 // handled on the IPC thread. | |
| 184 base::SequencedTaskRunnerHandle::Get()->PostTask( | |
| 185 FROM_HERE, | |
| 186 base::Bind(&CrashIf, | |
| 187 MockedReporterFailure::kCrashWhileWaitingForResponse)); | |
| 188 | |
| 189 (*g_chrome_prompt_ptr) | |
| 190 ->PromptUser( | |
| 191 std::move(removable_uws_found), elevation_status, | |
| 192 base::Bind(&PromptUserCallback, done, expected_prompt_acceptance, | |
| 193 expected_value_received)); | |
| 194 } | |
| 195 | |
| 196 // Connects to the parent process and sends mocked scan results. Returns true | |
| 197 // if connection was successful and the prompt acceptance results sent by the | |
| 198 // parent process are the same as expected. | |
| 199 bool ConnectAndSendDataToParentProcess( | |
| 200 const std::string& chrome_mojo_pipe_token, | |
| 201 const base::CommandLine& command_line) { | |
| 202 DCHECK(!chrome_mojo_pipe_token.empty()); | |
| 203 | |
| 204 mojo::edk::Init(); | |
| 205 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); | |
| 206 base::Thread io_thread("IPCThread"); | |
| 207 if (!io_thread.StartWithOptions(options)) | |
| 208 return false; | |
| 209 mojo::edk::ScopedIPCSupport ipc_support( | |
| 210 io_thread.task_runner(), | |
| 211 mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN); | |
| 212 | |
| 213 auto invitation = | |
| 214 mojo::edk::IncomingBrokerClientInvitation::AcceptFromCommandLine( | |
| 215 mojo::edk::TransportProtocol::kLegacy); | |
| 216 chrome_cleaner::mojom::ChromePromptPtrInfo prompt_ptr_info( | |
| 217 invitation->ExtractMessagePipe(chrome_mojo_pipe_token), 0); | |
| 218 | |
| 219 CrashIf(MockedReporterFailure::kCrashAfterConnectedToParentProcess); | |
| 220 | |
| 221 base::MessageLoop message_loop; | |
| 222 base::RunLoop run_loop; | |
| 223 // After the response from the parent process is received, this will post a | |
| 224 // task to unblock the child process's main thread. | |
| 225 auto done = base::Bind( | |
| 226 [](scoped_refptr<base::SequencedTaskRunner> main_runner, | |
| 227 base::Closure quit_closure) { | |
| 228 main_runner->PostTask(FROM_HERE, std::move(quit_closure)); | |
| 229 }, | |
| 230 base::SequencedTaskRunnerHandle::Get(), | |
| 231 base::Passed(run_loop.QuitClosure())); | |
| 232 | |
| 233 bool expected_value_received = false; | |
| 234 io_thread.task_runner()->PostTask( | |
| 235 FROM_HERE, base::BindOnce(&SendScanResults, std::move(prompt_ptr_info), | |
| 236 command_line, done, &expected_value_received)); | |
| 237 | |
| 238 run_loop.Run(); | |
| 239 | |
| 240 return expected_value_received; | |
| 241 } | |
| 242 | |
| 243 // Mocks a Software Reporter process that returns an exit code specified by | |
| 244 // command line switch kExitCodeToReturnSwitch. If a Mojo IPC is available, | |
| 245 // this will also connect to the parent process and send mocked scan results | |
| 246 // to the parent process using data passed as command line switches. | |
| 247 MULTIPROCESS_TEST_MAIN(MockSwReporterProcess) { | |
| 248 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
| 249 CrashIf(MockedReporterFailure::kCrashOnStartup); | |
| 250 const std::string& str = | |
| 251 command_line->GetSwitchValueASCII(kExitCodeToReturnSwitch); | |
| 252 const std::string& chrome_mojo_pipe_token = command_line->GetSwitchValueASCII( | |
| 253 chrome_cleaner::kChromeMojoPipeTokenSwitch); | |
| 254 int exit_code_to_report = kFailureExitCode; | |
| 255 bool success = base::StringToInt(str, &exit_code_to_report) && | |
| 256 (chrome_mojo_pipe_token.empty() || | |
| 257 ConnectAndSendDataToParentProcess(chrome_mojo_pipe_token, | |
| 258 *command_line)); | |
| 259 return success ? exit_code_to_report : kFailureExitCode; | |
| 260 } | |
| 261 | |
| 262 // Decorates a ChromePromptImpl object to simulate failures indentified by the | |
| 263 // parent process and keeps track of errors handled. By default, delegates all | |
| 264 // actions to the decorated object. | |
| 265 class ReportBadMessageChromePromptImpl : public ChromePromptImpl { | |
| 266 public: | |
| 267 ReportBadMessageChromePromptImpl( | |
| 268 chrome_cleaner::mojom::ChromePromptRequest request, | |
| 269 bool bad_message_expected, | |
| 270 base::Closure on_connection_closed) | |
| 271 : ChromePromptImpl(std::move(request), std::move(on_connection_closed)), | |
| 272 bad_message_expected_(bad_message_expected) {} | |
| 273 ~ReportBadMessageChromePromptImpl() override = default; | |
| 274 | |
| 275 void PromptUser( | |
| 276 std::vector<chrome_cleaner::mojom::UwSPtr> removable_uws_found, | |
| 277 chrome_cleaner::mojom::ElevationStatus elevation_status, | |
| 278 chrome_cleaner::mojom::ChromePrompt::PromptUserCallback callback) | |
| 279 override { | |
| 280 if (bad_message_expected_) | |
| 281 mojo::ReportBadMessage("bad message"); | |
| 282 | |
| 283 ChromePromptImpl::PromptUser(std::move(removable_uws_found), | |
| 284 elevation_status, std::move(callback)); | |
| 285 } | |
| 286 | |
| 287 private: | |
| 288 bool bad_message_expected_ = false; | |
| 289 | |
| 290 DISALLOW_COPY_AND_ASSIGN(ReportBadMessageChromePromptImpl); | |
| 291 }; | |
| 292 | |
| 293 // Parameters for this test: | |
| 294 // - bool in_browser_cleaner_ui: indicates if InBrowserCleanerUI experiment | |
| 295 // is enabled; if so, the parent and the child processes will communicate | |
| 296 // via a Mojo IPC. | |
| 297 // - ElevationStatus elevation_status: indicates if the scan results sent by | |
| 298 // the child process should consider that elevation will be required for | |
| 299 // cleanup. | |
| 300 // - MockedReporterFailure expected_reporter_failure: indicates errors that | |
| 301 // should be simulated in the reporter process. | |
| 302 class ReporterRunnerTest | |
| 303 : public InProcessBrowserTest, | |
| 304 public SwReporterTestingDelegate, | |
| 305 public ::testing::WithParamInterface< | |
| 306 std::tuple<bool, ElevationStatus, MockedReporterFailure>> { | |
| 307 public: | 57 public: |
| 308 ReporterRunnerTest() = default; | 58 ReporterRunnerTest() = default; |
| 309 | 59 |
| 310 void SetUpInProcessBrowserTestFixture() override { | 60 void SetUpInProcessBrowserTestFixture() override { |
| 311 SetSwReporterTestingDelegate(this); | 61 SetSwReporterTestingDelegate(this); |
| 312 | 62 |
| 313 std::tie(in_browser_cleaner_ui_, elevation_status_, | 63 in_browser_cleaner_ui_ = GetParam(); |
| 314 expected_reporter_failure_) = GetParam(); | |
| 315 // The config should only accept elevation_status_ if InBrowserCleanerUI | |
| 316 // feature is enabled. | |
| 317 ASSERT_TRUE(elevation_status_ == ElevationStatus::NOT_REQUIRED || | |
| 318 in_browser_cleaner_ui_); | |
| 319 | |
| 320 if (in_browser_cleaner_ui_) | 64 if (in_browser_cleaner_ui_) |
| 321 scoped_feature_list_.InitAndEnableFeature(kInBrowserCleanerUIFeature); | 65 scoped_feature_list_.InitAndEnableFeature(kInBrowserCleanerUIFeature); |
| 322 else | 66 else |
| 323 scoped_feature_list_.InitAndDisableFeature(kInBrowserCleanerUIFeature); | 67 scoped_feature_list_.InitAndDisableFeature(kInBrowserCleanerUIFeature); |
| 324 } | 68 } |
| 325 | 69 |
| 326 void SetUpOnMainThread() override { | 70 void SetUpOnMainThread() override { |
| 327 // During the test, use a task runner with a mock clock. | 71 // During the test, use a task runner with a mock clock. |
| 328 saved_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 72 saved_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 329 ASSERT_NE(mock_time_task_runner_, saved_task_runner_); | 73 ASSERT_NE(mock_time_task_runner_, saved_task_runner_); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 347 | 91 |
| 348 void TearDownInProcessBrowserTestFixture() override { | 92 void TearDownInProcessBrowserTestFixture() override { |
| 349 SetSwReporterTestingDelegate(nullptr); | 93 SetSwReporterTestingDelegate(nullptr); |
| 350 } | 94 } |
| 351 | 95 |
| 352 // Records that the prompt was shown. | 96 // Records that the prompt was shown. |
| 353 void TriggerPrompt(Browser* browser, const std::string& version) override { | 97 void TriggerPrompt(Browser* browser, const std::string& version) override { |
| 354 prompt_trigger_called_ = true; | 98 prompt_trigger_called_ = true; |
| 355 } | 99 } |
| 356 | 100 |
| 357 // Spawns and returns a subprocess to mock an execution of the reporter with | 101 // Records that the reporter was launched with the parameters given in |
| 358 // the parameters given in |invocation| that will return | 102 // |invocation| |
| 359 // |exit_code_to_report_|. If IPC communication needs to be mocked, this will | 103 int LaunchReporter(const SwReporterInvocation& invocation) override { |
| 360 // also provide values that define the expected behavior of the child | |
| 361 // process. | |
| 362 // Records the launch and parameters used for further verification. | |
| 363 base::Process LaunchReporter( | |
| 364 const SwReporterInvocation& invocation, | |
| 365 const base::LaunchOptions& launch_options) override { | |
| 366 ++reporter_launch_count_; | 104 ++reporter_launch_count_; |
| 367 reporter_launch_parameters_.push_back(invocation); | 105 reporter_launch_parameters_.push_back(invocation); |
| 368 if (first_launch_callback_) | 106 if (first_launch_callback_) |
| 369 std::move(first_launch_callback_).Run(); | 107 std::move(first_launch_callback_).Run(); |
| 370 | 108 return exit_code_to_report_; |
| 371 if (exit_code_to_report_ == kReporterNotLaunchedExitCode) | |
| 372 return base::Process(); // IsValid() will return false. | |
| 373 | |
| 374 base::CommandLine command_line( | |
| 375 base::GetMultiProcessTestChildBaseCommandLine()); | |
| 376 command_line.AppendArguments(invocation.command_line, | |
| 377 /*include_program=*/false); | |
| 378 command_line.AppendSwitchASCII(kExitCodeToReturnSwitch, | |
| 379 base::IntToString(exit_code_to_report_)); | |
| 380 | |
| 381 if (in_browser_cleaner_ui_) { | |
| 382 AddPromptAcceptanceToCommandLine(PromptAcceptance::DENIED, &command_line); | |
| 383 if (exit_code_to_report_ == chrome_cleaner::kSwReporterCleanupNeeded) { | |
| 384 command_line.AppendSwitch(kReportUwSFoundSwitch); | |
| 385 if (elevation_status_ == ElevationStatus::REQUIRED) | |
| 386 command_line.AppendSwitch(kReportElevationRequiredSwitch); | |
| 387 } | |
| 388 } | |
| 389 | |
| 390 if (expected_reporter_failure_ != MockedReporterFailure::kNone) | |
| 391 AddExpectedCrashToCommandLine(expected_reporter_failure_, &command_line); | |
| 392 | |
| 393 bad_message_expected_ = expected_reporter_failure_ == | |
| 394 MockedReporterFailure::kBadMessageReported; | |
| 395 bad_message_reported_ = false; | |
| 396 | |
| 397 base::SpawnChildResult result = base::SpawnMultiProcessTestChild( | |
| 398 "MockSwReporterProcess", command_line, launch_options); | |
| 399 return std::move(result.process); | |
| 400 } | 109 } |
| 401 | 110 |
| 402 // Returns the test's idea of the current time. | 111 // Returns the test's idea of the current time. |
| 403 base::Time Now() const override { return mock_time_task_runner_->Now(); } | 112 base::Time Now() const override { return mock_time_task_runner_->Now(); } |
| 404 | 113 |
| 405 // Returns a task runner to use when launching the reporter (which is | 114 // Returns a task runner to use when launching the reporter (which is |
| 406 // normally a blocking action). | 115 // normally a blocking action). |
| 407 base::TaskRunner* BlockingTaskRunner() const override { | 116 base::TaskRunner* BlockingTaskRunner() const override { |
| 408 // Use the test's main task runner so that we don't need to pump another | 117 // Use the test's main task runner so that we don't need to pump another |
| 409 // message loop. Since the test calls LaunchReporter instead of actually | 118 // message loop. Since the test calls LaunchReporter instead of actually |
| 410 // doing a blocking reporter launch, it doesn't matter that the task runner | 119 // doing a blocking reporter launch, it doesn't matter that the task runner |
| 411 // doesn't have the MayBlock trait. | 120 // doesn't have the MayBlock trait. |
| 412 return mock_time_task_runner_.get(); | 121 return mock_time_task_runner_.get(); |
| 413 } | 122 } |
| 414 | 123 |
| 415 std::unique_ptr<ChromePromptImpl> CreateChromePromptImpl( | |
| 416 chrome_cleaner::mojom::ChromePromptRequest request) override { | |
| 417 return base::MakeUnique<ReportBadMessageChromePromptImpl>( | |
| 418 std::move(request), bad_message_expected_, | |
| 419 base::Bind(&ReporterRunnerTest::OnConnectionClosed, | |
| 420 base::Unretained(this))); | |
| 421 } | |
| 422 | |
| 423 void OnConnectionClosed() override {} | |
| 424 | |
| 425 void OnConnectionError(const std::string& message) override { | |
| 426 bad_message_reported_ = true; | |
| 427 } | |
| 428 | |
| 429 // Schedules a single reporter to run. | 124 // Schedules a single reporter to run. |
| 430 void RunReporter(int exit_code_to_report, | 125 void RunReporter(int exit_code_to_report, |
| 431 const base::FilePath& exe_path = base::FilePath()) { | 126 const base::FilePath& exe_path = base::FilePath()) { |
| 432 exit_code_to_report_ = exit_code_to_report; | 127 exit_code_to_report_ = exit_code_to_report; |
| 433 auto invocation = SwReporterInvocation::FromFilePath(exe_path); | 128 auto invocation = SwReporterInvocation::FromFilePath(exe_path); |
| 434 invocation.supported_behaviours = | 129 invocation.supported_behaviours = |
| 435 SwReporterInvocation::BEHAVIOUR_LOG_EXIT_CODE_TO_PREFS | | 130 SwReporterInvocation::BEHAVIOUR_LOG_EXIT_CODE_TO_PREFS | |
| 436 SwReporterInvocation::BEHAVIOUR_TRIGGER_PROMPT | | 131 SwReporterInvocation::BEHAVIOUR_TRIGGER_PROMPT | |
| 437 SwReporterInvocation::BEHAVIOUR_ALLOW_SEND_REPORTER_LOGS; | 132 SwReporterInvocation::BEHAVIOUR_ALLOW_SEND_REPORTER_LOGS; |
| 438 | 133 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 507 bool expect_prompt) { | 202 bool expect_prompt) { |
| 508 EXPECT_TRUE(mock_time_task_runner_->HasPendingTask()); | 203 EXPECT_TRUE(mock_time_task_runner_->HasPendingTask()); |
| 509 reporter_launch_count_ = 0; | 204 reporter_launch_count_ = 0; |
| 510 reporter_launch_parameters_.clear(); | 205 reporter_launch_parameters_.clear(); |
| 511 prompt_trigger_called_ = false; | 206 prompt_trigger_called_ = false; |
| 512 | 207 |
| 513 mock_time_task_runner_->FastForwardBy( | 208 mock_time_task_runner_->FastForwardBy( |
| 514 base::TimeDelta::FromDays(days_until_launch)); | 209 base::TimeDelta::FromDays(days_until_launch)); |
| 515 | 210 |
| 516 EXPECT_EQ(expected_launch_count, reporter_launch_count_); | 211 EXPECT_EQ(expected_launch_count, reporter_launch_count_); |
| 517 // Note: a bad message error will not prevent the prompt that is shown to | 212 EXPECT_EQ(expect_prompt, prompt_trigger_called_); |
| 518 // the user today. Once we hook the new prompt here, we will need to review | |
| 519 // this expectation. | |
| 520 EXPECT_EQ(expect_prompt && | |
| 521 (expected_reporter_failure_ == MockedReporterFailure::kNone || | |
| 522 expected_reporter_failure_ == | |
| 523 MockedReporterFailure::kBadMessageReported), | |
| 524 prompt_trigger_called_); | |
| 525 | |
| 526 EXPECT_EQ(bad_message_expected_, bad_message_reported_); | |
| 527 } | 213 } |
| 528 | 214 |
| 529 // Expects that after |days_until_launched| days, the reporter will be | 215 // Expects that after |days_until_launched| days, the reporter will be |
| 530 // launched once with each path in |expected_launch_paths|, and TriggerPrompt | 216 // launched once with each path in |expected_launch_paths|, and TriggerPrompt |
| 531 // will be called if and only if |expect_prompt| is true. | 217 // will be called if and only if |expect_prompt| is true. |
| 532 void ExpectReporterLaunches( | 218 void ExpectReporterLaunches( |
| 533 int days_until_launch, | 219 int days_until_launch, |
| 534 const std::vector<base::FilePath>& expected_launch_paths, | 220 const std::vector<base::FilePath>& expected_launch_paths, |
| 535 bool expect_prompt) { | 221 bool expect_prompt) { |
| 536 ExpectReporterLaunches(days_until_launch, expected_launch_paths.size(), | 222 ExpectReporterLaunches(days_until_launch, expected_launch_paths.size(), |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 582 } | 268 } |
| 583 | 269 |
| 584 // A task runner with a mock clock. | 270 // A task runner with a mock clock. |
| 585 scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner_ = | 271 scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner_ = |
| 586 new base::TestMockTimeTaskRunner(); | 272 new base::TestMockTimeTaskRunner(); |
| 587 | 273 |
| 588 // The task runner that was in use before installing |mock_time_task_runner_|. | 274 // The task runner that was in use before installing |mock_time_task_runner_|. |
| 589 scoped_refptr<base::SingleThreadTaskRunner> saved_task_runner_; | 275 scoped_refptr<base::SingleThreadTaskRunner> saved_task_runner_; |
| 590 | 276 |
| 591 bool in_browser_cleaner_ui_; | 277 bool in_browser_cleaner_ui_; |
| 592 ElevationStatus elevation_status_; | |
| 593 MockedReporterFailure expected_reporter_failure_; | |
| 594 | |
| 595 // Indicates if a bad message error should be simulated by the parent | |
| 596 // process. | |
| 597 bool bad_message_expected_ = false; | |
| 598 | |
| 599 // Set by ReportBadMessageChromePromptImpl if a bad message error is reported. | |
| 600 bool bad_message_reported_ = false; | |
| 601 | 278 |
| 602 bool prompt_trigger_called_ = false; | 279 bool prompt_trigger_called_ = false; |
| 603 int reporter_launch_count_ = 0; | 280 int reporter_launch_count_ = 0; |
| 604 std::vector<SwReporterInvocation> reporter_launch_parameters_; | 281 std::vector<SwReporterInvocation> reporter_launch_parameters_; |
| 605 int exit_code_to_report_ = kReporterNotLaunchedExitCode; | 282 int exit_code_to_report_ = kReporterNotLaunchedExitCode; |
| 606 | 283 |
| 607 // A callback to invoke when the first reporter of a queue is launched. This | 284 // A callback to invoke when the first reporter of a queue is launched. This |
| 608 // can be used to perform actions in the middle of a queue of reporters which | 285 // can be used to perform actions in the middle of a queue of reporters which |
| 609 // all launch on the same mock clock tick. | 286 // all launch on the same mock clock tick. |
| 610 base::OnceClosure first_launch_callback_; | 287 base::OnceClosure first_launch_callback_; |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 960 // Logs should also be sent for the next run, even though LastTimeSentReport | 637 // Logs should also be sent for the next run, even though LastTimeSentReport |
| 961 // is now recent, because the run is part of the same set of invocations. | 638 // is now recent, because the run is part of the same set of invocations. |
| 962 { | 639 { |
| 963 SCOPED_TRACE("second launch"); | 640 SCOPED_TRACE("second launch"); |
| 964 ExpectLoggingSwitches(reporter_launch_parameters_[1], true); | 641 ExpectLoggingSwitches(reporter_launch_parameters_[1], true); |
| 965 ExpectLastReportSentInTheLastHour(); | 642 ExpectLastReportSentInTheLastHour(); |
| 966 } | 643 } |
| 967 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | 644 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); |
| 968 } | 645 } |
| 969 | 646 |
| 970 INSTANTIATE_TEST_CASE_P( | 647 INSTANTIATE_TEST_CASE_P(WithInBrowserCleanerUIParam, |
| 971 NoInBrowserCleanerUI, | 648 ReporterRunnerTest, |
| 972 ReporterRunnerTest, | 649 testing::Bool()); |
| 973 testing::Combine(testing::Values(false), | |
| 974 testing::Values(ElevationStatus::NOT_REQUIRED), | |
| 975 testing::Values(MockedReporterFailure::kNone, | |
| 976 MockedReporterFailure::kCrashOnStartup))); | |
| 977 | |
| 978 INSTANTIATE_TEST_CASE_P( | |
| 979 InBrowserCleanerUI, | |
| 980 ReporterRunnerTest, | |
| 981 testing::Combine( | |
| 982 testing::Values(true), | |
| 983 testing::Values(ElevationStatus::NOT_REQUIRED, | |
| 984 ElevationStatus::REQUIRED), | |
| 985 testing::Values( | |
| 986 MockedReporterFailure::kNone, | |
| 987 MockedReporterFailure::kCrashOnStartup, | |
| 988 MockedReporterFailure::kCrashAfterConnectedToParentProcess, | |
| 989 MockedReporterFailure::kCrashWhileWaitingForResponse, | |
| 990 MockedReporterFailure::kCrashAfterReceivedResponse, | |
| 991 MockedReporterFailure::kBadMessageReported))); | |
| 992 | 650 |
| 993 // This provide tests which allows explicit invocation of the SRT Prompt | 651 // This provide tests which allows explicit invocation of the SRT Prompt |
| 994 // useful for checking dialog layout or any other interactive functionality | 652 // useful for checking dialog layout or any other interactive functionality |
| 995 // tests. See docs/testing/test_browser_dialog.md for description of the | 653 // tests. See docs/testing/test_browser_dialog.md for description of the |
| 996 // testing framework. | 654 // testing framework. |
| 997 IN_PROC_BROWSER_TEST_F(ReporterRunnerPromptTest, InvokeDialog_SRTErrorNoFile) { | 655 IN_PROC_BROWSER_TEST_F(ReporterRunnerPromptTest, InvokeDialog_SRTErrorNoFile) { |
| 998 RunDialog(); | 656 RunDialog(); |
| 999 } | 657 } |
| 1000 | 658 |
| 1001 IN_PROC_BROWSER_TEST_F(ReporterRunnerPromptTest, InvokeDialog_SRTErrorFile) { | 659 IN_PROC_BROWSER_TEST_F(ReporterRunnerPromptTest, InvokeDialog_SRTErrorFile) { |
| 1002 RunDialog(); | 660 RunDialog(); |
| 1003 } | 661 } |
| 1004 | 662 |
| 1005 } // namespace safe_browsing | 663 } // namespace safe_browsing |
| OLD | NEW |