flutter_flutter/shell/common/shell_unittests.cc
Ben Konyi 12f48f7601
Allow for whitelisted flags to be passed to the Dart VM (#9148)
* Allow for whitelisted flags to be passed to the Dart VM

Fixed part of https://github.com/flutter/flutter/issues/32176
2019-06-04 14:51:29 -07:00

318 lines
12 KiB
C++

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#define FML_USED_ON_EMBEDDER
#include <functional>
#include <future>
#include <memory>
#include "flutter/fml/command_line.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/message_loop.h"
#include "flutter/fml/synchronization/count_down_latch.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell_test.h"
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/testing/testing.h"
namespace flutter {
namespace testing {
static bool ValidateShell(Shell* shell) {
if (!shell) {
return false;
}
if (!shell->IsSetup()) {
return false;
}
{
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
shell->GetPlatformView()->NotifyCreated();
latch.Signal();
});
latch.Wait();
}
{
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
shell->GetPlatformView()->NotifyDestroyed();
latch.Signal();
});
latch.Wait();
}
return true;
}
TEST_F(ShellTest, InitializeWithInvalidThreads) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
TaskRunners task_runners("test", nullptr, nullptr, nullptr, nullptr);
auto shell = Shell::Create(
std::move(task_runners), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_FALSE(shell);
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, InitializeWithDifferentThreads) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform | ThreadHost::Type::GPU |
ThreadHost::Type::IO | ThreadHost::Type::UI);
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.gpu_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
auto shell = Shell::Create(
std::move(task_runners), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_TRUE(ValidateShell(shell.get()));
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
shell.reset();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, InitializeWithSingleThread) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform);
auto task_runner = thread_host.platform_thread->GetTaskRunner();
TaskRunners task_runners("test", task_runner, task_runner, task_runner,
task_runner);
auto shell = Shell::Create(
std::move(task_runners), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
ASSERT_TRUE(ValidateShell(shell.get()));
shell.reset();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, InitializeWithSingleThreadWhichIsTheCallingThread) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
fml::MessageLoop::EnsureInitializedForCurrentThread();
auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
TaskRunners task_runners("test", task_runner, task_runner, task_runner,
task_runner);
auto shell = Shell::Create(
std::move(task_runners), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_TRUE(ValidateShell(shell.get()));
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
shell.reset();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest,
InitializeWithMultipleThreadButCallingThreadAsPlatformThread) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host(
"io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::GPU | ThreadHost::Type::IO | ThreadHost::Type::UI);
fml::MessageLoop::EnsureInitializedForCurrentThread();
TaskRunners task_runners("test",
fml::MessageLoop::GetCurrent().GetTaskRunner(),
thread_host.gpu_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
thread_host.io_thread->GetTaskRunner());
auto shell = Shell::Create(
std::move(task_runners), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_TRUE(ValidateShell(shell.get()));
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
shell.reset();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, InitializeWithGPUAndPlatformThreadsTheSame) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host(
"io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform | ThreadHost::Type::IO | ThreadHost::Type::UI);
TaskRunners task_runners(
"test",
thread_host.platform_thread->GetTaskRunner(), // platform
thread_host.platform_thread->GetTaskRunner(), // gpu
thread_host.ui_thread->GetTaskRunner(), // ui
thread_host.io_thread->GetTaskRunner() // io
);
auto shell = Shell::Create(
std::move(task_runners), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
ASSERT_TRUE(ValidateShell(shell.get()));
shell.reset();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, FixturesAreFunctional) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
const auto settings = CreateSettingsForFixture();
auto shell = Shell::Create(
GetTaskRunnersForFixture(), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_TRUE(ValidateShell(shell.get()));
auto configuration = RunConfiguration::InferFromSettings(settings);
ASSERT_TRUE(configuration.IsValid());
configuration.SetEntrypoint("fixturesAreFunctionalMain");
fml::AutoResetWaitableEvent main_latch;
AddNativeCallback(
"SayHiFromFixturesAreFunctionalMain",
CREATE_NATIVE_ENTRY([&main_latch](auto args) { main_latch.Signal(); }));
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetUITaskRunner(),
fml::MakeCopyable([&latch, config = std::move(configuration),
engine = shell->GetEngine()]() mutable {
ASSERT_TRUE(engine);
ASSERT_EQ(engine->Run(std::move(config)), Engine::RunStatus::Success);
latch.Signal();
}));
latch.Wait();
main_latch.Wait();
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
shell.reset();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, SecondaryIsolateBindingsAreSetupViaShellSettings) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
const auto settings = CreateSettingsForFixture();
auto shell = Shell::Create(
GetTaskRunnersForFixture(), settings,
[](Shell& shell) {
return std::make_unique<ShellTestPlatformView>(shell,
shell.GetTaskRunners());
},
[](Shell& shell) {
return std::make_unique<Rasterizer>(shell.GetTaskRunners());
});
ASSERT_TRUE(ValidateShell(shell.get()));
auto configuration = RunConfiguration::InferFromSettings(settings);
ASSERT_TRUE(configuration.IsValid());
configuration.SetEntrypoint("testCanLaunchSecondaryIsolate");
fml::CountDownLatch latch(2);
AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&latch](auto args) {
latch.CountDown();
}));
fml::TaskRunner::RunNowOrPostTask(
shell->GetTaskRunners().GetUITaskRunner(),
fml::MakeCopyable([config = std::move(configuration),
engine = shell->GetEngine()]() mutable {
ASSERT_TRUE(engine);
ASSERT_EQ(engine->Run(std::move(config)), Engine::RunStatus::Success);
}));
latch.Wait();
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
shell.reset();
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, BlacklistedDartVMFlag) {
// Run this test in a thread-safe manner, otherwise gtest will complain.
::testing::FLAGS_gtest_death_test_style = "threadsafe";
const std::vector<fml::CommandLine::Option> options = {
fml::CommandLine::Option("dart-flags", "--verify_after_gc")};
fml::CommandLine command_line("", options, std::vector<std::string>());
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
// Upon encountering a non-whitelisted Dart flag the process terminates.
const char* expected =
"Encountered blacklisted Dart VM flag: --verify_after_gc";
ASSERT_DEATH(flutter::SettingsFromCommandLine(command_line), expected);
#else
flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
EXPECT_EQ(settings.dart_flags.size(), 0u);
#endif
}
TEST_F(ShellTest, WhitelistedDartVMFlag) {
const std::vector<fml::CommandLine::Option> options = {
fml::CommandLine::Option("dart-flags",
"--max_profile_depth 1,--trace_service")};
fml::CommandLine command_line("", options, std::vector<std::string>());
flutter::Settings settings = flutter::SettingsFromCommandLine(command_line);
#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE && \
FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
EXPECT_EQ(settings.dart_flags.size(), 2u);
EXPECT_EQ(settings.dart_flags[0], "--max_profile_depth 1");
EXPECT_EQ(settings.dart_flags[1], "--trace_service");
#else
EXPECT_EQ(settings.dart_flags.size(), 0u);
#endif
}
} // namespace testing
} // namespace flutter