Add base::RunLoop and update ui_test_utils to use it to reduce flakiness
Timeout flakiness has been observed in multiple tests that use Quit. This changes various test utility APIs to use QuitNow via base::RunLoop instead. Some instances of Quit are left as-is where it appears they may have a use case.
The ui_test_utils QuitThisRunLoop function does a safer form of MessageLoop::QuitWhenIdle that allows a few generations of tasks to run before actually quitting the MessageLoop. This addresses the design assumptions of many existing tests while hopefully reducing flaky timeouts by moving away from QuitWhenIdle.
This fixes throughput_tests.cc which is currently timing out on Mac.
BUG=124906,130141,131220,128305,132932
Review URL: https://chromiumcodereview.appspot.com/10479018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144824 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/run_loop.cc b/base/run_loop.cc
new file mode 100644
index 0000000..991571e
--- /dev/null
+++ b/base/run_loop.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/run_loop.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+RunLoop::RunLoop()
+ : loop_(MessageLoop::current()),
+ weak_factory_(this),
+ previous_run_loop_(NULL),
+ run_depth_(0),
+ run_called_(false),
+ quit_called_(false),
+ running_(false),
+ quit_when_idle_received_(false) {
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+ dispatcher_ = NULL;
+#endif
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+RunLoop::RunLoop(MessageLoop::Dispatcher* dispatcher)
+ : loop_(MessageLoop::current()),
+ weak_factory_(this),
+ previous_run_loop_(NULL),
+ dispatcher_(dispatcher),
+ run_depth_(0),
+ run_called_(false),
+ quit_called_(false),
+ running_(false),
+ quit_when_idle_received_(false) {
+}
+#endif
+
+RunLoop::~RunLoop() {
+}
+
+void RunLoop::Run() {
+ if (!BeforeRun())
+ return;
+ loop_->RunHandler();
+ AfterRun();
+}
+
+void RunLoop::RunUntilIdle() {
+ quit_when_idle_received_ = true;
+ Run();
+}
+
+void RunLoop::Quit() {
+ quit_called_ = true;
+ if (running_ && loop_->run_loop_ == this) {
+ // This is the inner-most RunLoop, so quit now.
+ loop_->QuitNow();
+ }
+}
+
+base::Closure RunLoop::QuitClosure() {
+ return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
+}
+
+bool RunLoop::BeforeRun() {
+ DCHECK(!run_called_);
+ run_called_ = true;
+
+ // Allow Quit to be called before Run.
+ if (quit_called_)
+ return false;
+
+ // Push RunLoop stack:
+ previous_run_loop_ = loop_->run_loop_;
+ run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1;
+ loop_->run_loop_ = this;
+
+ running_ = true;
+ return true;
+}
+
+void RunLoop::AfterRun() {
+ running_ = false;
+
+ // Pop RunLoop stack:
+ loop_->run_loop_ = previous_run_loop_;
+
+ // Execute deferred QuitNow, if any:
+ if (previous_run_loop_ && previous_run_loop_->quit_called_)
+ loop_->QuitNow();
+}
+
+} // namespace base