Skip to content

Commit

Permalink
Update unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
liyuqian committed Sep 22, 2019
1 parent fda31bf commit a6f62c7
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 15 deletions.
36 changes: 21 additions & 15 deletions shell/common/input_events_unittests.cc
Expand Up @@ -78,12 +78,6 @@ static void TestSimulatedInputEvents(
fixture->AddNativeCallback("NativeOnPointerDataPacket",
CREATE_NATIVE_ENTRY(nativeOnPointerDataPacket));

auto nativeOnBeginFrame = [&will_draw_new_frame](Dart_NativeArguments args) {
will_draw_new_frame = true;
};
fixture->AddNativeCallback("NativeOnBeginFrame",
CREATE_NATIVE_ENTRY(nativeOnBeginFrame));

ASSERT_TRUE(configuration.IsValid());
fixture->RunEngine(shell.get(), std::move(configuration));

Expand Down Expand Up @@ -114,18 +108,30 @@ static void TestSimulatedInputEvents(
ASSERT_LT(j, continuous_frame_count);
}

// i is the input event's index.
// j is the frame's index.
for (int i = 0, j = 0; i < num_events; j += 1) {
double t = j * frame_time;
while (i < num_events && delivery_time(i) <= t) {
ShellTest::DispatchFakePointerData(shell.get());
i += 1;
// This has to be running on a different thread than Platform thread to avoid
// dead locks.
auto simulation = std::async(std::launch::async, [&]() {
// i is the input event's index.
// j is the frame's index.
for (int i = 0, j = 0; i < num_events; j += 1) {
double t = j * frame_time;
while (i < num_events && delivery_time(i) <= t) {
ShellTest::DispatchFakePointerData(shell.get());
i += 1;
}
ShellTest::VSyncFlush(shell.get(), will_draw_new_frame);
}
ShellTest::PumpOneFrame(shell.get());
}
// Finally, issue a vsync for the pending event that may be generated duing
// the last vsync.
ShellTest::VSyncFlush(shell.get(), will_draw_new_frame);
});

simulation.wait();
shell.reset();

// Make sure that all events have been consumed so
// https://github.com/flutter/flutter/issues/40863 won't happen again.
ASSERT_EQ(events_consumed_at_frame.back(), num_events);
}

TEST_F(ShellTest, MissAtMostOneFrameForIrregularInputEvents) {
Expand Down
67 changes: 67 additions & 0 deletions shell/common/shell_test.cc
Expand Up @@ -113,6 +113,29 @@ void ShellTest::RestartEngine(Shell* shell, RunConfiguration configuration) {
latch.Wait();
}

void ShellTest::VSyncFlush(Shell* shell, bool& will_draw_new_frame) {
fml::AutoResetWaitableEvent latch;
shell->GetTaskRunners().GetPlatformTaskRunner()->PostTask(
[shell, &will_draw_new_frame, &latch] {
// The following UI task ensures that all previous UI tasks are flushed.
fml::AutoResetWaitableEvent ui_latch;
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
[&ui_latch, &will_draw_new_frame]() {
will_draw_new_frame = true;
ui_latch.Signal();
});

ShellTestPlatformView* test_platform_view =
static_cast<ShellTestPlatformView*>(shell->GetPlatformView().get());
do {
test_platform_view->SimulateVSync();
} while (ui_latch.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(1)));

latch.Signal();
});
latch.Wait();
}

