blob: 61c963aa095f61e1e8847ba8efb47c57d8e6ac42 [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.
// ignore_for_file: avoid_as
import 'dart:convert' show utf8, json;
import 'dart:typed_data';
import 'package:fidl_fuchsia_mem/fidl_async.dart' as fuchsia_mem;
import 'package:fidl_fuchsia_modular_session/fidl_async.dart';
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 {
BasemgrConfig? _basemgrConfig = BasemgrConfig();
SessionmgrConfig _sessionmgrConfig = SessionmgrConfig();
final _componentsToIntercept = <InterceptSpec>[];
final _envServicesToInherit = <String>['fuchsia.logger.LogSink'];
final _envComponentServices = <ComponentService>[];
/// Add a non default basemgr configuration.
void setBasemgrConfig(BasemgrConfig? basemgrConfig) {
ArgumentError.checkNotNull(basemgrConfig, 'basemgrConfig');
_basemgrConfig = basemgrConfig!;
}
/// Add a non default sessionmgr configuration.
void setSessionmgrConfig(SessionmgrConfig? sessionmgrConfig) {
ArgumentError.checkNotNull(sessionmgrConfig, 'sessionmgrConfig');
_sessionmgrConfig = sessionmgrConfig!;
}
/// 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 addServiceFromComponent(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 = ComponentService(name: name, url: componentUrl);
if (_envComponentServices.contains(service)) {
throw Exception(
'Attempting to add [$service] twice. Services must be unique');
}
_envComponentServices.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(
basemgrConfig: _basemgrConfig,
sessionmgrConfig: _sessionmgrConfig,
componentsToIntercept: _componentsToIntercept,
envServicesToInherit: _envServicesToInherit,
envServices: EnvironmentServicesSpec(
servicesFromComponents: _envComponentServices,
));
}
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 as Uint8List);
return fuchsia_mem.Buffer(vmo: vmo, size: encodedContents.length);
}
}