Skip to content

Commit

Permalink
Add tests for RuntimeScheduler::scheduletTask and RuntimeScheduler::g…
Browse files Browse the repository at this point in the history
…etShouldYield

Summary:
Changelog: [internal]

Add tests for `RuntimeScheduler::scheduleTask` and `RuntimeScheduler::getShouldYield`

Reviewed By: JoshuaGross

Differential Revision: D27764464

fbshipit-source-id: 8f95dfd9ec1ddf9a0ee17d489961b19e4ceaa9de
  • Loading branch information
sammy-SC authored and facebook-github-bot committed Apr 15, 2021
1 parent e3a4de8 commit 4c1fd97
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 21 deletions.
1 change: 1 addition & 0 deletions ReactCommon/react/renderer/runtimescheduler/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ fb_xplat_cxx_test(
platforms = (ANDROID, APPLE, CXX),
deps = [
react_native_xplat_target("react/renderer/runtimescheduler:runtimescheduler"),
"//xplat/hermes/API:HermesAPI",
"//xplat/third-party/gmock:gtest",
],
)
2 changes: 1 addition & 1 deletion ReactCommon/react/renderer/runtimescheduler/Task.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class TaskPriorityComparer {
inline bool operator()(
std::shared_ptr<Task> const &lhs,
std::shared_ptr<Task> const &rhs) {
return lhs->getExpirationTime() < rhs->getExpirationTime();
return lhs->getExpirationTime() > rhs->getExpirationTime();
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,160 @@
*/

#include <gtest/gtest.h>
#include <hermes/API/hermes/hermes.h>
#include <jsi/jsi.h>
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include <memory>
#include "StubClock.h"
#include "StubQueue.h"

namespace facebook::react {

using namespace facebook::react;
using namespace std::chrono_literals;

TEST(RuntimeSchedulerTest, now) {
facebook::jsi::Runtime *runtime;
class RuntimeSchedulerTest : public testing::Test {
protected:
void SetUp() override {
runtime_ = facebook::hermes::makeHermesRuntime();
stubQueue_ = std::make_unique<StubQueue>();

RuntimeExecutor runtimeExecutor =
[this](
std::function<void(facebook::jsi::Runtime & runtime)> &&callback) {
stubQueue_->runOnQueue([this, callback = std::move(callback)]() {
callback(*runtime_);
});
};

stubClock_ = std::make_unique<StubClock>(StubClock());

auto stubNow = [this]() -> RuntimeSchedulerTimePoint {
return stubClock_->getNow();
};

runtimeScheduler_ =
std::make_unique<RuntimeScheduler>(runtimeExecutor, stubNow);
}

jsi::Function createHostFunctionFromLambda(std::function<void()> callback) {
return jsi::Function::createFromHostFunction(
*runtime_,
jsi::PropNameID::forUtf8(*runtime_, ""),
3,
[callback = std::move(callback)](
jsi::Runtime &,
jsi::Value const &,
jsi::Value const *,
size_t) noexcept -> jsi::Value {
callback();
return jsi::Value::undefined();
});
}

std::unique_ptr<facebook::hermes::HermesRuntime> runtime_;
std::unique_ptr<StubClock> stubClock_;
std::unique_ptr<StubQueue> stubQueue_;
std::unique_ptr<RuntimeScheduler> runtimeScheduler_;
};

TEST_F(RuntimeSchedulerTest, now) {
stubClock_->setTimePoint(1ms);

EXPECT_EQ(runtimeScheduler_->now(), RuntimeSchedulerTimePoint(1ms));

stubClock_->advanceTimeBy(10ms);

EXPECT_EQ(runtimeScheduler_->now(), RuntimeSchedulerTimePoint(11ms));

stubClock_->advanceTimeBy(6s);

EXPECT_EQ(runtimeScheduler_->now(), RuntimeSchedulerTimePoint(6011ms));
}

TEST_F(RuntimeSchedulerTest, getShouldYield) {
// Always returns false for now.
EXPECT_FALSE(runtimeScheduler_->getShouldYield());
}

TEST_F(RuntimeSchedulerTest, scheduleSingleTask) {
bool didRunTask = false;
auto callback =
createHostFunctionFromLambda([&didRunTask]() { didRunTask = true; });

RuntimeExecutor runtimeExecutor =
[&runtime](
std::function<void(facebook::jsi::Runtime & runtime)> &&callback) {
// TODO: This will crash if executed.
callback(*runtime);
};
runtimeScheduler_->scheduleTask(
SchedulerPriority::NormalPriority, std::move(callback));

auto stubClock = StubClock();
stubClock.setTimePoint(1ms);
EXPECT_FALSE(didRunTask);
EXPECT_EQ(stubQueue_->size(), 1);

auto stubNow = [&stubClock]() -> RuntimeSchedulerTimePoint {
return stubClock.getNow();
};
stubQueue_->tick();

auto runtimeScheduler = RuntimeScheduler(runtimeExecutor, stubNow);
EXPECT_EQ(runtimeScheduler.now(), RuntimeSchedulerTimePoint(1ms));
EXPECT_TRUE(didRunTask);
EXPECT_EQ(stubQueue_->size(), 0);
}

TEST_F(RuntimeSchedulerTest, scheduleTwoTasksWithSamePriority) {
bool didRunFirstTask = false;
auto callbackOne = createHostFunctionFromLambda(
[&didRunFirstTask]() { didRunFirstTask = true; });

runtimeScheduler_->scheduleTask(
SchedulerPriority::NormalPriority, std::move(callbackOne));

bool didRunSecondTask = false;
auto callbackTwo = createHostFunctionFromLambda(
[&didRunSecondTask]() { didRunSecondTask = true; });

runtimeScheduler_->scheduleTask(
SchedulerPriority::NormalPriority, std::move(callbackTwo));

stubClock.advanceTimeBy(10ms);
EXPECT_FALSE(didRunFirstTask);
EXPECT_FALSE(didRunSecondTask);
EXPECT_EQ(stubQueue_->size(), 2);

EXPECT_EQ(runtimeScheduler.now(), RuntimeSchedulerTimePoint(11ms));
stubQueue_->tick();

stubClock.advanceTimeBy(6s);
EXPECT_TRUE(didRunFirstTask);
EXPECT_FALSE(didRunSecondTask);
EXPECT_EQ(stubQueue_->size(), 1);

EXPECT_EQ(runtimeScheduler.now(), RuntimeSchedulerTimePoint(6011ms));
stubQueue_->tick();

EXPECT_TRUE(didRunSecondTask);
EXPECT_EQ(stubQueue_->size(), 0);
}

TEST_F(RuntimeSchedulerTest, scheduleTwoTasksWithDifferentPriorities) {
bool didRunLowPriorityTask = false;
auto callbackOne = createHostFunctionFromLambda(
[&didRunLowPriorityTask]() { didRunLowPriorityTask = true; });

runtimeScheduler_->scheduleTask(
SchedulerPriority::LowPriority, std::move(callbackOne));

bool didRunUserBLockingPriorityTask = false;
auto callbackTwo =
createHostFunctionFromLambda([&didRunUserBLockingPriorityTask]() {
didRunUserBLockingPriorityTask = true;
});

runtimeScheduler_->scheduleTask(
SchedulerPriority::UserBlockingPriority, std::move(callbackTwo));

EXPECT_FALSE(didRunLowPriorityTask);
EXPECT_FALSE(didRunUserBLockingPriorityTask);
EXPECT_EQ(stubQueue_->size(), 2);

stubQueue_->tick();

EXPECT_FALSE(didRunLowPriorityTask);
EXPECT_TRUE(didRunUserBLockingPriorityTask);
EXPECT_EQ(stubQueue_->size(), 1);

stubQueue_->tick();

EXPECT_TRUE(didRunLowPriorityTask);
EXPECT_EQ(stubQueue_->size(), 0);
}

} // namespace facebook::react
32 changes: 32 additions & 0 deletions ReactCommon/react/renderer/runtimescheduler/tests/StubQueue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <queue>

class StubQueue {
public:
void runOnQueue(std::function<void()> &&func) {
callbackQueue_.push(func);
}

void tick() {
if (!callbackQueue_.empty()) {
auto callback = callbackQueue_.front();
callback();
callbackQueue_.pop();
}
}

int size() {
return callbackQueue_.size();
}

private:
std::queue<std::function<void()>> callbackQueue_;
};

0 comments on commit 4c1fd97

Please sign in to comment.