void ShellTest::PumpOneFrame(Shell* shell) {
// Set viewport to nonempty, and call Animator::BeginFrame to make the layer
// tree pipeline nonempty. Without either of this, the layer tree below
Expand Down Expand Up @@ -232,13 +255,57 @@ void ShellTest::AddNativeCallback(std::string name,
native_resolver_->AddNativeCallback(std::move(name), callback);
}

void ShellTestVsyncClock::SimulateVSync() {
std::scoped_lock lock(mutex_);
if (vsync_issued_ >= vsync_promised_.size()) {
vsync_promised_.emplace_back();
}
FML_CHECK(vsync_issued_ < vsync_promised_.size());
vsync_promised_[vsync_issued_].set_value(vsync_issued_);
vsync_issued_ += 1;
}

std::future<int> ShellTestVsyncClock::NextVSync() {
std::scoped_lock lock(mutex_);
vsync_promised_.emplace_back();
return vsync_promised_.back().get_future();
}

void ShellTestVsyncWaiter::AwaitVSync() {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
auto vsync_future = clock_.NextVSync();
vsync_future.wait();

// Post the `FireCallback` to the Platform thread so earlier Platform tasks
// (specifically, the `VSyncFlush` call) will be finished before
// `FireCallback` is executed. This is only needed for our unit tests.
//
// Without this, the repeated VSYNC signals in `VSyncFlush` may start both the
// current frame in the UI thread and the next frame in the secondary
// callback (both of them are waiting for VSYNCs). That breaks the unit test's
// assumption that each frame's VSYNC must be issued by different `VSyncFlush`
// call (which reset the `will_draw_new_frame` bit).
//
// For example, HandlesActualIphoneXsInputEvents will fail without this.
task_runners_.GetPlatformTaskRunner()->PostTask(
[this]() { FireCallback(fml::TimePoint::Now(), fml::TimePoint::Now()); });
}

ShellTestPlatformView::ShellTestPlatformView(PlatformView::Delegate& delegate,
TaskRunners task_runners)
: PlatformView(delegate, std::move(task_runners)),
gl_surface_(SkISize::Make(800, 600)) {}

ShellTestPlatformView::~ShellTestPlatformView() = default;

std::unique_ptr<VsyncWaiter> ShellTestPlatformView::CreateVSyncWaiter() {
return std::make_unique<ShellTestVsyncWaiter>(task_runners_, vsync_clock_);
}

void ShellTestPlatformView::SimulateVSync() {
vsync_clock_.SimulateVSync();
}

// |PlatformView|
std::unique_ptr<Surface> ShellTestPlatformView::CreateRenderingSurface() {
return std::make_unique<GPUSurfaceGL>(this, true);
Expand Down
38 changes: 38 additions & 0 deletions shell/common/shell_test.h
Expand Up @@ -9,6 +9,7 @@

#include "flutter/common/settings.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/synchronization/thread_annotations.h"
#include "flutter/lib/ui/window/platform_message.h"
#include "flutter/shell/common/run_configuration.h"
#include "flutter/shell/common/shell.h"
Expand Down Expand Up @@ -43,6 +44,10 @@ class ShellTest : public ThreadTest {
static void RunEngine(Shell* shell, RunConfiguration configuration);
static void RestartEngine(Shell* shell, RunConfiguration configuration);

/// Issue as many VSYNC as needed to flush the UI tasks so far, and reset
/// the `will_draw_new_frame` to true.
static void VSyncFlush(Shell* shell, bool& will_draw_new_frame);

static void PumpOneFrame(Shell* shell);
static void DispatchFakePointerData(Shell* shell);

Expand Down Expand Up @@ -73,19 +78,50 @@ class ShellTest : public ThreadTest {
void SetSnapshotsAndAssets(Settings& settings);
};

class ShellTestVsyncClock {
public:
/// Simulate that a vsync signal is triggered.
void SimulateVSync();

/// A future that will return the index the next vsync signal.
std::future<int> NextVSync();

private:
std::mutex mutex_;
std::vector<std::promise<int>> vsync_promised_ FML_GUARDED_BY(mutex_);
size_t vsync_issued_ FML_GUARDED_BY(mutex_) = 0;
};

class ShellTestVsyncWaiter : public VsyncWaiter {
public:
ShellTestVsyncWaiter(TaskRunners task_runners, ShellTestVsyncClock& clock)
: VsyncWaiter(std::move(task_runners)), clock_(clock) {}

protected:
void AwaitVSync() override;

private:
ShellTestVsyncClock& clock_;
};

class ShellTestPlatformView : public PlatformView, public GPUSurfaceGLDelegate {
public:
ShellTestPlatformView(PlatformView::Delegate& delegate,
TaskRunners task_runners);

~ShellTestPlatformView() override;

void SimulateVSync();

private:
TestGLSurface gl_surface_;

// |PlatformView|
std::unique_ptr<Surface> CreateRenderingSurface() override;

// |PlatformView|
std::unique_ptr<VsyncWaiter> CreateVSyncWaiter() override;

// |PlatformView|
PointerDataDispatcherMaker GetDispatcherMaker() override;

Expand All @@ -107,6 +143,8 @@ class ShellTestPlatformView : public PlatformView, public GPUSurfaceGLDelegate {
// |GPUSurfaceGLDelegate|
ExternalViewEmbedder* GetExternalViewEmbedder() override;

ShellTestVsyncClock vsync_clock_;

FML_DISALLOW_COPY_AND_ASSIGN(ShellTestPlatformView);
};

Expand Down
2 changes: 2 additions & 0 deletions shell/common/vsync_waiter.cc
Expand Up @@ -56,6 +56,8 @@ void VsyncWaiter::AsyncWaitForVsync(Callback callback) {
}

void VsyncWaiter::ScheduleSecondaryCallback(std::function<void()> callback) {
FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());

if (!callback) {
return;
}
Expand Down

0 comments on commit a6f62c7

Please sign in to comment.