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