blob: 8a1e4343cb983e36351b634d792498c4b29509ca [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:convert' show utf8, json;
import 'package:fidl_fuchsia_mem/fidl_async.dart' as fuchsia_mem;
import 'package:fidl_fuchsia_modular_testing/fidl_async.dart';
import 'package:zircon/zircon.dart';
/// A class which aids in the building of [TestHarnessSpec] objects.
///
/// This class is used to build up the spec and then pass that to the
/// run method of the test harness.
/// ```
/// final builder = TestHarnessBuilder()
/// ..addComponentToIntercept(componentUrl);
/// await harness.run(builder.build());
/// ```
class TestHarnessSpecBuilder {
final _componentsToIntercept = <InterceptSpec>[];
final _envServicesToInherit = <String>['fuchsia.logger.LogSink'];
final _envServicesToInject = <InjectedService>[];
/// Registers the component url to be intercepted.
///
/// When a component with the given [componentUrl] is launched inside the
/// hermetic environment it will not be launched by the system but rather
/// passed to the [TestHarness]'s onNewComponent stream.
///
/// Optionally, additional [services] can be provided which will be added
/// to the intercepted components cmx file.
void addComponentToIntercept(String componentUrl, {List<String> services}) {
ArgumentError.checkNotNull(componentUrl, 'componentUrl');
if (componentUrl.isEmpty) {
throw ArgumentError('componentUrl must not be an empty string');
}
// verify that we have unique component urls
for (final spec in _componentsToIntercept) {
if (spec.componentUrl == componentUrl) {
throw Exception(
'Attempting to add [$componentUrl] twice. Component urls must be unique');
}
}
final extraContents = <String, dynamic>{};
if (services != null) {
extraContents['services'] = services;
}
_componentsToIntercept.add(InterceptSpec(
componentUrl: componentUrl,
extraCmxContents: _createCmxSandBox(extraContents)));
}
/// Adds [service] to the list of services which should be inherited by the
/// parent environment.
///
/// The following environemnt services will be added by default. If you wish
/// to not inherit these services you can remove them after building.
/// - fuchsia.logger.LogSink
void addEnvironmentServiceToInherit(String service) {
ArgumentError.checkNotNull(service, 'service');
if (service.isEmpty) {
throw ArgumentError('service must not be an empty string');
}
if (_envServicesToInherit.contains(service)) {
throw Exception(
'Attempting to add [$service] twice. Services must be unique');
}
_envServicesToInherit.add(service);
}
/// Adds the service with the given [name] and [componentUrl] to the list
/// of services to inject.
///
/// The [TestHarness] will automatically create these services and add
/// expose them to the environment under test.
void addEnvironmentServiceToInject(String name, String componentUrl) {
ArgumentError.checkNotNull(name, 'name');
ArgumentError.checkNotNull(componentUrl, 'componentUrl');
if (name.isEmpty || componentUrl.isEmpty) {
throw ArgumentError('name and componentUrl must not be an empty string');
}
final service = InjectedService(name: name, url: componentUrl);
if (_envServicesToInject.contains(service)) {
throw Exception(
'Attempting to add [$service] twice. Services must be unique');
}
_envServicesToInject.add(service);
}
/// Returns the [TestHarnessSpec] object which can be passed to the [TestHarnessProxy]
///
/// After building the [TestHarnessSpec] you may update its values directly if the builder
/// does not offer a method which satisfies your specific needs.
TestHarnessSpec build() {
return TestHarnessSpec(
componentsToIntercept: _componentsToIntercept,
envServicesToInherit: _envServicesToInherit,
envServicesToInject: _envServicesToInject,
);
}
fuchsia_mem.Buffer _createCmxSandBox(Map<String, dynamic> contents) {
if (contents.isEmpty) {
return null;
}
final encodedContents = utf8.encode(json.encode({'sandbox': contents}));
final vmo = SizedVmo.fromUint8List(encodedContents);
return fuchsia_mem.Buffer(vmo: vmo, size: encodedContents.length);
}
}