blob: 91648774a6e4258cb5673c85555df526bd5518fa [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:math';
import 'package:fidl/fidl.dart';
import 'package:fidl_fuchsia_io/fidl_async.dart';
import 'package:fidl_fuchsia_modular/fidl_async.dart' as fidl_modular;
import 'package:fidl_fuchsia_modular_testing/fidl_async.dart' as fidl_testing;
import 'package:fidl_fuchsia_sys/fidl_async.dart' as fidl_sys;
import 'package:fuchsia_services/services.dart';
import 'package:zircon/zircon.dart';
const _serviceRootPath = '/svc';
const _modularTestHarnessURL =
'fuchsia-pkg://fuchsia.com/modular_test_harness#meta/modular_test_harness.cmx';
/// Launches the test harness and connects to it.
///
/// It is the responsibility of the caller to close the connection to the
/// harness after each test.
Future<fidl_testing.TestHarnessProxy> launchTestHarness() async {
final harness = fidl_testing.TestHarnessProxy();
final launcher = fidl_sys.LauncherProxy();
final incoming = Incoming();
final componentControllerProxy = fidl_sys.ComponentControllerProxy();
final svc = Incoming.fromSvcPath()..connectToService(launcher);
final launchInfo = fidl_sys.LaunchInfo(
url: _modularTestHarnessURL,
directoryRequest: incoming.request().passChannel());
await launcher.createComponent(
launchInfo, componentControllerProxy.ctrl.request());
launcher.ctrl.close();
await svc.close();
// hold a reference to the componentControllerProxy so it lives as long as the
// harness and does not kill the service if it is garbage collected.
// ignore: unawaited_futures
harness.ctrl.whenClosed.then((_) {
componentControllerProxy.ctrl.close();
});
incoming.connectToService(harness);
await incoming.close();
return harness;
}
/// Generates a random component url with the correct format
String generateComponentUrl() {
final rand = Random();
final name = List.generate(10, (_) => rand.nextInt(9).toString()).join('');
return 'fuchsia-pkg://example.com/$name#meta/$name.cmx';
}
/// Returns the connection to [fidl_modular.ComponentContextProxy] which is
/// running inside the [harness]'s hermetic environment
Future<fidl_modular.ComponentContextProxy> getComponentContext(
fidl_testing.TestHarnessProxy harness) async {
final proxy = fidl_modular.ComponentContextProxy();
await harness.connectToModularService(
fidl_testing.ModularService.withComponentContext(proxy.ctrl.request()));
return proxy;
}
/// Creates an instance of [ComponentContext] from [fidl_sys.StartupInfo].
///
/// Note: This automatically serves [ComponentContext.outgoing].
ComponentContext createComponentContext(fidl_sys.StartupInfo startupInfo) {
final flat = startupInfo.flatNamespace;
if (flat.paths.length != flat.directories.length) {
throw Exception('The flat namespace in the given fuchsia.sys.StartupInfo '
'[$startupInfo] is misconfigured');
}
Channel? serviceRoot;
for (var i = 0; i < flat.paths.length; ++i) {
if (flat.paths[i] == _serviceRootPath) {
serviceRoot = flat.directories[i];
break;
}
}
final svcDirProxy = DirectoryProxy()..ctrl.bind(InterfaceHandle(serviceRoot));
return ComponentContext(
svc: Incoming.withDirectory(svcDirProxy),
outgoing: Outgoing()
..serve(InterfaceRequest<Node>(startupInfo.launchInfo.directoryRequest)),
);
}