| // Copyright 2018 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 'package:mockito/mockito.dart'; |
| import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc; |
| |
| import 'package:fuchsia_remote_debug_protocol/fuchsia_remote_debug_protocol.dart'; |
| |
| import 'common.dart'; |
| |
| void main() { |
| group('FuchsiaRemoteConnection.connect', () { |
| MockSshCommandRunner mockRunner; |
| List<MockPortForwarder> forwardedPorts; |
| List<MockPeer> mockPeerConnections; |
| List<Uri> uriConnections; |
| |
| setUp(() { |
| mockRunner = MockSshCommandRunner(); |
| // Adds some extra junk to make sure the strings will be cleaned up. |
| when(mockRunner.run(argThat(startsWith('/bin/find')))).thenAnswer( |
| (_) => Future<List<String>>.value( |
| <String>['/hub/blah/blah/blah/vmservice-port\n'])); |
| when(mockRunner.run(argThat(startsWith('/bin/ls')))).thenAnswer( |
| (_) => Future<List<String>>.value( |
| <String>['123\n\n\n', '456 ', '789'])); |
| const String address = 'fe80::8eae:4cff:fef4:9247'; |
| const String interface = 'eno1'; |
| when(mockRunner.address).thenReturn(address); |
| when(mockRunner.interface).thenReturn(interface); |
| forwardedPorts = <MockPortForwarder>[]; |
| int port = 0; |
| Future<PortForwarder> mockPortForwardingFunction( |
| String address, |
| int remotePort, [ |
| String interface = '', |
| String configFile, |
| ]) { |
| return Future<PortForwarder>(() { |
| final MockPortForwarder pf = MockPortForwarder(); |
| forwardedPorts.add(pf); |
| when(pf.port).thenReturn(port++); |
| when(pf.remotePort).thenReturn(remotePort); |
| return pf; |
| }); |
| } |
| |
| final List<Map<String, dynamic>> flutterViewCannedResponses = |
| <Map<String, dynamic>>[ |
| <String, dynamic>{ |
| 'views': <Map<String, dynamic>>[ |
| <String, dynamic>{ |
| 'type': 'FlutterView', |
| 'id': 'flutterView0', |
| }, |
| ], |
| }, |
| <String, dynamic>{ |
| 'views': <Map<String, dynamic>>[ |
| <String, dynamic>{ |
| 'type': 'FlutterView', |
| 'id': 'flutterView1', |
| 'isolate': <String, dynamic>{ |
| 'type': '@Isolate', |
| 'fixedId': 'true', |
| 'id': 'isolates/1', |
| 'name': 'file://flutterBinary1', |
| 'number': '1', |
| }, |
| }, |
| ], |
| }, |
| <String, dynamic>{ |
| 'views': <Map<String, dynamic>>[ |
| <String, dynamic>{ |
| 'type': 'FlutterView', |
| 'id': 'flutterView2', |
| 'isolate': <String, dynamic>{ |
| 'type': '@Isolate', |
| 'fixedId': 'true', |
| 'id': 'isolates/2', |
| 'name': 'file://flutterBinary2', |
| 'number': '2', |
| }, |
| }, |
| ], |
| }, |
| ]; |
| |
| mockPeerConnections = <MockPeer>[]; |
| uriConnections = <Uri>[]; |
| Future<json_rpc.Peer> mockVmConnectionFunction( |
| Uri uri, { |
| Duration timeout, |
| }) { |
| return Future<json_rpc.Peer>(() async { |
| final MockPeer mp = MockPeer(); |
| mockPeerConnections.add(mp); |
| uriConnections.add(uri); |
| when(mp.sendRequest(any, any)) |
| // The local ports match the desired indices for now, so get the |
| // canned response from the URI port. |
| .thenAnswer((_) => Future<Map<String, dynamic>>( |
| () => flutterViewCannedResponses[uri.port])); |
| return mp; |
| }); |
| } |
| |
| fuchsiaPortForwardingFunction = mockPortForwardingFunction; |
| fuchsiaVmServiceConnectionFunction = mockVmConnectionFunction; |
| }); |
| |
| tearDown(() { |
| /// Most tests will mock out the port forwarding and connection |
| /// functions. |
| restoreFuchsiaPortForwardingFunction(); |
| restoreVmServiceConnectionFunction(); |
| }); |
| |
| test('end-to-end with three vm connections and flutter view query', () async { |
| final FuchsiaRemoteConnection connection = |
| await FuchsiaRemoteConnection.connectWithSshCommandRunner(mockRunner); |
| |
| // [mockPortForwardingFunction] will have returned three different |
| // forwarded ports, incrementing the port each time by one. (Just a sanity |
| // check that the forwarding port was called). |
| expect(forwardedPorts.length, 3); |
| expect(forwardedPorts[0].remotePort, 123); |
| expect(forwardedPorts[1].remotePort, 456); |
| expect(forwardedPorts[2].remotePort, 789); |
| expect(forwardedPorts[0].port, 0); |
| expect(forwardedPorts[1].port, 1); |
| expect(forwardedPorts[2].port, 2); |
| |
| final List<FlutterView> views = await connection.getFlutterViews(); |
| expect(views, isNot(null)); |
| expect(views.length, 3); |
| // Since name can be null, check for the ID on all of them. |
| expect(views[0].id, 'flutterView0'); |
| expect(views[1].id, 'flutterView1'); |
| expect(views[2].id, 'flutterView2'); |
| |
| expect(views[0].name, equals(null)); |
| expect(views[1].name, 'file://flutterBinary1'); |
| expect(views[2].name, 'file://flutterBinary2'); |
| |
| // Ensure the ports are all closed after stop was called. |
| await connection.stop(); |
| verify(forwardedPorts[0].stop()); |
| verify(forwardedPorts[1].stop()); |
| verify(forwardedPorts[2].stop()); |
| }); |
| |
| test('env variable test without remote addr', () async { |
| Future<void> failingFunction() async { |
| await FuchsiaRemoteConnection.connect(); |
| } |
| |
| // Should fail as no env variable has been passed. |
| expect(failingFunction, |
| throwsA(isInstanceOf<FuchsiaRemoteConnectionError>())); |
| }); |
| }); |
| } |
| |
| class MockSshCommandRunner extends Mock implements SshCommandRunner {} |
| |
| class MockPortForwarder extends Mock implements PortForwarder {} |
| |
| class MockPeer extends Mock implements json_rpc.Peer {} |