blob: 07c47dac8e2cbd4cba84ca221365f0f123a07d6e [file] [log] [blame]
// Copyright 2014 The Flutter 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 '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', () {
List<MockPortForwarder> forwardedPorts;
List<MockPeer> mockPeerConnections;
List<Uri> uriConnections;
setUp(() {
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',
},
},
],
},
];
forwardedPorts = <MockPortForwarder>[];
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;
});
}
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 {
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;
});
}
fuchsiaPortForwardingFunction = mockPortForwardingFunction;
final MockSshCommandRunner 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']));
when(mockRunner.address).thenReturn('fe80::8eae:4cff:fef4:9247');
when(mockRunner.interface).thenReturn('eno1');
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);
// VMs should be accessed via localhost ports given by
// [mockPortForwardingFunction].
expect(uriConnections[0],
Uri(scheme:'ws', host:'[::1]', port:0, path:'/ws'));
expect(uriConnections[1],
Uri(scheme:'ws', host:'[::1]', port:1, path:'/ws'));
expect(uriConnections[2],
Uri(scheme:'ws', host:'[::1]', port:2, path:'/ws'));
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('end-to-end with three vms and remote open port', () async {
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);
when(pf.openPortAddress).thenReturn('fe80::1:2%eno2');
return pf;
});
}
fuchsiaPortForwardingFunction = mockPortForwardingFunction;
final MockSshCommandRunner 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']));
when(mockRunner.address).thenReturn('fe80::8eae:4cff:fef4:9247');
when(mockRunner.interface).thenReturn('eno1');
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);
// VMs should be accessed via the alternate adddress given by
// [mockPortForwardingFunction].
expect(uriConnections[0],
Uri(scheme:'ws', host:'[fe80::1:2%25eno2]', port:0, path:'/ws'));
expect(uriConnections[1],
Uri(scheme:'ws', host:'[fe80::1:2%25eno2]', port:1, path:'/ws'));
expect(uriConnections[2],
Uri(scheme:'ws', host:'[fe80::1:2%25eno2]', port:2, path:'/ws'));
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('end-to-end with three vms and ipv4', () async {
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;
});
}
fuchsiaPortForwardingFunction = mockPortForwardingFunction;
final MockSshCommandRunner 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']));
when(mockRunner.address).thenReturn('196.168.1.4');
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);
// VMs should be accessed via the ipv4 loopback.
expect(uriConnections[0],
Uri(scheme:'ws', host:'127.0.0.1', port:0, path:'/ws'));
expect(uriConnections[1],
Uri(scheme:'ws', host:'127.0.0.1', port:1, path:'/ws'));
expect(uriConnections[2],
Uri(scheme:'ws', host:'127.0.0.1', port:2, path:'/ws'));
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(isA<FuchsiaRemoteConnectionError>()));
});
});
}
class MockSshCommandRunner extends Mock implements SshCommandRunner {}
class MockPortForwarder extends Mock implements PortForwarder {}
class MockPeer extends Mock implements json_rpc.Peer {}