Unverified Commit 73b6702d authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] refactor iOS tests for Device.startApp into new file (#52854)

parent 2a93afa7
......@@ -383,7 +383,7 @@ class IOSDevice extends Device {
@override
DevicePortForwarder get portForwarder => _portForwarder ??= IOSDevicePortForwarder(
processManager: globals.processManager,
logger: globals.logger,
logger: _logger,
dyLdLibEntry: globals.cache.dyLdLibEntry,
id: id,
iproxyPath: _iproxyPath,
......
......@@ -30,6 +30,7 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/mocks.dart';
......@@ -54,7 +55,7 @@ void main() {
const int devicePort = 499;
const int hostPort = 42;
MockDeviceLogReader mockLogReader;
FakeDeviceLogReader mockLogReader;
MockPortForwarder portForwarder;
MockAndroidDevice device;
MockProcessManager mockProcessManager;
......@@ -63,7 +64,7 @@ void main() {
setUp(() {
mockProcessManager = MockProcessManager();
mockLogReader = MockDeviceLogReader();
mockLogReader = FakeDeviceLogReader();
portForwarder = MockPortForwarder();
device = MockAndroidDevice();
vmServiceDoneCompleter = Completer<void>();
......@@ -374,7 +375,7 @@ void main() {
testUsingContext('selects specified target', () async {
const int devicePort = 499;
const int hostPort = 42;
final MockDeviceLogReader mockLogReader = MockDeviceLogReader();
final FakeDeviceLogReader mockLogReader = FakeDeviceLogReader();
final MockPortForwarder portForwarder = MockPortForwarder();
final MockAndroidDevice device = MockAndroidDevice();
final MockHotRunner mockHotRunner = MockHotRunner();
......@@ -434,7 +435,7 @@ void main() {
testUsingContext('fallbacks to protocol observatory if MDNS failed on iOS', () async {
const int devicePort = 499;
const int hostPort = 42;
final MockDeviceLogReader mockLogReader = MockDeviceLogReader();
final FakeDeviceLogReader mockLogReader = FakeDeviceLogReader();
final MockPortForwarder portForwarder = MockPortForwarder();
final MockIOSDevice device = MockIOSDevice();
final MockHotRunner mockHotRunner = MockHotRunner();
......
......@@ -21,6 +21,7 @@ import 'package:webdriver/sync_io.dart' as sync_io;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/mocks.dart';
void main() {
......@@ -351,7 +352,7 @@ void main() {
final Device mockDevice = MockDevice();
testDeviceManager.addDevice(mockDevice);
final MockDeviceLogReader mockDeviceLogReader = MockDeviceLogReader();
final FakeDeviceLogReader mockDeviceLogReader = FakeDeviceLogReader();
when(mockDevice.getLogReader()).thenReturn(mockDeviceLogReader);
final MockLaunchResult mockLaunchResult = MockLaunchResult();
when(mockLaunchResult.started).thenReturn(true);
......@@ -481,7 +482,7 @@ void main() {
final Device mockDevice = MockDevice();
testDeviceManager.addDevice(mockDevice);
final MockDeviceLogReader mockDeviceLogReader = MockDeviceLogReader();
final FakeDeviceLogReader mockDeviceLogReader = FakeDeviceLogReader();
when(mockDevice.getLogReader()).thenReturn(mockDeviceLogReader);
final MockLaunchResult mockLaunchResult = MockLaunchResult();
when(mockLaunchResult.started).thenReturn(true);
......
......@@ -32,6 +32,7 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/mocks.dart';
import '../../src/testbed.dart';
......@@ -279,7 +280,7 @@ void main() {
applyMocksToCommand(command);
final MockDevice mockDevice = MockDevice(TargetPlatform.ios);
when(mockDevice.isLocalEmulator).thenAnswer((Invocation invocation) => Future<bool>.value(false));
when(mockDevice.getLogReader(app: anyNamed('app'))).thenReturn(MockDeviceLogReader());
when(mockDevice.getLogReader(app: anyNamed('app'))).thenReturn(FakeDeviceLogReader());
when(mockDevice.supportsFastStart).thenReturn(true);
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) => Future<String>.value('iOS 13'));
// App fails to start because we're only interested in usage
......@@ -633,7 +634,7 @@ class FakeDevice extends Fake implements Device {
@override
DeviceLogReader getLogReader({ ApplicationPackage app }) {
return MockDeviceLogReader();
return FakeDeviceLogReader();
}
@override
......
......@@ -36,6 +36,7 @@ import 'package:quiver/testing/async.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/mocks.dart';
void main() {
......@@ -395,12 +396,10 @@ void main() {
MockFileSystem mockFileSystem;
MockPlatform mockPlatform;
MockProcessManager mockProcessManager;
MockDeviceLogReader mockLogReader;
MockMDnsObservatoryDiscovery mockMDnsObservatoryDiscovery;
FakeDeviceLogReader mockLogReader;
MockPortForwarder mockPortForwarder;
MockIMobileDevice mockIMobileDevice;
MockIOSDeploy mockIosDeploy;
MockUsage mockUsage;
Directory tempDir;
Directory projectDir;
......@@ -428,13 +427,11 @@ void main() {
mockFileSystem = MockFileSystem();
mockPlatform = MockPlatform();
when(mockPlatform.isMacOS).thenReturn(true);
mockMDnsObservatoryDiscovery = MockMDnsObservatoryDiscovery();
mockProcessManager = MockProcessManager();
mockLogReader = MockDeviceLogReader();
mockLogReader = FakeDeviceLogReader();
mockPortForwarder = MockPortForwarder();
mockIMobileDevice = MockIMobileDevice();
mockIosDeploy = MockIOSDeploy();
mockUsage = MockUsage();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_create_test.');
projectDir = tempDir.childDirectory('flutter_project');
......@@ -493,367 +490,6 @@ void main() {
Cache.enableLocking();
});
testWithoutContext('disposing device disposes the portForwarder', () async {
final IOSDevice device = IOSDevice(
'123',
artifacts: mockArtifacts,
fileSystem: mockFileSystem,
platform: macPlatform,
iosDeploy: iosDeploy,
logger: logger,
name: 'iPhone 1',
sdkVersion: '13.3',
cpuArchitecture: DarwinArch.arm64,
);
device.portForwarder = mockPortForwarder;
device.setLogReader(mockApp, mockLogReader);
await device.dispose();
verify(mockPortForwarder.dispose()).called(1);
});
testUsingContext('succeeds in debug mode via mDNS', () async {
final IOSDevice device = IOSDevice(
'123',
name: 'iPhone 1',
sdkVersion: '13.3',
artifacts: mockArtifacts,
fileSystem: mockFileSystem,
logger: logger,
platform: macPlatform,
iosDeploy: mockIosDeploy,
cpuArchitecture: DarwinArch.arm64,
);
when(mockIosDeploy.installApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: <String>[],
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
when(mockIosDeploy.runApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
device.portForwarder = mockPortForwarder;
device.setLogReader(mockApp, mockLogReader);
final Uri uri = Uri(
scheme: 'http',
host: '127.0.0.1',
port: 1234,
path: 'observatory',
);
when(mockMDnsObservatoryDiscovery.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) => Future<Uri>.value(uri));
final LaunchResult launchResult = await device.startApp(mockApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(const BuildInfo(BuildMode.debug, null, treeShakeIcons: false)),
platformArgs: <String, dynamic>{},
);
verify(mockUsage.sendEvent('ios-handshake', 'mdns-success')).called(1);
expect(launchResult.started, isTrue);
expect(launchResult.hasObservatory, isTrue);
expect(await device.stopApp(mockApp), isFalse);
}, overrides: <Type, Generator>{
MDnsObservatoryDiscovery: () => mockMDnsObservatoryDiscovery,
Usage: () => mockUsage,
});
testUsingContext('succeeds in debug mode when mDNS fails by falling back to manual protocol discovery', () async {
final IOSDevice device = IOSDevice(
'123',
artifacts: mockArtifacts,
fileSystem: mockFileSystem,
logger: logger,
platform: macPlatform,
iosDeploy: mockIosDeploy,
name: 'iPhone 1',
sdkVersion: '13.3',
cpuArchitecture: DarwinArch.arm64,
);
when(
mockIosDeploy.installApp(deviceId: device.id, bundlePath: anyNamed('bundlePath'), launchArguments: <String>[])
).thenAnswer((Invocation invocation) => Future<int>.value(0));
when(mockIosDeploy.runApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
device.portForwarder = mockPortForwarder;
device.setLogReader(mockApp, mockLogReader);
// 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');
});
when(mockMDnsObservatoryDiscovery.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) => Future<Uri>.value(null));
final LaunchResult launchResult = await device.startApp(mockApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(const BuildInfo(BuildMode.debug, null, treeShakeIcons: false)),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, isTrue);
expect(launchResult.hasObservatory, isTrue);
verify(mockUsage.sendEvent('ios-handshake', 'mdns-failure')).called(1);
verify(mockUsage.sendEvent('ios-handshake', 'fallback-success')).called(1);
expect(await device.stopApp(mockApp), isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
MDnsObservatoryDiscovery: () => mockMDnsObservatoryDiscovery,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
});
testUsingContext('fails in debug mode when mDNS fails and when Observatory URI is malformed', () async {
final IOSDevice device = IOSDevice(
'123',
artifacts: mockArtifacts,
fileSystem: mockFileSystem,
logger: logger,
platform: macPlatform,
iosDeploy: mockIosDeploy,
name: 'iPhone 1',
sdkVersion: '13.3',
cpuArchitecture: DarwinArch.arm64,
);
when(mockIosDeploy.installApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: <String>[],
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
when(mockIosDeploy.runApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
device.portForwarder = mockPortForwarder;
device.setLogReader(mockApp, mockLogReader);
// 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');
});
when(mockMDnsObservatoryDiscovery.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) => Future<Uri>.value(null));
final LaunchResult launchResult = await device.startApp(mockApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(const BuildInfo(BuildMode.debug, null, treeShakeIcons: false)),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, isFalse);
expect(launchResult.hasObservatory, isFalse);
verify(mockUsage.sendEvent(
'ios-handshake',
'failure-other',
label: anyNamed('label'),
value: anyNamed('value'),
)).called(1);
verify(mockUsage.sendEvent('ios-handshake', 'mdns-failure')).called(1);
verify(mockUsage.sendEvent('ios-handshake', 'fallback-failure')).called(1);
}, overrides: <Type, Generator>{
FileSystem: () => mockFileSystem,
MDnsObservatoryDiscovery: () => mockMDnsObservatoryDiscovery,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
});
testUsingContext('succeeds in release mode', () async {
final IOSDevice device = IOSDevice(
'123',
name: 'iPhone 1',
fileSystem: mockFileSystem,
sdkVersion: '13.3',
cpuArchitecture: DarwinArch.arm64,
logger: logger,
platform: mockPlatform,
artifacts: mockArtifacts,
iosDeploy: mockIosDeploy,
);
when(mockIosDeploy.installApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: <String>[],
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
when(mockIosDeploy.runApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
final LaunchResult launchResult = await device.startApp(mockApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.disabled(const BuildInfo(BuildMode.release, null, treeShakeIcons: false)),
platformArgs: <String, dynamic>{},
);
verify(mockIosDeploy.installApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: <String>[],
));
verify(mockIosDeploy.runApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
));
expect(launchResult.started, isTrue);
expect(launchResult.hasObservatory, isFalse);
expect(await device.stopApp(mockApp), isFalse);
});
testUsingContext('trace whitelist flags', () async {
final IOSDevice device = IOSDevice(
'123',
name: 'iPhone 1',
fileSystem: mockFileSystem,
sdkVersion: '13.3',
cpuArchitecture: DarwinArch.arm64,
logger: logger,
platform: mockPlatform,
artifacts: mockArtifacts,
iosDeploy: mockIosDeploy,
);
when(mockIosDeploy.installApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: <String>[],
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
when(mockIosDeploy.runApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
await device.startApp(mockApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.disabled(
const BuildInfo(BuildMode.release, null, treeShakeIcons: false),
traceWhitelist: 'foo'),
platformArgs: <String, dynamic>{},
);
final VerificationResult toVerify = verify(mockIosDeploy.runApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: captureAnyNamed('launchArguments'),
));
expect(toVerify.captured[0], contains('--trace-whitelist="foo"'));
await device.stopApp(mockApp);
});
testUsingContext('succeeds with --cache-sksl', () async {
final IOSDevice device = IOSDevice(
'123',
name: 'iPhone 1',
sdkVersion: '13.3',
artifacts: mockArtifacts,
fileSystem: mockFileSystem,
logger: logger,
platform: macPlatform,
iosDeploy: mockIosDeploy,
cpuArchitecture: DarwinArch.arm64,
);
device.setLogReader(mockApp, mockLogReader);
final Uri uri = Uri(
scheme: 'http',
host: '127.0.0.1',
port: 1234,
path: 'observatory',
);
when(mockMDnsObservatoryDiscovery.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) => Future<Uri>.value(uri));
List<String> args;
when(mockIosDeploy.runApp(
deviceId: anyNamed('deviceId'),
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation inv) {
args = inv.namedArguments[const Symbol('launchArguments')] as List<String>;
return Future<int>.value(0);
});
when(mockIosDeploy.installApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
final LaunchResult launchResult = await device.startApp(mockApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(
const BuildInfo(BuildMode.debug, null, treeShakeIcons: false),
cacheSkSL: true,
),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, isTrue);
expect(args, contains('--cache-sksl'));
expect(await device.stopApp(mockApp), isFalse);
}, overrides: <Type, Generator>{
Artifacts: () => mockArtifacts,
Cache: () => mockCache,
FileSystem: () => mockFileSystem,
MDnsObservatoryDiscovery: () => mockMDnsObservatoryDiscovery,
Platform: () => macPlatform,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
IOSDeploy: () => mockIosDeploy,
});
testUsingContext('succeeds with --device-vmservice-port', () async {
final IOSDevice device = IOSDevice(
'123',
name: 'iPhone 1',
sdkVersion: '13.3',
artifacts: mockArtifacts,
fileSystem: mockFileSystem,
logger: logger,
platform: macPlatform,
iosDeploy: mockIosDeploy,
cpuArchitecture: DarwinArch.arm64,
);
device.setLogReader(mockApp, mockLogReader);
final Uri uri = Uri(
scheme: 'http',
host: '127.0.0.1',
port: 1234,
path: 'observatory',
);
when(mockMDnsObservatoryDiscovery.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) => Future<Uri>.value(uri));
List<String> args;
when(mockIosDeploy.runApp(
deviceId: anyNamed('deviceId'),
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation inv) {
args = inv.namedArguments[const Symbol('launchArguments')] as List<String>;
return Future<int>.value(0);
});
when(mockIosDeploy.installApp(
deviceId: device.id,
bundlePath: anyNamed('bundlePath'),
launchArguments: anyNamed('launchArguments'),
)).thenAnswer((Invocation invocation) => Future<int>.value(0));
final LaunchResult launchResult = await device.startApp(mockApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(
const BuildInfo(BuildMode.debug, null, treeShakeIcons: false),
deviceVmServicePort: 8181,
),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, isTrue);
expect(args, contains('--observatory-port=8181'));
expect(await device.stopApp(mockApp), isFalse);
}, overrides: <Type, Generator>{
Cache: () => mockCache,
MDnsObservatoryDiscovery: () => mockMDnsObservatoryDiscovery,
ProcessManager: () => mockProcessManager,
Usage: () => mockUsage,
});
void testNonPrebuilt(
String name, {
@required bool showBuildSettingsFlakes,
......
// 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:file/memory.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/ios/ios_deploy.dart';
import 'package:flutter_tools/src/mdns_discovery.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
const FakeCommand kDeployCommand = FakeCommand(
command: <String>[
'ios-deploy',
'--id',
'123',
'--bundle',
'/',
'--no-wifi',
],
environment: <String, String>{
'PATH': '/usr/bin:null',
'DYLD_LIBRARY_PATH': '/path/to/libraries',
}
);
// The command used to actually launch the app with args in release/profile.
const FakeCommand kLaunchReleaseCommand = FakeCommand(
command: <String>[
'ios-deploy',
'--id',
'123',
'--bundle',
'/',
'--no-wifi',
'--justlaunch',
// These args are the default on DebuggingOptions.
'--args',
'--enable-dart-profiling --enable-service-port-fallback --disable-service-auth-codes --observatory-port=60700',
],
environment: <String, String>{
'PATH': '/usr/bin:null',
'DYLD_LIBRARY_PATH': '/path/to/libraries',
}
);
// The command used to actually launch the app with args in debug.
const FakeCommand kLaunchDebugCommand = FakeCommand(command: <String>[
'ios-deploy',
'--id',
'123',
'--bundle',
'/',
'--no-wifi',
'--justlaunch',
'--args',
'--enable-dart-profiling --enable-service-port-fallback --disable-service-auth-codes --observatory-port=60700 --enable-checked-mode --verify-entry-points'
], environment: <String, String>{
'PATH': '/usr/bin:null',
'DYLD_LIBRARY_PATH': '/path/to/libraries',
});
void main() {
// TODO(jonahwilliams): This test doesn't really belong here but
// I don't have a better place for it for now.
testWithoutContext('disposing device disposes the portForwarder and logReader', () async {
final IOSDevice device = setUpIOSDevice();
final DevicePortForwarder devicePortForwarder = MockDevicePortForwarder();
final DeviceLogReader deviceLogReader = MockDeviceLogReader();
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
);
device.portForwarder = devicePortForwarder;
device.setLogReader(iosApp, deviceLogReader);
await device.dispose();
verify(deviceLogReader.dispose()).called(1);
verify(devicePortForwarder.dispose()).called(1);
});
// Still uses context for analytics and mDNS.
testUsingContext('IOSDevice.startApp succeeds in debug mode via mDNS discovery', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
kDeployCommand,
kLaunchDebugCommand,
]);
final IOSDevice device = setUpIOSDevice(
processManager: processManager,
fileSystem: fileSystem,
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
bundleDir: fileSystem.currentDirectory,
);
final Uri uri = Uri(
scheme: 'http',
host: '127.0.0.1',
port: 1234,
path: 'observatory',
);
device.portForwarder = const NoOpDevicePortForwarder();
device.setLogReader(iosApp, FakeDeviceLogReader());
when(MDnsObservatoryDiscovery.instance.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) async => uri);
final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
platformArgs: <String, dynamic>{},
);
verify(globals.flutterUsage.sendEvent('ios-handshake', 'mdns-success')).called(1);
expect(launchResult.started, true);
expect(launchResult.hasObservatory, true);
expect(await device.stopApp(iosApp), false);
}, overrides: <Type, Generator>{
MDnsObservatoryDiscovery: () => MockMDnsObservatoryDiscovery(),
Usage: () => MockUsage(),
});
// Still uses context for analytics and mDNS.
testUsingContext('IOSDevice.startApp succeeds in debug mode when mDNS fails', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
kDeployCommand,
kLaunchDebugCommand,
]);
final IOSDevice device = setUpIOSDevice(
processManager: processManager,
fileSystem: fileSystem,
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
bundleDir: fileSystem.currentDirectory,
);
final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader();
device.portForwarder = const NoOpDevicePortForwarder();
device.setLogReader(iosApp, deviceLogReader);
// Now that the reader is used, start writing messages to it.
Timer.run(() {
deviceLogReader.addLine('Foo');
deviceLogReader.addLine('Observatory listening on http://127.0.0.1:456');
});
when(MDnsObservatoryDiscovery.instance.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) async => null);
final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, true);
expect(launchResult.hasObservatory, true);
verify(globals.flutterUsage.sendEvent('ios-handshake', 'mdns-failure')).called(1);
verify(globals.flutterUsage.sendEvent('ios-handshake', 'fallback-success')).called(1);
expect(await device.stopApp(iosApp), false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
MDnsObservatoryDiscovery: () => MockMDnsObservatoryDiscovery(),
});
// Still uses context for analytics and mDNS.
testUsingContext('IOSDevice.startApp fails in debug mode when mDNS fails and '
'when Observatory URI is malformed', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
kDeployCommand,
kLaunchDebugCommand,
]);
final IOSDevice device = setUpIOSDevice(
processManager: processManager,
fileSystem: fileSystem,
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
bundleDir: fileSystem.currentDirectory,
);
final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader();
device.portForwarder = const NoOpDevicePortForwarder();
device.setLogReader(iosApp, deviceLogReader);
// Now that the reader is used, start writing messages to it.
Timer.run(() {
deviceLogReader.addLine('Foo');
deviceLogReader.addLine('Observatory listening on http:/:/127.0.0.1:456');
});
when(MDnsObservatoryDiscovery.instance.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) async => null);
final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, false);
expect(launchResult.hasObservatory, false);
verify(globals.flutterUsage.sendEvent(
'ios-handshake',
'failure-other',
label: anyNamed('label'),
value: anyNamed('value'),
)).called(1);
verify(globals.flutterUsage.sendEvent('ios-handshake', 'mdns-failure')).called(1);
verify(globals.flutterUsage.sendEvent('ios-handshake', 'fallback-failure')).called(1);
}, overrides: <Type, Generator>{
MDnsObservatoryDiscovery: () => MockMDnsObservatoryDiscovery(),
Usage: () => MockUsage(),
});
// Still uses context for TimeoutConfiguration and usage
testUsingContext('IOSDevice.startApp succeeds in release mode', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
kDeployCommand,
kLaunchReleaseCommand,
]);
final IOSDevice device = setUpIOSDevice(
processManager: processManager,
fileSystem: fileSystem,
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
bundleDir: fileSystem.currentDirectory,
);
final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, true);
expect(launchResult.hasObservatory, false);
expect(await device.stopApp(iosApp), false);
expect(processManager.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
Usage: () => MockUsage(),
});
// Still uses context for analytics and mDNS.
testUsingContext('IOSDevice.startApp forwards all supported debugging options', () async {
final FileSystem fileSystem = MemoryFileSystem.test();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
kDeployCommand,
FakeCommand(
command: <String>[
'ios-deploy',
'--id',
'123',
'--bundle',
'/',
'--no-wifi',
'--justlaunch',
// The arguments below are determined by what is passed into
// the debugging options argument to startApp.
'--args',
<String>[
'--enable-dart-profiling',
'--enable-service-port-fallback',
'--disable-service-auth-codes',
'--observatory-port=60700',
'--start-paused',
'--dart-flags="--foo"',
'--enable-checked-mode',
'--verify-entry-points',
'--enable-software-rendering',
'--skia-deterministic-rendering',
'--trace-skia',
'--endless-trace-buffer',
'--dump-skp-on-shader-compilation',
'--verbose-logging',
'--cache-sksl',
].join(' '),
], environment: const <String, String>{
'PATH': '/usr/bin:null',
'DYLD_LIBRARY_PATH': '/path/to/libraries',
}
)
]);
final IOSDevice device = setUpIOSDevice(
sdkVersion: '13.3',
processManager: processManager,
fileSystem: fileSystem,
);
final IOSApp iosApp = PrebuiltIOSApp(
projectBundleId: 'app',
bundleName: 'Runner',
bundleDir: fileSystem.currentDirectory,
);
final Uri uri = Uri(
scheme: 'http',
host: '127.0.0.1',
port: 1234,
path: 'observatory',
);
device.setLogReader(iosApp, FakeDeviceLogReader());
device.portForwarder = const NoOpDevicePortForwarder();
when(MDnsObservatoryDiscovery.instance.getObservatoryUri(any, any, usesIpv6: anyNamed('usesIpv6')))
.thenAnswer((Invocation invocation) async => uri);
final LaunchResult launchResult = await device.startApp(iosApp,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(
BuildInfo.debug,
startPaused: true,
disableServiceAuthCodes: true,
dartFlags: '--foo',
enableSoftwareRendering: true,
skiaDeterministicRendering: true,
traceSkia: true,
traceSystrace: true,
endlessTraceBuffer: true,
dumpSkpOnShaderCompilation: true,
cacheSkSL: true,
verboseSystemLogs: true,
),
platformArgs: <String, dynamic>{},
);
expect(launchResult.started, true);
expect(await device.stopApp(iosApp), false);
expect(processManager.hasRemainingExpectations, false);
}, overrides: <Type, Generator>{
MDnsObservatoryDiscovery: () => MockMDnsObservatoryDiscovery(),
Usage: () => MockUsage(),
});
}
IOSDevice setUpIOSDevice({
String sdkVersion = '13.0.1',
FileSystem fileSystem,
Logger logger,
ProcessManager processManager,
}) {
const MapEntry<String, String> dyldLibraryEntry = MapEntry<String, String>(
'DYLD_LIBRARY_PATH',
'/path/to/libraries',
);
final MockCache cache = MockCache();
final MockArtifacts artifacts = MockArtifacts();
final FakePlatform macPlatform = FakePlatform(
operatingSystem: 'macos',
environment: <String, String>{},
);
when(cache.dyLdLibEntry).thenReturn(dyldLibraryEntry);
when(artifacts.getArtifactPath(Artifact.iosDeploy, platform: anyNamed('platform')))
.thenReturn('ios-deploy');
return IOSDevice('123',
name: 'iPhone 1',
sdkVersion: sdkVersion,
fileSystem: fileSystem ?? MemoryFileSystem.test(),
platform: macPlatform,
artifacts: artifacts,
logger: BufferLogger.test(),
iosDeploy: IOSDeploy(
logger: logger ?? BufferLogger.test(),
platform: macPlatform,
processManager: processManager ?? FakeProcessManager.any(),
artifacts: artifacts,
cache: cache,
),
cpuArchitecture: DarwinArch.arm64,
);
}
class MockDevicePortForwarder extends Mock implements DevicePortForwarder {}
class MockDeviceLogReader extends Mock implements DeviceLogReader {}
class MockUsage extends Mock implements Usage {}
class MockMDnsObservatoryDiscovery extends Mock implements MDnsObservatoryDiscovery {}
class MockArtifacts extends Mock implements Artifacts {}
class MockCache extends Mock implements Cache {}
......@@ -10,11 +10,11 @@ import 'package:quiver/testing/async.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
import '../src/fakes.dart';
void main() {
group('service_protocol discovery', () {
MockDeviceLogReader logReader;
FakeDeviceLogReader logReader;
ProtocolDiscovery discoverer;
/// Performs test set-up functionality that must be performed as part of
......@@ -37,7 +37,7 @@ void main() {
int devicePort,
Duration throttleDuration = const Duration(milliseconds: 200),
}) {
logReader = MockDeviceLogReader();
logReader = FakeDeviceLogReader();
discoverer = ProtocolDiscovery.observatory(
logReader,
ipv6: false,
......@@ -261,7 +261,7 @@ void main() {
group('port forwarding', () {
testUsingContext('default port', () async {
final MockDeviceLogReader logReader = MockDeviceLogReader();
final FakeDeviceLogReader logReader = FakeDeviceLogReader();
final ProtocolDiscovery discoverer = ProtocolDiscovery.observatory(
logReader,
portForwarder: MockPortForwarder(99),
......@@ -282,7 +282,7 @@ void main() {
});
testUsingContext('specified port', () async {
final MockDeviceLogReader logReader = MockDeviceLogReader();
final FakeDeviceLogReader logReader = FakeDeviceLogReader();
final ProtocolDiscovery discoverer = ProtocolDiscovery.observatory(
logReader,
portForwarder: MockPortForwarder(99),
......@@ -303,7 +303,7 @@ void main() {
});
testUsingContext('specified port zero', () async {
final MockDeviceLogReader logReader = MockDeviceLogReader();
final FakeDeviceLogReader logReader = FakeDeviceLogReader();
final ProtocolDiscovery discoverer = ProtocolDiscovery.observatory(
logReader,
portForwarder: MockPortForwarder(99),
......@@ -324,7 +324,7 @@ void main() {
});
testUsingContext('ipv6', () async {
final MockDeviceLogReader logReader = MockDeviceLogReader();
final FakeDeviceLogReader logReader = FakeDeviceLogReader();
final ProtocolDiscovery discoverer = ProtocolDiscovery.observatory(
logReader,
portForwarder: MockPortForwarder(99),
......@@ -345,7 +345,7 @@ void main() {
});
testUsingContext('ipv6 with Ascii Escape code', () async {
final MockDeviceLogReader logReader = MockDeviceLogReader();
final FakeDeviceLogReader logReader = FakeDeviceLogReader();
final ProtocolDiscovery discoverer = ProtocolDiscovery.observatory(
logReader,
portForwarder: MockPortForwarder(99),
......
......@@ -82,39 +82,14 @@ class FakeCommand {
/// resolves.
final Completer<void> completer;
static bool _listEquals<T>(List<T> a, List<T> b) {
if (a == null) {
return b == null;
}
if (b == null || a.length != b.length) {
return false;
}
for (int index = 0; index < a.length; index += 1) {
if (a[index] != b[index]) {
return false;
}
}
return true;
}
bool _matches(List<String> command, String workingDirectory, Map<String, String> environment) {
if (!_listEquals(command, this.command)) {
return false;
}
if (this.workingDirectory != null && workingDirectory != this.workingDirectory) {
return false;
void _matches(List<String> command, String workingDirectory, Map<String, String> environment) {
expect(command, equals(this.command));
if (this.workingDirectory != null) {
expect(this.workingDirectory, workingDirectory);
}
if (this.environment != null) {
if (environment == null) {
return false;
}
for (final String key in environment.keys) {
if (environment[key] != this.environment[key]) {
return false;
}
}
expect(this.environment, environment);
}
return true;
}
}
......@@ -322,12 +297,7 @@ class _SequenceProcessManager extends FakeProcessManager {
reason: 'ProcessManager was told to execute $command (in $workingDirectory) '
'but the FakeProcessManager.list expected no more processes.'
);
expect(_commands.first._matches(command, workingDirectory, environment), isTrue,
reason: 'ProcessManager was told to execute $command '
'(in $workingDirectory, with environment $environment) '
'but the next process that was expected was ${_commands.first.command} '
'(in ${_commands.first.workingDirectory}, with environment ${_commands.first.environment})}.'
);
_commands.first._matches(command, workingDirectory, environment);
return _commands.removeAt(0);
}
......
// 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/device.dart';
/// A fake implementation of the [DeviceLogReader].
class FakeDeviceLogReader extends DeviceLogReader {
@override
String get name => 'FakeLogReader';
StreamController<String> _cachedLinesController;
final List<String> _lineQueue = <String>[];
StreamController<String> get _linesController {
_cachedLinesController ??= StreamController<String>
.broadcast(onListen: () {
_lineQueue.forEach(_linesController.add);
_lineQueue.clear();
});
return _cachedLinesController;
}
@override
Stream<String> get logLines => _linesController.stream;
void addLine(String line) {
if (_linesController.hasListener) {
_linesController.add(line);
} else {
_lineQueue.add(line);
}
}
@override
Future<void> dispose() async {
_lineQueue.clear();
await _linesController.close();
}
}
......@@ -612,40 +612,6 @@ class MockIOSSimulator extends Mock implements IOSSimulator {
bool isSupportedForProject(FlutterProject flutterProject) => true;
}
class MockDeviceLogReader extends DeviceLogReader {
@override
String get name => 'MockLogReader';
StreamController<String> _cachedLinesController;
final List<String> _lineQueue = <String>[];
StreamController<String> get _linesController {
_cachedLinesController ??= StreamController<String>
.broadcast(onListen: () {
_lineQueue.forEach(_linesController.add);
_lineQueue.clear();
});
return _cachedLinesController;
}
@override
Stream<String> get logLines => _linesController.stream;
void addLine(String line) {
if (_linesController.hasListener) {
_linesController.add(line);
} else {
_lineQueue.add(line);
}
}
@override
Future<void> dispose() async {
_lineQueue.clear();
await _linesController.close();
}
}
void applyMocksToCommand(FlutterCommand command) {
command.applicationPackages = MockApplicationPackageStore();
}
......
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