Index: chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc |
diff --git a/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc b/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc |
index e8100bf555ec1cc4b5a83912a409603936617993..943de73f4d9ce51fbe2b00f5b5ae3ad7c57d16af 100644 |
--- a/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc |
+++ b/chrome/browser/safe_browsing/srt_fetcher_browsertest_win.cc |
@@ -53,8 +53,21 @@ class SRTFetcherTest : public InProcessBrowserTest, |
} |
void RunReporter(const base::FilePath& exe_path = base::FilePath()) { |
- RunSwReporter(SwReporterInvocation::FromFilePath(exe_path), |
- base::Version("1.2.3"), task_runner_, task_runner_); |
+ auto invocation = SwReporterInvocation::FromFilePath(exe_path); |
+ invocation.flags = SwReporterInvocation::FLAG_LOG_TO_RAPPOR | |
+ SwReporterInvocation::FLAG_LOG_EXIT_CODE_TO_PREFS | |
+ SwReporterInvocation::FLAG_TRIGGER_PROMPT | |
+ SwReporterInvocation::FLAG_SEND_REPORTER_LOGS; |
+ |
+ SwReporterQueue invocations; |
+ invocations.push(invocation); |
+ RunSwReporters(invocations, base::Version("1.2.3"), task_runner_, |
+ task_runner_); |
+ } |
+ |
+ void RunReporterQueue(const SwReporterQueue& invocations) { |
+ RunSwReporters(invocations, base::Version("1.2.3"), task_runner_, |
+ task_runner_); |
} |
void TriggerPrompt(Browser* browser, const std::string& version) override { |
@@ -135,15 +148,26 @@ class SRTFetcherTest : public InProcessBrowserTest, |
EXPECT_LT(last_time_sent_logs, now); |
} |
- void TestReporterLaunchCycle(int expected_launch_count, |
- const base::FilePath& expected_launch_path) { |
+ // Run through the steps needed to launch the reporter, as many times as |
+ // needed to launch all the reporters given in |expected_launch_paths|. Test |
+ // that each of those launches succeeded. But do not test that ONLY those |
+ // launches succeeded. |
+ // |
+ // After this, if more launches are expected you can call |
+ // |TestPartialLaunchCycle| again with another list of paths, to test that |
+ // the launch cycle will continue with those paths. |
+ // |
+ // To test that a list of paths are launched AND NO OTHERS, use |
+ // |TestReporterLaunchCycle|. |
+ void TestPartialLaunchCycle( |
+ const std::vector<base::FilePath>& expected_launch_paths) { |
// This test has an unfortunate amount of knowledge of the internals of |
// ReporterRunner, because it needs to pump the right message loops at the |
// right time so that all its internal messages are delivered. This |
// function might need to be updated if the internals change. |
// |
// The basic sequence is: |
- |
+ // |
// 1. TryToRun kicks the whole thing off. If the reporter should not be |
// launched now (eg. DaysSinceLastReport is too low) it posts a call to |
// itself again. (In a regular task runner this will be scheduled with a |
@@ -171,47 +195,100 @@ class SRTFetcherTest : public InProcessBrowserTest, |
ASSERT_TRUE(task_runner_->HasPendingTask()); |
ASSERT_FALSE(reporter_done_notified_); |
- // Clear out any pending TryToRun calls. Use a bounded loop so that if the |
- // reporter will never be called, we'll eventually continue. (If |
- // LaunchAndWaitForExit was pending but TryToRun wasn't, this will call |
- // it.) |
- const int max_expected_launch_count = reporter_launch_count_ + 1; |
- for (int i = 0; !launch_ready_notified_ && i < 100; ++i) |
+ reporter_launch_count_ = 0; |
+ reporter_launch_parameters_ = SwReporterInvocation(); |
+ |
+ int current_launch_count = reporter_launch_count_; |
+ for (const auto& expected_launch_path : expected_launch_paths) { |
+ // If RunReporter was called with no pending messages, and it was already |
+ // time to launch the reporter, then |launch_ready_notified_| will |
+ // already be true. Otherwise there will be a TryToRun message pending, |
+ // which must be processed first. |
+ if (!launch_ready_notified_) { |
+ task_runner_->RunPendingTasks(); |
+ // Since we're expecting a launch here, we expect it to schedule |
+ // LaunchAndWaitForExit. So NOW |launch_ready_notified_| should be |
+ // true. |
+ ASSERT_TRUE(task_runner_->HasPendingTask()); |
+ } |
+ ASSERT_TRUE(launch_ready_notified_); |
+ ASSERT_EQ(current_launch_count, reporter_launch_count_); |
+ |
+ // Reset |launch_ready_notified_| so that we can tell if TryToRun gets |
+ // called again unexpectedly. |
+ launch_ready_notified_ = false; |
+ |
+ // Call the pending LaunchAndWaitForExit. |
task_runner_->RunPendingTasks(); |
- ASSERT_GE(max_expected_launch_count, reporter_launch_count_); |
- |
- // Reset launch_ready_notified_ so that we can tell if TryToRun gets called |
- // again unexpectedly. |
- launch_ready_notified_ = false; |
+ ASSERT_FALSE(launch_ready_notified_); |
+ ASSERT_FALSE(reporter_done_notified_); |
+ |
+ // At this point LaunchAndWaitForExit has definitely been called if |
+ // it's going to be called at all. (If not, TryToRun will have been |
+ // scheduled again.) |
+ EXPECT_EQ(current_launch_count + 1, reporter_launch_count_); |
+ EXPECT_EQ(expected_launch_path, |
+ reporter_launch_parameters_.command_line.GetProgram()); |
+ |
+ // Pump the UI message loop to process the ReporterDone call (which |
+ // will schedule the next TryToRun.) If LaunchAndWaitForExit wasn't |
+ // called, this does nothing. |
+ base::RunLoop().RunUntilIdle(); |
+ |
+ // At this point there are three things that could have happened: |
+ // |
+ // 1. LaunchAndWaitForExit was not called. There should be a TryToRun |
+ // scheduled. |
+ // |
+ // 2. ReporterDone was called and there was nothing left in the queue |
+ // of SwReporterInvocation's. There should be a TryToRun scheduled. |
+ // |
+ // 3. ReporterDone was called and there were more |
+ // SwReporterInvocation's in the queue to run immediately. There should |
+ // be a LaunchAndWaitForExit scheduled. |
+ // |
+ // So in all cases there should be a pending task, and if we are expecting |
+ // more launches in this loop, |launch_ready_notified_| will already be |
+ // true. |
+ ASSERT_TRUE(task_runner_->HasPendingTask()); |
+ |
+ // The test task runner does not actually advance the clock. Pretend that |
+ // one day has passed. (Otherwise, when we launch the last |
+ // SwReporterInvocation in the queue, the next call to TryToRun will |
+ // start a whole new launch cycle.) |
+ SetDaysSinceLastReport(1); |
+ |
+ reporter_done_notified_ = false; |
+ current_launch_count = reporter_launch_count_; |
+ } |
+ } |
- // This will trigger LaunchAndWaitForExit if it's on the queue and hasn't |
- // been called already. If it was called already, this will do nothing. |
- // (There definitely isn't anything queued up yet after |
- // LaunchAndWaitForExit because ReporterDone wasn't called yet.) |
- task_runner_->RunPendingTasks(); |
- ASSERT_GE(max_expected_launch_count, reporter_launch_count_); |
- ASSERT_FALSE(launch_ready_notified_); |
+ // Run through the steps needed to launch the reporter, as many times as |
+ // needed to launch all the reporters given in |expected_launch_paths|. Test |
+ // that each of those launches succeeded. Then, run through the steps needed |
+ // to launch the reporter again, to test that the launch cycle is complete |
+ // (no more reporters will be launched). |
+ void TestReporterLaunchCycle( |
+ const std::vector<base::FilePath>& expected_launch_paths) { |
+ TestPartialLaunchCycle(expected_launch_paths); |
+ |
+ // Now that all expected launches have been tested, run the cycle once more |
+ // to make sure no more launches happen. |
+ ASSERT_TRUE(task_runner_->HasPendingTask()); |
ASSERT_FALSE(reporter_done_notified_); |
+ ASSERT_FALSE(launch_ready_notified_); |
- // At this point LaunchAndWaitForExit has definitely been called if it's |
- // going to be called at all. (If not, TryToRun will have been scheduled |
- // again.) |
- EXPECT_EQ(expected_launch_count, reporter_launch_count_); |
- EXPECT_EQ(expected_launch_path, |
- reporter_launch_parameters_.command_line.GetProgram()); |
+ int current_launch_count = reporter_launch_count_; |
- // Pump the UI message loop to process the ReporterDone call (which will |
- // schedule the next TryToRun.) If LaunchAndWaitForExit wasn't called, this |
- // does nothing. |
- base::RunLoop().RunUntilIdle(); |
+ // Call the pending TryToRun. |
+ task_runner_->RunPendingTasks(); |
- // At this point another call to TryToRun should be scheduled, whether or |
- // not LaunchAndWaitForExit was called. |
+ // We expect that this scheduled another TryToRun. If it scheduled |
+ // LaunchAndWaitForExit an unexpected launch is about to happen. |
ASSERT_TRUE(task_runner_->HasPendingTask()); |
- |
- // Make sure the flags are false for the next launch cycle test. |
ASSERT_FALSE(launch_ready_notified_); |
- reporter_done_notified_ = false; |
+ ASSERT_FALSE(reporter_done_notified_); |
+ ASSERT_EQ(current_launch_count, reporter_launch_count_); |
} |
// Expects |reporter_launch_parameters_| to contain exactly the command line |
@@ -243,7 +320,11 @@ class SRTFetcherTest : public InProcessBrowserTest, |
int reporter_launch_count_ = 0; |
SwReporterInvocation reporter_launch_parameters_; |
int exit_code_to_report_ = kReporterFailureExitCode; |
+ |
+ // This will be set to true when a call to |LaunchAndWaitForExit| is next in |
+ // the task queue. |
bool launch_ready_notified_ = false; |
+ |
bool reporter_done_notified_ = false; |
}; |
@@ -352,7 +433,7 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ParameterChange) { |
SCOPED_TRACE("N days left until next reporter run"); |
SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns - kDaysLeft); |
RunReporter(path1); |
- TestReporterLaunchCycle(0, base::FilePath()); |
+ TestReporterLaunchCycle({}); |
} |
// Schedule path2 just as we enter the next reporting period. |
@@ -363,15 +444,16 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ParameterChange) { |
RunReporter(path2); |
// Schedule it twice; it should only actually run once. |
RunReporter(path2); |
- TestReporterLaunchCycle(1, path2); |
+ TestReporterLaunchCycle({path2}); |
} |
// Schedule path3 before any more time has passed. |
// The reporter should not launch. |
{ |
SCOPED_TRACE("No more time passed"); |
+ SetDaysSinceLastReport(0); |
RunReporter(path3); |
- TestReporterLaunchCycle(1, path2); |
+ TestReporterLaunchCycle({}); |
} |
// Enter the next reporting period as path3 is still scheduled. |
@@ -380,7 +462,7 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ParameterChange) { |
{ |
SCOPED_TRACE("Previous run still scheduled"); |
SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
- TestReporterLaunchCycle(2, path3); |
+ TestReporterLaunchCycle({path3}); |
} |
// Schedule path3 again in the next reporting period. |
@@ -390,7 +472,75 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ParameterChange) { |
SCOPED_TRACE("Run with same parameters"); |
SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
RunReporter(path3); |
- TestReporterLaunchCycle(3, path3); |
+ TestReporterLaunchCycle({path3}); |
+ } |
+} |
+ |
+IN_PROC_BROWSER_TEST_F(SRTFetcherTest, MultipleLaunches) { |
+ exit_code_to_report_ = kSwReporterNothingFound; |
+ |
+ const base::FilePath path1(L"path1"); |
+ const base::FilePath path2(L"path2"); |
+ const base::FilePath path3(L"path3"); |
+ |
+ SwReporterQueue invocations; |
+ invocations.push(SwReporterInvocation::FromFilePath(path1)); |
+ invocations.push(SwReporterInvocation::FromFilePath(path2)); |
+ |
+ { |
+ SCOPED_TRACE("Launch 2 times"); |
+ SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
+ RunReporterQueue(invocations); |
+ TestReporterLaunchCycle({path1, path2}); |
+ } |
+ |
+ // Schedule a launch with 2 elements, then another with the same 2. It should |
+ // just run 2 times, not 4. |
+ { |
+ SCOPED_TRACE("Launch 2 times with retry"); |
+ SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
+ RunReporterQueue(invocations); |
+ RunReporterQueue(invocations); |
+ TestReporterLaunchCycle({path1, path2}); |
+ } |
+ |
+ // Schedule a launch with 2 elements, then add a third while the queue is |
+ // running. |
+ { |
+ SCOPED_TRACE("Add third launch while running"); |
+ SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
+ RunReporterQueue(invocations); |
+ |
+ // Only test the cycle once, to process the first element in queue. |
+ TestPartialLaunchCycle({path1}); |
+ |
+ invocations.push(SwReporterInvocation::FromFilePath(path3)); |
+ RunReporterQueue(invocations); |
+ |
+ // There is still a 2nd element on the queue - that should execute, and |
+ // nothing more. |
+ TestReporterLaunchCycle({path2}); |
+ |
+ // Time passes... Now the 3-element queue should run. |
+ SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
+ TestReporterLaunchCycle({path1, path2, path3}); |
+ } |
+ |
+ // Second launch should not occur after a failure. |
+ { |
+ SCOPED_TRACE("Launch multiple times with failure"); |
+ exit_code_to_report_ = kReporterFailureExitCode; |
+ SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
+ RunReporterQueue(invocations); |
+ TestReporterLaunchCycle({path1}); |
+ |
+ // If we try again before the reporting period is up, it should not do |
+ // anything. |
+ TestReporterLaunchCycle({}); |
+ |
+ // After enough time has passed, should try the queue again. |
+ SetDaysSinceLastReport(kDaysBetweenSuccessfulSwReporterRuns); |
+ TestReporterLaunchCycle({path1}); |
} |
} |
@@ -400,7 +550,7 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ReporterLogging_FeatureDisabled) { |
scoped_feature_list.InitAndDisableFeature( |
kSwReporterExtendedSafeBrowsingFeature); |
RunReporter(); |
- TestReporterLaunchCycle(1, base::FilePath()); |
+ TestReporterLaunchCycle({base::FilePath()}); |
ExpectLoggingSwitches({/*expect no switches*/}); |
ExpectLastTimeSentReportNotSet(); |
} |
@@ -411,7 +561,7 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ReporterLogging_NoSBExtendedReporting) { |
scoped_feature_list.InitAndEnableFeature( |
kSwReporterExtendedSafeBrowsingFeature); |
RunReporter(); |
- TestReporterLaunchCycle(1, base::FilePath()); |
+ TestReporterLaunchCycle({base::FilePath()}); |
ExpectLoggingSwitches({/*expect no switches*/}); |
ExpectLastTimeSentReportNotSet(); |
} |
@@ -426,7 +576,7 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ReporterLogging_EnabledFirstRun) { |
// SBER is enabled and there is no record in the local state of the last time |
// logs have been sent, so we should send logs in this run. |
RunReporter(); |
- TestReporterLaunchCycle(1, base::FilePath()); |
+ TestReporterLaunchCycle({base::FilePath()}); |
ExpectLoggingSwitches(std::set<std::string>(std::begin(kExpectedSwitches), |
std::end(kExpectedSwitches))); |
ExpectLastReportSentInTheLastHour(); |
@@ -442,7 +592,7 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ReporterLogging_EnabledNoRecentLogging) { |
EnableSBExtendedReporting(); |
SetLastTimeSentReport(kDaysBetweenReporterLogsSent + 3); |
RunReporter(); |
- TestReporterLaunchCycle(1, base::FilePath()); |
+ TestReporterLaunchCycle({base::FilePath()}); |
ExpectLoggingSwitches(std::set<std::string>(std::begin(kExpectedSwitches), |
std::end(kExpectedSwitches))); |
ExpectLastReportSentInTheLastHour(); |
@@ -460,7 +610,7 @@ IN_PROC_BROWSER_TEST_F(SRTFetcherTest, ReporterLogging_EnabledRecentlyLogged) { |
SetLastTimeSentReport(kDaysBetweenReporterLogsSent - 1); |
int64_t last_time_sent_logs = GetLastTimeSentReport(); |
RunReporter(); |
- TestReporterLaunchCycle(1, base::FilePath()); |
+ TestReporterLaunchCycle({base::FilePath()}); |
ExpectLoggingSwitches(std::set<std::string>{/*expect no switches*/}); |
EXPECT_EQ(last_time_sent_logs, GetLastTimeSentReport()); |
} |