flutter_platform.dart 4.13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2015 The Chromium 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:convert';
import 'dart:io';

import 'package:async/async.dart';
import 'package:path/path.dart' as path;
import 'package:stream_channel/stream_channel.dart';

Ian Hickson's avatar
Ian Hickson committed
13 14 15
import 'package:test/src/backend/test_platform.dart'; // ignore: implementation_imports
import 'package:test/src/runner/plugin/platform.dart'; // ignore: implementation_imports
import 'package:test/src/runner/plugin/hack_register_platform.dart' as hack; // ignore: implementation_imports
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

import '../artifacts.dart';

final String _kSkyShell = Platform.environment['SKY_SHELL'];
const String _kHost = '127.0.0.1';
const String _kPath = '/runner';

String shellPath;

void installHook() {
  hack.registerPlatformPlugin([TestPlatform.vm], () => new FlutterPlatform());
}

class _ServerInfo {
  final String url;
  final Future<WebSocket> socket;
  final HttpServer server;

  _ServerInfo(this.server, this.url, this.socket);
}

Future<_ServerInfo> _startServer() async {
  HttpServer server = await HttpServer.bind(_kHost, 0);
  Completer<WebSocket> socket = new Completer<WebSocket>();
  server.listen((HttpRequest request) {
    if (request.uri.path == _kPath)
      socket.complete(WebSocketTransformer.upgrade(request));
  });
  return new _ServerInfo(server, 'ws://$_kHost:${server.port}$_kPath', socket.future);
}

Future<Process> _startProcess(String mainPath, { String packageRoot }) {
  assert(shellPath != null || _kSkyShell != null); // Please provide the path to the shell in the SKY_SHELL environment variable.
  return Process.start(shellPath ?? _kSkyShell, [
    '--enable-checked-mode',
    '--non-interactive',
    '--package-root=$packageRoot',
    mainPath,
  ]);
}

class FlutterPlatform extends PlatformPlugin {
58
  @override
Ian Hickson's avatar
Ian Hickson committed
59
  StreamChannel<String> loadChannel(String mainPath, TestPlatform platform) {
60 61 62
    return StreamChannelCompleter.fromFuture(_startTest(mainPath));
  }

Ian Hickson's avatar
Ian Hickson committed
63
  Future<StreamChannel<String>> _startTest(String mainPath) async {
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    _ServerInfo info = await _startServer();
    Directory tempDir = Directory.systemTemp.createTempSync(
        'dart_test_listener');
    File listenerFile = new File('${tempDir.path}/listener.dart');
    listenerFile.createSync();
    listenerFile.writeAsStringSync('''
import 'dart:convert';
import 'dart:io';

import 'package:stream_channel/stream_channel.dart';
import 'package:test/src/runner/plugin/remote_platform_helpers.dart';
import 'package:test/src/runner/vm/catch_isolate_errors.dart';

import '${path.toUri(path.absolute(mainPath))}' as test;

void main() {
  String server = Uri.decodeComponent('${Uri.encodeComponent(info.url)}');
  StreamChannel channel = serializeSuite(() {
    catchIsolateErrors();
    return test.main;
  });
  WebSocket.connect(server).then((WebSocket socket) {
    socket.map(JSON.decode).pipe(channel.sink);
    socket.addStream(channel.stream.map(JSON.encode));
  });
}
''');

    Process process = await _startProcess(
      listenerFile.path,
      packageRoot: path.absolute(ArtifactStore.packageRoot)
    );

    void finalize() {
      if (process != null) {
        Process processToKill = process;
        process = null;
        processToKill.kill();
      }
      if (tempDir != null) {
        Directory dirToDelete = tempDir;
        tempDir = null;
        dirToDelete.deleteSync(recursive: true);
      }
    }

    try {
      WebSocket socket = await info.socket;
Ian Hickson's avatar
Ian Hickson committed
112
      StreamChannel<String> channel = new StreamChannel<String>(socket.map(JSON.decode), socket);
113
      return channel.transformStream(
Ian Hickson's avatar
Ian Hickson committed
114 115
        new StreamTransformer<String, String>.fromHandlers(
          handleDone: (EventSink<String> sink) {
116 117 118 119
            finalize();
            sink.close();
          }
        )
Ian Hickson's avatar
Ian Hickson committed
120 121
      ).transformSink(new StreamSinkTransformer<String, String>.fromHandlers(
        handleData: (String data, StreamSink<String> sink) {
122 123
          sink.add(JSON.encode(data));
        },
Ian Hickson's avatar
Ian Hickson committed
124
        handleDone: (EventSink<String> sink) {
125 126 127 128 129 130 131 132 133 134
          finalize();
          sink.close();
        }
      ));
    } catch(e) {
      finalize();
      rethrow;
    }
  }
}