1 // Copyright 2015 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.
6 #include "platform/Timer.h"
8 #include "public/platform/Platform.h"
9 #include "public/platform/WebScheduler.h"
10 #include "public/platform/WebThread.h"
11 #include <gmock/gmock.h>
12 #include <gtest/gtest.h>
15 using testing::ElementsAre
;
19 double gCurrentTimeSecs
= 0.0;
23 return gCurrentTimeSecs
;
26 // This class exists because gcc doesn't know how to move an OwnPtr.
27 class RefCountedTaskContainer
: public RefCounted
<RefCountedTaskContainer
> {
29 explicit RefCountedTaskContainer(WebTaskRunner::Task
* task
) : m_task(adoptPtr(task
)) { }
31 ~RefCountedTaskContainer() { }
39 OwnPtr
<WebTaskRunner::Task
> m_task
;
44 DelayedTask(WebTaskRunner::Task
* task
, long long delayMs
)
45 : m_task(adoptRef(new RefCountedTaskContainer(task
)))
46 , m_runTimeSecs(monotonicallyIncreasingTime() + 0.001 * static_cast<double>(delayMs
))
47 , m_delayMs(delayMs
) { }
49 bool operator<(const DelayedTask
& other
) const
51 return m_runTimeSecs
> other
.m_runTimeSecs
;
59 double runTimeSecs() const
64 long long delayMs() const
70 RefPtr
<RefCountedTaskContainer
> m_task
;
75 class MockWebTaskRunner
: public WebTaskRunner
{
77 explicit MockWebTaskRunner(std::priority_queue
<DelayedTask
>* timerTasks
) : m_timerTasks(timerTasks
) { }
78 ~MockWebTaskRunner() override
{ }
80 virtual void postTask(const WebTraceLocation
&, Task
* task
)
82 m_timerTasks
->push(DelayedTask(task
, 0));
85 void postDelayedTask(const WebTraceLocation
&, Task
* task
, long long delayMs
) override
87 m_timerTasks
->push(DelayedTask(task
, delayMs
));
90 std::priority_queue
<DelayedTask
>* m_timerTasks
; // NOT OWNED
93 class MockWebScheduler
: public WebScheduler
{
95 MockWebScheduler() : m_timerWebTaskRunner(&m_timerTasks
) { }
96 ~MockWebScheduler() override
{ }
98 bool shouldYieldForHighPriorityWork() override
103 bool canExceedIdleDeadlineIfRequired() override
108 void postIdleTask(const WebTraceLocation
&, WebThread::IdleTask
*) override
112 void postNonNestableIdleTask(const WebTraceLocation
&, WebThread::IdleTask
*) override
116 void postIdleTaskAfterWakeup(const WebTraceLocation
&, WebThread::IdleTask
*) override
120 WebTaskRunner
* timerTaskRunner() override
122 return &m_timerWebTaskRunner
;
125 WebTaskRunner
* loadingTaskRunner() override
127 ASSERT_NOT_REACHED();
131 void postTimerTaskAt(const WebTraceLocation
&, WebTaskRunner::Task
* task
, double monotonicTime
) override
133 m_timerTasks
.push(DelayedTask(task
, (monotonicTime
- monotonicallyIncreasingTime()) * 1000));
138 while (!m_timerTasks
.empty()) {
139 gCurrentTimeSecs
= m_timerTasks
.top().runTimeSecs();
140 m_timerTasks
.top().run();
145 void runUntilIdleOrDeadlinePassed(double deadline
)
147 while (!m_timerTasks
.empty()) {
148 if (m_timerTasks
.top().runTimeSecs() > deadline
) {
149 gCurrentTimeSecs
= deadline
;
152 gCurrentTimeSecs
= m_timerTasks
.top().runTimeSecs();
153 m_timerTasks
.top().run();
158 bool hasOneTimerTask() const
160 return m_timerTasks
.size() == 1;
163 long nextTimerTaskDelayMillis() const
165 ASSERT(hasOneTimerTask());
166 return m_timerTasks
.top().delayMs();
170 std::priority_queue
<DelayedTask
> m_timerTasks
;
171 MockWebTaskRunner m_timerWebTaskRunner
;
174 class FakeWebThread
: public WebThread
{
176 FakeWebThread() : m_webScheduler(adoptPtr(new MockWebScheduler())) { }
177 ~FakeWebThread() override
{ }
179 virtual bool isCurrentThread() const
181 ASSERT_NOT_REACHED();
185 virtual PlatformThreadId
threadId() const
187 ASSERT_NOT_REACHED();
191 WebTaskRunner
* taskRunner() override
193 ASSERT_NOT_REACHED();
197 WebScheduler
* scheduler() const override
199 return m_webScheduler
.get();
202 virtual void enterRunLoop()
204 ASSERT_NOT_REACHED();
207 virtual void exitRunLoop()
209 ASSERT_NOT_REACHED();
213 OwnPtr
<MockWebScheduler
> m_webScheduler
;
216 class TimerTestPlatform
: public Platform
{
219 : m_webThread(adoptPtr(new FakeWebThread())) { }
220 ~TimerTestPlatform() override
{ }
222 WebThread
* currentThread() override
224 return m_webThread
.get();
227 void cryptographicallyRandomValues(unsigned char*, size_t) override
229 ASSERT_NOT_REACHED();
232 const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName
) override
234 static const unsigned char enabled
[] = {0};
240 mockScheduler()->runUntilIdle();
243 void runUntilIdleOrDeadlinePassed(double deadline
)
245 mockScheduler()->runUntilIdleOrDeadlinePassed(deadline
);
248 bool hasOneTimerTask() const
250 return mockScheduler()->hasOneTimerTask();
253 long nextTimerTaskDelayMillis() const
255 return mockScheduler()->nextTimerTaskDelayMillis();
259 MockWebScheduler
* mockScheduler() const
261 return static_cast<MockWebScheduler
*>(m_webThread
->scheduler());
264 OwnPtr
<FakeWebThread
> m_webThread
;
267 class TimerTest
: public testing::Test
{
269 void SetUp() override
271 m_platform
= adoptPtr(new TimerTestPlatform());
272 m_oldPlatform
= Platform::current();
273 Platform::initialize(m_platform
.get());
274 WTF::setMonotonicallyIncreasingTimeFunction(currentTime
);
277 gCurrentTimeSecs
= 10.0;
278 m_startTime
= gCurrentTimeSecs
;
281 void TearDown() override
283 Platform::initialize(m_oldPlatform
);
286 void countingTask(Timer
<TimerTest
>*)
288 m_runTimes
.push_back(monotonicallyIncreasingTime());
291 void advanceTimeBy(double timeSecs
)
293 gCurrentTimeSecs
+= timeSecs
;
298 m_platform
->runUntilIdle();
301 void runUntilIdleOrDeadlinePassed(double deadline
)
303 m_platform
->runUntilIdleOrDeadlinePassed(deadline
);
306 bool hasOneTimerTask() const
308 return m_platform
->hasOneTimerTask();
311 long nextTimerTaskDelayMillis() const
313 return m_platform
->nextTimerTaskDelayMillis();
318 std::vector
<double> m_runTimes
;
321 OwnPtr
<TimerTestPlatform
> m_platform
;
322 Platform
* m_oldPlatform
;
325 TEST_F(TimerTest
, StartOneShot_Zero
)
327 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
328 timer
.startOneShot(0, FROM_HERE
);
330 ASSERT(hasOneTimerTask());
331 EXPECT_EQ(0ll, nextTimerTaskDelayMillis());
334 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
));
337 TEST_F(TimerTest
, StartOneShot_ZeroAndCancel
)
339 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
340 timer
.startOneShot(0, FROM_HERE
);
342 ASSERT(hasOneTimerTask());
343 EXPECT_EQ(0ll, nextTimerTaskDelayMillis());
348 EXPECT_TRUE(m_runTimes
.empty());
351 TEST_F(TimerTest
, StartOneShot_ZeroAndCancelThenRepost
)
353 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
354 timer
.startOneShot(0, FROM_HERE
);
356 ASSERT(hasOneTimerTask());
357 EXPECT_EQ(0ll, nextTimerTaskDelayMillis());
362 EXPECT_TRUE(m_runTimes
.empty());
364 timer
.startOneShot(0, FROM_HERE
);
366 ASSERT(hasOneTimerTask());
367 EXPECT_EQ(0ll, nextTimerTaskDelayMillis());
370 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
));
373 TEST_F(TimerTest
, StartOneShot_Zero_RepostingAfterRunning
)
375 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
376 timer
.startOneShot(0, FROM_HERE
);
378 ASSERT(hasOneTimerTask());
379 EXPECT_EQ(0ll, nextTimerTaskDelayMillis());
382 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
));
384 timer
.startOneShot(0, FROM_HERE
);
386 ASSERT(hasOneTimerTask());
387 EXPECT_EQ(0ll, nextTimerTaskDelayMillis());
390 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
, m_startTime
));
393 TEST_F(TimerTest
, StartOneShot_NonZero
)
395 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
396 timer
.startOneShot(10.0, FROM_HERE
);
398 ASSERT(hasOneTimerTask());
399 EXPECT_EQ(10000ll, nextTimerTaskDelayMillis());
402 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 10.0));
405 TEST_F(TimerTest
, StartOneShot_NonZeroAndCancel
)
407 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
408 timer
.startOneShot(10, FROM_HERE
);
410 ASSERT(hasOneTimerTask());
411 EXPECT_EQ(10000ll, nextTimerTaskDelayMillis());
416 EXPECT_TRUE(m_runTimes
.empty());
419 TEST_F(TimerTest
, StartOneShot_NonZeroAndCancelThenRepost
)
421 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
422 timer
.startOneShot(10, FROM_HERE
);
424 ASSERT(hasOneTimerTask());
425 EXPECT_EQ(10000ll, nextTimerTaskDelayMillis());
430 EXPECT_TRUE(m_runTimes
.empty());
432 double secondPostTime
= monotonicallyIncreasingTime();
433 timer
.startOneShot(10, FROM_HERE
);
435 ASSERT(hasOneTimerTask());
436 EXPECT_EQ(10000ll, nextTimerTaskDelayMillis());
439 EXPECT_THAT(m_runTimes
, ElementsAre(secondPostTime
+ 10.0));
442 TEST_F(TimerTest
, StartOneShot_NonZero_RepostingAfterRunning
)
444 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
445 timer
.startOneShot(10, FROM_HERE
);
447 ASSERT(hasOneTimerTask());
448 EXPECT_EQ(10000ll, nextTimerTaskDelayMillis());
451 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 10.0));
453 timer
.startOneShot(20, FROM_HERE
);
455 ASSERT(hasOneTimerTask());
456 EXPECT_EQ(20000ll, nextTimerTaskDelayMillis());
459 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 10.0, m_startTime
+ 30.0));
462 TEST_F(TimerTest
, PostingTimerTwiceWithSameRunTimeDoesNothing
)
464 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
465 timer
.startOneShot(10, FROM_HERE
);
466 timer
.startOneShot(10, FROM_HERE
);
468 ASSERT(hasOneTimerTask());
469 EXPECT_EQ(10000ll, nextTimerTaskDelayMillis());
472 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 10.0));
475 TEST_F(TimerTest
, PostingTimerTwiceWithNewerRunTimeCancelsOriginalTask
)
477 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
478 timer
.startOneShot(10, FROM_HERE
);
479 timer
.startOneShot(0, FROM_HERE
);
482 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 0.0));
485 TEST_F(TimerTest
, PostingTimerTwiceWithLaterRunTimeCancelsOriginalTask
)
487 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
488 timer
.startOneShot(0, FROM_HERE
);
489 timer
.startOneShot(10, FROM_HERE
);
492 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 10.0));
495 TEST_F(TimerTest
, StartRepeatingTask
)
497 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
498 timer
.startRepeating(1.0, FROM_HERE
);
500 ASSERT(hasOneTimerTask());
501 EXPECT_EQ(1000ll, nextTimerTaskDelayMillis());
503 runUntilIdleOrDeadlinePassed(m_startTime
+ 5.5);
504 EXPECT_THAT(m_runTimes
, ElementsAre(
505 m_startTime
+ 1.0, m_startTime
+ 2.0, m_startTime
+ 3.0, m_startTime
+ 4.0, m_startTime
+ 5.0));
508 TEST_F(TimerTest
, StartRepeatingTask_ThenCancel
)
510 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
511 timer
.startRepeating(1.0, FROM_HERE
);
513 ASSERT(hasOneTimerTask());
514 EXPECT_EQ(1000ll, nextTimerTaskDelayMillis());
516 runUntilIdleOrDeadlinePassed(m_startTime
+ 2.5);
517 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 1.0, m_startTime
+ 2.0));
522 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 1.0, m_startTime
+ 2.0));
525 TEST_F(TimerTest
, StartRepeatingTask_ThenPostOneShot
)
527 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
528 timer
.startRepeating(1.0, FROM_HERE
);
530 ASSERT(hasOneTimerTask());
531 EXPECT_EQ(1000ll, nextTimerTaskDelayMillis());
533 runUntilIdleOrDeadlinePassed(m_startTime
+ 2.5);
534 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 1.0, m_startTime
+ 2.0));
536 timer
.startOneShot(0, FROM_HERE
);
539 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 1.0, m_startTime
+ 2.0, m_startTime
+ 2.5));
542 TEST_F(TimerTest
, IsActive_NeverPosted
)
544 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
546 EXPECT_FALSE(timer
.isActive());
549 TEST_F(TimerTest
, IsActive_AfterPosting_OneShotZero
)
551 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
552 timer
.startOneShot(0, FROM_HERE
);
554 EXPECT_TRUE(timer
.isActive());
557 TEST_F(TimerTest
, IsActive_AfterPosting_OneShotNonZero
)
559 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
560 timer
.startOneShot(10, FROM_HERE
);
562 EXPECT_TRUE(timer
.isActive());
565 TEST_F(TimerTest
, IsActive_AfterPosting_Repeating
)
567 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
568 timer
.startRepeating(1.0, FROM_HERE
);
570 EXPECT_TRUE(timer
.isActive());
573 TEST_F(TimerTest
, IsActive_AfterRunning_OneShotZero
)
575 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
576 timer
.startOneShot(0, FROM_HERE
);
579 EXPECT_FALSE(timer
.isActive());
582 TEST_F(TimerTest
, IsActive_AfterRunning_OneShotNonZero
)
584 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
585 timer
.startOneShot(10, FROM_HERE
);
588 EXPECT_FALSE(timer
.isActive());
591 TEST_F(TimerTest
, IsActive_AfterRunning_Repeating
)
593 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
594 timer
.startRepeating(1.0, FROM_HERE
);
596 runUntilIdleOrDeadlinePassed(m_startTime
+ 10);
597 EXPECT_TRUE(timer
.isActive()); // It should run until cancelled.
600 TEST_F(TimerTest
, NextFireInterval_OneShotZero
)
602 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
603 timer
.startOneShot(0, FROM_HERE
);
605 EXPECT_FLOAT_EQ(0.0, timer
.nextFireInterval());
608 TEST_F(TimerTest
, NextFireInterval_OneShotNonZero
)
610 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
611 timer
.startOneShot(10, FROM_HERE
);
613 EXPECT_FLOAT_EQ(10.0, timer
.nextFireInterval());
616 TEST_F(TimerTest
, NextFireInterval_OneShotNonZero_AfterAFewSeconds
)
618 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
619 timer
.startOneShot(10, FROM_HERE
);
622 EXPECT_FLOAT_EQ(8.0, timer
.nextFireInterval());
625 TEST_F(TimerTest
, NextFireInterval_Repeating
)
627 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
628 timer
.startRepeating(20, FROM_HERE
);
630 EXPECT_FLOAT_EQ(20.0, timer
.nextFireInterval());
633 TEST_F(TimerTest
, RepeatInterval_NeverStarted
)
635 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
637 EXPECT_FLOAT_EQ(0.0, timer
.repeatInterval());
640 TEST_F(TimerTest
, RepeatInterval_OneShotZero
)
642 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
643 timer
.startOneShot(0, FROM_HERE
);
645 EXPECT_FLOAT_EQ(0.0, timer
.repeatInterval());
648 TEST_F(TimerTest
, RepeatInterval_OneShotNonZero
)
650 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
651 timer
.startOneShot(10, FROM_HERE
);
653 EXPECT_FLOAT_EQ(0.0, timer
.repeatInterval());
656 TEST_F(TimerTest
, RepeatInterval_Repeating
)
658 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
659 timer
.startRepeating(20, FROM_HERE
);
661 EXPECT_FLOAT_EQ(20.0, timer
.repeatInterval());
664 TEST_F(TimerTest
, AugmentRepeatInterval
)
666 Timer
<TimerTest
> timer(this, &TimerTest::countingTask
);
667 timer
.startRepeating(10, FROM_HERE
);
668 EXPECT_FLOAT_EQ(10.0, timer
.repeatInterval());
669 EXPECT_FLOAT_EQ(10.0, timer
.nextFireInterval());
672 timer
.augmentRepeatInterval(10);
674 EXPECT_FLOAT_EQ(20.0, timer
.repeatInterval());
675 EXPECT_FLOAT_EQ(18.0, timer
.nextFireInterval());
677 runUntilIdleOrDeadlinePassed(m_startTime
+ 50.0);
678 EXPECT_THAT(m_runTimes
, ElementsAre(m_startTime
+ 20.0, m_startTime
+ 40.0));
681 class MockTimerWithAlignment
: public TimerBase
{
683 MockTimerWithAlignment() : m_lastFireTime(0.0), m_alignedFireTime(0.0) { }
685 void fired() override
689 double alignedFireTime(double fireTime
) const override
691 m_lastFireTime
= fireTime
;
692 return m_alignedFireTime
;
695 void setAlignedFireTime(double alignedFireTime
)
697 m_alignedFireTime
= alignedFireTime
;
700 double lastFireTime() const
702 return m_lastFireTime
;
706 mutable double m_lastFireTime
;
707 double m_alignedFireTime
;
710 TEST_F(TimerTest
, TimerAlignment_OneShotZero
)
712 MockTimerWithAlignment timer
;
713 timer
.setAlignedFireTime(m_startTime
+ 1.0);
715 timer
.start(0.0, 0.0, FROM_HERE
);
717 // The nextFireInterval gets overrriden.
718 EXPECT_FLOAT_EQ(1.0, timer
.nextFireInterval());
719 EXPECT_FLOAT_EQ(0.0, timer
.nextUnalignedFireInterval());
720 EXPECT_FLOAT_EQ(m_startTime
, timer
.lastFireTime());
723 TEST_F(TimerTest
, TimerAlignment_OneShotNonZero
)
725 MockTimerWithAlignment timer
;
726 timer
.setAlignedFireTime(m_startTime
+ 1.0);
728 timer
.start(0.5, 0.0, FROM_HERE
);
730 // The nextFireInterval gets overrriden.
731 EXPECT_FLOAT_EQ(1.0, timer
.nextFireInterval());
732 EXPECT_FLOAT_EQ(0.5, timer
.nextUnalignedFireInterval());
733 EXPECT_FLOAT_EQ(m_startTime
+ 0.5, timer
.lastFireTime());
736 TEST_F(TimerTest
, DidChangeAlignmentInterval
)
738 MockTimerWithAlignment timer
;
739 timer
.setAlignedFireTime(m_startTime
+ 1.0);
741 timer
.start(0.0, 0.0, FROM_HERE
);
743 EXPECT_FLOAT_EQ(1.0, timer
.nextFireInterval());
744 EXPECT_FLOAT_EQ(0.0, timer
.nextUnalignedFireInterval());
745 EXPECT_FLOAT_EQ(m_startTime
, timer
.lastFireTime());
747 timer
.setAlignedFireTime(m_startTime
);
748 timer
.didChangeAlignmentInterval(monotonicallyIncreasingTime());
750 EXPECT_FLOAT_EQ(0.0, timer
.nextFireInterval());
751 EXPECT_FLOAT_EQ(0.0, timer
.nextUnalignedFireInterval());
752 EXPECT_FLOAT_EQ(m_startTime
, timer
.lastFireTime());