default-platform-unittest.cc 8.53 KB
Newer Older
1 2 3 4 5
// 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"
6
#include "src/base/platform/semaphore.h"
7
#include "src/base/platform/time.h"
8 9 10 11 12 13 14
#include "testing/gmock/include/gmock/gmock.h"

using testing::InSequence;
using testing::StrictMock;

namespace v8 {
namespace platform {
15
namespace default_platform_unittest {
16 17 18 19

namespace {

struct MockTask : public Task {
20 21
  // See issue v8:8185
  ~MockTask() /* override */ { Die(); }
22 23
  MOCK_METHOD(void, Run, (), (override));
  MOCK_METHOD(void, Die, ());
24 25
};

26
struct MockIdleTask : public IdleTask {
27 28
  // See issue v8:8185
  ~MockIdleTask() /* override */ { Die(); }
29 30
  MOCK_METHOD(void, Run, (double deadline_in_seconds), (override));
  MOCK_METHOD(void, Die, ());
31
};
32 33 34

class DefaultPlatformWithMockTime : public DefaultPlatform {
 public:
35 36
  explicit DefaultPlatformWithMockTime(int thread_pool_size = 0)
      : DefaultPlatform(thread_pool_size, IdleTaskSupport::kEnabled, nullptr) {
37 38
    mock_time_ = 0.0;
    SetTimeFunctionForTesting([]() { return mock_time_; });
39
  }
40
  void IncreaseTime(double seconds) { mock_time_ += seconds; }
41 42

 private:
43
  static double mock_time_;
44 45
};

46 47
double DefaultPlatformWithMockTime::mock_time_ = 0.0;

48 49 50 51
template <typename Platform>
class PlatformTest : public ::testing::Test {
 public:
  Isolate* isolate() { return reinterpret_cast<Isolate*>(dummy_); }
52

53 54 55 56 57 58 59 60 61
  Platform* platform() { return &platform_; }

  std::shared_ptr<TaskRunner> task_runner() {
    if (!task_runner_) {
      task_runner_ = platform_.GetForegroundTaskRunner(isolate());
    }
    DCHECK_NOT_NULL(task_runner_);
    return task_runner_;
  }
62

63 64 65 66 67
  // These methods take ownership of the task. Tests might still reference them,
  // if the tasks are expected to still exist.
  void CallOnForegroundThread(Task* task) {
    task_runner()->PostTask(std::unique_ptr<Task>(task));
  }
68 69 70
  void CallNonNestableOnForegroundThread(Task* task) {
    task_runner()->PostNonNestableTask(std::unique_ptr<Task>(task));
  }
71 72 73 74 75 76 77
  void CallDelayedOnForegroundThread(Task* task, double delay_in_seconds) {
    task_runner()->PostDelayedTask(std::unique_ptr<Task>(task),
                                   delay_in_seconds);
  }
  void CallIdleOnForegroundThread(IdleTask* task) {
    task_runner()->PostIdleTask(std::unique_ptr<IdleTask>(task));
  }
78

79
  bool PumpMessageLoop() { return platform_.PumpMessageLoop(isolate()); }
80

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
 private:
  Platform platform_;
  InSequence in_sequence_;
  std::shared_ptr<TaskRunner> task_runner_;

