Unverified Commit e1534b8e authored by Alexander Aprelev's avatar Alexander Aprelev Committed by GitHub

Add '-t' option to 'attach' command. (#20539)

* Add '-t' option to 'attach' command.

* Add test

* Make analyzer happy

* Fix tests so they use memory file system and can find lib/main.dart
parent b5b55447
......@@ -35,7 +35,7 @@ final String ipv4Loopback = InternetAddress.loopbackIPv4.address;
/// As soon as a new observatory is detected the command attaches to it and
/// enables hot reloading.
class AttachCommand extends FlutterCommand {
AttachCommand({bool verboseHelp = false}) {
AttachCommand({bool verboseHelp = false, this.hotRunnerFactory}) {
addBuildModeFlags(defaultToRelease: false);
argParser
..addOption(
......@@ -53,8 +53,12 @@ class AttachCommand extends FlutterCommand {
help: 'Handle machine structured JSON command input and provide output\n'
'and progress in machine friendly format.',
);
usesTargetOption();
hotRunnerFactory ??= new HotRunnerFactory();
}
HotRunnerFactory hotRunnerFactory;
@override
final String name = 'attach';
......@@ -116,8 +120,9 @@ class AttachCommand extends FlutterCommand {
final FlutterDevice flutterDevice = new FlutterDevice(device,
trackWidgetCreation: false, previewDart2: argResults['preview-dart-2']);
flutterDevice.observatoryUris = <Uri>[ observatoryUri ];
final HotRunner hotRunner = new HotRunner(
final HotRunner hotRunner = hotRunnerFactory.build(
<FlutterDevice>[flutterDevice],
target: targetFile,
debuggingOptions: new DebuggingOptions.enabled(getBuildInfo()),
packagesFilePath: globalResults['packages'],
usesTerminalUI: daemon == null,
......@@ -145,3 +150,32 @@ class AttachCommand extends FlutterCommand {
Future<void> _validateArguments() async {}
}
class HotRunnerFactory {
HotRunner build(List<FlutterDevice> devices, {
String target,
DebuggingOptions debuggingOptions,
bool usesTerminalUI = true,
bool benchmarkMode = false,
File applicationBinary,
bool hostIsIde = false,
String projectRootPath,
String packagesFilePath,
String dillOutputPath,
bool stayResident = true,
bool ipv6 = false,
}) => new HotRunner(
devices,
target: target,
debuggingOptions: debuggingOptions,
usesTerminalUI: usesTerminalUI,
benchmarkMode: benchmarkMode,
applicationBinary: applicationBinary,
hostIsIde: hostIsIde,
projectRootPath: projectRootPath,
packagesFilePath: packagesFilePath,
dillOutputPath: dillOutputPath,
stayResident: stayResident,
ipv6: ipv6,
);
}
\ No newline at end of file
......@@ -4,10 +4,14 @@
import 'dart:async';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/attach.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/run_hot.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
......@@ -16,8 +20,15 @@ import '../src/mocks.dart';
void main() {
group('attach', () {
final FileSystem testFileSystem = new MemoryFileSystem(
style: platform.isWindows ? FileSystemStyle.windows : FileSystemStyle
.posix,
);
setUpAll(() {
Cache.disableLocking();
testFileSystem.directory('lib').createSync();
testFileSystem.file('lib/main.dart').createSync();
});
testUsingContext('finds observatory port and forwards', () async {
......@@ -30,14 +41,17 @@ void main() {
// Now that the reader is used, start writing messages to it.
Timer.run(() {
mockLogReader.addLine('Foo');
mockLogReader.addLine('Observatory listening on http://127.0.0.1:$devicePort');
mockLogReader.addLine(
'Observatory listening on http://127.0.0.1:$devicePort');
});
return mockLogReader;
});
when(device.portForwarder).thenReturn(portForwarder);
when(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort'))).thenAnswer((_) async => hostPort);
when(portForwarder.forwardedPorts).thenReturn(<ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
when(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort')))
.thenAnswer((_) async => hostPort);
when(portForwarder.forwardedPorts).thenReturn(
<ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
when(portForwarder.unforward(any)).thenAnswer((_) async => null);
testDeviceManager.addDevice(device);
......@@ -45,10 +59,62 @@ void main() {
await createTestCommandRunner(command).run(<String>['attach']);
verify(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort'))).called(1);
verify(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort')))
.called(1);
mockLogReader.dispose();
});
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
},
);
testUsingContext('selects specified target', () async {
const int devicePort = 499;
const int hostPort = 42;
final MockDeviceLogReader mockLogReader = new MockDeviceLogReader();
final MockPortForwarder portForwarder = new MockPortForwarder();
final MockAndroidDevice device = new MockAndroidDevice();
final MockHotRunnerFactory mockHotRunnerFactory = new MockHotRunnerFactory();
when(device.portForwarder).thenReturn(portForwarder);
when(portForwarder.forward(devicePort, hostPort: anyNamed('hostPort')))
.thenAnswer((_) async => hostPort);
when(portForwarder.forwardedPorts).thenReturn(
<ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
when(portForwarder.unforward(any)).thenAnswer((_) async => null);
when(mockHotRunnerFactory.build(any,
target: anyNamed('target'),
debuggingOptions: anyNamed('debuggingOptions'),
packagesFilePath: anyNamed('packagesFilePath'),
usesTerminalUI: anyNamed('usesTerminalUI'))).thenReturn(
new MockHotRunner());
testDeviceManager.addDevice(device);
when(device.getLogReader()).thenAnswer((_) {
// Now that the reader is used, start writing messages to it.
Timer.run(() {
mockLogReader.addLine('Foo');
mockLogReader.addLine(
'Observatory listening on http://127.0.0.1:$devicePort');
});
return mockLogReader;
});
final File foo = fs.file('lib/foo.dart')
..createSync();
final AttachCommand command = new AttachCommand(
hotRunnerFactory: mockHotRunnerFactory);
await createTestCommandRunner(command).run(
<String>['attach', '-t', foo.path, '-v']);
verify(mockHotRunnerFactory.build(any,
target: foo.path,
debuggingOptions: anyNamed('debuggingOptions'),
packagesFilePath: anyNamed('packagesFilePath'),
usesTerminalUI: anyNamed('usesTerminalUI'))).called(1);
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
},);
testUsingContext('forwards to given port', () async {
const int devicePort = 499;
......@@ -58,16 +124,20 @@ void main() {
when(device.portForwarder).thenReturn(portForwarder);
when(portForwarder.forward(devicePort)).thenAnswer((_) async => hostPort);
when(portForwarder.forwardedPorts).thenReturn(<ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
when(portForwarder.forwardedPorts).thenReturn(
<ForwardedPort>[new ForwardedPort(hostPort, devicePort)]);
when(portForwarder.unforward(any)).thenAnswer((_) async => null);
testDeviceManager.addDevice(device);
final AttachCommand command = new AttachCommand();
await createTestCommandRunner(command).run(<String>['attach', '--debug-port', '$devicePort']);
await createTestCommandRunner(command).run(
<String>['attach', '--debug-port', '$devicePort']);
verify(portForwarder.forward(devicePort)).called(1);
});
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
},);
testUsingContext('exits when no device connected', () async {
final AttachCommand command = new AttachCommand();
......@@ -76,7 +146,9 @@ void main() {
throwsA(isInstanceOf<ToolExit>()),
);
expect(testLogger.statusText, contains('No connected devices'));
});
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
},);
testUsingContext('exits when multiple devices connected', () async {
Device aDeviceWithId(String id) {
......@@ -98,8 +170,14 @@ void main() {
expect(testLogger.statusText, contains('More than one device'));
expect(testLogger.statusText, contains('xx1'));
expect(testLogger.statusText, contains('yy2'));
});
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
},);
});
}
class MockPortForwarder extends Mock implements DevicePortForwarder {}
class MockHotRunner extends Mock implements HotRunner {}
class MockHotRunnerFactory extends Mock implements HotRunnerFactory {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment