Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / scheduler / SchedulerTest.cpp
index 7b03e94..7578940 100644 (file)
 #include <vector>
 
 using blink::Scheduler;
-using namespace std;
 
 namespace {
 
+class SchedulerForTest : public blink::Scheduler {
+public:
+    static void initializeOnMainThread()
+    {
+        s_sharedScheduler = new SchedulerForTest();
+    }
+
+    using Scheduler::Normal;
+    using Scheduler::CompositorPriority;
+    using Scheduler::enterSchedulerPolicy;
+};
+
 class TestMainThread : public blink::WebThread {
 public:
     // blink::WebThread implementation.
@@ -38,6 +49,12 @@ public:
         return true;
     }
 
+    virtual blink::PlatformThreadId threadId() const OVERRIDE
+    {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
     virtual void enterRunLoop() OVERRIDE
     {
         ASSERT_NOT_REACHED();
@@ -54,6 +71,11 @@ public:
             m_pendingTasks.takeFirst()->run();
     }
 
+    size_t numPendingMainThreadTasks() const
+    {
+        return m_pendingTasks.size();
+    }
+
 private:
     WTF::Deque<OwnPtr<Task> > m_pendingTasks;
 };
@@ -65,6 +87,7 @@ public:
         , m_sharedTimerFunction(nullptr)
         , m_sharedTimerRunning(false)
         , m_sharedTimerFireInterval(0)
+        , m_monotonicallyIncreasingTime(0)
     {
     }
 
@@ -79,6 +102,11 @@ public:
         m_sharedTimerFunction = timerFunction;
     }
 
+    virtual double monotonicallyIncreasingTime() OVERRIDE
+    {
+        return m_monotonicallyIncreasingTime;
+    }
+
     virtual void setSharedTimerFireInterval(double)
     {
         m_sharedTimerFireInterval = 0;
@@ -110,11 +138,22 @@ public:
         m_sharedTimerFunction();
     }
 
+    size_t numPendingMainThreadTasks() const
+    {
+        return m_mainThread.numPendingMainThreadTasks();
+    }
+
+    void setMonotonicTimeForTest(double time)
+    {
+        m_monotonicallyIncreasingTime = time;
+    }
+
 private:
     TestMainThread m_mainThread;
     SharedTimerFunction m_sharedTimerFunction;
     bool m_sharedTimerRunning;
     double m_sharedTimerFireInterval;
+    double m_monotonicallyIncreasingTime;
 };
 
 class SchedulerTest : public testing::Test {
@@ -123,8 +162,8 @@ public:
         : m_reentrantCount(0)
         , m_maxRecursion(4)
     {
-        Scheduler::initializeOnMainThread();
-        m_scheduler = Scheduler::shared();
+        SchedulerForTest::initializeOnMainThread();
+        m_scheduler = static_cast<SchedulerForTest*>(Scheduler::shared());
     }
 
     ~SchedulerTest()
@@ -132,12 +171,24 @@ public:
         Scheduler::shutdown();
     }
 
+    virtual void SetUp() OVERRIDE
+    {
+        m_scheduler->enterSchedulerPolicy(SchedulerForTest::Normal);
+    }
+
+    virtual void TearDown() OVERRIDE
+    {
+        // If the Scheduler hasn't been shut down then explicitly flush the tasks.
+        if (Scheduler::shared())
+            runPendingTasks();
+    }
+
     void runPendingTasks()
     {
         m_platformSupport.runPendingTasks();
     }
 
-    void appendToVector(string value)
+    void appendToVector(std::string value)
     {
         m_order.push_back(value);
     }
@@ -171,8 +222,8 @@ public:
 
 protected:
     SchedulerTestingPlatformSupport m_platformSupport;
-    Scheduler* m_scheduler;
-    std::vector<string> m_order;
+    SchedulerForTest* m_scheduler;
+    std::vector<std::string> m_order;
     std::vector<int> m_reentrantOrder;
     int m_reentrantCount;
     int m_maxRecursion;