  int dummy_ = 0;
};

class DefaultPlatformTest : public PlatformTest<DefaultPlatform> {};
class DefaultPlatformTestWithMockTime
    : public PlatformTest<DefaultPlatformWithMockTime> {};

}  // namespace

TEST_F(DefaultPlatformTest, PumpMessageLoop) {
  EXPECT_FALSE(platform()->PumpMessageLoop(isolate()));
97 98

  StrictMock<MockTask>* task = new StrictMock<MockTask>;
99
  CallOnForegroundThread(task);
100 101
  EXPECT_CALL(*task, Run());
  EXPECT_CALL(*task, Die());
102 103
  EXPECT_TRUE(PumpMessageLoop());
  EXPECT_FALSE(PumpMessageLoop());
104 105
}

106
TEST_F(DefaultPlatformTest, PumpMessageLoopWithTaskRunner) {
107
  std::shared_ptr<TaskRunner> taskrunner =
108 109
      platform()->GetForegroundTaskRunner(isolate());
  EXPECT_FALSE(PumpMessageLoop());
110 111 112 113 114

  StrictMock<MockTask>* task = new StrictMock<MockTask>;
  taskrunner->PostTask(std::unique_ptr<Task>(task));
  EXPECT_CALL(*task, Run());
  EXPECT_CALL(*task, Die());
115 116
  EXPECT_TRUE(PumpMessageLoop());
  EXPECT_FALSE(PumpMessageLoop());
117 118
}

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
TEST_F(DefaultPlatformTest, PumpMessageLoopNested) {
  EXPECT_FALSE(PumpMessageLoop());

  StrictMock<MockTask>* nestable_task1 = new StrictMock<MockTask>;
  StrictMock<MockTask>* non_nestable_task2 = new StrictMock<MockTask>;
  StrictMock<MockTask>* nestable_task3 = new StrictMock<MockTask>;
  StrictMock<MockTask>* non_nestable_task4 = new StrictMock<MockTask>;
  CallOnForegroundThread(nestable_task1);
  CallNonNestableOnForegroundThread(non_nestable_task2);
  CallOnForegroundThread(nestable_task3);
  CallNonNestableOnForegroundThread(non_nestable_task4);

  // Nestable tasks are FIFO; non-nestable tasks are FIFO. A task being
  // non-nestable may cause it to be executed later, but not earlier.
  EXPECT_CALL(*nestable_task1, Run).WillOnce([this]() {
    EXPECT_TRUE(PumpMessageLoop());
  });
  EXPECT_CALL(*nestable_task3, Run());
  EXPECT_CALL(*nestable_task3, Die());
  EXPECT_CALL(*nestable_task1, Die());
  EXPECT_TRUE(PumpMessageLoop());
  EXPECT_CALL(*non_nestable_task2, Run());
  EXPECT_CALL(*non_nestable_task2, Die());
  EXPECT_TRUE(PumpMessageLoop());
  EXPECT_CALL(*non_nestable_task4, Run());
  EXPECT_CALL(*non_nestable_task4, Die());
  EXPECT_TRUE(PumpMessageLoop());

  EXPECT_FALSE(PumpMessageLoop());
}

150 151
TEST_F(DefaultPlatformTestWithMockTime, PumpMessageLoopDelayed) {
  EXPECT_FALSE(PumpMessageLoop());
152 153 154

  StrictMock<MockTask>* task1 = new StrictMock<MockTask>;
  StrictMock<MockTask>* task2 = new StrictMock<MockTask>;
155 156
  CallDelayedOnForegroundThread(task2, 100);
  CallDelayedOnForegroundThread(task1, 10);
157

158
  EXPECT_FALSE(PumpMessageLoop());
159

160
  platform()->IncreaseTime(11);
161 162
  EXPECT_CALL(*task1, Run());
  EXPECT_CALL(*task1, Die());
163
  EXPECT_TRUE(PumpMessageLoop());
164

165
  EXPECT_FALSE(PumpMessageLoop());
166

167
  platform()->IncreaseTime(90);
168 169
  EXPECT_CALL(*task2, Run());
  EXPECT_CALL(*task2, Die());
170
  EXPECT_TRUE(PumpMessageLoop());
171 172
}

173 174
TEST_F(DefaultPlatformTestWithMockTime, PumpMessageLoopNoStarvation) {
  EXPECT_FALSE(PumpMessageLoop());
175 176 177 178

  StrictMock<MockTask>* task1 = new StrictMock<MockTask>;
  StrictMock<MockTask>* task2 = new StrictMock<MockTask>;
  StrictMock<MockTask>* task3 = new StrictMock<MockTask>;
179 180 181
  CallOnForegroundThread(task1);
  CallDelayedOnForegroundThread(task2, 10);
  platform()->IncreaseTime(11);
182 183 184

  EXPECT_CALL(*task1, Run());
  EXPECT_CALL(*task1, Die());
185
  EXPECT_TRUE(PumpMessageLoop());
186

187
  CallOnForegroundThread(task3);
188 189 190

  EXPECT_CALL(*task2, Run());
  EXPECT_CALL(*task2, Die());
191
  EXPECT_TRUE(PumpMessageLoop());
192 193
  EXPECT_CALL(*task3, Run());
  EXPECT_CALL(*task3, Die());
194
  EXPECT_TRUE(PumpMessageLoop());
195 196
}

197 198 199 200 201
TEST_F(DefaultPlatformTestWithMockTime,
       PendingDelayedTasksAreDestroyedOnShutdown) {
  StrictMock<MockTask>* task = new StrictMock<MockTask>;
  CallDelayedOnForegroundThread(task, 10);
  EXPECT_CALL(*task, Die());
202 203
}

204
TEST_F(DefaultPlatformTestWithMockTime, RunIdleTasks) {
205
  StrictMock<MockIdleTask>* task = new StrictMock<MockIdleTask>;
206
  CallIdleOnForegroundThread(task);
207 208
  EXPECT_CALL(*task, Run(42.0 + 23.0));
  EXPECT_CALL(*task, Die());
209 210
  platform()->IncreaseTime(23.0);
  platform()->RunIdleTasks(isolate(), 42.0);
211 212
}

213 214
TEST_F(DefaultPlatformTestWithMockTime,
       PendingIdleTasksAreDestroyedOnShutdown) {
215
  StrictMock<MockIdleTask>* task = new StrictMock<MockIdleTask>;
216
  CallIdleOnForegroundThread(task);
217
  EXPECT_CALL(*task, Die());
218
}
219

220 221 222 223 224 225 226
namespace {

class TestBackgroundTask : public Task {
 public:
  explicit TestBackgroundTask(base::Semaphore* sem, bool* executed)
      : sem_(sem), executed_(executed) {}

227
  ~TestBackgroundTask() override { Die(); }
228
  MOCK_METHOD(void, Die, ());
229

230
  void Run() override {
231 232 233 234 235 236 237 238 239 240 241
    *executed_ = true;
    sem_->Signal();
  }

