mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
387f885481
* add trailing commas on list/map/parameters * add trailing commas on Invocation with nb of arg>1 * add commas for widget containing widgets * add trailing commas if instantiation contains trailing comma * revert bad change
321 lines
12 KiB
Dart
321 lines
12 KiB
Dart
// 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 'dart:convert';
|
|
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/vmservice.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:process/process.dart';
|
|
|
|
import 'package:flutter_tools/src/base/common.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/time.dart';
|
|
import 'package:flutter_tools/src/device.dart';
|
|
import 'package:flutter_tools/src/fuchsia/fuchsia_device.dart';
|
|
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
|
|
void main() {
|
|
group('fuchsia device', () {
|
|
testUsingContext('stores the requested id and name', () {
|
|
const String deviceId = 'e80::0000:a00a:f00f:2002/3';
|
|
const String name = 'halfbaked';
|
|
final FuchsiaDevice device = FuchsiaDevice(deviceId, name: name);
|
|
expect(device.id, deviceId);
|
|
expect(device.name, name);
|
|
});
|
|
|
|
test('parse dev_finder output', () {
|
|
const String example = '192.168.42.56 paper-pulp-bush-angel';
|
|
final List<FuchsiaDevice> names = parseListDevices(example);
|
|
|
|
expect(names.length, 1);
|
|
expect(names.first.name, 'paper-pulp-bush-angel');
|
|
expect(names.first.id, '192.168.42.56');
|
|
});
|
|
|
|
test('parse junk dev_finder output', () {
|
|
const String example = 'junk';
|
|
final List<FuchsiaDevice> names = parseListDevices(example);
|
|
|
|
expect(names.length, 0);
|
|
});
|
|
|
|
test('default capabilities', () async {
|
|
final FuchsiaDevice device = FuchsiaDevice('123');
|
|
|
|
expect(device.supportsHotReload, true);
|
|
expect(device.supportsHotRestart, false);
|
|
expect(device.supportsStopApp, false);
|
|
expect(await device.stopApp(null), false);
|
|
});
|
|
});
|
|
|
|
group('displays friendly error when', () {
|
|
final MockProcessManager mockProcessManager = MockProcessManager();
|
|
final MockProcessResult mockProcessResult = MockProcessResult();
|
|
final MockFile mockFile = MockFile();
|
|
when(mockProcessManager.run(
|
|
any,
|
|
environment: anyNamed('environment'),
|
|
workingDirectory: anyNamed('workingDirectory'),
|
|
)).thenAnswer((Invocation invocation) => Future<ProcessResult>.value(mockProcessResult));
|
|
when(mockProcessResult.exitCode).thenReturn(1);
|
|
when<String>(mockProcessResult.stdout).thenReturn('');
|
|
when<String>(mockProcessResult.stderr).thenReturn('');
|
|
when(mockFile.absolute).thenReturn(mockFile);
|
|
when(mockFile.path).thenReturn('');
|
|
|
|
final MockProcessManager emptyStdoutProcessManager = MockProcessManager();
|
|
final MockProcessResult emptyStdoutProcessResult = MockProcessResult();
|
|
when(emptyStdoutProcessManager.run(
|
|
any,
|
|
environment: anyNamed('environment'),
|
|
workingDirectory: anyNamed('workingDirectory'),
|
|
)).thenAnswer((Invocation invocation) => Future<ProcessResult>.value(emptyStdoutProcessResult));
|
|
when(emptyStdoutProcessResult.exitCode).thenReturn(0);
|
|
when<String>(emptyStdoutProcessResult.stdout).thenReturn('');
|
|
when<String>(emptyStdoutProcessResult.stderr).thenReturn('');
|
|
|
|
testUsingContext('No vmservices found', () async {
|
|
final FuchsiaDevice device = FuchsiaDevice('id');
|
|
ToolExit toolExit;
|
|
try {
|
|
await device.servicePorts();
|
|
} on ToolExit catch (err) {
|
|
toolExit = err;
|
|
}
|
|
expect(toolExit.message, contains('No Dart Observatories found. Are you running a debug build?'));
|
|
}, overrides: <Type, Generator>{
|
|
ProcessManager: () => emptyStdoutProcessManager,
|
|
FuchsiaArtifacts: () => FuchsiaArtifacts(
|
|
sshConfig: mockFile,
|
|
devFinder: mockFile,
|
|
),
|
|
});
|
|
|
|
group('device logs', () {
|
|
const String exampleUtcLogs = '''
|
|
[2018-11-09 01:27:45][3][297950920][log] INFO: example_app(flutter): Error doing thing
|
|
[2018-11-09 01:27:58][46257][46269][foo] INFO: Using a thing
|
|
[2018-11-09 01:29:58][46257][46269][foo] INFO: Blah blah blah
|
|
[2018-11-09 01:29:58][46257][46269][foo] INFO: other_app(flutter): Do thing
|
|
[2018-11-09 01:30:02][41175][41187][bar] INFO: Invoking a bar
|
|
[2018-11-09 01:30:12][52580][52983][log] INFO: example_app(flutter): Did thing this time
|
|
|
|
''';
|
|
final MockProcessManager mockProcessManager = MockProcessManager();
|
|
final MockProcess mockProcess = MockProcess();
|
|
Completer<int> exitCode;
|
|
StreamController<List<int>> stdout;
|
|
StreamController<List<int>> stderr;
|
|
when(mockProcessManager.start(any)).thenAnswer((Invocation _) => Future<Process>.value(mockProcess));
|
|
when(mockProcess.exitCode).thenAnswer((Invocation _) => exitCode.future);
|
|
when(mockProcess.stdout).thenAnswer((Invocation _) => stdout.stream);
|
|
when(mockProcess.stderr).thenAnswer((Invocation _) => stderr.stream);
|
|
|
|
setUp(() {
|
|
stdout = StreamController<List<int>>(sync: true);
|
|
stderr = StreamController<List<int>>(sync: true);
|
|
exitCode = Completer<int>();
|
|
});
|
|
|
|
tearDown(() {
|
|
exitCode.complete(0);
|
|
});
|
|
|
|
testUsingContext('can be parsed for an app', () async {
|
|
final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester');
|
|
final DeviceLogReader reader = device.getLogReader(app: FuchsiaModulePackage(name: 'example_app'));
|
|
final List<String> logLines = <String>[];
|
|
final Completer<void> lock = Completer<void>();
|
|
reader.logLines.listen((String line) {
|
|
logLines.add(line);
|
|
if (logLines.length == 2) {
|
|
lock.complete();
|
|
}
|
|
});
|
|
expect(logLines, isEmpty);
|
|
|
|
stdout.add(utf8.encode(exampleUtcLogs));
|
|
await stdout.close();
|
|
await lock.future.timeout(const Duration(seconds: 1));
|
|
|
|
expect(logLines, <String>[
|
|
'[2018-11-09 01:27:45.000] Flutter: Error doing thing',
|
|
'[2018-11-09 01:30:12.000] Flutter: Did thing this time',
|
|
]);
|
|
}, overrides: <Type, Generator>{
|
|
ProcessManager: () => mockProcessManager,
|
|
SystemClock: () => SystemClock.fixed(DateTime(2018, 11, 9, 1, 25, 45)),
|
|
});
|
|
|
|
testUsingContext('cuts off prior logs', () async {
|
|
final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester');
|
|
final DeviceLogReader reader = device.getLogReader(app: FuchsiaModulePackage(name: 'example_app'));
|
|
final List<String> logLines = <String>[];
|
|
final Completer<void> lock = Completer<void>();
|
|
reader.logLines.listen((String line) {
|
|
logLines.add(line);
|
|
lock.complete();
|
|
});
|
|
expect(logLines, isEmpty);
|
|
|
|
stdout.add(utf8.encode(exampleUtcLogs));
|
|
await stdout.close();
|
|
await lock.future.timeout(const Duration(seconds: 1));
|
|
|
|
expect(logLines, <String>[
|
|
'[2018-11-09 01:30:12.000] Flutter: Did thing this time',
|
|
]);
|
|
}, overrides: <Type, Generator>{
|
|
ProcessManager: () => mockProcessManager,
|
|
SystemClock: () => SystemClock.fixed(DateTime(2018, 11, 9, 1, 29, 45)),
|
|
});
|
|
|
|
testUsingContext('can be parsed for all apps', () async {
|
|
final FuchsiaDevice device = FuchsiaDevice('id', name: 'tester');
|
|
final DeviceLogReader reader = device.getLogReader();
|
|
final List<String> logLines = <String>[];
|
|
final Completer<void> lock = Completer<void>();
|
|
reader.logLines.listen((String line) {
|
|
logLines.add(line);
|
|
if (logLines.length == 3) {
|
|
lock.complete();
|
|
}
|
|
});
|
|
expect(logLines, isEmpty);
|
|
|
|
stdout.add(utf8.encode(exampleUtcLogs));
|
|
await stdout.close();
|
|
await lock.future.timeout(const Duration(seconds: 1));
|
|
|
|
expect(logLines, <String>[
|
|
'[2018-11-09 01:27:45.000] Flutter: Error doing thing',
|
|
'[2018-11-09 01:29:58.000] Flutter: Do thing',
|
|
'[2018-11-09 01:30:12.000] Flutter: Did thing this time',
|
|
]);
|
|
}, overrides: <Type, Generator>{
|
|
ProcessManager: () => mockProcessManager,
|
|
SystemClock: () => SystemClock.fixed(DateTime(2018, 11, 9, 1, 25, 45)),
|
|
});
|
|
});
|
|
});
|
|
|
|
group(FuchsiaIsolateDiscoveryProtocol, () {
|
|
Future<Uri> findUri(List<MockFlutterView> views, String expectedIsolateName) {
|
|
final MockPortForwarder portForwarder = MockPortForwarder();
|
|
final MockVMService vmService = MockVMService();
|
|
final MockVM vm = MockVM();
|
|
vm.vmService = vmService;
|
|
vmService.vm = vm;
|
|
vm.views = views;
|
|
for (MockFlutterView view in views) {
|
|
view.owner = vm;
|
|
}
|
|
final MockFuchsiaDevice fuchsiaDevice = MockFuchsiaDevice('123', portForwarder, false);
|
|
final FuchsiaIsolateDiscoveryProtocol discoveryProtocol = FuchsiaIsolateDiscoveryProtocol(
|
|
fuchsiaDevice,
|
|
expectedIsolateName,
|
|
(Uri uri) async => vmService,
|
|
true, // only poll once.
|
|
);
|
|
when(fuchsiaDevice.servicePorts()).thenAnswer((Invocation invocation) async => <int>[1]);
|
|
when(portForwarder.forward(1)).thenAnswer((Invocation invocation) async => 2);
|
|
when(vmService.getVM()).thenAnswer((Invocation invocation) => Future<void>.value(null));
|
|
when(vmService.refreshViews()).thenAnswer((Invocation invocation) => Future<void>.value(null));
|
|
when(vmService.httpAddress).thenReturn(Uri.parse('example'));
|
|
return discoveryProtocol.uri;
|
|
}
|
|
testUsingContext('can find flutter view with matching isolate name', () async {
|
|
const String expectedIsolateName = 'foobar';
|
|
final Uri uri = await findUri(<MockFlutterView>[
|
|
MockFlutterView(null), // no ui isolate.
|
|
MockFlutterView(MockIsolate('wrong name')), // wrong name.
|
|
MockFlutterView(MockIsolate(expectedIsolateName)), // matching name.
|
|
], expectedIsolateName);
|
|
expect(uri.toString(), 'http://${InternetAddress.loopbackIPv4.address}:0/');
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => StdoutLogger(),
|
|
});
|
|
|
|
testUsingContext('can handle flutter view without matching isolate name', () async {
|
|
const String expectedIsolateName = 'foobar';
|
|
final Future<Uri> uri = findUri(<MockFlutterView>[
|
|
MockFlutterView(null), // no ui isolate.
|
|
MockFlutterView(MockIsolate('wrong name')), // wrong name.
|
|
], expectedIsolateName);
|
|
expect(uri, throwsException);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => StdoutLogger(),
|
|
});
|
|
|
|
testUsingContext('can handle non flutter view', () async {
|
|
const String expectedIsolateName = 'foobar';
|
|
final Future<Uri> uri = findUri(<MockFlutterView>[
|
|
MockFlutterView(null), // no ui isolate.
|
|
], expectedIsolateName);
|
|
expect(uri, throwsException);
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => StdoutLogger(),
|
|
});
|
|
});
|
|
}
|
|
|
|
class MockProcessManager extends Mock implements ProcessManager {}
|
|
|
|
class MockProcessResult extends Mock implements ProcessResult {}
|
|
|
|
class MockFile extends Mock implements File {}
|
|
|
|
class MockProcess extends Mock implements Process {}
|
|
|
|
class MockFuchsiaDevice extends Mock implements FuchsiaDevice {
|
|
MockFuchsiaDevice(this.id, this.portForwarder, this.ipv6);
|
|
|
|
@override
|
|
final bool ipv6;
|
|
@override
|
|
final String id;
|
|
@override
|
|
final DevicePortForwarder portForwarder;
|
|
}
|
|
|
|
class MockPortForwarder extends Mock implements DevicePortForwarder {}
|
|
|
|
class MockVMService extends Mock implements VMService {
|
|
@override
|
|
VM vm;
|
|
}
|
|
|
|
class MockVM extends Mock implements VM {
|
|
@override
|
|
VMService vmService;
|
|
|
|
@override
|
|
List<FlutterView> views;
|
|
}
|
|
|
|
class MockFlutterView extends Mock implements FlutterView {
|
|
MockFlutterView(this.uiIsolate);
|
|
|
|
@override
|
|
final Isolate uiIsolate;
|
|
|
|
@override
|
|
ServiceObjectOwner owner;
|
|
}
|
|
|
|
class MockIsolate extends Mock implements Isolate {
|
|
MockIsolate(this.name);
|
|
|
|
@override
|
|
final String name;
|
|
}
|