@@ -211,8 +262,9 @@ TEST_F(SchedulerTest, TestPostMixedTaskTypes)
     m_scheduler->postInputTask(FROM_HERE, WTF::bind(&unorderedTestTask, 2, &result));
     m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&unorderedTestTask, 4, &result));
     m_scheduler->postTask(FROM_HERE, WTF::bind(&unorderedTestTask, 8, &result));
+    m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&unorderedTestTask, 16, &result));
     runPendingTasks();
-    EXPECT_EQ(15, result);
+    EXPECT_EQ(31, result);
 }
 
 int s_sharedTimerTickCount;
@@ -251,18 +303,37 @@ TEST_F(SchedulerTest, TestIdleTask)
     EXPECT_EQ(4, result);
 }
 
-TEST_F(SchedulerTest, TestTaskPrioritization)
+TEST_F(SchedulerTest, TestTaskPrioritization_normalPolicy)
+{
+    m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L1")));
+    m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L2")));
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I1")));
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C1")));
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I2")));
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C2")));
+    m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("IPC")));
+
+    runPendingTasks();
+    EXPECT_THAT(m_order, testing::ElementsAre(
+        std::string("L1"), std::string("L2"), std::string("I1"), std::string("C1"), std::string("I2"), std::string("C2"),
+        std::string("IPC")));
+}
+
+TEST_F(SchedulerTest, TestTaskPrioritization_compositorPriorityPolicy)
 {
-    m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, string("L1")));
-    m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, string("L2")));
-    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, string("I1")));
-    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, string("I2")));
-    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, string("C1")));
-    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, string("C2")));
+    m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
+    m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L1")));
+    m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L2")));
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I1")));
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C1")));
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I2")));
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C2")));
+    m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("IPC")));
 
     runPendingTasks();
     EXPECT_THAT(m_order, testing::ElementsAre(
-        string("I1"), string("I2"), string("C1"), string("C2"), string("L1"), string("L2")));
+        std::string("I1"), std::string("C1"), std::string("I2"), std::string("C2"), std::string("L1"), std::string("L2"),
+        std::string("IPC")));
 }
 
 TEST_F(SchedulerTest, TestRentrantTask)
@@ -290,4 +361,195 @@ TEST_F(SchedulerTest, TestRentrantCompositorTaskDuringShutdown)
     EXPECT_THAT(m_reentrantOrder, testing::ElementsAre(0, 1, 2, 3, 4));
 }
 
