Make TestMockTimeTaskRunner a RunLoop::Delegate.
Introducing TestMockTimeTaskRunner::Type::kBound which will make that
TestMockTimeTaskRunner takeover the thread it's created on (a la
MessageLoop), enabling RunLoop and Thread/SequencedTaskRunnerHandle.
Also introduces RunLoop::ScopedDisallowRunningForTesting to enforce
mutual exclusion TestMockTimeTaskRunner::ScopedContext (used to toggle
context to another task runner on the main thread) and RunLoop::Run()
(meant to run the current thread's associated task runner). Mixing the
two would result in running the incorrect task runner. While I don't
think this is a use case worth supporting, experience with //base
APIs has taught me that if there's a way to use it wrong, someone
will, and it's much easier to prevent than to heal; hence this check.
(there should already be no RunLoop usage during TaskRunnerHandle
overrides per RunLoop not being previously supported by
TestMockTimeTaskRunner and this check ensures it stays that way :))
EDIT: Well except that HeartbeatSenderTest had found a way to use it
the deprecated way, but it's a nice fit for using a kBound
TestMockTimeTaskRunner so all good :).
Had to drop support for virtual
TestMockTimeTaskRunner::IsElapsingStopped() which in turn forced
removal of custom task runner in remote_commands_service_unittest.cc
whose use case is now supported by the new API :).
This enables follow-ups to:
1) Add mock time to base::test::ScopedTaskEnvironment :)
https://docs.google.com/document/d/1QabRo8c7D9LsYY3cEcaPQbOCLo8Tu-6VLykYXyl3Pkk/edit
2) Fixing a race in base::Timer which requires RunLoop from
TestMockTimeTaskRunner to get rid of the two remaining problematic
use cases (see bug blocked by 703346).
Bug: 703346
Change-Id: I062b77b669853a36c30813e44dd984d01fcefbe2
[email protected] (for components/policy test side-effects)
Change-Id: I062b77b669853a36c30813e44dd984d01fcefbe2
Reviewed-on: https://chromium-review.googlesource.com/614788
Reviewed-by: Gabriel Charette <[email protected]>
Reviewed-by: Dirk Pranke <[email protected]>
Reviewed-by: Scott Nichols <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Commit-Queue: Gabriel Charette <[email protected]>
Cr-Commit-Position: refs/heads/master@{#496111}
diff --git a/base/run_loop.cc b/base/run_loop.cc
index b11e71364..96af51e 100644
--- a/base/run_loop.cc
+++ b/base/run_loop.cc
@@ -244,10 +244,40 @@
tls_delegate.Get().Get()->active_run_loops_.top()->QuitWhenIdle();
}
+#if DCHECK_IS_ON()
+RunLoop::ScopedDisallowRunningForTesting::ScopedDisallowRunningForTesting()
+ : current_delegate_(tls_delegate.Get().Get()),
+ previous_run_allowance_(
+ current_delegate_ ? current_delegate_->allow_running_for_testing_
+ : false) {
+ if (current_delegate_)
+ current_delegate_->allow_running_for_testing_ = false;
+}
+
+RunLoop::ScopedDisallowRunningForTesting::~ScopedDisallowRunningForTesting() {
+ DCHECK_EQ(current_delegate_, tls_delegate.Get().Get());
+ if (current_delegate_)
+ current_delegate_->allow_running_for_testing_ = previous_run_allowance_;
+}
+#else // DCHECK_IS_ON()
+// Defined out of line so that the compiler doesn't inline these and realize
+// the scope has no effect and then throws an "unused variable" warning in
+// non-dcheck builds.
+RunLoop::ScopedDisallowRunningForTesting::ScopedDisallowRunningForTesting() =
+ default;
+RunLoop::ScopedDisallowRunningForTesting::~ScopedDisallowRunningForTesting() =
+ default;
+#endif // DCHECK_IS_ON()
+
bool RunLoop::BeforeRun() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
#if DCHECK_IS_ON()
+ DCHECK(delegate_->allow_running_for_testing_)
+ << "RunLoop::Run() isn't allowed in the scope of a "
+ "ScopedDisallowRunningForTesting. Hint: if mixing "
+ "TestMockTimeTaskRunners on same thread, use TestMockTimeTaskRunner's "
+ "API instead of RunLoop to drive individual task runners.";
DCHECK(!run_called_);
run_called_ = true;
#endif // DCHECK_IS_ON()