LCOV - code coverage report
Current view: top level - test-0.12.24+8/lib/src/frontend - spawn_hybrid.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 0 25 0.0 %
Date: 2017-10-10 20:17:03 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
       2             : // for details. All rights reserved. Use of this source code is governed by a
       3             : // BSD-style license that can be found in the LICENSE file.
       4             : 
       5             : import 'dart:async';
       6             : import 'dart:convert';
       7             : 
       8             : import 'package:async/async.dart';
       9             : import 'package:path/path.dart' as p;
      10             : import 'package:stream_channel/stream_channel.dart';
      11             : 
      12             : import '../../test.dart';
      13             : import '../backend/invoker.dart';
      14             : import '../util/remote_exception.dart';
      15             : import '../utils.dart';
      16             : 
      17             : /// A transformer that handles messages from the spawned isolate and ensures
      18             : /// that messages sent to it are JSON-encodable.
      19             : ///
      20             : /// The spawned isolate sends three kinds of messages. Data messages are emitted
      21             : /// as data events, error messages are emitted as error events, and print
      22             : /// messages are printed using `print()`.
      23             : final _transformer = new StreamChannelTransformer<Object, Map>(
      24             :     new StreamTransformer.fromHandlers(handleData: (message, sink) {
      25             :   switch (message["type"]) {
      26             :     case "data":
      27             :       sink.add(message["data"]);
      28             :       break;
      29             : 
      30             :     case "print":
      31             :       print(message["line"]);
      32             :       break;
      33             : 
      34             :     case "error":
      35             :       var error = RemoteException.deserialize(message["error"]);
      36             :       sink.addError(error.error, error.stackTrace);
      37             :       break;
      38             :   }
      39             : }), new StreamSinkTransformer.fromHandlers(handleData: (message, sink) {
      40             :   // This is called synchronously from the user's `Sink.add()` call, so if
      41             :   // [ensureJsonEncodable] throws here they'll get a helpful stack trace.
      42             :   ensureJsonEncodable(message);
      43             :   sink.add(message);
      44             : }));
      45             : 
      46             : /// Spawns a VM isolate for the given [uri], which may be a [Uri] or a [String].
      47             : ///
      48             : /// This allows browser tests to spawn servers with which they can communicate
      49             : /// to test client/server interactions. It can also be used by VM tests to
      50             : /// easily spawn an isolate.
      51             : ///
      52             : /// The Dart file at [uri] must define a top-level `hybridMain()` function that
      53             : /// takes a `StreamChannel` argument and, optionally, an `Object` argument to
      54             : /// which [message] will be passed. Note that [message] must be JSON-encodable.
      55             : /// For example:
      56             : ///
      57             : /// ```dart
      58             : /// import "package:stream_channel/stream_channel.dart";
      59             : ///
      60             : /// hybridMain(StreamChannel channel, Object message) {
      61             : ///   // ...
      62             : /// }
      63             : /// ```
      64             : ///
      65             : /// If [uri] is relative, it will be interpreted relative to the `file:` URL for
      66             : /// the test suite being executed. If it's a `package:` URL, it will be resolved
      67             : /// using the current package's dependency constellation.
      68             : ///
      69             : /// Returns a [StreamChannel] that's connected to the channel passed to
      70             : /// `hybridMain()`. Only JSON-encodable objects may be sent through this
      71             : /// channel. If the channel is closed, the hybrid isolate is killed. If the
      72             : /// isolate is killed, the channel's stream will emit a "done" event.
      73             : ///
      74             : /// Any unhandled errors loading or running the hybrid isolate will be emitted
      75             : /// as errors over the channel's stream. Any calls to `print()` in the hybrid
      76             : /// isolate will be printed as though they came from the test that created the
      77             : /// isolate.
      78             : ///
      79             : /// Code in the hybrid isolate is not considered to be running in a test
      80             : /// context, so it can't access test functions like `expect()` and
      81             : /// `expectAsync()`.
      82             : ///
      83             : /// By default, the hybrid isolate is automatically killed when the test
      84             : /// finishes running. If [stayAlive] is `true`, it won't be killed until the
      85             : /// entire test suite finishes running.
      86             : ///
      87             : /// **Note**: If you use this API, be sure to add a dependency on the
      88             : /// **`stream_channel` package, since you're using its API as well!
      89             : StreamChannel spawnHybridUri(uri, {Object message, bool stayAlive: false}) {
      90             :   Uri parsedUrl;
      91           0 :   if (uri is Uri) {
      92             :     parsedUrl = uri;
      93           0 :   } else if (uri is String) {
      94           0 :     parsedUrl = Uri.parse(uri);
      95             :   } else {
      96           0 :     throw new ArgumentError.value(uri, "uri", "must be a Uri or a String.");
      97             :   }
      98             : 
      99             :   String absoluteUri;
     100           0 :   if (parsedUrl.scheme.isEmpty) {
     101             :     // If we're running in a browser context, the working directory is already
     102             :     // relative to the test file, whereas on the VM the working directory is the
     103             :     // root of the package.
     104           0 :     if (p.style == p.Style.url) {
     105           0 :       absoluteUri = p.absolute(parsedUrl.toString());
     106             :     } else {
     107           0 :       var suitePath = Invoker.current.liveTest.suite.path;
     108           0 :       absoluteUri = p.url.join(
     109           0 :           p.url.dirname(p.toUri(p.absolute(suitePath)).toString()),
     110           0 :           parsedUrl.toString());
     111             :     }
     112             :   } else {
     113           0 :     absoluteUri = uri.toString();
     114             :   }
     115             : 
     116           0 :   return _spawn(absoluteUri, message, stayAlive: stayAlive);
     117             : }
     118             : 
     119             : /// Spawns a VM isolate that runs the given [dartCode], which is loaded as the
     120             : /// contents of a Dart library.
     121             : ///
     122             : /// This allows browser tests to spawn servers with which they can communicate
     123             : /// to test client/server interactions. It can also be used by VM tests to
     124             : /// easily spawn an isolate.
     125             : ///
     126             : /// The [dartCode] must define a top-level `hybridMain()` function that takes a
     127             : /// `StreamChannel` argument and, optionally, an `Object` argument to which
     128             : /// [message] will be passed. Note that [message] must be JSON-encodable. For
     129             : /// example:
     130             : ///
     131             : /// ```dart
     132             : /// import "package:stream_channel/stream_channel.dart";
     133             : ///
     134             : /// hybridMain(StreamChannel channel, Object message) {
     135             : ///   // ...
     136             : /// }
     137             : /// ```
     138             : ///
     139             : /// Returns a [StreamChannel] that's connected to the channel passed to
     140             : /// `hybridMain()`. Only JSON-encodable objects may be sent through this
     141             : /// channel. If the channel is closed, the hybrid isolate is killed. If the
     142             : /// isolate is killed, the channel's stream will emit a "done" event.
     143             : ///
     144             : /// Any unhandled errors loading or running the hybrid isolate will be emitted
     145             : /// as errors over the channel's stream. Any calls to `print()` in the hybrid
     146             : /// isolate will be printed as though they came from the test that created the
     147             : /// isolate.
     148             : ///
     149             : /// Code in the hybrid isolate is not considered to be running in a test
     150             : /// context, so it can't access test functions like `expect()` and
     151             : /// `expectAsync()`.
     152             : ///
     153             : /// By default, the hybrid isolate is automatically killed when the test
     154             : /// finishes running. If [stayAlive] is `true`, it won't be killed until the
     155             : /// entire test suite finishes running.
     156             : ///
     157             : /// **Note**: If you use this API, be sure to add a dependency on the
     158             : /// **`stream_channel` package, since you're using its API as well!
     159             : StreamChannel spawnHybridCode(String dartCode,
     160             :     {Object message, bool stayAlive: false}) {
     161           0 :   var uri = new Uri.dataFromString(dartCode,
     162             :       encoding: UTF8, mimeType: 'application/dart');
     163           0 :   return _spawn(uri.toString(), message, stayAlive: stayAlive);
     164             : }
     165             : 
     166             : /// Like [spawnHybridUri], but doesn't take [Uri] objects and doesn't handle
     167             : /// relative URLs.
     168             : StreamChannel _spawn(String uri, Object message, {bool stayAlive: false}) {
     169           0 :   var channel = Zone.current[#test.runner.test_channel] as MultiChannel;
     170             :   if (channel == null) {
     171             :     // TODO(nweiz): Link to an issue tracking support when running the test file
     172             :     // directly.
     173           0 :     throw new UnsupportedError("Can't connect to the test runner.\n"
     174             :         'spawnHybridUri() is currently only supported within "pub run test".');
     175             :   }
     176             : 
     177           0 :   ensureJsonEncodable(message);
     178             : 
     179           0 :   var isolateChannel = channel.virtualChannel();
     180           0 :   channel.sink.add({
     181             :     "type": "spawn-hybrid-uri",
     182             :     "url": uri,
     183             :     "message": message,
     184           0 :     "channel": isolateChannel.id
     185             :   });
     186             : 
     187             :   if (!stayAlive) {
     188           0 :     var disconnector = new Disconnector();
     189           0 :     addTearDown(() => disconnector.disconnect());
     190           0 :     isolateChannel = isolateChannel.transform(disconnector);
     191             :   }
     192             : 
     193           0 :   return isolateChannel.transform(_transformer);
     194             : }

Generated by: LCOV version 1.13