// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/libplatform/default-platform.h" #include "src/base/platform/semaphore.h" #include "src/base/platform/time.h" #include "testing/gmock/include/gmock/gmock.h" using testing::InSequence; using testing::StrictMock; namespace v8 { namespace platform { namespace default_platform_unittest { namespace { struct MockTask : public Task { virtual ~MockTask() { Die(); } MOCK_METHOD0(Run, void()); MOCK_METHOD0(Die, void()); }; struct MockIdleTask : public IdleTask { virtual ~MockIdleTask() { Die(); } MOCK_METHOD1(Run, void(double deadline_in_seconds)); MOCK_METHOD0(Die, void()); }; class DefaultPlatformWithMockTime : public DefaultPlatform { public: DefaultPlatformWithMockTime() : DefaultPlatform(IdleTaskSupport::kEnabled, nullptr) { mock_time_ = 0.0; SetTimeFunctionForTesting([]() { return mock_time_; }); } void IncreaseTime(double seconds) { mock_time_ += seconds; } private: static double mock_time_; }; double DefaultPlatformWithMockTime::mock_time_ = 0.0; } // namespace TEST(DefaultPlatformTest, PumpMessageLoop) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatform platform; EXPECT_FALSE(platform.PumpMessageLoop(isolate)); StrictMock* task = new StrictMock; platform.CallOnForegroundThread(isolate, task); EXPECT_CALL(*task, Run()); EXPECT_CALL(*task, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); } TEST(DefaultPlatformTest, PumpMessageLoopWithTaskRunner) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatform platform; std::shared_ptr taskrunner = platform.GetForegroundTaskRunner(isolate); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); StrictMock* task = new StrictMock; taskrunner->PostTask(std::unique_ptr(task)); EXPECT_CALL(*task, Run()); EXPECT_CALL(*task, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); } TEST(DefaultPlatformTest, PumpMessageLoopDelayed) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatformWithMockTime platform; EXPECT_FALSE(platform.PumpMessageLoop(isolate)); StrictMock* task1 = new StrictMock; StrictMock* task2 = new StrictMock; platform.CallDelayedOnForegroundThread(isolate, task2, 100); platform.CallDelayedOnForegroundThread(isolate, task1, 10); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); platform.IncreaseTime(11); EXPECT_CALL(*task1, Run()); EXPECT_CALL(*task1, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); platform.IncreaseTime(90); EXPECT_CALL(*task2, Run()); EXPECT_CALL(*task2, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); } TEST(DefaultPlatformTest, PumpMessageLoopDelayedWithTaskRunner) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatformWithMockTime platform; std::shared_ptr taskrunner = platform.GetForegroundTaskRunner(isolate); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); StrictMock* task1 = new StrictMock; StrictMock* task2 = new StrictMock; taskrunner->PostDelayedTask(std::unique_ptr(task2), 100); taskrunner->PostDelayedTask(std::unique_ptr(task1), 10); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); platform.IncreaseTime(11); EXPECT_CALL(*task1, Run()); EXPECT_CALL(*task1, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); EXPECT_FALSE(platform.PumpMessageLoop(isolate)); platform.IncreaseTime(90); EXPECT_CALL(*task2, Run()); EXPECT_CALL(*task2, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); } TEST(DefaultPlatformTest, PumpMessageLoopNoStarvation) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatformWithMockTime platform; EXPECT_FALSE(platform.PumpMessageLoop(isolate)); StrictMock* task1 = new StrictMock; StrictMock* task2 = new StrictMock; StrictMock* task3 = new StrictMock; platform.CallOnForegroundThread(isolate, task1); platform.CallDelayedOnForegroundThread(isolate, task2, 10); platform.IncreaseTime(11); EXPECT_CALL(*task1, Run()); EXPECT_CALL(*task1, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); platform.CallOnForegroundThread(isolate, task3); EXPECT_CALL(*task2, Run()); EXPECT_CALL(*task2, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); EXPECT_CALL(*task3, Run()); EXPECT_CALL(*task3, Die()); EXPECT_TRUE(platform.PumpMessageLoop(isolate)); } TEST(DefaultPlatformTest, PendingDelayedTasksAreDestroyedOnShutdown) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); { DefaultPlatformWithMockTime platform; StrictMock* task = new StrictMock; platform.CallDelayedOnForegroundThread(isolate, task, 10); EXPECT_CALL(*task, Die()); } } TEST(DefaultPlatformTest, RunIdleTasks) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatformWithMockTime platform; StrictMock* task = new StrictMock; platform.CallIdleOnForegroundThread(isolate, task); EXPECT_CALL(*task, Run(42.0 + 23.0)); EXPECT_CALL(*task, Die()); platform.IncreaseTime(23.0); platform.RunIdleTasks(isolate, 42.0); } TEST(DefaultPlatformTest, RunIdleTasksWithTaskRunner) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatformWithMockTime platform; std::shared_ptr taskrunner = platform.GetForegroundTaskRunner(isolate); StrictMock* task = new StrictMock; taskrunner->PostIdleTask(std::unique_ptr(task)); EXPECT_CALL(*task, Run(42.0 + 23.0)); EXPECT_CALL(*task, Die()); platform.IncreaseTime(23.0); platform.RunIdleTasks(isolate, 42.0); } TEST(DefaultPlatformTest, PendingIdleTasksAreDestroyedOnShutdown) { InSequence s; int dummy; Isolate* isolate = reinterpret_cast(&dummy); { DefaultPlatformWithMockTime platform; StrictMock* task = new StrictMock; platform.CallIdleOnForegroundThread(isolate, task); EXPECT_CALL(*task, Die()); } } namespace { class TestBackgroundTask : public Task { public: explicit TestBackgroundTask(base::Semaphore* sem, bool* executed) : sem_(sem), executed_(executed) {} virtual ~TestBackgroundTask() { Die(); } MOCK_METHOD0(Die, void()); void Run() { *executed_ = true; sem_->Signal(); } private: base::Semaphore* sem_; bool* executed_; }; } // namespace TEST(DefaultPlatformTest, RunBackgroundTask) { int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatform platform; platform.SetThreadPoolSize(1); std::shared_ptr taskrunner = platform.GetBackgroundTaskRunner(isolate); base::Semaphore sem(0); bool task_executed = false; StrictMock* task = new StrictMock(&sem, &task_executed); EXPECT_CALL(*task, Die()); taskrunner->PostTask(std::unique_ptr(task)); EXPECT_TRUE(sem.WaitFor(base::TimeDelta::FromSeconds(1))); EXPECT_TRUE(task_executed); } TEST(DefaultPlatformTest, NoIdleTasksInBackground) { int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatform platform; platform.SetThreadPoolSize(1); std::shared_ptr taskrunner = platform.GetBackgroundTaskRunner(isolate); EXPECT_FALSE(taskrunner->IdleTasksEnabled()); } TEST(DefaultPlatformTest, PostTaskAfterPlatformTermination) { std::shared_ptr foreground_taskrunner; std::shared_ptr background_taskrunner; { int dummy; Isolate* isolate = reinterpret_cast(&dummy); DefaultPlatformWithMockTime platform; platform.SetThreadPoolSize(1); foreground_taskrunner = platform.GetForegroundTaskRunner(isolate); background_taskrunner = platform.GetBackgroundTaskRunner(isolate); } // It should still be possible to post tasks, even when the platform does not // exist anymore. StrictMock* task1 = new StrictMock; EXPECT_CALL(*task1, Die()); foreground_taskrunner->PostTask(std::unique_ptr(task1)); StrictMock* task2 = new StrictMock; EXPECT_CALL(*task2, Die()); foreground_taskrunner->PostDelayedTask(std::unique_ptr(task2), 10); StrictMock* task3 = new StrictMock; EXPECT_CALL(*task3, Die()); foreground_taskrunner->PostIdleTask(std::unique_ptr(task3)); StrictMock* task4 = new StrictMock; EXPECT_CALL(*task4, Die()); background_taskrunner->PostTask(std::unique_ptr(task4)); } } // namespace default_platform_unittest } // namespace platform } // namespace v8