38using component_testing::ChildOptions;
39using component_testing::ChildRef;
40using component_testing::DirectoryContents;
41using component_testing::ParentRef;
42using component_testing::Protocol;
43using component_testing::RealmRoot;
44using component_testing::Route;
45using component_testing::StartupMode;
51constexpr auto kVulkanLoaderServiceName =
"fuchsia.vulkan.loader.Loader";
53constexpr auto kFlutterJitRunnerUrl =
54 "fuchsia-pkg://fuchsia.com/oot_flutter_jit_runner#meta/"
55 "flutter_jit_runner.cm";
56constexpr auto kFlutterJitProductRunnerUrl =
57 "fuchsia-pkg://fuchsia.com/oot_flutter_jit_product_runner#meta/"
58 "flutter_jit_product_runner.cm";
59constexpr auto kFlutterAotRunnerUrl =
60 "fuchsia-pkg://fuchsia.com/oot_flutter_aot_runner#meta/"
61 "flutter_aot_runner.cm";
62constexpr auto kFlutterAotProductRunnerUrl =
63 "fuchsia-pkg://fuchsia.com/oot_flutter_aot_product_runner#meta/"
64 "flutter_aot_product_runner.cm";
65constexpr char kChildViewUrl[] =
66 "fuchsia-pkg://fuchsia.com/child-view#meta/child-view.cm";
67constexpr char kParentViewUrl[] =
68 "fuchsia-pkg://fuchsia.com/parent-view#meta/parent-view.cm";
69static constexpr auto kTestUiStackUrl =
70 "fuchsia-pkg://fuchsia.com/flatland-scene-manager-test-ui-stack#meta/"
73constexpr auto kFlutterRunnerEnvironment =
"flutter_runner_env";
74constexpr auto kFlutterJitRunner =
"flutter_jit_runner";
75constexpr auto kFlutterJitRunnerRef = ChildRef{kFlutterJitRunner};
76constexpr auto kFlutterJitProductRunner =
"flutter_jit_product_runner";
77constexpr auto kFlutterJitProductRunnerRef = ChildRef{kFlutterJitProductRunner};
78constexpr auto kFlutterAotRunner =
"flutter_aot_runner";
79constexpr auto kFlutterAotRunnerRef = ChildRef{kFlutterAotRunner};
80constexpr auto kFlutterAotProductRunner =
"flutter_aot_product_runner";
81constexpr auto kFlutterAotProductRunnerRef = ChildRef{kFlutterAotProductRunner};
82constexpr auto kChildView =
"child_view";
83constexpr auto kChildViewRef = ChildRef{kChildView};
84constexpr auto kParentView =
"parent_view";
85constexpr auto kParentViewRef = ChildRef{kParentView};
86constexpr auto kTestUiStack =
"ui";
87constexpr auto kTestUiStackRef = ChildRef{kTestUiStack};
103static uint32_t OverlayPixelCount(
104 std::map<fuchsia_test_utils::Pixel, uint32_t>& histogram) {
105 return histogram[kFlatlandOverlayColor];
109constexpr zx::duration kScreenshotTimeout = zx::sec(10);
111constexpr zx::duration kTestTimeout = zx::min(1);
116 public ::testing::Test {
119 : realm_builder_(component_testing::RealmBuilder::Create()) {
120 FML_VLOG(1) <<
"Setting up base realm";
124 async::PostDelayedTask(
128 <<
"\n\n>> Test did not complete in time, terminating. <<\n\n";
134 const fuchsia::ui::observation::geometry::ViewTreeWatcherPtr&
136 std::optional<fuchsia::ui::observation::geometry::WatchResponse>&
138 zx_koid_t view_ref_koid);
141 const std::vector<std::string>& component_args = {});
147 fit::function<
void(std::map<fuchsia_test_utils::Pixel, uint32_t>)>
149 zx::duration timeout = kTestTimeout);
152 void SetUpRealmBase();
154 fuchsia::ui::test::scene::ControllerPtr scene_provider_;
155 fuchsia::ui::observation::geometry::ViewTreeWatcherPtr view_tree_watcher_;
156 fuchsia::ui::composition::ScreenshotPtr screenshot_;
159 component_testing::RealmBuilder realm_builder_;
160 std::unique_ptr<component_testing::RealmRoot> realm_;
162 uint64_t display_width_ = 0;
163 uint64_t display_height_ = 0;
166void FlutterEmbedderTest::SetUpRealmBase() {
167 FML_LOG(INFO) <<
"Setting up realm base.";
170 realm_builder_.AddChild(kFlutterJitRunner, kFlutterJitRunnerUrl);
171 realm_builder_.AddChild(kFlutterJitProductRunner,
172 kFlutterJitProductRunnerUrl);
173 realm_builder_.AddChild(kFlutterAotRunner, kFlutterAotRunnerUrl);
174 realm_builder_.AddChild(kFlutterAotProductRunner,
175 kFlutterAotProductRunnerUrl);
178 fuchsia::component::decl::Environment flutter_runner_environment;
179 flutter_runner_environment.set_name(kFlutterRunnerEnvironment);
180 flutter_runner_environment.set_extends(
181 fuchsia::component::decl::EnvironmentExtends::REALM);
182 flutter_runner_environment.set_runners({});
183 auto environment_runners = flutter_runner_environment.mutable_runners();
184 fuchsia::component::decl::RunnerRegistration flutter_jit_runner_reg;
185 flutter_jit_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild(
186 fuchsia::component::decl::ChildRef{.name = kFlutterJitRunner}));
187 flutter_jit_runner_reg.set_source_name(kFlutterJitRunner);
188 flutter_jit_runner_reg.set_target_name(kFlutterJitRunner);
189 environment_runners->push_back(std::move(flutter_jit_runner_reg));
190 fuchsia::component::decl::RunnerRegistration flutter_jit_product_runner_reg;
191 flutter_jit_product_runner_reg.set_source(
192 fuchsia::component::decl::Ref::WithChild(
193 fuchsia::component::decl::ChildRef{.name =
194 kFlutterJitProductRunner}));
195 flutter_jit_product_runner_reg.set_source_name(kFlutterJitProductRunner);
196 flutter_jit_product_runner_reg.set_target_name(kFlutterJitProductRunner);
197 environment_runners->push_back(std::move(flutter_jit_product_runner_reg));
198 fuchsia::component::decl::RunnerRegistration flutter_aot_runner_reg;
199 flutter_aot_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild(
200 fuchsia::component::decl::ChildRef{.name = kFlutterAotRunner}));
201 flutter_aot_runner_reg.set_source_name(kFlutterAotRunner);
202 flutter_aot_runner_reg.set_target_name(kFlutterAotRunner);
203 environment_runners->push_back(std::move(flutter_aot_runner_reg));
204 fuchsia::component::decl::RunnerRegistration flutter_aot_product_runner_reg;
205 flutter_aot_product_runner_reg.set_source(
206 fuchsia::component::decl::Ref::WithChild(
207 fuchsia::component::decl::ChildRef{.name =
208 kFlutterAotProductRunner}));
209 flutter_aot_product_runner_reg.set_source_name(kFlutterAotProductRunner);
210 flutter_aot_product_runner_reg.set_target_name(kFlutterAotProductRunner);
211 environment_runners->push_back(std::move(flutter_aot_product_runner_reg));
212 auto realm_decl = realm_builder_.GetRealmDecl();
213 if (!realm_decl.has_environments()) {
214 realm_decl.set_environments({});
216 auto realm_environments = realm_decl.mutable_environments();
217 realm_environments->push_back(std::move(flutter_runner_environment));
218 realm_builder_.ReplaceRealmDecl(std::move(realm_decl));
221 realm_builder_.AddChild(kTestUiStack, kTestUiStackUrl);
224 realm_builder_.AddChild(kChildView, kChildViewUrl,
226 .environment = kFlutterRunnerEnvironment,
228 realm_builder_.AddChild(kParentView, kParentViewUrl,
230 .environment = kFlutterRunnerEnvironment,
234 realm_builder_.AddRoute(
235 Route{.capabilities =
237 Protocol{fuchsia::logger::LogSink::Name_},
238 Protocol{fuchsia::inspect::InspectSink::Name_},
239 Protocol{fuchsia::sysmem::Allocator::Name_},
240 Protocol{fuchsia::sysmem2::Allocator::Name_},
241 Protocol{fuchsia::tracing::provider::Registry::Name_},
242 Protocol{kVulkanLoaderServiceName},
244 .source = ParentRef{},
245 .targets = {kFlutterJitRunnerRef, kFlutterJitProductRunnerRef,
246 kFlutterAotRunnerRef, kFlutterAotProductRunnerRef}});
249 realm_builder_.AddRoute(Route{
250 .capabilities = {Protocol{fuchsia::logger::LogSink::Name_},
251 Protocol{fuchsia::inspect::InspectSink::Name_},
252 Protocol{fuchsia::sysmem::Allocator::Name_},
253 Protocol{fuchsia::sysmem2::Allocator::Name_},
254 Protocol{fuchsia::tracing::provider::Registry::Name_},
255 Protocol{kVulkanLoaderServiceName}},
256 .source = ParentRef{},
257 .targets = {kTestUiStackRef}});
260 realm_builder_.AddRoute(Route{
261 .capabilities = {Protocol{fuchsia::ui::composition::Allocator::Name_},
262 Protocol{fuchsia::ui::composition::Flatland::Name_}},
263 .source = kTestUiStackRef,
264 .targets = {kFlutterJitRunnerRef, kFlutterJitProductRunnerRef,
265 kFlutterAotRunnerRef, kFlutterAotProductRunnerRef}});
268 realm_builder_.AddRoute(Route{
269 .capabilities = {Protocol{fuchsia::ui::composition::Screenshot::Name_},
270 Protocol{fuchsia::ui::test::input::Registry::Name_},
271 Protocol{fuchsia::ui::test::scene::Controller::Name_},
272 Protocol{fuchsia::ui::display::singleton::Info::Name_}},
273 .source = kTestUiStackRef,
274 .targets = {ParentRef()}});
277 realm_builder_.AddRoute(
278 Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
279 .source = kParentViewRef,
280 .targets = {ParentRef()}});
281 realm_builder_.AddRoute(
282 Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}},
283 .source = kChildViewRef,
284 .targets = {kParentViewRef}});
291 const fuchsia::ui::observation::geometry::ViewTreeWatcherPtr&
293 std::optional<fuchsia::ui::observation::geometry::WatchResponse>&
295 zx_koid_t view_ref_koid) {
296 std::optional<fuchsia::ui::observation::geometry::WatchResponse> watch_result;
297 view_tree_watcher->Watch(
298 [&watch_result](
auto response) { watch_result = std::move(response); });
299 FML_LOG(INFO) <<
"Waiting for view tree watch result";
300 RunLoopUntil([&watch_result] {
return watch_result.has_value(); });
301 FML_LOG(INFO) <<
"Received for view tree watch result";
302 if (CheckViewExistsInUpdates(watch_result->updates(), view_ref_koid)) {
303 watch_response = std::move(watch_result);
305 return watch_response.has_value();
309 const std::vector<std::string>& component_args) {
310 FML_LOG(INFO) <<
"Launching parent-view";
312 if (!component_args.empty()) {
316 for (
const auto& arg : component_args) {
322 auto config_directory_contents = DirectoryContents();
323 config_directory_contents.AddFile(
"args.csv", csv);
324 realm_builder_.RouteReadOnlyDirectory(
"config-data", {kParentViewRef},
325 std::move(config_directory_contents));
327 realm_ = std::make_unique<RealmRoot>(realm_builder_.Build());
330 std::optional<bool> display_metrics_obtained;
331 fuchsia::ui::display::singleton::InfoPtr display_info =
332 realm_->component().Connect<fuchsia::ui::display::singleton::Info>();
333 display_info->GetMetrics([
this, &display_metrics_obtained](
auto info) {
334 display_width_ = info.extent_in_px().width;
335 display_height_ = info.extent_in_px().height;
336 display_metrics_obtained =
true;
338 RunLoopUntil([&display_metrics_obtained] {
339 return display_metrics_obtained.has_value();
341 FML_LOG(INFO) <<
"Got display_width " << display_width_ <<
" display_height "
345 std::optional<zx_koid_t> view_ref_koid;
347 realm_->component().Connect<fuchsia::ui::test::scene::Controller>();
348 scene_provider_.set_error_handler(
349 [](
auto) {
FML_LOG(ERROR) <<
"Error from test scene provider"; });
350 fuchsia::ui::test::scene::ControllerAttachClientViewRequest request;
351 request.set_view_provider(
352 realm_->component().Connect<fuchsia::ui::app::ViewProvider>());
353 scene_provider_->RegisterViewTreeWatcher(view_tree_watcher_.NewRequest(),
355 scene_provider_->AttachClientView(
356 std::move(request), [&view_ref_koid](
auto client_view_ref_koid) {
357 view_ref_koid = client_view_ref_koid;
360 FML_LOG(INFO) <<
"Waiting for client view ref koid";
361 RunLoopUntil([&view_ref_koid] {
return view_ref_koid.has_value(); });
364 std::optional<fuchsia::ui::observation::geometry::WatchResponse>
366 FML_LOG(INFO) <<
"Waiting for client view to render; koid is "
367 << (view_ref_koid.has_value() ? view_ref_koid.value() : 0);
368 RunLoopUntil([
this, &watch_response, &view_ref_koid] {
369 return HasViewConnected(view_tree_watcher_, watch_response, *view_ref_koid);
371 FML_LOG(INFO) <<
"Client view has rendered";
374 realm_->component().Connect<fuchsia::ui::composition::Screenshot>();
375 FML_LOG(INFO) <<
"Launched parent-view";
379 FML_LOG(INFO) <<
"Taking screenshot... ";
381 fuchsia::ui::composition::ScreenshotTakeRequest request;
382 request.set_format(fuchsia::ui::composition::ScreenshotFormat::BGRA_RAW);
384 std::optional<fuchsia::ui::composition::ScreenshotTakeResponse> response;
385 screenshot_->Take(std::move(request), [
this, &response](
auto screenshot) {
386 response = std::move(screenshot);
390 EXPECT_FALSE(RunLoopWithTimeout(kScreenshotTimeout))
391 <<
"Timed out waiting for screenshot.";
392 FML_LOG(INFO) <<
"Screenshot captured.";
395 response->vmo(), display_width_, display_height_, 0);
400 fit::function<
void(std::map<fuchsia_test_utils::Pixel, uint32_t>)>
callback,
401 zx::duration timeout) {
402 return RunLoopWithTimeoutOrUntil(
405 auto histogram = screenshot.Histogram();
407 bool color_found = histogram[color] > 0;
408 if (color_found &&
callback !=
nullptr) {
417 LaunchParentViewInRealm();
420 ASSERT_TRUE(TakeScreenshotUntil(
421 kChildBackgroundColor,
422 [](std::map<fuchsia_test_utils::Pixel, uint32_t> histogram) {
425 EXPECT_GT(histogram[kParentBackgroundColor], 0u);
426 EXPECT_GT(histogram[kChildBackgroundColor], 0u);
427 EXPECT_GT(histogram[kParentBackgroundColor],
428 histogram[kChildBackgroundColor]);
433 LaunchParentViewInRealm({
"--showOverlay"});
436 ASSERT_TRUE(TakeScreenshotUntil(
437 kChildBackgroundColor,
438 [](std::map<fuchsia_test_utils::Pixel, uint32_t> histogram) {
441 const uint32_t overlay_pixel_count = OverlayPixelCount(histogram);
442 EXPECT_GT(histogram[kParentBackgroundColor], 0u);
443 EXPECT_GT(overlay_pixel_count, 0u);
444 EXPECT_GT(histogram[kChildBackgroundColor], 0u);
445 EXPECT_GT(histogram[kParentBackgroundColor],
446 histogram[kChildBackgroundColor]);
447 EXPECT_GT(overlay_pixel_count, histogram[kChildBackgroundColor]);