blob: fb192f0a4e05b07a8206ad664b20ea3d454b0a3a [file] [log] [blame]
// 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: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 netls log output', () {
const String example = 'device lilia-shore-only-last (fe80::0000:a00a:f00f:2002/3)';
final List<String> names = parseFuchsiaDeviceOutput(example);
expect(names.length, 1);
expect(names.first, 'lilia-shore-only-last');
});
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 MockFuchsiaArtifacts mockFuchsiaArtifacts = MockFuchsiaArtifacts();
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(mockFuchsiaArtifacts.sshConfig).thenReturn(mockFile);
when(mockFile.absolute).thenReturn(mockFile);
when(mockFile.path).thenReturn('');
testUsingContext('No BUILD_DIR set', () async {
final FuchsiaDevice device = FuchsiaDevice('id');
ToolExit toolExit;
try {
await device.servicePorts();
} on ToolExit catch (err) {
toolExit = err;
}
expect(toolExit.message, contains('BUILD_DIR must be supplied to locate SSH keys'));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
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: () => mockFuchsiaArtifacts,
});
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)),
});
});
});
}
class MockFuchsiaArtifacts extends Mock implements FuchsiaArtifacts {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcessResult extends Mock implements ProcessResult {}
class MockFile extends Mock implements File {}
class MockProcess extends Mock implements Process {}