1 // 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
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/containers/queue.h"
12 #include "base/location.h"
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/synchronization/lock.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/test/gtest_util.h"
20 #include "base/test/scoped_task_environment.h"
21 #include "base/test/test_timeouts.h"
22 #include "base/threading/platform_thread.h"
23 #include "base/threading/thread.h"
24 #include "base/threading/thread_checker_impl.h"
25 #include "base/threading/thread_task_runner_handle.h"
26 #include "build/build_config.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 namespace base {
31
32 namespace {
33
QuitWhenIdleTask(RunLoop * run_loop,int * counter)34 void QuitWhenIdleTask(RunLoop* run_loop, int* counter) {
35 run_loop->QuitWhenIdle();
36 ++(*counter);
37 }
38
ShouldRunTask(int * counter)39 void ShouldRunTask(int* counter) {
40 ++(*counter);
41 }
42
ShouldNotRunTask()43 void ShouldNotRunTask() {
44 ADD_FAILURE() << "Ran a task that shouldn't run.";
45 }
46
RunNestedLoopTask(int * counter)47 void RunNestedLoopTask(int* counter) {
48 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
49
50 // This task should quit |nested_run_loop| but not the main RunLoop.
51 ThreadTaskRunnerHandle::Get()->PostTask(
52 FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&nested_run_loop),
53 Unretained(counter)));
54
55 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
56 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
57
58 nested_run_loop.Run();
59
60 ++(*counter);
61 }
62
63 // 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.
66 class SimpleSingleThreadTaskRunner : public SingleThreadTaskRunner {
67 public:
68 SimpleSingleThreadTaskRunner() = default;
69
PostDelayedTask(const Location & from_here,OnceClosure task,base::TimeDelta delay)70 bool PostDelayedTask(const 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
PostNonNestableDelayedTask(const Location & from_here,OnceClosure task,base::TimeDelta delay)80 bool PostNonNestableDelayedTask(const Location& from_here,
81 OnceClosure task,
82 base::TimeDelta delay) override {
83 return PostDelayedTask(from_here, std::move(task), delay);
84 }
85
RunsTasksInCurrentSequence() const86 bool RunsTasksInCurrentSequence() const override {
87 return origin_thread_checker_.CalledOnValidThread();
88 }
89
ProcessSingleTask()90 bool ProcessSingleTask() {
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 ProcessSingleTask().
101 std::move(task).Run();
102 return true;
103 }
104
105 private:
106 ~SimpleSingleThreadTaskRunner() override = default;
107
108 Lock tasks_lock_;
109 base::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 // The basis of all TestDelegates, allows safely injecting a OnceClosure to be
120 // run in the next idle phase of this delegate's Run() implementation. This can
121 // be used to have code run on a thread that is otherwise livelocked in an idle
122 // phase (sometimes a simple PostTask() won't do it -- e.g. when processing
123 // application tasks is disallowed).
124 class InjectableTestDelegate : public RunLoop::Delegate {
125 public:
InjectClosureOnDelegate(OnceClosure closure)126 void InjectClosureOnDelegate(OnceClosure closure) {
127 AutoLock auto_lock(closure_lock_);
128 closure_ = std::move(closure);
129 }
130
RunInjectedClosure()131 bool RunInjectedClosure() {
132 AutoLock auto_lock(closure_lock_);
133 if (closure_.is_null())
134 return false;
135 std::move(closure_).Run();
136 return true;
137 }
138
139 private:
140 Lock closure_lock_;
141 OnceClosure closure_;
142 };
143
144 // A simple test RunLoop::Delegate to exercise Runloop logic independent of any
145 // other base constructs. BindToCurrentThread() must be called before this
146 // TestBoundDelegate is operational.
147 class TestBoundDelegate final : public InjectableTestDelegate {
148 public:
149 TestBoundDelegate() = default;
150
151 // Makes this TestBoundDelegate become the RunLoop::Delegate and
152 // ThreadTaskRunnerHandle for this thread.
BindToCurrentThread()153 void BindToCurrentThread() {
154 thread_task_runner_handle_ =
155 std::make_unique<ThreadTaskRunnerHandle>(simple_task_runner_);
156 RunLoop::RegisterDelegateForCurrentThread(this);
157 }
158
159 private:
Run(bool application_tasks_allowed)160 void Run(bool application_tasks_allowed) override {
161 if (nested_run_allowing_tasks_incoming_) {
162 EXPECT_TRUE(RunLoop::IsNestedOnCurrentThread());
163 EXPECT_TRUE(application_tasks_allowed);
164 } else if (RunLoop::IsNestedOnCurrentThread()) {
165 EXPECT_FALSE(application_tasks_allowed);
166 }
167 nested_run_allowing_tasks_incoming_ = false;
168
169 while (!should_quit_) {
170 if (application_tasks_allowed && simple_task_runner_->ProcessSingleTask())
171 continue;
172
173 if (ShouldQuitWhenIdle())
174 break;
175
176 if (RunInjectedClosure())
177 continue;
178
179 PlatformThread::YieldCurrentThread();
180 }
181 should_quit_ = false;
182 }
183
Quit()184 void Quit() override { should_quit_ = true; }
185
EnsureWorkScheduled()186 void EnsureWorkScheduled() override {
187 nested_run_allowing_tasks_incoming_ = true;
188 }
189
190 // True if the next invocation of Run() is expected to be from a
191 // kNestableTasksAllowed RunLoop.
192 bool nested_run_allowing_tasks_incoming_ = false;
193
194 scoped_refptr<SimpleSingleThreadTaskRunner> simple_task_runner_ =
195 MakeRefCounted<SimpleSingleThreadTaskRunner>();
196
197 std::unique_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
198
199 bool should_quit_ = false;
200 };
201
202 enum class RunLoopTestType {
203 // Runs all RunLoopTests under a ScopedTaskEnvironment to make sure real world
204 // scenarios work.
205 kRealEnvironment,
206
207 // Runs all RunLoopTests under a test RunLoop::Delegate to make sure the
208 // delegate interface fully works standalone.
209 kTestDelegate,
210 };
211
212 // The task environment for the RunLoopTest of a given type. A separate class
213 // so it can be instantiated on the stack in the RunLoopTest fixture.
214 class RunLoopTestEnvironment {
215 public:
RunLoopTestEnvironment(RunLoopTestType type)216 RunLoopTestEnvironment(RunLoopTestType type) {
217 switch (type) {
218 case RunLoopTestType::kRealEnvironment: {
219 task_environment_ = std::make_unique<test::ScopedTaskEnvironment>();
220 break;
221 }
222 case RunLoopTestType::kTestDelegate: {
223 auto test_delegate = std::make_unique<TestBoundDelegate>();
224 test_delegate->BindToCurrentThread();
225 test_delegate_ = std::move(test_delegate);
226 break;
227 }
228 }
229 }
230
231 private:
232 // Instantiates one or the other based on the RunLoopTestType.
233 std::unique_ptr<test::ScopedTaskEnvironment> task_environment_;
234 std::unique_ptr<InjectableTestDelegate> test_delegate_;
235 };
236
237 class RunLoopTest : public testing::TestWithParam<RunLoopTestType> {
238 protected:
RunLoopTest()239 RunLoopTest() : test_environment_(GetParam()) {}
240
241 RunLoopTestEnvironment test_environment_;
242 RunLoop run_loop_;
243 int counter_ = 0;
244
245 private:
246 DISALLOW_COPY_AND_ASSIGN(RunLoopTest);
247 };
248
249 } // namespace
250
TEST_P(RunLoopTest,QuitWhenIdle)251 TEST_P(RunLoopTest, QuitWhenIdle) {
252 ThreadTaskRunnerHandle::Get()->PostTask(
253 FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_),
254 Unretained(&counter_)));
255 ThreadTaskRunnerHandle::Get()->PostTask(
256 FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
257 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
258 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
259
260 run_loop_.Run();
261 EXPECT_EQ(2, counter_);
262 }
263
TEST_P(RunLoopTest,QuitWhenIdleNestedLoop)264 TEST_P(RunLoopTest, QuitWhenIdleNestedLoop) {
265 ThreadTaskRunnerHandle::Get()->PostTask(
266 FROM_HERE, BindOnce(&RunNestedLoopTask, Unretained(&counter_)));
267 ThreadTaskRunnerHandle::Get()->PostTask(
268 FROM_HERE, BindOnce(&QuitWhenIdleTask, Unretained(&run_loop_),
269 Unretained(&counter_)));
270 ThreadTaskRunnerHandle::Get()->PostTask(
271 FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
272 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
273 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
274
275 run_loop_.Run();
276 EXPECT_EQ(4, counter_);
277 }
278
TEST_P(RunLoopTest,QuitWhenIdleClosure)279 TEST_P(RunLoopTest, QuitWhenIdleClosure) {
280 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
281 run_loop_.QuitWhenIdleClosure());
282 ThreadTaskRunnerHandle::Get()->PostTask(
283 FROM_HERE, BindOnce(&ShouldRunTask, Unretained(&counter_)));
284 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
285 FROM_HERE, BindOnce(&ShouldNotRunTask), TimeDelta::FromDays(1));
286
287 run_loop_.Run();
288 EXPECT_EQ(1, counter_);
289 }
290
291 // Verify that the QuitWhenIdleClosure() can run after the RunLoop has been
292 // deleted. It should have no effect.
TEST_P(RunLoopTest,QuitWhenIdleClosureAfterRunLoopScope)293 TEST_P(RunLoopTest, QuitWhenIdleClosureAfterRunLoopScope) {
294 Closure quit_when_idle_closure;
295 {
296 RunLoop run_loop;
297 quit_when_idle_closure = run_loop.QuitWhenIdleClosure();
298 run_loop.RunUntilIdle();
299 }
300 quit_when_idle_closure.Run();
301 }
302
303 // Verify that Quit can be executed from another sequence.
TEST_P(RunLoopTest,QuitFromOtherSequence)304 TEST_P(RunLoopTest, QuitFromOtherSequence) {
305 Thread other_thread("test");
306 other_thread.Start();
307 scoped_refptr<SequencedTaskRunner> other_sequence =
308 other_thread.task_runner();
309
310 // Always expected to run before asynchronous Quit() kicks in.
311 ThreadTaskRunnerHandle::Get()->PostTask(
312 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
313
314 WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL,
315 WaitableEvent::InitialState::NOT_SIGNALED);
316 other_sequence->PostTask(
317 FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); },
318 Unretained(&run_loop_)));
319 other_sequence->PostTask(
320 FROM_HERE,
321 base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit)));
322
323 // Anything that's posted after the Quit closure was posted back to this
324 // sequence shouldn't get a chance to run.
325 loop_was_quit.Wait();
326 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
327 base::BindOnce(&ShouldNotRunTask));
328
329 run_loop_.Run();
330
331 EXPECT_EQ(1, counter_);
332 }
333
334 // Verify that QuitClosure can be executed from another sequence.
TEST_P(RunLoopTest,QuitFromOtherSequenceWithClosure)335 TEST_P(RunLoopTest, QuitFromOtherSequenceWithClosure) {
336 Thread other_thread("test");
337 other_thread.Start();
338 scoped_refptr<SequencedTaskRunner> other_sequence =
339 other_thread.task_runner();
340
341 // Always expected to run before asynchronous Quit() kicks in.
342 ThreadTaskRunnerHandle::Get()->PostTask(
343 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
344
345 WaitableEvent loop_was_quit(WaitableEvent::ResetPolicy::MANUAL,
346 WaitableEvent::InitialState::NOT_SIGNALED);
347 other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure());
348 other_sequence->PostTask(
349 FROM_HERE,
350 base::BindOnce(&WaitableEvent::Signal, base::Unretained(&loop_was_quit)));
351
352 // Anything that's posted after the Quit closure was posted back to this
353 // sequence shouldn't get a chance to run.
354 loop_was_quit.Wait();
355 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
356 base::BindOnce(&ShouldNotRunTask));
357
358 run_loop_.Run();
359
360 EXPECT_EQ(1, counter_);
361 }
362
363 // Verify that Quit can be executed from another sequence even when the
364 // Quit is racing with Run() -- i.e. forgo the WaitableEvent used above.
TEST_P(RunLoopTest,QuitFromOtherSequenceRacy)365 TEST_P(RunLoopTest, QuitFromOtherSequenceRacy) {
366 Thread other_thread("test");
367 other_thread.Start();
368 scoped_refptr<SequencedTaskRunner> other_sequence =
369 other_thread.task_runner();
370
371 // Always expected to run before asynchronous Quit() kicks in.
372 ThreadTaskRunnerHandle::Get()->PostTask(
373 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
374
375 other_sequence->PostTask(
376 FROM_HERE, base::BindOnce([](RunLoop* run_loop) { run_loop->Quit(); },
377 Unretained(&run_loop_)));
378
379 run_loop_.Run();
380
381 EXPECT_EQ(1, counter_);
382 }
383
384 // Verify that QuitClosure can be executed from another sequence even when the
385 // Quit is racing with Run() -- i.e. forgo the WaitableEvent used above.
TEST_P(RunLoopTest,QuitFromOtherSequenceRacyWithClosure)386 TEST_P(RunLoopTest, QuitFromOtherSequenceRacyWithClosure) {
387 Thread other_thread("test");
388 other_thread.Start();
389 scoped_refptr<SequencedTaskRunner> other_sequence =
390 other_thread.task_runner();
391
392 // Always expected to run before asynchronous Quit() kicks in.
393 ThreadTaskRunnerHandle::Get()->PostTask(
394 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
395
396 other_sequence->PostTask(FROM_HERE, run_loop_.QuitClosure());
397
398 run_loop_.Run();
399
400 EXPECT_EQ(1, counter_);
401 }
402
403 // Verify that QuitWhenIdle can be executed from another sequence.
TEST_P(RunLoopTest,QuitWhenIdleFromOtherSequence)404 TEST_P(RunLoopTest, QuitWhenIdleFromOtherSequence) {
405 Thread other_thread("test");
406 other_thread.Start();
407 scoped_refptr<SequencedTaskRunner> other_sequence =
408 other_thread.task_runner();
409
410 ThreadTaskRunnerHandle::Get()->PostTask(
411 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
412
413 other_sequence->PostTask(
414 FROM_HERE,
415 base::BindOnce([](RunLoop* run_loop) { run_loop->QuitWhenIdle(); },
416 Unretained(&run_loop_)));
417
418 ThreadTaskRunnerHandle::Get()->PostTask(
419 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
420
421 run_loop_.Run();
422
423 // Regardless of the outcome of the race this thread shouldn't have been idle
424 // until the counter was ticked twice.
425 EXPECT_EQ(2, counter_);
426 }
427
428 // Verify that QuitWhenIdleClosure can be executed from another sequence.
TEST_P(RunLoopTest,QuitWhenIdleFromOtherSequenceWithClosure)429 TEST_P(RunLoopTest, QuitWhenIdleFromOtherSequenceWithClosure) {
430 Thread other_thread("test");
431 other_thread.Start();
432 scoped_refptr<SequencedTaskRunner> other_sequence =
433 other_thread.task_runner();
434
435 ThreadTaskRunnerHandle::Get()->PostTask(
436 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
437
438 other_sequence->PostTask(FROM_HERE, run_loop_.QuitWhenIdleClosure());
439
440 ThreadTaskRunnerHandle::Get()->PostTask(
441 FROM_HERE, base::BindOnce(&ShouldRunTask, Unretained(&counter_)));
442
443 run_loop_.Run();
444
445 // Regardless of the outcome of the race this thread shouldn't have been idle
446 // until the counter was ticked twice.
447 EXPECT_EQ(2, counter_);
448 }
449
TEST_P(RunLoopTest,IsRunningOnCurrentThread)450 TEST_P(RunLoopTest, IsRunningOnCurrentThread) {
451 EXPECT_FALSE(RunLoop::IsRunningOnCurrentThread());
452 ThreadTaskRunnerHandle::Get()->PostTask(
453 FROM_HERE,
454 BindOnce([]() { EXPECT_TRUE(RunLoop::IsRunningOnCurrentThread()); }));
455 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
456 run_loop_.Run();
457 }
458
TEST_P(RunLoopTest,IsNestedOnCurrentThread)459 TEST_P(RunLoopTest, IsNestedOnCurrentThread) {
460 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
461
462 ThreadTaskRunnerHandle::Get()->PostTask(
463 FROM_HERE, BindOnce([]() {
464 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
465
466 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
467
468 ThreadTaskRunnerHandle::Get()->PostTask(
469 FROM_HERE, BindOnce([]() {
470 EXPECT_TRUE(RunLoop::IsNestedOnCurrentThread());
471 }));
472 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
473 nested_run_loop.QuitClosure());
474
475 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
476 nested_run_loop.Run();
477 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
478 }));
479
480 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_loop_.QuitClosure());
481 run_loop_.Run();
482 }
483
484 namespace {
485
486 class MockNestingObserver : public RunLoop::NestingObserver {
487 public:
488 MockNestingObserver() = default;
489
490 // RunLoop::NestingObserver:
491 MOCK_METHOD0(OnBeginNestedRunLoop, void());
492 MOCK_METHOD0(OnExitNestedRunLoop, void());
493
494 private:
495 DISALLOW_COPY_AND_ASSIGN(MockNestingObserver);
496 };
497
498 class MockTask {
499 public:
500 MockTask() = default;
501 MOCK_METHOD0(Task, void());
502
503 private:
504 DISALLOW_COPY_AND_ASSIGN(MockTask);
505 };
506
507 } // namespace
508
TEST_P(RunLoopTest,NestingObservers)509 TEST_P(RunLoopTest, NestingObservers) {
510 testing::StrictMock<MockNestingObserver> nesting_observer;
511 testing::StrictMock<MockTask> mock_task_a;
512 testing::StrictMock<MockTask> mock_task_b;
513
514 RunLoop::AddNestingObserverOnCurrentThread(&nesting_observer);
515
516 const RepeatingClosure run_nested_loop = Bind([]() {
517 RunLoop nested_run_loop(RunLoop::Type::kNestableTasksAllowed);
518 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
519 nested_run_loop.QuitClosure());
520 nested_run_loop.Run();
521 });
522
523 // Generate a stack of nested RunLoops. OnBeginNestedRunLoop() is expected
524 // when beginning each nesting depth and OnExitNestedRunLoop() is expected
525 // when exiting each nesting depth. Each one of these tasks is ahead of the
526 // QuitClosures as those are only posted at the end of the queue when
527 // |run_nested_loop| is executed.
528 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
529 ThreadTaskRunnerHandle::Get()->PostTask(
530 FROM_HERE,
531 base::BindOnce(&MockTask::Task, base::Unretained(&mock_task_a)));
532 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, run_nested_loop);
533 ThreadTaskRunnerHandle::Get()->PostTask(
534 FROM_HERE,
535 base::BindOnce(&MockTask::Task, base::Unretained(&mock_task_b)));
536
537 {
538 testing::InSequence in_sequence;
539 EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop());
540 EXPECT_CALL(mock_task_a, Task());
541 EXPECT_CALL(nesting_observer, OnBeginNestedRunLoop());
542 EXPECT_CALL(mock_task_b, Task());
543 EXPECT_CALL(nesting_observer, OnExitNestedRunLoop()).Times(2);
544 }
545 run_loop_.RunUntilIdle();
546
547 RunLoop::RemoveNestingObserverOnCurrentThread(&nesting_observer);
548 }
549
TEST_P(RunLoopTest,DisallowRunningForTesting)550 TEST_P(RunLoopTest, DisallowRunningForTesting) {
551 RunLoop::ScopedDisallowRunningForTesting disallow_running;
552 EXPECT_DCHECK_DEATH({ run_loop_.RunUntilIdle(); });
553 }
554
TEST_P(RunLoopTest,ExpiredDisallowRunningForTesting)555 TEST_P(RunLoopTest, ExpiredDisallowRunningForTesting) {
556 { RunLoop::ScopedDisallowRunningForTesting disallow_running; }
557 // Running should be fine after |disallow_running| goes out of scope.
558 run_loop_.RunUntilIdle();
559 }
560
561 INSTANTIATE_TEST_CASE_P(Real,
562 RunLoopTest,
563 testing::Values(RunLoopTestType::kRealEnvironment));
564 INSTANTIATE_TEST_CASE_P(Mock,
565 RunLoopTest,
566 testing::Values(RunLoopTestType::kTestDelegate));
567
TEST(RunLoopDeathTest,MustRegisterBeforeInstantiating)568 TEST(RunLoopDeathTest, MustRegisterBeforeInstantiating) {
569 TestBoundDelegate unbound_test_delegate_;
570 // RunLoop::RunLoop() should CHECK fetching the ThreadTaskRunnerHandle.
571 EXPECT_DEATH_IF_SUPPORTED({ RunLoop(); }, "");
572 }
573
TEST(RunLoopDelegateTest,NestableTasksDontRunInDefaultNestedLoops)574 TEST(RunLoopDelegateTest, NestableTasksDontRunInDefaultNestedLoops) {
575 TestBoundDelegate test_delegate;
576 test_delegate.BindToCurrentThread();
577
578 base::Thread other_thread("test");
579 other_thread.Start();
580
581 RunLoop main_loop;
582 // A nested run loop which isn't kNestableTasksAllowed.
583 RunLoop nested_run_loop(RunLoop::Type::kDefault);
584
585 bool nested_run_loop_ended = false;
586
587 // The first task on the main loop will result in a nested run loop. Since
588 // it's not kNestableTasksAllowed, no further task should be processed until
589 // it's quit.
590 ThreadTaskRunnerHandle::Get()->PostTask(
591 FROM_HERE,
592 BindOnce([](RunLoop* nested_run_loop) { nested_run_loop->Run(); },
593 Unretained(&nested_run_loop)));
594
595 // Post a task that will fail if it runs inside the nested run loop.
596 ThreadTaskRunnerHandle::Get()->PostTask(
597 FROM_HERE, BindOnce(
598 [](const bool& nested_run_loop_ended,
599 OnceClosure continuation_callback) {
600 EXPECT_TRUE(nested_run_loop_ended);
601 EXPECT_FALSE(RunLoop::IsNestedOnCurrentThread());
602 std::move(continuation_callback).Run();
603 },
604 ConstRef(nested_run_loop_ended), main_loop.QuitClosure()));
605
606 // Post a task flipping the boolean bit for extra verification right before
607 // quitting |nested_run_loop|.
608 other_thread.task_runner()->PostDelayedTask(
609 FROM_HERE,
610 BindOnce(
611 [](bool* nested_run_loop_ended) {
612 EXPECT_FALSE(*nested_run_loop_ended);
613 *nested_run_loop_ended = true;
614 },
615 Unretained(&nested_run_loop_ended)),
616 TestTimeouts::tiny_timeout());
617 // Post an async delayed task to exit the run loop when idle. This confirms
618 // that (1) the test task only ran in the main loop after the nested loop
619 // exited and (2) the nested run loop actually considers itself idle while
620 // spinning. Note: The quit closure needs to be injected directly on the
621 // delegate as invoking QuitWhenIdle() off-thread results in a thread bounce
622 // which will not processed because of the very logic under test (nestable
623 // tasks don't run in |nested_run_loop|).
624 other_thread.task_runner()->PostDelayedTask(
625 FROM_HERE,
626 BindOnce(
627 [](TestBoundDelegate* test_delegate, OnceClosure injected_closure) {
628 test_delegate->InjectClosureOnDelegate(std::move(injected_closure));
629 },
630 Unretained(&test_delegate), nested_run_loop.QuitWhenIdleClosure()),
631 TestTimeouts::tiny_timeout());
632
633 main_loop.Run();
634 }
635
636 } // namespace base
637