 private:
  base::Semaphore* sem_;
  bool* executed_;
};

}  // namespace

242
TEST(CustomDefaultPlatformTest, RunBackgroundTask) {
243
  DefaultPlatform platform(1);
244 245 246 247 248 249

  base::Semaphore sem(0);
  bool task_executed = false;
  StrictMock<TestBackgroundTask>* task =
      new StrictMock<TestBackgroundTask>(&sem, &task_executed);
  EXPECT_CALL(*task, Die());
250
  platform.CallOnWorkerThread(std::unique_ptr<Task>(task));
251 252 253 254
  EXPECT_TRUE(sem.WaitFor(base::TimeDelta::FromSeconds(1)));
  EXPECT_TRUE(task_executed);
}

255
TEST(CustomDefaultPlatformTest, PostForegroundTaskAfterPlatformTermination) {
256 257
  std::shared_ptr<TaskRunner> foreground_taskrunner;
  {
258
    DefaultPlatformWithMockTime platform(1);
259

260 261 262 263 264
    int dummy;
    Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);

    foreground_taskrunner = platform.GetForegroundTaskRunner(isolate);
  }
265 266
  // It should still be possible to post foreground tasks, even when the
  // platform does not exist anymore.
267 268 269 270 271 272 273 274 275 276 277 278 279
  StrictMock<MockTask>* task1 = new StrictMock<MockTask>;
  EXPECT_CALL(*task1, Die());
  foreground_taskrunner->PostTask(std::unique_ptr<Task>(task1));

  StrictMock<MockTask>* task2 = new StrictMock<MockTask>;
  EXPECT_CALL(*task2, Die());
  foreground_taskrunner->PostDelayedTask(std::unique_ptr<Task>(task2), 10);

  StrictMock<MockIdleTask>* task3 = new StrictMock<MockIdleTask>;
  EXPECT_CALL(*task3, Die());
  foreground_taskrunner->PostIdleTask(std::unique_ptr<IdleTask>(task3));
}

280
}  // namespace default_platform_unittest
281 282
}  // namespace platform
}  // namespace v8