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 |