mirror of
https://github.com/flutter/flutter
synced 2024-10-14 04:02:56 +00:00
421 lines
12 KiB
Dart
421 lines
12 KiB
Dart
// 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 'dart:async';
|
|
|
|
import 'package:flutter_tools/src/base/common.dart';
|
|
import 'package:flutter_tools/src/base/io.dart' as io;
|
|
import 'package:flutter_tools/src/convert.dart';
|
|
import 'package:vm_service/vm_service.dart' as vm_service;
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/device.dart';
|
|
import 'package:flutter_tools/src/version.dart';
|
|
import 'package:flutter_tools/src/vmservice.dart';
|
|
import 'package:quiver/testing/async.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
|
|
final Map<String, Object> vm = <String, dynamic>{
|
|
'type': 'VM',
|
|
'name': 'vm',
|
|
'architectureBits': 64,
|
|
'targetCPU': 'x64',
|
|
'hostCPU': ' Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz',
|
|
'version': '2.1.0-dev.7.1.flutter-45f9462398 (Fri Oct 19 19:27:56 2018 +0000) on "linux_x64"',
|
|
'_profilerMode': 'Dart',
|
|
'_nativeZoneMemoryUsage': 0,
|
|
'pid': 103707,
|
|
'startTime': 1540426121876,
|
|
'_embedder': 'Flutter',
|
|
'_maxRSS': 312614912,
|
|
'_currentRSS': 33091584,
|
|
'isolates': <dynamic>[
|
|
<String, dynamic>{
|
|
'type': '@Isolate',
|
|
'fixedId': true,
|
|
'id': 'isolates/242098474',
|
|
'name': 'main.dart:main()',
|
|
'number': 242098474,
|
|
},
|
|
],
|
|
};
|
|
|
|
final vm_service.Isolate isolate = vm_service.Isolate.parse(
|
|
<String, dynamic>{
|
|
'type': 'Isolate',
|
|
'fixedId': true,
|
|
'id': 'isolates/242098474',
|
|
'name': 'main.dart:main()',
|
|
'number': 242098474,
|
|
'_originNumber': 242098474,
|
|
'startTime': 1540488745340,
|
|
'_heaps': <String, dynamic>{
|
|
'new': <String, dynamic>{
|
|
'used': 0,
|
|
'capacity': 0,
|
|
'external': 0,
|
|
'collections': 0,
|
|
'time': 0.0,
|
|
'avgCollectionPeriodMillis': 0.0,
|
|
},
|
|
'old': <String, dynamic>{
|
|
'used': 0,
|
|
'capacity': 0,
|
|
'external': 0,
|
|
'collections': 0,
|
|
'time': 0.0,
|
|
'avgCollectionPeriodMillis': 0.0,
|
|
},
|
|
},
|
|
}
|
|
);
|
|
|
|
final Map<String, Object> listViews = <String, dynamic>{
|
|
'type': 'FlutterViewList',
|
|
'views': <dynamic>[
|
|
<String, dynamic>{
|
|
'type': 'FlutterView',
|
|
'id': '_flutterView/0x4a4c1f8',
|
|
'isolate': <String, dynamic>{
|
|
'type': '@Isolate',
|
|
'fixedId': true,
|
|
'id': 'isolates/242098474',
|
|
'name': 'main.dart:main()',
|
|
'number': 242098474,
|
|
},
|
|
},
|
|
]
|
|
};
|
|
|
|
typedef ServiceCallback = Future<Map<String, dynamic>> Function(Map<String, Object>);
|
|
|
|
void main() {
|
|
testUsingContext('VmService registers reloadSources', () async {
|
|
Future<void> reloadSources(String isolateId, { bool pause, bool force}) async {}
|
|
|
|
final MockVMService mockVMService = MockVMService();
|
|
setUpVmService(
|
|
reloadSources,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
mockVMService,
|
|
);
|
|
|
|
verify(mockVMService.registerService('reloadSources', 'Flutter Tools')).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => BufferLogger.test()
|
|
});
|
|
|
|
testUsingContext('VmService registers reloadMethod', () async {
|
|
Future<void> reloadMethod({ String classId, String libraryId,}) async {}
|
|
|
|
final MockVMService mockVMService = MockVMService();
|
|
setUpVmService(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
reloadMethod,
|
|
null,
|
|
null,
|
|
mockVMService,
|
|
);
|
|
|
|
verify(mockVMService.registerService('reloadMethod', 'Flutter Tools')).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => BufferLogger.test()
|
|
});
|
|
|
|
testUsingContext('VmService registers flutterMemoryInfo service', () async {
|
|
final MockDevice mockDevice = MockDevice();
|
|
|
|
final MockVMService mockVMService = MockVMService();
|
|
setUpVmService(
|
|
null,
|
|
null,
|
|
null,
|
|
mockDevice,
|
|
null,
|
|
null,
|
|
null,
|
|
mockVMService,
|
|
);
|
|
|
|
verify(mockVMService.registerService('flutterMemoryInfo', 'Flutter Tools')).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => BufferLogger.test()
|
|
});
|
|
|
|
testUsingContext('VmService registers flutterGetSkSL service', () async {
|
|
final MockVMService mockVMService = MockVMService();
|
|
setUpVmService(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
() async => 'hello',
|
|
null,
|
|
mockVMService,
|
|
);
|
|
|
|
verify(mockVMService.registerService('flutterGetSkSL', 'Flutter Tools')).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => BufferLogger.test()
|
|
});
|
|
|
|
testUsingContext('VmService registers flutterPrintStructuredErrorLogMethod', () async {
|
|
final MockVMService mockVMService = MockVMService();
|
|
when(mockVMService.onExtensionEvent).thenAnswer((Invocation invocation) {
|
|
return const Stream<vm_service.Event>.empty();
|
|
});
|
|
setUpVmService(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
(vm_service.Event event) async => 'hello',
|
|
mockVMService,
|
|
);
|
|
verify(mockVMService.streamListen(vm_service.EventStreams.kExtension)).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => BufferLogger.test()
|
|
});
|
|
|
|
testUsingContext('VMService returns correct FlutterVersion', () async {
|
|
final MockVMService mockVMService = MockVMService();
|
|
setUpVmService(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
mockVMService,
|
|
);
|
|
|
|
verify(mockVMService.registerService('flutterVersion', 'Flutter Tools')).called(1);
|
|
}, overrides: <Type, Generator>{
|
|
FlutterVersion: () => MockFlutterVersion(),
|
|
});
|
|
|
|
testUsingContext('VMService prints messages for connection failures', () {
|
|
FakeAsync().run((FakeAsync time) {
|
|
final Uri uri = Uri.parse('ws://127.0.0.1:12345/QqL7EFEDNG0=/ws');
|
|
unawaited(connectToVmService(uri));
|
|
|
|
time.elapse(const Duration(seconds: 5));
|
|
expect(testLogger.statusText, isEmpty);
|
|
|
|
time.elapse(const Duration(minutes: 2));
|
|
|
|
final String statusText = testLogger.statusText;
|
|
expect(
|
|
statusText,
|
|
containsIgnoringWhitespace('Connecting to the VM Service is taking longer than expected...'),
|
|
);
|
|
expect(
|
|
statusText,
|
|
containsIgnoringWhitespace('try re-running with --host-vmservice-port'),
|
|
);
|
|
expect(
|
|
statusText,
|
|
containsIgnoringWhitespace('Exception attempting to connect to the VM Service:'),
|
|
);
|
|
expect(
|
|
statusText,
|
|
containsIgnoringWhitespace('This was attempt #50. Will retry'),
|
|
);
|
|
});
|
|
}, overrides: <Type, Generator>{
|
|
WebSocketConnector: () => failingWebSocketConnector,
|
|
});
|
|
|
|
testWithoutContext('setAssetDirectory forwards arguments correctly', () async {
|
|
final Completer<String> completer = Completer<String>();
|
|
final vm_service.VmService vmService = vm_service.VmService(
|
|
const Stream<String>.empty(),
|
|
completer.complete,
|
|
);
|
|
|
|
unawaited(vmService.setAssetDirectory(
|
|
assetsDirectory: Uri(path: 'abc', scheme: 'file'),
|
|
viewId: 'abc',
|
|
uiIsolateId: 'def',
|
|
));
|
|
|
|
final Map<String, Object> rawRequest = json.decode(await completer.future) as Map<String, Object>;
|
|
|
|
expect(rawRequest, allOf(<Matcher>[
|
|
containsPair('method', kSetAssetBundlePathMethod),
|
|
containsPair('params', allOf(<Matcher>[
|
|
containsPair('viewId', 'abc'),
|
|
containsPair('assetDirectory', '/abc'),
|
|
containsPair('isolateId', 'def'),
|
|
]))
|
|
]));
|
|
});
|
|
|
|
testWithoutContext('getSkSLs forwards arguments correctly', () async {
|
|
final Completer<String> completer = Completer<String>();
|
|
final vm_service.VmService vmService = vm_service.VmService(
|
|
const Stream<String>.empty(),
|
|
completer.complete,
|
|
);
|
|
|
|
unawaited(vmService.getSkSLs(
|
|
viewId: 'abc',
|
|
));
|
|
|
|
final Map<String, Object> rawRequest = json.decode(await completer.future) as Map<String, Object>;
|
|
|
|
expect(rawRequest, allOf(<Matcher>[
|
|
containsPair('method', kGetSkSLsMethod),
|
|
containsPair('params', allOf(<Matcher>[
|
|
containsPair('viewId', 'abc'),
|
|
]))
|
|
]));
|
|
});
|
|
|
|
testWithoutContext('flushUIThreadTasks forwards arguments correctly', () async {
|
|
final Completer<String> completer = Completer<String>();
|
|
final vm_service.VmService vmService = vm_service.VmService(
|
|
const Stream<String>.empty(),
|
|
completer.complete,
|
|
);
|
|
|
|
unawaited(vmService.flushUIThreadTasks(
|
|
uiIsolateId: 'def',
|
|
));
|
|
|
|
final Map<String, Object> rawRequest = json.decode(await completer.future) as Map<String, Object>;
|
|
|
|
expect(rawRequest, allOf(<Matcher>[
|
|
containsPair('method', kFlushUIThreadTasksMethod),
|
|
containsPair('params', allOf(<Matcher>[
|
|
containsPair('isolateId', 'def'),
|
|
]))
|
|
]));
|
|
});
|
|
|
|
testWithoutContext('runInView forwards arguments correctly', () async {
|
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
|
requests: <VmServiceExpectation>[
|
|
const FakeVmServiceRequest(method: 'streamListen', args: <String, Object>{
|
|
'streamId': 'Isolate'
|
|
}),
|
|
const FakeVmServiceRequest(method: kRunInViewMethod, args: <String, Object>{
|
|
'viewId': '1234',
|
|
'mainScript': 'main.dart',
|
|
'assetDirectory': 'flutter_assets/',
|
|
}),
|
|
FakeVmServiceStreamResponse(
|
|
streamId: 'Isolate',
|
|
event: vm_service.Event(
|
|
kind: vm_service.EventKind.kIsolateRunnable,
|
|
timestamp: 1,
|
|
)
|
|
),
|
|
]
|
|
);
|
|
|
|
await fakeVmServiceHost.vmService.runInView(
|
|
viewId: '1234',
|
|
main: Uri.file('main.dart'),
|
|
assetsDirectory: Uri.file('flutter_assets/'),
|
|
);
|
|
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
|
});
|
|
|
|
testWithoutContext('getFlutterViews polls until a view is returned', () async {
|
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
|
requests: <VmServiceExpectation>[
|
|
const FakeVmServiceRequest(
|
|
method: kListViewsMethod,
|
|
jsonResponse: <String, Object>{
|
|
'views': <Object>[],
|
|
},
|
|
),
|
|
const FakeVmServiceRequest(
|
|
method: kListViewsMethod,
|
|
jsonResponse: <String, Object>{
|
|
'views': <Object>[],
|
|
},
|
|
),
|
|
const FakeVmServiceRequest(
|
|
method: kListViewsMethod,
|
|
jsonResponse: <String, Object>{
|
|
'views': <Object>[
|
|
<String, Object>{
|
|
'id': 'a',
|
|
'isolate': <String, Object>{},
|
|
},
|
|
],
|
|
},
|
|
),
|
|
]
|
|
);
|
|
|
|
expect(
|
|
await fakeVmServiceHost.vmService.getFlutterViews(
|
|
delay: Duration.zero,
|
|
),
|
|
isNotEmpty,
|
|
);
|
|
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
|
});
|
|
|
|
testWithoutContext('getFlutterViews does not poll if returnEarly is true', () async {
|
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
|
requests: <VmServiceExpectation>[
|
|
const FakeVmServiceRequest(
|
|
method: kListViewsMethod,
|
|
jsonResponse: <String, Object>{
|
|
'views': <Object>[],
|
|
},
|
|
),
|
|
]
|
|
);
|
|
|
|
expect(
|
|
await fakeVmServiceHost.vmService.getFlutterViews(
|
|
returnEarly: true,
|
|
),
|
|
isEmpty,
|
|
);
|
|
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
|
});
|
|
|
|
testWithoutContext('expandos are null safe', () {
|
|
vm_service.VmService vmService;
|
|
|
|
expect(vmService.httpAddress, null);
|
|
expect(vmService.wsAddress, null);
|
|
});
|
|
}
|
|
|
|
class MockDevice extends Mock implements Device {}
|
|
class MockVMService extends Mock implements vm_service.VmService {}
|
|
class MockFlutterVersion extends Mock implements FlutterVersion {
|
|
@override
|
|
Map<String, Object> toJson() => const <String, Object>{'Mock': 'Version'};
|
|
}
|
|
|
|
/// A [WebSocketConnector] that always throws an [io.SocketException].
|
|
Future<io.WebSocket> failingWebSocketConnector(
|
|
String url, {
|
|
io.CompressionOptions compression,
|
|
}) {
|
|
throw const io.SocketException('Failed WebSocket connection');
|
|
}
|