[fuchsia_modular_test] add TestHarnessSpecBuilder
TEST=
- fx run-test fuchsia_modular_test_package_integration_tests
Change-Id: I8fcc06826e782371824cad91d7a976d843081177
diff --git a/public/dart/fuchsia_modular_test/BUILD.gn b/public/dart/fuchsia_modular_test/BUILD.gn
index 8df7c5a..9e3370c 100644
--- a/public/dart/fuchsia_modular_test/BUILD.gn
+++ b/public/dart/fuchsia_modular_test/BUILD.gn
@@ -14,8 +14,9 @@
sdk_category = "partner"
sources = [
- "test.dart",
"src/test_harness_fixtures.dart",
+ "src/test_harness_spec_builder.dart",
+ "test.dart",
]
deps = [
@@ -30,6 +31,7 @@
"//topaz/public/dart/fuchsia_modular",
"//topaz/public/dart/fuchsia_services",
"//topaz/public/dart/zircon",
+ "//zircon/public/fidl/fuchsia-mem",
]
}
@@ -45,6 +47,7 @@
sources = [
"launch_harness_test.dart",
+ "test_harness_spec_builder_test.dart",
]
deps = [
diff --git a/public/dart/fuchsia_modular_test/lib/src/test_harness_fixtures.dart b/public/dart/fuchsia_modular_test/lib/src/test_harness_fixtures.dart
index b12876d..33e440d 100644
--- a/public/dart/fuchsia_modular_test/lib/src/test_harness_fixtures.dart
+++ b/public/dart/fuchsia_modular_test/lib/src/test_harness_fixtures.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
+import 'dart:math';
import 'package:fidl_fuchsia_modular_testing/fidl_async.dart' as fidl_testing;
import 'package:fidl_fuchsia_sys/fidl_async.dart' as fidl_sys;
@@ -40,3 +41,10 @@
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';
+}
diff --git a/public/dart/fuchsia_modular_test/lib/src/test_harness_spec_builder.dart b/public/dart/fuchsia_modular_test/lib/src/test_harness_spec_builder.dart
new file mode 100644
index 0000000..9cc02aa
--- /dev/null
+++ b/public/dart/fuchsia_modular_test/lib/src/test_harness_spec_builder.dart
@@ -0,0 +1,65 @@
+// 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>[];
+
+ /// 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');
+
+ // 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)));
+ }
+
+ /// Returns the [TestHarnessSpec] object which can be passed to the [TestHarnessProxy]
+ TestHarnessSpec build() {
+ return TestHarnessSpec(componentsToIntercept: _componentsToIntercept);
+ }
+
+ 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);
+ }
+}
diff --git a/public/dart/fuchsia_modular_test/lib/test.dart b/public/dart/fuchsia_modular_test/lib/test.dart
index 4a347d2..059ce58 100644
--- a/public/dart/fuchsia_modular_test/lib/test.dart
+++ b/public/dart/fuchsia_modular_test/lib/test.dart
@@ -5,3 +5,4 @@
/// A collection of utilities to help with writing tests
/// against the fuchsia_modular package.
export 'src/test_harness_fixtures.dart';
+export 'src/test_harness_spec_builder.dart';
diff --git a/public/dart/fuchsia_modular_test/test/test_harness_spec_builder_test.dart b/public/dart/fuchsia_modular_test/test/test_harness_spec_builder_test.dart
new file mode 100644
index 0000000..b7b2291
--- /dev/null
+++ b/public/dart/fuchsia_modular_test/test/test_harness_spec_builder_test.dart
@@ -0,0 +1,71 @@
+// 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';
+
+// ignore_for_file: implementation_imports
+import 'package:test/test.dart';
+import 'package:fuchsia_logger/logger.dart';
+import 'package:fuchsia_modular_test/src/test_harness_spec_builder.dart';
+import 'package:fuchsia_modular_test/src/test_harness_fixtures.dart';
+import 'package:zircon/zircon.dart';
+
+void main() {
+ setupLogger();
+
+ group('spec builder', () {
+ TestHarnessSpecBuilder builder;
+
+ setUp(() {
+ builder = TestHarnessSpecBuilder();
+ });
+
+ test('addComponentToIntercept fails on null component url', () {
+ expect(() => builder.addComponentToIntercept(null), throwsArgumentError);
+ });
+
+ test('addComponentToIntercept adds to the spec', () {
+ final url = generateComponentUrl();
+ builder.addComponentToIntercept(url);
+
+ final spec = builder.build();
+ expect(spec.componentsToIntercept,
+ contains(predicate((ispec) => ispec.componentUrl == url)));
+ });
+
+ test('able to add many components', () {
+ builder
+ ..addComponentToIntercept(generateComponentUrl())
+ ..addComponentToIntercept(generateComponentUrl());
+
+ expect(builder.build().componentsToIntercept.length, 2);
+ });
+
+ test('componentUrl can only be added once', () {
+ final url = generateComponentUrl();
+ builder.addComponentToIntercept(url);
+ expect(() => builder.addComponentToIntercept(url), throwsException);
+ });
+
+ test('can add services to the components cmx file', () {
+ const service = 'fuchsia.sys.Launcher';
+ builder
+ .addComponentToIntercept(generateComponentUrl(), services: [service]);
+
+ final spec = builder.build();
+ final interceptSpec = spec.componentsToIntercept.first;
+ final contents = interceptSpec.extraCmxContents;
+ final vmo = SizedVmo(contents.vmo.handle, contents.size);
+ final bytes = vmo.read(contents.size).bytesAsUint8List();
+
+ final expectedSandbox = {
+ 'sandbox': {
+ 'services': [service]
+ }
+ };
+
+ expect(expectedSandbox, json.decode(utf8.decode(bytes)));
+ });
+ });
+}