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