+bool s_shouldContinue;
+void reentrantInputTask(Scheduler* scheduler)
+{
+    if (s_shouldContinue)
+        scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantInputTask, scheduler));
+}
+
+void reentrantCompositorTask(Scheduler* scheduler)
+{
+    if (s_shouldContinue)
+        scheduler->postCompositorTask(FROM_HERE, WTF::bind(&reentrantCompositorTask, scheduler));
+}
+
+void stopReentrantTask()
+{
+    s_shouldContinue = false;
+}
+
+TEST_F(SchedulerTest, TestRentrantInputTaskDoesNotStarveOutLowPriorityTask)
+{
+    s_shouldContinue = true;
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantInputTask, m_scheduler));
+    m_scheduler->postTask(FROM_HERE, WTF::bind(&stopReentrantTask));
+
+    // If starvation occurs then this will never exit.
+    runPendingTasks();
+}
+
+TEST_F(SchedulerTest, TestRentrantCompositorTaskDoesNotStarveOutLowPriorityTask)
+{
+    s_shouldContinue = true;
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantCompositorTask, m_scheduler));
+    m_scheduler->postTask(FROM_HERE, WTF::bind(&stopReentrantTask));
+
+    // If starvation occurs then this will never exit.
+    runPendingTasks();
+}
+
+int s_dummyTaskCount;
+void dummyTask()
+{
+    s_dummyTaskCount++;
+}
+
+TEST_F(SchedulerTest, TestMultipleCallsToPostInputOrCompositorTaskResultsInOnlyOneMainThreadTask)
+{
+    EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
+
+    for (int i = 0; i < 10; i++) {
+        m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
+        m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
+    }
+
+    EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
+}
+
+TEST_F(SchedulerTest, TestMainThreadTaskLifeCycle)
+{
+    EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
+
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
+    EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
+
+    runPendingTasks();
+    EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
+
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
+    EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
+
+    runPendingTasks();
+    EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
+}
+
+void postDummyInputTask()
+{
+    Scheduler::shared()->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
+}
+
+TEST_F(SchedulerTest, HighPriorityTasksOnlyDontRunBecauseOfSharedTimerFiring_InNormalMode)
+{
+    s_dummyTaskCount = 0;
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
+    // Trigger the posting of an input task during execution of the shared timer function.
+    m_scheduler->setSharedTimerFiredFunction(&postDummyInputTask);
+    m_scheduler->setSharedTimerFireInterval(0);
+    m_platformSupport.triggerSharedTimer();
+
+    EXPECT_EQ(0, s_dummyTaskCount);
+
+    // Clean up.
+    m_scheduler->stopSharedTimer();
+    m_scheduler->setSharedTimerFiredFunction(nullptr);
+}
+
+TEST_F(SchedulerTest, HighPriorityTasksOnlyRunOncePerSharedTimerFiring_InLowSchedulerPolicy)
+{
+    s_dummyTaskCount = 0;
+    m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
+    // Trigger the posting of an input task during execution of the shared timer function.
+    m_scheduler->setSharedTimerFiredFunction(&postDummyInputTask);
+    m_scheduler->setSharedTimerFireInterval(0);
+    m_platformSupport.triggerSharedTimer();
+
+    EXPECT_EQ(1, s_dummyTaskCount);
+
+    // Clean up.
+    m_scheduler->stopSharedTimer();
+    m_scheduler->setSharedTimerFiredFunction(nullptr);
+}
+
+TEST_F(SchedulerTest, TestInputEventDoesNotTriggerShouldYield_InNormalMode)
+{
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+TEST_F(SchedulerTest, TestDidReceiveInputEventDoesNotTriggerShouldYield)
+{
+    m_scheduler->didReceiveInputEvent();
+
+    EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+TEST_F(SchedulerTest, TestCompositorTaskDoesNotTriggerShouldYield_InNormalMode)
+{
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+TEST_F(SchedulerTest, TestIpcTaskDoesNotTriggerShouldYield_InNormalMode)
+{
+    m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+TEST_F(SchedulerTest, TestCompositorTaskDoesTriggerShouldYieldAfterDidReceiveInputEvent)
+{
+    m_scheduler->didReceiveInputEvent();
+
+    ASSERT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+TEST_F(SchedulerTest, TestInputTaskDoesTriggerShouldYield_InCompositorPriorityMode)
+{
+    m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
+    m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+
+TEST_F(SchedulerTest, TestCompositorTaskDoesTriggerShouldYield_InCompositorPriorityMode)
+{
+    m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+TEST_F(SchedulerTest, TestIpcTaskDoesNotTriggerShouldYield_InCompositorPriorityMode)
+{
+    m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
+    m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
+TEST_F(SchedulerTest, testDidReceiveInputEvent_DoesntTriggerLowLatencyModeForLong)
+{
+    m_platformSupport.setMonotonicTimeForTest(1000.0);
+
+    // Note the latency mode gets reset by executeHighPriorityTasks, so we need a dummy task here
+    // to make sure runPendingTasks triggers executeHighPriorityTasks.
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
+    m_scheduler->didReceiveInputEvent();
+    m_platformSupport.setMonotonicTimeForTest(1000.5);
+    runPendingTasks();
+
+    ASSERT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+    m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
+
+    EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
+}
+
 } // namespace