blob: b739242b3540ebf3c858e09cf76acf479d150ca0 [file] [log] [blame]
fdoraya4f28ec2016-06-10 00:08:581// Copyright 2016 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 "base/run_loop.h"
6
Gabriel Charettee2b632b2017-08-02 03:52:167#include <queue>
8#include <utility>
9
fdoraya4f28ec2016-06-10 00:08:5810#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "base/location.h"
13#include "base/macros.h"
Gabriel Charettee2b632b2017-08-02 03:52:1614#include "base/memory/ptr_util.h"
15#include "base/memory/ref_counted.h"
fdoraya4f28ec2016-06-10 00:08:5816#include "base/single_thread_task_runner.h"
Gabriel Charettee2b632b2017-08-02 03:52:1617#include "base/synchronization/lock.h"
gabcf5e4ce2017-05-19 22:56:5718#include "base/synchronization/waitable_event.h"
Gabriel Charettee2b632b2017-08-02 03:52:1619#include "base/test/gtest_util.h"
gabcf5e4ce2017-05-19 22:56:5720#include "base/test/scoped_task_environment.h"
Gabriel Charette3ff403e2017-08-07 04:22:4821#include "base/test/test_timeouts.h"
Gabriel Charettee2b632b2017-08-02 03:52:1622#include "base/threading/platform_thread.h"
23#include "base/threading/thread.h"
24#include "base/threading/thread_checker_impl.h"
fdoraya4f28ec2016-06-10 00:08:5825#include "base/threading/thread_task_runner_handle.h"
Gabriel Charettee2b632b2017-08-02 03:52:1626#include "build/build_config.h"
gab7af9dc02017-05-05 13:38:5427#include "testing/gmock/include/gmock/gmock.h"
fdoraya4f28ec2016-06-10 00:08:5828#include "testing/gtest/include/gtest/gtest.h"
29
30namespace base {
31
32namespace {
33
34void QuitWhenIdleTask(RunLoop* run_loop, int* counter) {
35 run_loop->QuitWhenIdle();
36 ++(*counter);
37}
38
39void ShouldRunTask(int* counter) {
40 ++(*counter);
41}
42
43void ShouldNotRunTask() {
44 ADD_FAILURE() << "Ran a task that shouldn't run.";
45}
46
47void RunNestedLoopTask(int* counter) {
Gabriel Charette3ff403e2017-08-07 04:22:4848 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
fdoraya4f28ec2016-06-10 00:08:5849
50 // This task should quit |nested_run_loop| but not the main RunLoop.
51 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:4452 FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&nested_run_loop),
53 Unretained(counter)));
fdoraya4f28ec2016-06-10 00:08:5854
55 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:4456 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
fdoraya4f28ec2016-06-10 00:08:5857
fdoraya4f28ec2016-06-10 00:08:5858 nested_run_loop.Run();
59
60 ++(*counter);
61}
62
Gabriel Charettee2b632b2017-08-02 03:52:1663// A simple SingleThreadTaskRunner that just queues undelayed tasks (and ignores
64// delayed tasks). Tasks can then be processed one by one by ProcessTask() which
65// will return true if it processed a task and false otherwise.
66class SimpleSingleThreadTaskRunner : public SingleThreadTaskRunner {
67 public:
68 SimpleSingleThreadTaskRunner() = default;
fdoraya4f28ec2016-06-10 00:08:5869
Gabriel Charettee2b632b2017-08-02 03:52:1670 bool PostDelayedTask(const tracked_objects::Location& from_here,
71 OnceClosure task,
72 base::TimeDelta delay) override {
73 if (delay > base::TimeDelta())
74 return false;
75 AutoLock auto_lock(tasks_lock_);
76 pending_tasks_.push(std::move(task));
77 return true;
78 }
79
80 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
81 OnceClosure task,
82 base::TimeDelta delay) override {
83 return PostDelayedTask(from_here, std::move(task), delay);
84 }
85
86 bool RunsTasksInCurrentSequence() const override {
87 return origin_thread_checker_.CalledOnValidThread();
88 }
89
90 bool ProcessTask() {
91 OnceClosure task;
92 {
93 AutoLock auto_lock(tasks_lock_);
94 if (pending_tasks_.empty())
95 return false;
96 task = std::move(pending_tasks_.front());
97 pending_tasks_.pop();
98 }
99 // It's important to Run() after pop() and outside the lock as |task| may
100 // run a nested loop which will re-enter ProcessTask().
101 std::move(task).Run();
102 return true;
103 }
104
105 private:
106 ~SimpleSingleThreadTaskRunner() override = default;
107
108 Lock tasks_lock_;
109 std::queue<OnceClosure> pending_tasks_;
110
111 // RunLoop relies on RunsTasksInCurrentSequence() signal. Use a
112 // ThreadCheckerImpl to be able to reliably provide that signal even in
113 // non-dcheck builds.
114 ThreadCheckerImpl origin_thread_checker_;
115
116 DISALLOW_COPY_AND_ASSIGN(SimpleSingleThreadTaskRunner);
117};
118
119// A simple test RunLoop::Delegate to exercise Runloop logic independent of any
120// other base constructs.
121class TestDelegate : public RunLoop::Delegate {
122 public:
123 TestDelegate() = default;
124
125 void BindToCurrentThread() {
126 thread_task_runner_handle_ =
Jeremy Roman9532f252017-08-16 23:27:24127 std::make_unique<ThreadTaskRunnerHandle>(simple_task_runner_);
Gabriel Charettee2b632b2017-08-02 03:52:16128 run_loop_client_ = RunLoop::RegisterDelegateForCurrentThread(this);
129 }
130
Gabriel Charette3ff403e2017-08-07 04:22:48131 // Runs |closure| on the TestDelegate thread as part of Run(). Useful to
132 // inject code in an otherwise livelocked Run() state.
133 void RunClosureOnDelegate(OnceClosure closure) {
134 AutoLock auto_lock(closure_lock_);
135 closure_ = std::move(closure);
136 }
137
Gabriel Charettee2b632b2017-08-02 03:52:16138 private:
139 void Run() override {
Gabriel Charette3ff403e2017-08-07 04:22:48140 if (nested_run_allowing_tasks_incoming_) {
141 EXPECT_TRUE(run_loop_client_->IsNested());
142 EXPECT_TRUE(run_loop_client_->ProcessingTasksAllowed());
143 } else if (run_loop_client_->IsNested()) {
144 EXPECT_FALSE(run_loop_client_->ProcessingTasksAllowed());
145 }
146 nested_run_allowing_tasks_incoming_ = false;
147
Gabriel Charettee2b632b2017-08-02 03:52:16148 while (!should_quit_) {
Gabriel Charette3ff403e2017-08-07 04:22:48149 if (run_loop_client_->ProcessingTasksAllowed() &&
150 simple_task_runner_->ProcessTask()) {
Gabriel Charettee2b632b2017-08-02 03:52:16151 continue;
Gabriel Charette3ff403e2017-08-07 04:22:48152 }
Gabriel Charettee2b632b2017-08-02 03:52:16153
154 if (run_loop_client_->ShouldQuitWhenIdle())
155 break;
156
Gabriel Charette3ff403e2017-08-07 04:22:48157 {
158 AutoLock auto_lock(closure_lock_);
159 if (!closure_.is_null()) {
160 std::move(closure_).Run();
161 continue;
162 }
163 }
164
Gabriel Charettee2b632b2017-08-02 03:52:16165 PlatformThread::YieldCurrentThread();
166 }
167 should_quit_ = false;
168 }
169
170 void Quit() override { should_quit_ = true; }
171
Gabriel Charette3ff403e2017-08-07 04:22:48172 void EnsureWorkScheduled() override {
173 nested_run_allowing_tasks_incoming_ = true;
174 }
175
176 // True if the next invocation of Run() is expected to be from a
177 // kNestableTasksAllowed RunLoop.
178 bool nested_run_allowing_tasks_incoming_ = false;
179
Gabriel Charettee2b632b2017-08-02 03:52:16180 scoped_refptr<SimpleSingleThreadTaskRunner> simple_task_runner_ =
181 MakeRefCounted<SimpleSingleThreadTaskRunner>();
182 std::unique_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
183
184 bool should_quit_ = false;
185
Gabriel Charette3ff403e2017-08-07 04:22:48186 Lock closure_lock_;
187 OnceClosure closure_;
188
Gabriel Charettee2b632b2017-08-02 03:52:16189 RunLoop::Delegate::Client* run_loop_client_ = nullptr;
190};
191
192enum class RunLoopTestType {
193 // Runs all RunLoopTests under a ScopedTaskEnvironment to make sure real world
194 // scenarios work.
195 kRealEnvironment,
196
197 // Runs all RunLoopTests under a test RunLoop::Delegate to make sure the
198 // delegate interface fully works standalone.
199 kTestDelegate,
200};
201
202// The task environment for the RunLoopTest of a given type. A separate class
203// so it can be instantiated on the stack in the RunLoopTest fixture.
204class RunLoopTestEnvironment {
205 public:
206 RunLoopTestEnvironment(RunLoopTestType type) {
207 switch (type) {
208 case RunLoopTestType::kRealEnvironment:
Jeremy Roman9532f252017-08-16 23:27:24209 task_environment_ = std::make_unique<test::ScopedTaskEnvironment>();
Gabriel Charettee2b632b2017-08-02 03:52:16210 break;
211 case RunLoopTestType::kTestDelegate:
Jeremy Roman9532f252017-08-16 23:27:24212 test_delegate_ = std::make_unique<TestDelegate>();
Gabriel Charettee2b632b2017-08-02 03:52:16213 test_delegate_->BindToCurrentThread();
214 break;
215 }
216 }
217
218 private:
219 // Instantiates one or the other based on the RunLoopTestType.
220 std::unique_ptr<test::ScopedTaskEnvironment> task_environment_;
221 std::unique_ptr<TestDelegate> test_delegate_;
222};
223
224class RunLoopTest : public testing::TestWithParam<RunLoopTestType> {
225 protected:
226 RunLoopTest() : test_environment_(GetParam()) {}
227
228 RunLoopTestEnvironment test_environment_;
fdoraya4f28ec2016-06-10 00:08:58229 RunLoop run_loop_;
230 int counter_ = 0;
231
232 private:
233 DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
234};
235
236} // namespace
237
Gabriel Charettee2b632b2017-08-02 03:52:16238TEST_P(RunLoopTest, QuitWhenIdle) {
gab7af9dc02017-05-05 13:38:54239 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44240 FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_),
241 Unretained(&counter_)));
gab7af9dc02017-05-05 13:38:54242 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44243 FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
gab7af9dc02017-05-05 13:38:54244 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44245 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
fdoraya4f28ec2016-06-10 00:08:58246
247 run_loop_.Run();
248 EXPECT_EQ(2, counter_);
249}
250
Gabriel Charettee2b632b2017-08-02 03:52:16251TEST_P(RunLoopTest, QuitWhenIdleNestedLoop) {
gab7af9dc02017-05-05 13:38:54252 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44253 FROM_HERE, BindOnce(&RunNestedLoopTask, Unretained(&counter_)));
gab7af9dc02017-05-05 13:38:54254 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44255 FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_),
256 Unretained(&counter_)));
gab7af9dc02017-05-05 13:38:54257 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44258 FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
gab7af9dc02017-05-05 13:38:54259 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44260 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
fdoraya4f28ec2016-06-10 00:08:58261
262 run_loop_.Run();
263 EXPECT_EQ(4, counter_);
264}
265
Gabriel Charettee2b632b2017-08-02 03:52:16266TEST_P(RunLoopTest, QuitWhenIdleClosure) {
gab7af9dc02017-05-05 13:38:54267 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
268 run_loop_.QuitWhenIdleClosure());
269 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44270 FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
gab7af9dc02017-05-05 13:38:54271 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44272 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
fdoraya3658602016-06-10 18:23:15273
274 run_loop_.Run();
275 EXPECT_EQ(1, counter_);
276}
277
278// Verify that the QuitWhenIdleClosure() can run after the RunLoop has been
279// deleted. It should have no effect.
Gabriel Charettee2b632b2017-08-02 03:52:16280TEST_P(RunLoopTest, QuitWhenIdleClosureAfterRunLoopScope) {
fdoraya3658602016-06-10 18:23:15281 Closure quit_when_idle_closure;
282 {
283 RunLoop run_loop;
284 quit_when_idle_closure = run_loop.QuitWhenIdleClosure();
285 run_loop.RunUntilIdle();
286 }
287 quit_when_idle_closure.Run();
288}
289
gabcf5e4ce2017-05-19 22:56:57290// Verify that Quit can be executed from another sequence.
Gabriel Charettee2b632b2017-08-02 03:52:16291TEST_P(RunLoopTest, QuitFromOtherSequence) {
292 Thread other_thread("test");
293 other_thread.Start();
gabcf5e4ce2017-05-19 22:56:57294 scoped_refptr<SequencedTaskRunner> other_sequence =
Gabriel Charettee2b632b2017-08-02 03:52:16295 other_thread.task_runner();
gabcf5e4ce2017-05-19 22:56:57296
297 // Always expected to run before asynchronous Quit() kicks in.
298 ThreadTaskRunnerHandle::Get()->PostTask(
299 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
300
301 WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL,
302 WaitableEvent::InitialState::NOT_SIGNALED);
303 other_sequence->PostTask(
304 FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); },
305 Unretained(&run_loop_)));
306 other_sequence->PostTask(
307 FROM_HERE,
308 base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit)));
309
310 // Anything that's posted after the Quit closure was posted back to this
311 // sequence shouldn't get a chance to run.
312 loop_was_quit.Wait();
Gabriel Charettee2b632b2017-08-02 03:52:16313 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
314 base::BindOnce(&ShouldNotRunTask));
gabcf5e4ce2017-05-19 22:56:57315
316 run_loop_.Run();
317
318 EXPECT_EQ(1, counter_);
319}
320
321// Verify that QuitClosure can be executed from another sequence.
Gabriel Charettee2b632b2017-08-02 03:52:16322TEST_P(RunLoopTest, QuitFromOtherSequenceWithClosure) {
323 Thread other_thread("test");
324 other_thread.Start();
gabcf5e4ce2017-05-19 22:56:57325 scoped_refptr<SequencedTaskRunner> other_sequence =
Gabriel Charettee2b632b2017-08-02 03:52:16326 other_thread.task_runner();
gabcf5e4ce2017-05-19 22:56:57327
328 // Always expected to run before asynchronous Quit() kicks in.
329 ThreadTaskRunnerHandle::Get()->PostTask(
330 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
331
332 WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL,
333 WaitableEvent::InitialState::NOT_SIGNALED);
334 other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure());
335 other_sequence->PostTask(
336 FROM_HERE,
337 base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit)));
338
339 // Anything that's posted after the Quit closure was posted back to this
340 // sequence shouldn't get a chance to run.
341 loop_was_quit.Wait();
Gabriel Charettee2b632b2017-08-02 03:52:16342 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
343 base::BindOnce(&ShouldNotRunTask));
gabcf5e4ce2017-05-19 22:56:57344
345 run_loop_.Run();
346
347 EXPECT_EQ(1, counter_);
348}
349
350// Verify that Quit can be executed from another sequence even when the
351// Quit is racing with Run() -- i.e. forgo the WaitableEvent used above.
Gabriel Charettee2b632b2017-08-02 03:52:16352TEST_P(RunLoopTest, QuitFromOtherSequenceRacy) {
353 Thread other_thread("test");
354 other_thread.Start();
gabcf5e4ce2017-05-19 22:56:57355 scoped_refptr<SequencedTaskRunner> other_sequence =
Gabriel Charettee2b632b2017-08-02 03:52:16356 other_thread.task_runner();
gabcf5e4ce2017-05-19 22:56:57357
358 // Always expected to run before asynchronous Quit() kicks in.
359 ThreadTaskRunnerHandle::Get()->PostTask(
360 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
361
362 other_sequence->PostTask(
363 FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); },
364 Unretained(&run_loop_)));
365
366 run_loop_.Run();
367
368 EXPECT_EQ(1, counter_);
369}
370
371// Verify that QuitClosure can be executed from another sequence even when the
372// Quit is racing with Run() -- i.e. forgo the WaitableEvent used above.
Gabriel Charettee2b632b2017-08-02 03:52:16373TEST_P(RunLoopTest, QuitFromOtherSequenceRacyWithClosure) {
374 Thread other_thread("test");
375 other_thread.Start();
gabcf5e4ce2017-05-19 22:56:57376 scoped_refptr<SequencedTaskRunner> other_sequence =
Gabriel Charettee2b632b2017-08-02 03:52:16377 other_thread.task_runner();
gabcf5e4ce2017-05-19 22:56:57378
379 // Always expected to run before asynchronous Quit() kicks in.
380 ThreadTaskRunnerHandle::Get()->PostTask(
381 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
382
383 other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure());
384
385 run_loop_.Run();
386
387 EXPECT_EQ(1, counter_);
388}
389
390// Verify that QuitWhenIdle can be executed from another sequence.
Gabriel Charettee2b632b2017-08-02 03:52:16391TEST_P(RunLoopTest, QuitWhenIdleFromOtherSequence) {
392 Thread other_thread("test");
393 other_thread.Start();
gabcf5e4ce2017-05-19 22:56:57394 scoped_refptr<SequencedTaskRunner> other_sequence =
Gabriel Charettee2b632b2017-08-02 03:52:16395 other_thread.task_runner();
gabcf5e4ce2017-05-19 22:56:57396
397 ThreadTaskRunnerHandle::Get()->PostTask(
398 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
399
400 other_sequence->PostTask(
401 FROM_HERE,
402 base::BindOnce([](RunLoop* run_loop) { run_loop->QuitWhenIdle(); },
403 Unretained(&run_loop_)));
404
405 ThreadTaskRunnerHandle::Get()->PostTask(
406 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
407
408 run_loop_.Run();
409
410 // Regardless of the outcome of the race this thread shouldn't have been idle
411 // until the counter was ticked twice.
412 EXPECT_EQ(2, counter_);
413}
414
415// Verify that QuitWhenIdleClosure can be executed from another sequence.
Gabriel Charettee2b632b2017-08-02 03:52:16416TEST_P(RunLoopTest, QuitWhenIdleFromOtherSequenceWithClosure) {
417 Thread other_thread("test");
418 other_thread.Start();
gabcf5e4ce2017-05-19 22:56:57419 scoped_refptr<SequencedTaskRunner> other_sequence =
Gabriel Charettee2b632b2017-08-02 03:52:16420 other_thread.task_runner();
gabcf5e4ce2017-05-19 22:56:57421
422 ThreadTaskRunnerHandle::Get()->PostTask(
423 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
424
425 other_sequence->PostTask(FROM_HERE, run_loop_.QuitWhenIdleClosure());
426
427 ThreadTaskRunnerHandle::Get()->PostTask(
428 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
429
430 run_loop_.Run();
431
432 // Regardless of the outcome of the race this thread shouldn't have been idle
433 // until the counter was ticked twice.
434 EXPECT_EQ(2, counter_);
435}
436
Gabriel Charettee2b632b2017-08-02 03:52:16437TEST_P(RunLoopTest, IsRunningOnCurrentThread) {
gab7af9dc02017-05-05 13:38:54438 EXPECT_FALSE(RunLoop::IsRunningOnCurrentThread());
439 ThreadTaskRunnerHandle::Get()->PostTask(
440 FROM_HERE,
tzik0c100dc2017-06-26 06:13:17441 BindOnce([]() { EXPECT_TRUE(RunLoop::IsRunningOnCurrentThread()); }));
gab7af9dc02017-05-05 13:38:54442 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
443 run_loop_.Run();
444}
445
Gabriel Charettee2b632b2017-08-02 03:52:16446TEST_P(RunLoopTest, IsNestedOnCurrentThread) {
gab7af9dc02017-05-05 13:38:54447 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
448
449 ThreadTaskRunnerHandle::Get()->PostTask(
tzik0c100dc2017-06-26 06:13:17450 FROM_HERE, BindOnce([]() {
gab7af9dc02017-05-05 13:38:54451 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
452
Gabriel Charette3ff403e2017-08-07 04:22:48453 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
gab7af9dc02017-05-05 13:38:54454
455 ThreadTaskRunnerHandle::Get()->PostTask(
tzik0c100dc2017-06-26 06:13:17456 FROM_HERE, BindOnce([]() {
457 EXPECT_TRUE(RunLoop::IsNestedOnCurrentThread());
458 }));
gab7af9dc02017-05-05 13:38:54459 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
460 nested_run_loop.QuitClosure());
461
462 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
gab7af9dc02017-05-05 13:38:54463 nested_run_loop.Run();
464 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
465 }));
466
467 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
468 run_loop_.Run();
469}
470
471class MockNestingObserver : public RunLoop::NestingObserver {
472 public:
473 MockNestingObserver() = default;
474
475 // RunLoop::NestingObserver:
476 MOCK_METHOD0(OnBeginNestedRunLoop, void());
477
478 private:
479 DISALLOW_COPY_AND_ASSIGN(MockNestingObserver);
480};
481
Gabriel Charettee2b632b2017-08-02 03:52:16482TEST_P(RunLoopTest, NestingObservers) {
gab7af9dc02017-05-05 13:38:54483 EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
484
485 testing::StrictMock<MockNestingObserver> nesting_observer;
486
487 RunLoop::AddNestingObserverOnCurrentThread(&nesting_observer);
488
489 const RepeatingClosure run_nested_loop = Bind([]() {
Gabriel Charette3ff403e2017-08-07 04:22:48490 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
gab7af9dc02017-05-05 13:38:54491 ThreadTaskRunnerHandle::Get()->PostTask(
tzik0c100dc2017-06-26 06:13:17492 FROM_HERE, BindOnce([]() {
gab7af9dc02017-05-05 13:38:54493 EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
494 }));
495 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
496 nested_run_loop.QuitClosure());
gab7af9dc02017-05-05 13:38:54497 nested_run_loop.Run();
498 });
499
500 // Generate a stack of nested RunLoops, an OnBeginNestedRunLoop() is
501 // expected when beginning each nesting depth.
502 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
503 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
504 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
505
506 EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop()).Times(2);
507 run_loop_.Run();
508
509 RunLoop::RemoveNestingObserverOnCurrentThread(&nesting_observer);
510}
511
512// Disabled on Android per http://crbug.com/643760.
513#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
Gabriel Charettee2b632b2017-08-02 03:52:16514TEST_P(RunLoopTest, DisallowNestingDeathTest) {
gab7af9dc02017-05-05 13:38:54515 EXPECT_TRUE(RunLoop::IsNestingAllowedOnCurrentThread());
516 RunLoop::DisallowNestingOnCurrentThread();
517 EXPECT_FALSE(RunLoop::IsNestingAllowedOnCurrentThread());
518
tzik0c100dc2017-06-26 06:13:17519 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, BindOnce([]() {
gab7af9dc02017-05-05 13:38:54520 RunLoop nested_run_loop;
521 nested_run_loop.RunUntilIdle();
522 }));
gab968d9ebc2017-05-05 19:24:10523 EXPECT_DEATH({ run_loop_.RunUntilIdle(); }, "");
gab7af9dc02017-05-05 13:38:54524}
525#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
526
Gabriel Charettea44975052017-08-21 23:14:04527TEST_P(RunLoopTest, DisallowRunningForTesting) {
528 RunLoop::ScopedDisallowRunningForTesting disallow_running;
529 EXPECT_DCHECK_DEATH({ run_loop_.Run(); });
530}
531
532TEST_P(RunLoopTest, ExpiredDisallowRunningForTesting) {
533 { RunLoop::ScopedDisallowRunningForTesting disallow_running; }
534 // Running should be fine after |disallow_running| goes out of scope.
535 run_loop_.RunUntilIdle();
536}
537
Gabriel Charettee2b632b2017-08-02 03:52:16538INSTANTIATE_TEST_CASE_P(Real,
539 RunLoopTest,
540 testing::Values(RunLoopTestType::kRealEnvironment));
541INSTANTIATE_TEST_CASE_P(Mock,
542 RunLoopTest,
543 testing::Values(RunLoopTestType::kTestDelegate));
544
545TEST(RunLoopDeathTest, MustRegisterBeforeInstantiating) {
546 TestDelegate unbound_test_delegate_;
547 // Exercise the DCHECK in RunLoop::RunLoop().
548 EXPECT_DCHECK_DEATH({ RunLoop(); });
549}
550
Gabriel Charette3ff403e2017-08-07 04:22:48551TEST(RunLoopDelegateTest, NestableTasksDontRunInDefaultNestedLoops) {
552 TestDelegate test_delegate;
553 test_delegate.BindToCurrentThread();
554
555 base::Thread other_thread("test");
556 other_thread.Start();
557
558 RunLoop main_loop;
559 // A nested run loop which isn't kNestableTasksAllowed.
560 RunLoop nested_run_loop(RunLoop::Type::kDefault);
561
562 bool nested_run_loop_ended = false;
563
564 // The first task on the main loop will result in a nested run loop. Since
565 // it's not kNestableTasksAllowed, no further task should be processed until
566 // it's quit.
567 ThreadTaskRunnerHandle::Get()->PostTask(
568 FROM_HERE,
569 BindOnce([](RunLoop* nested_run_loop) { nested_run_loop->Run(); },
570 Unretained(&nested_run_loop)));
571
572 // Post a task that will fail if it runs inside the nested run loop.
573 ThreadTaskRunnerHandle::Get()->PostTask(
574 FROM_HERE, BindOnce(
575 [](const bool& nested_run_loop_ended,
576 OnceClosure continuation_callback) {
577 EXPECT_TRUE(nested_run_loop_ended);
578 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
579 std::move(continuation_callback).Run();
580 },
581 ConstRef(nested_run_loop_ended), main_loop.QuitClosure()));
582
583 // Post a task flipping the boolean bit for extra verification right before
584 // quitting |nested_run_loop|.
585 other_thread.task_runner()->PostDelayedTask(
586 FROM_HERE,
587 BindOnce(
588 [](bool* nested_run_loop_ended) {
589 EXPECT_FALSE(*nested_run_loop_ended);
590 *nested_run_loop_ended = true;
591 },
592 Unretained(&nested_run_loop_ended)),
593 TestTimeouts::tiny_timeout());
594 // Post an async delayed task to exit the run loop when idle. This confirms
595 // that (1) the test task only ran in the main loop after the nested loop
596 // exited and (2) the nested run loop actually considers itself idle while
597 // spinning. Note: The quit closure needs to be injected directly on the
598 // delegate as invoking QuitWhenIdle() off-thread results in a thread bounce
599 // which will not processed because of the very logic under test (nestable
600 // tasks don't run in |nested_run_loop|).
601 other_thread.task_runner()->PostDelayedTask(
602 FROM_HERE,
603 BindOnce(
604 [](TestDelegate* test_delegate, OnceClosure injected_closure) {
605 test_delegate->RunClosureOnDelegate(std::move(injected_closure));
606 },
607 Unretained(&test_delegate), nested_run_loop.QuitWhenIdleClosure()),
608 TestTimeouts::tiny_timeout());
609
610 main_loop.Run();
611}
612
fdoraya4f28ec2016-06-10 00:08:58613} // namespace base