| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/safe_browsing/srt_fetcher_win.h" | |
| 6 | |
| 7 #include <initializer_list> | |
| 8 #include <set> | |
| 9 #include <tuple> | |
| 10 #include <utility> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "base/bind.h" | |
| 14 #include "base/bind_helpers.h" | |
| 15 #include "base/callback.h" | |
| 16 #include "base/callback_helpers.h" | |
| 17 #include "base/files/file_path.h" | |
| 18 #include "base/macros.h" | |
| 19 #include "base/memory/ref_counted.h" | |
| 20 #include "base/message_loop/message_loop.h" | |
| 21 #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" | |
| 25 #include "base/test/test_mock_time_task_runner.h" | |
| 26 #include "base/threading/sequenced_task_runner_handle.h" | |
| 27 #include "base/threading/thread_task_runner_handle.h" | |
| 28 #include "base/time/time.h" | |
| 29 #include "base/version.h" | |
| 30 #include "chrome/browser/browser_process.h" | |
| 31 #include "chrome/browser/lifetime/keep_alive_types.h" | |
| 32 #include "chrome/browser/lifetime/scoped_keep_alive.h" | |
| 33 #include "chrome/browser/profiles/profile.h" | |
| 34 #include "chrome/browser/safe_browsing/srt_chrome_prompt_impl.h" | |
| 35 #include "chrome/browser/safe_browsing/srt_client_info_win.h" | |
| 36 #include "chrome/browser/ui/browser.h" | |
| 37 #include "chrome/browser/ui/browser_finder.h" | |
| 38 #include "chrome/browser/ui/test/test_browser_dialog.h" | |
| 39 #include "chrome/common/pref_names.h" | |
| 40 #include "chrome/test/base/in_process_browser_test.h" | |
| 41 #include "components/chrome_cleaner/public/constants/constants.h" | |
| 42 #include "components/component_updater/pref_names.h" | |
| 43 #include "components/prefs/pref_service.h" | |
| 44 #include "components/safe_browsing_db/safe_browsing_prefs.h" | |
| 45 #include "mojo/edk/embedder/embedder.h" | |
| 46 #include "mojo/edk/embedder/scoped_ipc_support.h" | |
| 47 #include "mojo/edk/system/core.h" | |
| 48 #include "testing/multiprocess_func_list.h" | |
| 49 | |
| 50 namespace safe_browsing { | |
| 51 | |
| 52 namespace { | |
| 53 | |
| 54 using chrome_cleaner::mojom::ElevationStatus; | |
| 55 using chrome_cleaner::mojom::PromptAcceptance; | |
| 56 | |
| 57 // Special switches passed by the parent process (test case) to the reporter | |
| 58 // child process to indicate the behavior that should be mocked. | |
| 59 constexpr char kExitCodeToReturnSwitch[] = "exit-code-to-return"; | |
| 60 constexpr char kReportUwSFoundSwitch[] = "report-uws-found"; | |
| 61 constexpr char kReportElevationRequiredSwitch[] = "report-elevation-required"; | |
| 62 constexpr char kExpectedPromptAcceptanceSwitch[] = "expected-prompt-acceptance"; | |
| 63 constexpr char kExpectedReporterFailureSwitch[] = "expected-reporter-crash"; | |
| 64 | |
| 65 // The exit code to be returned in case of failure in the child process. | |
| 66 // This should never be passed as the expected exit code to be reported by | |
| 67 // tests. | |
| 68 constexpr int kFailureExitCode = -1; | |
| 69 | |
| 70 // Pass the |prompt_acceptance| to the mock child process in command line | |
| 71 // switch kExpectedPromptAcceptanceSwitch. | |
| 72 void AddPromptAcceptanceToCommandLine(PromptAcceptance prompt_acceptance, | |
| 73 base::CommandLine* command_line) { | |
| 74 command_line->AppendSwitchASCII( | |
| 75 kExpectedPromptAcceptanceSwitch, | |
| 76 base::IntToString(static_cast<int>(prompt_acceptance))); | |
| 77 } | |
| 78 | |
| 79 // Parses and returns the prompt acceptance value passed by the parent process | |
| 80 // in command line switch kExpectedPromptAcceptanceSwitch. Returns | |
| 81 // PromptAcceptance::UNSPECIFIED if the switch doesn't exist or can't be | |
| 82 // parsed to a valid PromptAcceptance enumerator. | |
| 83 PromptAcceptance PromptAcceptanceFromCommandLine( | |
| 84 const base::CommandLine& command_line) { | |
| 85 const std::string& prompt_acceptance_str = | |
| 86 command_line.GetSwitchValueASCII(kExpectedPromptAcceptanceSwitch); | |
| 87 int val = -1; | |
| 88 if (base::StringToInt(prompt_acceptance_str, &val)) { | |
| 89 PromptAcceptance prompt_acceptance = static_cast<PromptAcceptance>(val); | |
| 90 if (chrome_cleaner::mojom::IsKnownEnumValue(prompt_acceptance)) | |
| 91 return prompt_acceptance; | |
| 92 } | |
| 93 return PromptAcceptance::UNSPECIFIED; | |
| 94 } | |
| 95 | |
| 96 // Pointer to ChromePromptPtr object to be used by the child process. The | |
| 97 // object must be created, deleted, and accessed on the IPC thread only. | |
| 98 chrome_cleaner::mojom::ChromePromptPtr* g_chrome_prompt_ptr = nullptr; | |
| 99 | |
| 100 // Potential failures in the reporter process that should be handled by the | |
| 101 // parent process. | |
| 102 enum class MockedReporterFailure { | |
| 103 kNone = 0, | |
| 104 // Crashes at specific moments in the reporter when connected to the IPC. | |
| 105 kCrashOnStartup = 1, | |
| 106 kCrashAfterConnectedToParentProcess = 2, | |
| 107 kCrashWhileWaitingForResponse = 3, | |
| 108 kCrashAfterReceivedResponse = 4, | |
| 109 // Once an IPC message is sent by the reporter, the parent process will | |
| 110 // report a bad message that will lead to an invocation of OnConnectionError. | |
| 111 kBadMessageReported = 5, | |
| 112 }; | |
| 113 | |
| 114 void AddExpectedCrashToCommandLine(MockedReporterFailure reporter_failure, | |
| 115 base::CommandLine* command_line) { | |
| 116 command_line->AppendSwitchASCII( | |
| 117 kExpectedReporterFailureSwitch, | |
| 118 base::IntToString(static_cast<int>(reporter_failure))); | |
| 119 } | |
| 120 | |
| 121 void CrashIf(MockedReporterFailure reporter_failure) { | |
| 122 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
| 123 const std::string& expected_str = | |
| 124 command_line->GetSwitchValueASCII(kExpectedReporterFailureSwitch); | |
| 125 int val = -1; | |
| 126 if (base::StringToInt(expected_str, &val) && | |
| 127 static_cast<MockedReporterFailure>(val) == reporter_failure) { | |
| 128 exit(kFailureExitCode); | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 // The callback function to be passed to ChromePrompt::PromptUser to check if | |
| 133 // the prompt accepted returned by the parent process is equal to | |
| 134 // |expected_prompt_acceptance|. Will set |expected_value_received| with the | |
| 135 // comparison result, so that the main thread can report failure. Will invoke | |
| 136 // |done| callback when done. | |
| 137 void PromptUserCallback(const base::Closure& done, | |
| 138 PromptAcceptance expected_prompt_acceptance, | |
| 139 bool* expected_value_received, | |
| 140 PromptAcceptance prompt_acceptance) { | |
| 141 *expected_value_received = prompt_acceptance == expected_prompt_acceptance; | |
| 142 // It's safe to delete the ChromePromptPtr object here, since it will not be | |
| 143 // used anymore by the child process. | |
| 144 delete g_chrome_prompt_ptr; | |
| 145 g_chrome_prompt_ptr = nullptr; | |
| 146 CrashIf(MockedReporterFailure::kCrashAfterReceivedResponse); | |
| 147 done.Run(); | |
| 148 } | |
| 149 | |
| 150 // Mocks the sending of scan results from the child process to the parent | |
| 151 // process. Obtains the behavior to be mocked from special switches in | |
| 152 // |command_line|. Sets |expected_value_received| as true if the parent | |
| 153 // process replies with the expected prompt acceptance value. | |
| 154 void SendScanResults(const std::string& chrome_mojo_pipe_token, | |
| 155 const base::CommandLine& command_line, | |
| 156 const base::Closure& done, | |
| 157 bool* expected_value_received) { | |
| 158 constexpr int kDefaultUwSId = 10; | |
| 159 constexpr char kDefaultUwSName[] = "RemovedUwS"; | |
| 160 | |
| 161 mojo::ScopedMessagePipeHandle message_pipe_handle = | |
| 162 mojo::edk::CreateChildMessagePipe(chrome_mojo_pipe_token); | |
| 163 // This pointer will be deleted by PromptUserCallback. | |
| 164 g_chrome_prompt_ptr = new chrome_cleaner::mojom::ChromePromptPtr(); | |
| 165 g_chrome_prompt_ptr->Bind(chrome_cleaner::mojom::ChromePromptPtrInfo( | |
| 166 std::move(message_pipe_handle), 0)); | |
| 167 | |
| 168 std::vector<chrome_cleaner::mojom::UwSPtr> removable_uws_found; | |
| 169 if (command_line.HasSwitch(kReportUwSFoundSwitch)) { | |
| 170 chrome_cleaner::mojom::UwSPtr uws = chrome_cleaner::mojom::UwS::New(); | |
| 171 uws->id = kDefaultUwSId; | |
| 172 uws->name = kDefaultUwSName; | |
| 173 uws->observed_behaviours = chrome_cleaner::mojom::ObservedBehaviours::New(); | |
| 174 removable_uws_found.push_back(std::move(uws)); | |
| 175 } | |
| 176 const ElevationStatus elevation_status = | |
| 177 command_line.HasSwitch(kReportElevationRequiredSwitch) | |
| 178 ? ElevationStatus::REQUIRED | |
| 179 : ElevationStatus::NOT_REQUIRED; | |
| 180 const PromptAcceptance expected_prompt_acceptance = | |
| 181 PromptAcceptanceFromCommandLine(command_line); | |
| 182 | |
| 183 // This task is posted to the IPC thread so that it will happen after the | |
| 184 // request is sent to the parent process and before the response gets | |
| 185 // handled on the IPC thread. | |
| 186 base::SequencedTaskRunnerHandle::Get()->PostTask( | |
| 187 FROM_HERE, | |
| 188 base::Bind(&CrashIf, | |
| 189 MockedReporterFailure::kCrashWhileWaitingForResponse)); | |
| 190 | |
| 191 (*g_chrome_prompt_ptr) | |
| 192 ->PromptUser( | |
| 193 std::move(removable_uws_found), elevation_status, | |
| 194 base::Bind(&PromptUserCallback, done, expected_prompt_acceptance, | |
| 195 expected_value_received)); | |
| 196 } | |
| 197 | |
| 198 // Connects to the parent process and sends mocked scan results. Returns true | |
| 199 // if connection was successful and the prompt acceptance results sent by the | |
| 200 // parent process are the same as expected. | |
| 201 bool ConnectAndSendDataToParentProcess( | |
| 202 const std::string& chrome_mojo_pipe_token, | |
| 203 const base::CommandLine& command_line) { | |
| 204 DCHECK(!chrome_mojo_pipe_token.empty()); | |
| 205 | |
| 206 mojo::edk::Init(); | |
| 207 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); | |
| 208 base::Thread io_thread("IPCThread"); | |
| 209 if (!io_thread.StartWithOptions(options)) | |
| 210 return false; | |
| 211 mojo::edk::ScopedIPCSupport ipc_support( | |
| 212 io_thread.task_runner(), | |
| 213 mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN); | |
| 214 mojo::edk::SetParentPipeHandleFromCommandLine(); | |
| 215 | |
| 216 CrashIf(MockedReporterFailure::kCrashAfterConnectedToParentProcess); | |
| 217 | |
| 218 base::MessageLoop message_loop; | |
| 219 base::RunLoop run_loop; | |
| 220 // After the response from the parent process is received, this will post a | |
| 221 // task to unblock the child process's main thread. | |
| 222 auto done = base::Bind( | |
| 223 [](scoped_refptr<base::SequencedTaskRunner> main_runner, | |
| 224 base::Closure quit_closure) { | |
| 225 main_runner->PostTask(FROM_HERE, std::move(quit_closure)); | |
| 226 }, | |
| 227 base::SequencedTaskRunnerHandle::Get(), | |
| 228 base::Passed(run_loop.QuitClosure())); | |
| 229 | |
| 230 bool expected_value_received = false; | |
| 231 io_thread.task_runner()->PostTask( | |
| 232 FROM_HERE, base::Bind(&SendScanResults, chrome_mojo_pipe_token, | |
| 233 command_line, done, &expected_value_received)); | |
| 234 | |
| 235 run_loop.Run(); | |
| 236 | |
| 237 return expected_value_received; | |
| 238 } | |
| 239 | |
| 240 // Mocks a Software Reporter process that returns an exit code specified by | |
| 241 // command line switch kExitCodeToReturnSwitch. If a Mojo IPC is available, | |
| 242 // this will also connect to the parent process and send mocked scan results | |
| 243 // to the parent process using data passed as command line switches. | |
| 244 MULTIPROCESS_TEST_MAIN(MockSwReporterProcess) { | |
| 245 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
| 246 CrashIf(MockedReporterFailure::kCrashOnStartup); | |
| 247 const std::string& str = | |
| 248 command_line->GetSwitchValueASCII(kExitCodeToReturnSwitch); | |
| 249 const std::string& chrome_mojo_pipe_token = command_line->GetSwitchValueASCII( | |
| 250 chrome_cleaner::kChromeMojoPipeTokenSwitch); | |
| 251 int exit_code_to_report = kFailureExitCode; | |
| 252 bool success = base::StringToInt(str, &exit_code_to_report) && | |
| 253 (chrome_mojo_pipe_token.empty() || | |
| 254 ConnectAndSendDataToParentProcess(chrome_mojo_pipe_token, | |
| 255 *command_line)); | |
| 256 return success ? exit_code_to_report : kFailureExitCode; | |
| 257 } | |
| 258 | |
| 259 // Decorates a ChromePromptImpl object to simulate failures indentified by the | |
| 260 // parent process and keeps track of errors handled. By default, delegates all | |
| 261 // actions to the decorated object. | |
| 262 class ReportBadMessageChromePromptImpl : public ChromePromptImpl { | |
| 263 public: | |
| 264 ReportBadMessageChromePromptImpl( | |
| 265 chrome_cleaner::mojom::ChromePromptRequest request, | |
| 266 bool bad_message_expected, | |
| 267 base::Closure on_connection_closed) | |
| 268 : ChromePromptImpl(std::move(request), std::move(on_connection_closed)), | |
| 269 bad_message_expected_(bad_message_expected) {} | |
| 270 ~ReportBadMessageChromePromptImpl() override = default; | |
| 271 | |
| 272 void PromptUser( | |
| 273 std::vector<chrome_cleaner::mojom::UwSPtr> removable_uws_found, | |
| 274 chrome_cleaner::mojom::ElevationStatus elevation_status, | |
| 275 const chrome_cleaner::mojom::ChromePrompt::PromptUserCallback& callback) | |
| 276 override { | |
| 277 if (bad_message_expected_) | |
| 278 mojo::ReportBadMessage("bad message"); | |
| 279 | |
| 280 ChromePromptImpl::PromptUser(std::move(removable_uws_found), | |
| 281 elevation_status, callback); | |
| 282 } | |
| 283 | |
| 284 private: | |
| 285 bool bad_message_expected_ = false; | |
| 286 | |
| 287 DISALLOW_COPY_AND_ASSIGN(ReportBadMessageChromePromptImpl); | |
| 288 }; | |
| 289 | |
| 290 // Parameters for this test: | |
| 291 // - bool in_browser_cleaner_ui: indicates if InBrowserCleanerUI experiment | |
| 292 // is enabled; if so, the parent and the child processes will communicate | |
| 293 // via a Mojo IPC. | |
| 294 // - ElevationStatus elevation_status: indicates if the scan results sent by | |
| 295 // the child process should consider that elevation will be required for | |
| 296 // cleanup. | |
| 297 // - MockedReporterFailure expected_reporter_failure: indicates errors that | |
| 298 // should be simulated in the reporter process. | |
| 299 class SRTFetcherTest | |
| 300 : public InProcessBrowserTest, | |
| 301 public SwReporterTestingDelegate, | |
| 302 public ::testing::WithParamInterface< | |
| 303 std::tuple<bool, ElevationStatus, MockedReporterFailure>> { | |
| 304 public: | |
| 305 SRTFetcherTest() = default; | |
| 306 | |
| 307 void SetUpInProcessBrowserTestFixture() override { | |
| 308 SetSwReporterTestingDelegate(this); | |
| 309 | |
| 310 std::tie(in_browser_cleaner_ui_, elevation_status_, | |
| 311 expected_reporter_failure_) = GetParam(); | |
| 312 // The config should only accept elevation_status_ if InBrowserCleanerUI | |
| 313 // feature is enabled. | |
| 314 ASSERT_TRUE(elevation_status_ == ElevationStatus::NOT_REQUIRED || | |
| 315 in_browser_cleaner_ui_); | |
| 316 | |
| 317 if (in_browser_cleaner_ui_) | |
| 318 scoped_feature_list_.InitAndEnableFeature(kInBrowserCleanerUIFeature); | |
| 319 else | |
| 320 scoped_feature_list_.InitAndDisableFeature(kInBrowserCleanerUIFeature); | |
| 321 } | |
| 322 | |
| 323 void SetUpOnMainThread() override { | |
| 324 // During the test, use a task runner with a mock clock. | |
| 325 saved_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
| 326 ASSERT_NE(mock_time_task_runner_, saved_task_runner_); | |
| 327 base::MessageLoop::current()->SetTaskRunner(mock_time_task_runner_); | |
| 328 | |
| 329 InProcessBrowserTest::SetUpOnMainThread(); | |
| 330 | |
| 331 // SetDateInLocalState calculates a time as Now() minus an offset. Move the | |
| 332 // simulated clock ahead far enough that this calculation won't underflow. | |
| 333 mock_time_task_runner_->FastForwardBy( | |
| 334 base::TimeDelta::FromDays(kDaysBetweenSuccessfulSwReporterRuns * 2)); | |
| 335 | |
| 336 ClearLastTimeSentReport(); | |
| 337 } | |
| 338 | |
| 339 void TearDownOnMainThread() override { | |
| 340 // Restore the standard task runner to perform browser cleanup, which will | |
| 341 // wait forever with the mock clock. | |
| 342 base::MessageLoop::current()->SetTaskRunner(saved_task_runner_); | |
| 343 } | |
| 344 | |
| 345 void TearDownInProcessBrowserTestFixture() override { | |
| 346 SetSwReporterTestingDelegate(nullptr); | |
| 347 } | |
| 348 | |
| 349 // Records that the prompt was shown. | |
| 350 void TriggerPrompt(Browser* browser, const std::string& version) override { | |
| 351 prompt_trigger_called_ = true; | |
| 352 } | |
| 353 | |
| 354 // Spawns and returns a subprocess to mock an execution of the reporter with | |
| 355 // the parameters given in |invocation| that will return | |
| 356 // |exit_code_to_report_|. If IPC communication needs to be mocked, this will | |
| 357 // also provide values that define the expected behavior of the child | |
| 358 // process. | |
| 359 // Records the launch and parameters used for further verification. | |
| 360 base::Process LaunchReporter( | |
| 361 const SwReporterInvocation& invocation, | |
| 362 const base::LaunchOptions& launch_options) override { | |
| 363 ++reporter_launch_count_; | |
| 364 reporter_launch_parameters_.push_back(invocation); | |
| 365 if (first_launch_callback_) | |
| 366 std::move(first_launch_callback_).Run(); | |
| 367 | |
| 368 if (exit_code_to_report_ == kReporterNotLaunchedExitCode) | |
| 369 return base::Process(); // IsValid() will return false. | |
| 370 | |
| 371 base::CommandLine command_line( | |
| 372 base::GetMultiProcessTestChildBaseCommandLine()); | |
| 373 command_line.AppendArguments(invocation.command_line, | |
| 374 /*include_program=*/false); | |
| 375 command_line.AppendSwitchASCII(kExitCodeToReturnSwitch, | |
| 376 base::IntToString(exit_code_to_report_)); | |
| 377 | |
| 378 if (in_browser_cleaner_ui_) { | |
| 379 AddPromptAcceptanceToCommandLine(PromptAcceptance::DENIED, &command_line); | |
| 380 if (exit_code_to_report_ == chrome_cleaner::kSwReporterCleanupNeeded) { | |
| 381 command_line.AppendSwitch(kReportUwSFoundSwitch); | |
| 382 if (elevation_status_ == ElevationStatus::REQUIRED) | |
| 383 command_line.AppendSwitch(kReportElevationRequiredSwitch); | |
| 384 } | |
| 385 } | |
| 386 | |
| 387 if (expected_reporter_failure_ != MockedReporterFailure::kNone) | |
| 388 AddExpectedCrashToCommandLine(expected_reporter_failure_, &command_line); | |
| 389 | |
| 390 bad_message_expected_ = expected_reporter_failure_ == | |
| 391 MockedReporterFailure::kBadMessageReported; | |
| 392 bad_message_reported_ = false; | |
| 393 | |
| 394 base::SpawnChildResult result = base::SpawnMultiProcessTestChild( | |
| 395 "MockSwReporterProcess", command_line, launch_options); | |
| 396 return std::move(result.process); | |
| 397 } | |
| 398 | |
| 399 // Returns the test's idea of the current time. | |
| 400 base::Time Now() const override { return mock_time_task_runner_->Now(); } | |
| 401 | |
| 402 // Returns a task runner to use when launching the reporter (which is | |
| 403 // normally a blocking action). | |
| 404 base::TaskRunner* BlockingTaskRunner() const override { | |
| 405 // Use the test's main task runner so that we don't need to pump another | |
| 406 // message loop. Since the test calls LaunchReporter instead of actually | |
| 407 // doing a blocking reporter launch, it doesn't matter that the task runner | |
| 408 // doesn't have the MayBlock trait. | |
| 409 return mock_time_task_runner_.get(); | |
| 410 } | |
| 411 | |
| 412 std::unique_ptr<ChromePromptImpl> CreateChromePromptImpl( | |
| 413 chrome_cleaner::mojom::ChromePromptRequest request) override { | |
| 414 return base::MakeUnique<ReportBadMessageChromePromptImpl>( | |
| 415 std::move(request), bad_message_expected_, | |
| 416 base::Bind(&SRTFetcherTest::OnConnectionClosed, | |
| 417 base::Unretained(this))); | |
| 418 } | |
| 419 | |
| 420 void OnConnectionClosed() override {} | |
| 421 | |
| 422 void OnConnectionError(const std::string& message) override { | |
| 423 bad_message_reported_ = true; | |
| 424 } | |
| 425 | |
| 426 // Schedules a single reporter to run. | |
| 427 void RunReporter(int exit_code_to_report, | |
| 428 const base::FilePath& exe_path = base::FilePath()) { | |
| 429 exit_code_to_report_ = exit_code_to_report; | |
| 430 auto invocation = SwReporterInvocation::FromFilePath(exe_path); | |
| 431 invocation.supported_behaviours = | |
| 432 SwReporterInvocation::BEHAVIOUR_LOG_EXIT_CODE_TO_PREFS | | |
| 433 SwReporterInvocation::BEHAVIOUR_TRIGGER_PROMPT | | |
| 434 SwReporterInvocation::BEHAVIOUR_ALLOW_SEND_REPORTER_LOGS; | |
| 435 | |
| 436 SwReporterQueue invocations; | |
| 437 invocations.push(invocation); | |
| 438 RunSwReporters(invocations, base::Version("1.2.3")); | |
| 439 } | |
| 440 | |
| 441 // Schedules a queue of reporters to run. | |
| 442 void RunReporterQueue(int exit_code_to_report, | |
| 443 const SwReporterQueue& invocations) { | |
| 444 exit_code_to_report_ = exit_code_to_report; | |
| 445 RunSwReporters(invocations, base::Version("1.2.3")); | |
| 446 } | |
| 447 | |
| 448 // Sets |path| in the local state to a date corresponding to |days| days ago. | |
| 449 void SetDateInLocalState(const std::string& path, int days) { | |
| 450 PrefService* local_state = g_browser_process->local_state(); | |
| 451 local_state->SetInt64( | |
| 452 path, (Now() - base::TimeDelta::FromDays(days)).ToInternalValue()); | |
| 453 } | |
| 454 | |
| 455 // Sets local state for last time the software reporter ran to |days| days | |
| 456 // ago. | |
| 457 void SetDaysSinceLastTriggered(int days) { | |
| 458 SetDateInLocalState(prefs::kSwReporterLastTimeTriggered, days); | |
| 459 } | |
| 460 | |
| 461 // Sets local state for last time the software reporter sent logs to |days| | |
| 462 // days ago. | |
| 463 void SetLastTimeSentReport(int days) { | |
| 464 SetDateInLocalState(prefs::kSwReporterLastTimeSentReport, days); | |
| 465 } | |
| 466 | |
| 467 // Clears local state for last time the software reporter sent logs. This | |
| 468 // prevents potential false positives that could arise from state not | |
| 469 // properly cleaned between successive tests. | |
| 470 void ClearLastTimeSentReport() { | |
| 471 PrefService* local_state = g_browser_process->local_state(); | |
| 472 local_state->ClearPref(prefs::kSwReporterLastTimeSentReport); | |
| 473 } | |
| 474 | |
| 475 // Retrieves the timestamp of the last time the software reporter sent logs. | |
| 476 int64_t GetLastTimeSentReport() { | |
| 477 const PrefService* local_state = g_browser_process->local_state(); | |
| 478 DCHECK(local_state->HasPrefPath(prefs::kSwReporterLastTimeSentReport)); | |
| 479 return local_state->GetInt64(prefs::kSwReporterLastTimeSentReport); | |
| 480 } | |
| 481 | |
| 482 void EnableSBExtendedReporting() { | |
| 483 Browser* browser = chrome::FindLastActive(); | |
| 484 DCHECK(browser); | |
| 485 Profile* profile = browser->profile(); | |
| 486 SetExtendedReportingPref(profile->GetPrefs(), true); | |
| 487 } | |
| 488 | |
| 489 // Expects that the reporter has been scheduled to launch again in |days| | |
| 490 // days. | |
| 491 void ExpectToRunAgain(int days) { | |
| 492 EXPECT_TRUE(mock_time_task_runner_->HasPendingTask()); | |
| 493 EXPECT_LT(base::TimeDelta::FromDays(days) - base::TimeDelta::FromHours(1), | |
| 494 mock_time_task_runner_->NextPendingTaskDelay()); | |
| 495 EXPECT_GE(base::TimeDelta::FromDays(days), | |
| 496 mock_time_task_runner_->NextPendingTaskDelay()); | |
| 497 } | |
| 498 | |
| 499 // Expects that after |days_until_launch| days, the reporter will be | |
| 500 // launched |expected_launch_count| times, and TriggerPrompt will be | |
| 501 // called if and only if |expect_prompt| is true. | |
| 502 void ExpectReporterLaunches(int days_until_launch, | |
| 503 int expected_launch_count, | |
| 504 bool expect_prompt) { | |
| 505 EXPECT_TRUE(mock_time_task_runner_->HasPendingTask()); | |
| 506 reporter_launch_count_ = 0; | |
| 507 reporter_launch_parameters_.clear(); | |
| 508 prompt_trigger_called_ = false; | |
| 509 | |
| 510 mock_time_task_runner_->FastForwardBy( | |
| 511 base::TimeDelta::FromDays(days_until_launch)); | |
| 512 | |
| 513 EXPECT_EQ(expected_launch_count, reporter_launch_count_); | |
| 514 // Note: a bad message error will not prevent the prompt that is shown to | |
| 515 // the user today. Once we hook the new prompt here, we will need to review | |
| 516 // this expectation. | |
| 517 EXPECT_EQ(expect_prompt && | |
| 518 (expected_reporter_failure_ == MockedReporterFailure::kNone || | |
| 519 expected_reporter_failure_ == | |
| 520 MockedReporterFailure::kBadMessageReported), | |
| 521 prompt_trigger_called_); | |
| 522 | |
| 523 EXPECT_EQ(bad_message_expected_, bad_message_reported_); | |
| 524 } | |
| 525 | |
| 526 // Expects that after |days_until_launched| days, the reporter will be | |
| 527 // launched once with each path in |expected_launch_paths|, and TriggerPrompt | |
| 528 // will be called if and only if |expect_prompt| is true. | |
| 529 void ExpectReporterLaunches( | |
| 530 int days_until_launch, | |
| 531 const std::vector<base::FilePath>& expected_launch_paths, | |
| 532 bool expect_prompt) { | |
| 533 ExpectReporterLaunches(days_until_launch, expected_launch_paths.size(), | |
| 534 expect_prompt); | |
| 535 EXPECT_EQ(expected_launch_paths.size(), reporter_launch_parameters_.size()); | |
| 536 for (size_t i = 0; i < expected_launch_paths.size() && | |
| 537 i < reporter_launch_parameters_.size(); | |
| 538 ++i) { | |
| 539 EXPECT_EQ(expected_launch_paths[i], | |
| 540 reporter_launch_parameters_[i].command_line.GetProgram()); | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 void ExpectLastTimeSentReportNotSet() { | |
| 545 PrefService* local_state = g_browser_process->local_state(); | |
| 546 EXPECT_FALSE( | |
| 547 local_state->HasPrefPath(prefs::kSwReporterLastTimeSentReport)); | |
| 548 } | |
| 549 | |
| 550 void ExpectLastReportSentInTheLastHour() { | |
| 551 const PrefService* local_state = g_browser_process->local_state(); | |
| 552 const base::Time now = Now(); | |
| 553 const base::Time last_time_sent_logs = base::Time::FromInternalValue( | |
| 554 local_state->GetInt64(prefs::kSwReporterLastTimeSentReport)); | |
| 555 | |
| 556 // Checks if the last time sent logs is set as no more than one hour ago, | |
| 557 // which should be enough time if the execution does not fail. | |
| 558 EXPECT_LT(now - base::TimeDelta::FromHours(1), last_time_sent_logs); | |
| 559 EXPECT_GE(now, last_time_sent_logs); | |
| 560 } | |
| 561 | |
| 562 // Expects |invocation|'s command line to contain all the switches required | |
| 563 // for reporter logging if and only if |expect_switches| is true. | |
| 564 void ExpectLoggingSwitches(const SwReporterInvocation& invocation, | |
| 565 bool expect_switches) { | |
| 566 static const std::set<std::string> logging_switches{ | |
| 567 chrome_cleaner::kExtendedSafeBrowsingEnabledSwitch, | |
| 568 chrome_cleaner::kChromeVersionSwitch, | |
| 569 chrome_cleaner::kChromeChannelSwitch}; | |
| 570 | |
| 571 const base::CommandLine::SwitchMap& invocation_switches = | |
| 572 invocation.command_line.GetSwitches(); | |
| 573 // Checks if switches that enable logging on the reporter are present on | |
| 574 // the invocation if and only if logging is allowed. | |
| 575 for (const std::string& logging_switch : logging_switches) { | |
| 576 EXPECT_EQ(expect_switches, invocation_switches.find(logging_switch) != | |
| 577 invocation_switches.end()); | |
| 578 } | |
| 579 } | |
| 580 | |
| 581 // A task runner with a mock clock. | |
| 582 scoped_refptr<base::TestMockTimeTaskRunner> mock_time_task_runner_ = | |
| 583 new base::TestMockTimeTaskRunner(); | |
| 584 | |
| 585 // The task runner that was in use before installing |mock_time_task_runner_|. | |
| 586 scoped_refptr<base::SingleThreadTaskRunner> saved_task_runner_; | |
| 587 | |
| 588 bool in_browser_cleaner_ui_; | |
| 589 ElevationStatus elevation_status_; | |
| 590 MockedReporterFailure expected_reporter_failure_; | |
| 591 | |
| 592 // Indicates if a bad message error should be simulated by the parent | |
| 593 // process. | |
| 594 bool bad_message_expected_ = false; | |
| 595 | |
| 596 // Set by ReportBadMessageChromePromptImpl if a bad message error is reported. | |
| 597 bool bad_message_reported_ = false; | |
| 598 | |
| 599 bool prompt_trigger_called_ = false; | |
| 600 int reporter_launch_count_ = 0; | |
| 601 std::vector<SwReporterInvocation> reporter_launch_parameters_; | |
| 602 int exit_code_to_report_ = kReporterNotLaunchedExitCode; | |
| 603 | |
| 604 // A callback to invoke when the first reporter of a queue is launched. This | |
| 605 // can be used to perform actions in the middle of a queue of reporters which | |
| 606 // all launch on the same mock clock tick. | |
| 607 base::OnceClosure first_launch_callback_; | |
| 608 | |
| 609 base::test::ScopedFeatureList scoped_feature_list_; | |
| 610 | |
| 611 DISALLOW_COPY_AND_ASSIGN(SRTFetcherTest); | |
| 612 }; | |
| 613 | |
| 614 class SRTFetcherPromptTest : public DialogBrowserTest { | |
| 615 public: | |
| 616 void ShowDialog(const std::string& name) override { | |
| 617 if (name == "SRTErrorNoFile") | |
| 618 DisplaySRTPromptForTesting(base::FilePath()); | |
| 619 else if (name == "SRTErrorFile") | |
| 620 DisplaySRTPromptForTesting( | |
| 621 base::FilePath().Append(FILE_PATH_LITERAL("c:\temp\testfile.txt"))); | |
| 622 else | |
| 623 ADD_FAILURE() << "Unknown dialog type."; | |
| 624 } | |
| 625 }; | |
| 626 | |
| 627 } // namespace | |
| 628 | |
| 629 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, NothingFound) { | |
| 630 RunReporter(chrome_cleaner::kSwReporterNothingFound); | |
| 631 ExpectReporterLaunches(0, 1, false); | |
| 632 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 633 } | |
| 634 | |
| 635 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, CleanupNeeded) { | |
| 636 RunReporter(chrome_cleaner::kSwReporterCleanupNeeded); | |
| 637 ExpectReporterLaunches(0, 1, true); | |
| 638 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 639 } | |
| 640 | |
| 641 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, RanRecently) { | |
| 642 constexpr int kDaysLeft = 1; | |
| 643 SetDaysSinceLastTriggered(kDaysBetweenSuccessfulSwReporterRuns - kDaysLeft); | |
| 644 RunReporter(chrome_cleaner::kSwReporterNothingFound); | |
| 645 ExpectReporterLaunches(0, 0, false); | |
| 646 ExpectToRunAgain(kDaysLeft); | |
| 647 ExpectReporterLaunches(kDaysLeft, 1, false); | |
| 648 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 649 } | |
| 650 | |
| 651 // Test is flaky. crbug.com/705608 | |
| 652 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, DISABLED_WaitForBrowser) { | |
| 653 Profile* profile = browser()->profile(); | |
| 654 | |
| 655 // Ensure that even though we're closing the last browser, we don't enter the | |
| 656 // "shutting down" state, which will prevent the test from starting another | |
| 657 // browser. | |
| 658 ScopedKeepAlive test_keep_alive(KeepAliveOrigin::SESSION_RESTORE, | |
| 659 KeepAliveRestartOption::ENABLED); | |
| 660 | |
| 661 // Use the standard task runner for browser cleanup, which will wait forever | |
| 662 // with the mock clock. | |
| 663 base::MessageLoop::current()->SetTaskRunner(saved_task_runner_); | |
| 664 CloseBrowserSynchronously(browser()); | |
| 665 base::MessageLoop::current()->SetTaskRunner(mock_time_task_runner_); | |
| 666 ASSERT_EQ(0u, chrome::GetTotalBrowserCount()); | |
| 667 ASSERT_FALSE(chrome::FindLastActive()); | |
| 668 | |
| 669 // Start the reporter while the browser is closed. The prompt should not open. | |
| 670 RunReporter(chrome_cleaner::kSwReporterCleanupNeeded); | |
| 671 ExpectReporterLaunches(0, 1, false); | |
| 672 | |
| 673 // Create a Browser object directly instead of using helper functions like | |
| 674 // CreateBrowser, because they all wait on timed events but do not advance the | |
| 675 // mock timer. The Browser constructor registers itself with the global | |
| 676 // BrowserList, which is cleaned up when InProcessBrowserTest exits. | |
| 677 new Browser(Browser::CreateParams(profile, /*user_gesture=*/false)); | |
| 678 ASSERT_EQ(1u, chrome::GetTotalBrowserCount()); | |
| 679 | |
| 680 // Some browser startup tasks are scheduled to run in the first few minutes | |
| 681 // after creation. Make sure they've all been processed so that the only | |
| 682 // pending task in the queue is the next reporter check. | |
| 683 mock_time_task_runner_->FastForwardBy(base::TimeDelta::FromMinutes(10)); | |
| 684 | |
| 685 // On opening the new browser, the prompt should be shown and the reporter | |
| 686 // should be scheduled to run later. | |
| 687 EXPECT_EQ(1, reporter_launch_count_); | |
| 688 EXPECT_TRUE(prompt_trigger_called_); | |
| 689 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 690 } | |
| 691 | |
| 692 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, Failure) { | |
| 693 RunReporter(kReporterNotLaunchedExitCode); | |
| 694 ExpectReporterLaunches(0, 1, false); | |
| 695 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 696 } | |
| 697 | |
| 698 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, RunDaily) { | |
| 699 PrefService* local_state = g_browser_process->local_state(); | |
| 700 local_state->SetBoolean(prefs::kSwReporterPendingPrompt, true); | |
| 701 SetDaysSinceLastTriggered(kDaysBetweenSuccessfulSwReporterRuns - 1); | |
| 702 ASSERT_GT(kDaysBetweenSuccessfulSwReporterRuns - 1, | |
| 703 kDaysBetweenSwReporterRunsForPendingPrompt); | |
| 704 RunReporter(chrome_cleaner::kSwReporterNothingFound); | |
| 705 | |
| 706 // Expect the reporter to run immediately, since a prompt is pending and it | |
| 707 // has been more than kDaysBetweenSwReporterRunsForPendingPrompt days. | |
| 708 ExpectReporterLaunches(0, 1, false); | |
| 709 ExpectToRunAgain(kDaysBetweenSwReporterRunsForPendingPrompt); | |
| 710 | |
| 711 // Move the clock ahead kDaysBetweenSwReporterRunsForPendingPrompt days. The | |
| 712 // expected run should trigger, but not cause the reporter to launch because | |
| 713 // a prompt is no longer pending. | |
| 714 local_state->SetBoolean(prefs::kSwReporterPendingPrompt, false); | |
| 715 ExpectReporterLaunches(kDaysBetweenSwReporterRunsForPendingPrompt, 0, false); | |
| 716 | |
| 717 // Instead it should now run kDaysBetweenSuccessfulSwReporterRuns after the | |
| 718 // first prompt (of which kDaysBetweenSwReporterRunsForPendingPrompt has | |
| 719 // already passed.) | |
| 720 int days_left = kDaysBetweenSuccessfulSwReporterRuns - | |
| 721 kDaysBetweenSwReporterRunsForPendingPrompt; | |
| 722 ExpectToRunAgain(days_left); | |
| 723 ExpectReporterLaunches(days_left, 1, false); | |
| 724 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 725 } | |
| 726 | |
| 727 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, ParameterChange) { | |
| 728 // If the reporter is run several times with different parameters, it should | |
| 729 // only be launched once, with the last parameter set. | |
| 730 const base::FilePath path1(L"path1"); | |
| 731 const base::FilePath path2(L"path2"); | |
| 732 const base::FilePath path3(L"path3"); | |
| 733 | |
| 734 // Schedule path1 with a day left in the reporting period. | |
| 735 // The reporter should not launch. | |
| 736 constexpr int kDaysLeft = 1; | |
| 737 { | |
| 738 SCOPED_TRACE("N days left until next reporter run"); | |
| 739 SetDaysSinceLastTriggered(kDaysBetweenSuccessfulSwReporterRuns - kDaysLeft); | |
| 740 RunReporter(chrome_cleaner::kSwReporterNothingFound, path1); | |
| 741 ExpectReporterLaunches(0, {}, false); | |
| 742 } | |
| 743 | |
| 744 // Schedule path2 just as we enter the next reporting period. | |
| 745 // Now the reporter should launch, just once, using path2. | |
| 746 { | |
| 747 SCOPED_TRACE("Reporter runs now"); | |
| 748 RunReporter(chrome_cleaner::kSwReporterNothingFound, path2); | |
| 749 // Schedule it twice; it should only actually run once. | |
| 750 RunReporter(chrome_cleaner::kSwReporterNothingFound, path2); | |
| 751 ExpectReporterLaunches(kDaysLeft, {path2}, false); | |
| 752 } | |
| 753 | |
| 754 // Schedule path3 before any more time has passed. | |
| 755 // The reporter should not launch. | |
| 756 { | |
| 757 SCOPED_TRACE("No more time passed"); | |
| 758 RunReporter(chrome_cleaner::kSwReporterNothingFound, path3); | |
| 759 ExpectReporterLaunches(0, {}, false); | |
| 760 } | |
| 761 | |
| 762 // Enter the next reporting period as path3 is still scheduled. | |
| 763 // Now the reporter should launch again using path3. (Tests that the | |
| 764 // parameters from the first launch aren't reused.) | |
| 765 { | |
| 766 SCOPED_TRACE("Previous run still scheduled"); | |
| 767 ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, {path3}, | |
| 768 false); | |
| 769 } | |
| 770 | |
| 771 // Schedule path3 again in the next reporting period. | |
| 772 // The reporter should launch again using path3, since enough time has | |
| 773 // passed, even though the parameters haven't changed. | |
| 774 { | |
| 775 SCOPED_TRACE("Run with same parameters"); | |
| 776 RunReporter(chrome_cleaner::kSwReporterNothingFound, path3); | |
| 777 ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, {path3}, | |
| 778 false); | |
| 779 } | |
| 780 | |
| 781 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 782 } | |
| 783 | |
| 784 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, MultipleLaunches) { | |
| 785 const base::FilePath path1(L"path1"); | |
| 786 const base::FilePath path2(L"path2"); | |
| 787 const base::FilePath path3(L"path3"); | |
| 788 | |
| 789 SwReporterQueue invocations; | |
| 790 invocations.push(SwReporterInvocation::FromFilePath(path1)); | |
| 791 invocations.push(SwReporterInvocation::FromFilePath(path2)); | |
| 792 | |
| 793 { | |
| 794 SCOPED_TRACE("Launch 2 times"); | |
| 795 SetDaysSinceLastTriggered(kDaysBetweenSuccessfulSwReporterRuns); | |
| 796 RunReporterQueue(chrome_cleaner::kSwReporterNothingFound, invocations); | |
| 797 ExpectReporterLaunches(0, {path1, path2}, false); | |
| 798 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 799 } | |
| 800 | |
| 801 // Schedule a launch with 2 elements, then another with the same 2. It should | |
| 802 // just run 2 times, not 4. | |
| 803 { | |
| 804 SCOPED_TRACE("Launch 2 times with retry"); | |
| 805 RunReporterQueue(chrome_cleaner::kSwReporterNothingFound, invocations); | |
| 806 RunReporterQueue(chrome_cleaner::kSwReporterNothingFound, invocations); | |
| 807 ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, {path1, path2}, | |
| 808 false); | |
| 809 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 810 } | |
| 811 | |
| 812 // Another launch with 2 elements is already scheduled. Add a third while the | |
| 813 // queue is running. | |
| 814 { | |
| 815 SCOPED_TRACE("Add third launch while running"); | |
| 816 invocations.push(SwReporterInvocation::FromFilePath(path3)); | |
| 817 first_launch_callback_ = base::BindOnce( | |
| 818 &SRTFetcherTest::RunReporterQueue, base::Unretained(this), | |
| 819 chrome_cleaner::kSwReporterNothingFound, invocations); | |
| 820 | |
| 821 // Only the first two elements should execute since the third was added | |
| 822 // during the cycle. | |
| 823 ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, {path1, path2}, | |
| 824 false); | |
| 825 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 826 | |
| 827 // Time passes... Now the 3-element queue should run. | |
| 828 ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, | |
| 829 {path1, path2, path3}, false); | |
| 830 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 831 } | |
| 832 | |
| 833 // Second launch should not occur after a failure. | |
| 834 { | |
| 835 SCOPED_TRACE("Launch multiple times with failure"); | |
| 836 RunReporterQueue(kReporterNotLaunchedExitCode, invocations); | |
| 837 ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, {path1}, | |
| 838 false); | |
| 839 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 840 | |
| 841 // If we try again before the reporting period is up, it should not do | |
| 842 // anything. | |
| 843 ExpectReporterLaunches(0, {}, false); | |
| 844 | |
| 845 // After enough time has passed, should try the queue again. | |
| 846 ExpectReporterLaunches(kDaysBetweenSuccessfulSwReporterRuns, {path1}, | |
| 847 false); | |
| 848 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 849 } | |
| 850 } | |
| 851 | |
| 852 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, ReporterLogging_NoSBExtendedReporting) { | |
| 853 RunReporter(chrome_cleaner::kSwReporterNothingFound); | |
| 854 ExpectReporterLaunches(0, 1, false); | |
| 855 ExpectLoggingSwitches(reporter_launch_parameters_.front(), false); | |
| 856 ExpectLastTimeSentReportNotSet(); | |
| 857 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 858 } | |
| 859 | |
| 860 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, ReporterLogging_EnabledFirstRun) { | |
| 861 EnableSBExtendedReporting(); | |
| 862 // Note: don't set last time sent logs in the local state. | |
| 863 // SBER is enabled and there is no record in the local state of the last time | |
| 864 // logs have been sent, so we should send logs in this run. | |
| 865 RunReporter(chrome_cleaner::kSwReporterNothingFound); | |
| 866 ExpectReporterLaunches(0, 1, false); | |
| 867 ExpectLoggingSwitches(reporter_launch_parameters_.front(), true); | |
| 868 ExpectLastReportSentInTheLastHour(); | |
| 869 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 870 } | |
| 871 | |
| 872 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, ReporterLogging_EnabledNoRecentLogging) { | |
| 873 // SBER is enabled and last time logs were sent was more than | |
| 874 // |kDaysBetweenReporterLogsSent| day ago, so we should send logs in this run. | |
| 875 EnableSBExtendedReporting(); | |
| 876 SetLastTimeSentReport(kDaysBetweenReporterLogsSent + 3); | |
| 877 RunReporter(chrome_cleaner::kSwReporterNothingFound); | |
| 878 ExpectReporterLaunches(0, 1, false); | |
| 879 ExpectLoggingSwitches(reporter_launch_parameters_.front(), true); | |
| 880 ExpectLastReportSentInTheLastHour(); | |
| 881 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 882 } | |
| 883 | |
| 884 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, ReporterLogging_EnabledRecentlyLogged) { | |
| 885 // SBER is enabled, but logs have been sent less than | |
| 886 // |kDaysBetweenReporterLogsSent| day ago, so we shouldn't send any logs in | |
| 887 // this run. | |
| 888 EnableSBExtendedReporting(); | |
| 889 SetLastTimeSentReport(kDaysBetweenReporterLogsSent - 1); | |
| 890 int64_t last_time_sent_logs = GetLastTimeSentReport(); | |
| 891 RunReporter(chrome_cleaner::kSwReporterNothingFound); | |
| 892 ExpectReporterLaunches(0, 1, false); | |
| 893 ExpectLoggingSwitches(reporter_launch_parameters_.front(), false); | |
| 894 EXPECT_EQ(last_time_sent_logs, GetLastTimeSentReport()); | |
| 895 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 896 } | |
| 897 | |
| 898 IN_PROC_BROWSER_TEST_P(SRTFetcherTest, ReporterLogging_MultipleLaunches) { | |
| 899 EnableSBExtendedReporting(); | |
| 900 SetLastTimeSentReport(kDaysBetweenReporterLogsSent + 3); | |
| 901 | |
| 902 const base::FilePath path1(L"path1"); | |
| 903 const base::FilePath path2(L"path2"); | |
| 904 SwReporterQueue invocations; | |
| 905 for (const auto& path : {path1, path2}) { | |
| 906 auto invocation = SwReporterInvocation::FromFilePath(path); | |
| 907 invocation.supported_behaviours = | |
| 908 SwReporterInvocation::BEHAVIOUR_ALLOW_SEND_REPORTER_LOGS; | |
| 909 invocations.push(invocation); | |
| 910 } | |
| 911 RunReporterQueue(chrome_cleaner::kSwReporterNothingFound, invocations); | |
| 912 | |
| 913 // SBER is enabled and last time logs were sent was more than | |
| 914 // |kDaysBetweenReporterLogsSent| day ago, so we should send logs in this run. | |
| 915 { | |
| 916 SCOPED_TRACE("first launch"); | |
| 917 first_launch_callback_ = | |
| 918 base::BindOnce(&SRTFetcherTest::ExpectLastReportSentInTheLastHour, | |
| 919 base::Unretained(this)); | |
| 920 ExpectReporterLaunches(0, {path1, path2}, false); | |
| 921 ExpectLoggingSwitches(reporter_launch_parameters_[0], true); | |
| 922 } | |
| 923 | |
| 924 // Logs should also be sent for the next run, even though LastTimeSentReport | |
| 925 // is now recent, because the run is part of the same set of invocations. | |
| 926 { | |
| 927 SCOPED_TRACE("second launch"); | |
| 928 ExpectLoggingSwitches(reporter_launch_parameters_[1], true); | |
| 929 ExpectLastReportSentInTheLastHour(); | |
| 930 } | |
| 931 ExpectToRunAgain(kDaysBetweenSuccessfulSwReporterRuns); | |
| 932 } | |
| 933 | |
| 934 INSTANTIATE_TEST_CASE_P( | |
| 935 NoInBrowserCleanerUI, | |
| 936 SRTFetcherTest, | |
| 937 testing::Combine(testing::Values(false), | |
| 938 testing::Values(ElevationStatus::NOT_REQUIRED), | |
| 939 testing::Values(MockedReporterFailure::kNone, | |
| 940 MockedReporterFailure::kCrashOnStartup))); | |
| 941 | |
| 942 INSTANTIATE_TEST_CASE_P( | |
| 943 InBrowserCleanerUI, | |
| 944 SRTFetcherTest, | |
| 945 testing::Combine( | |
| 946 testing::Values(true), | |
| 947 testing::Values(ElevationStatus::NOT_REQUIRED, | |
| 948 ElevationStatus::REQUIRED), | |
| 949 testing::Values( | |
| 950 MockedReporterFailure::kNone, | |
| 951 MockedReporterFailure::kCrashOnStartup, | |
| 952 MockedReporterFailure::kCrashAfterConnectedToParentProcess, | |
| 953 MockedReporterFailure::kCrashWhileWaitingForResponse, | |
| 954 MockedReporterFailure::kCrashAfterReceivedResponse, | |
| 955 MockedReporterFailure::kBadMessageReported))); | |
| 956 | |
| 957 // This provide tests which allows explicit invocation of the SRT Prompt | |
| 958 // useful for checking dialog layout or any other interactive functionality | |
| 959 // tests. See docs/testing/test_browser_dialog.md for description of the | |
| 960 // testing framework. | |
| 961 IN_PROC_BROWSER_TEST_F(SRTFetcherPromptTest, InvokeDialog_SRTErrorNoFile) { | |
| 962 RunDialog(); | |
| 963 } | |
| 964 | |
| 965 IN_PROC_BROWSER_TEST_F(SRTFetcherPromptTest, InvokeDialog_SRTErrorFile) { | |
| 966 RunDialog(); | |
| 967 } | |
| 968 | |
| 969 } // namespace safe_browsing | |
| OLD | NEW |