blob: 13fccc843506ca3d6fd073926c72a2943ab44365 [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 'dart:async';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/run_cold.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
group('cold attach', () {
MockResidentCompiler residentCompiler;
BufferLogger mockLogger;
setUp(() {
mockLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: null,
platform: const LocalPlatform(),
),
outputPreferences: OutputPreferences.test(),
);
residentCompiler = MockResidentCompiler();
});
testUsingContext('Prints message when HttpException is thrown - 1', () async {
final MockDevice mockDevice = MockDevice();
when(mockDevice.supportsHotReload).thenReturn(true);
when(mockDevice.supportsHotRestart).thenReturn(false);
when(mockDevice.targetPlatform).thenAnswer((Invocation _) async => TargetPlatform.tester);
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation _) async => 'Android 10');
final List<FlutterDevice> devices = <FlutterDevice>[
TestFlutterDevice(
device: mockDevice,
generator: residentCompiler,
exception: const HttpException('Connection closed before full header was received, '
'uri = http://127.0.0.1:63394/5ZmLv8A59xY=/ws'),
),
];
final int exitCode = await ColdRunner(devices,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
).attach();
expect(exitCode, 2);
expect(mockLogger.statusText, contains('If you are using an emulator running Android Q Beta, '
'consider using an emulator running API level 29 or lower.'));
expect(mockLogger.statusText, contains('Learn more about the status of this issue on '
'https://issuetracker.google.com/issues/132325318'));
}, overrides: <Type, Generator>{
Logger: () => mockLogger,
});
testUsingContext('Prints message when HttpException is thrown - 2', () async {
final MockDevice mockDevice = MockDevice();
when(mockDevice.supportsHotReload).thenReturn(true);
when(mockDevice.supportsHotRestart).thenReturn(false);
when(mockDevice.targetPlatform).thenAnswer((Invocation _) async => TargetPlatform.tester);
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation _) async => 'Android 10');
final List<FlutterDevice> devices = <FlutterDevice>[
TestFlutterDevice(
device: mockDevice,
generator: residentCompiler,
exception: const HttpException(', uri = http://127.0.0.1:63394/5ZmLv8A59xY=/ws'),
),
];
final int exitCode = await ColdRunner(devices,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
).attach();
expect(exitCode, 2);
expect(mockLogger.statusText, contains('If you are using an emulator running Android Q Beta, '
'consider using an emulator running API level 29 or lower.'));
expect(mockLogger.statusText, contains('Learn more about the status of this issue on '
'https://issuetracker.google.com/issues/132325318'));
}, overrides: <Type, Generator>{
Logger: () => mockLogger,
});
});
group('cleanupAtFinish()', () {
MockFlutterDevice mockFlutterDeviceFactory(Device device) {
final MockFlutterDevice mockFlutterDevice = MockFlutterDevice();
when(mockFlutterDevice.stopEchoingDeviceLog()).thenAnswer((Invocation invocation) => Future<void>.value(null));
when(mockFlutterDevice.device).thenReturn(device);
return mockFlutterDevice;
}
testUsingContext('disposes each device', () async {
final MockDevice mockDevice1 = MockDevice();
final MockDevice mockDevice2 = MockDevice();
final MockFlutterDevice mockFlutterDevice1 = mockFlutterDeviceFactory(mockDevice1);
final MockFlutterDevice mockFlutterDevice2 = mockFlutterDeviceFactory(mockDevice2);
final List<FlutterDevice> devices = <FlutterDevice>[mockFlutterDevice1, mockFlutterDevice2];
await ColdRunner(devices,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
).cleanupAtFinish();
verify(mockDevice1.dispose());
verify(mockFlutterDevice1.stopEchoingDeviceLog());
verify(mockDevice2.dispose());
verify(mockFlutterDevice2.stopEchoingDeviceLog());
});
});
group('cold run', () {
testUsingContext('returns 1 if not prebuilt mode & mainPath does not exist', () async {
final MockDevice mockDevice = MockDevice();
final MockFlutterDevice mockFlutterDevice = MockFlutterDevice();
when(mockFlutterDevice.device).thenReturn(mockDevice);
final List<FlutterDevice> devices = <FlutterDevice>[mockFlutterDevice];
final int result = await ColdRunner(devices).run();
expect(result, 1);
expect(testLogger.errorText, matches(r'Tried to run .*, but that file does not exist\.'));
expect(testLogger.errorText, matches(r'Consider using the -t option to specify the Dart file to start\.'));
});
testUsingContext('calls runCold on attached device', () async {
final MockDevice mockDevice = MockDevice();
final MockFlutterDevice mockFlutterDevice = MockFlutterDevice();
when(mockFlutterDevice.device).thenReturn(mockDevice);
when(mockFlutterDevice.runCold(
coldRunner: anyNamed('coldRunner'),
route: anyNamed('route')
)).thenAnswer((Invocation invocation) => Future<int>.value(1));
final List<FlutterDevice> devices = <FlutterDevice>[mockFlutterDevice];
final MockFile applicationBinary = MockFile();
final int result = await ColdRunner(
devices,
applicationBinary: applicationBinary,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
).run();
expect(result, 1);
verify(mockFlutterDevice.runCold(
coldRunner: anyNamed('coldRunner'),
route: anyNamed('route'),
));
});
});
}
class MockFile extends Mock implements File {}
class MockFlutterDevice extends Mock implements FlutterDevice {}
class MockDevice extends Mock implements Device {
MockDevice() {
when(isSupported()).thenReturn(true);
}
}
class TestFlutterDevice extends FlutterDevice {
TestFlutterDevice({
@required Device device,
@required this.exception,
@required ResidentCompiler generator,
}) : assert(exception != null),
super(device, buildInfo: BuildInfo.debug, generator: generator);
/// The exception to throw when the connect method is called.
final Exception exception;
@override
Future<void> connect({
ReloadSources reloadSources,
Restart restart,
CompileExpression compileExpression,
ReloadMethod reloadMethod,
}) async {
throw exception;
}
}