Unverified Commit 298f18b5 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] remove mocks from devices test (#82369)

parent 66cb3786
...@@ -5,10 +5,12 @@ ...@@ -5,10 +5,12 @@
// @dart = 2.8 // @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:io' as io;
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
...@@ -25,7 +27,7 @@ import 'package:flutter_tools/src/ios/ios_workflow.dart'; ...@@ -25,7 +27,7 @@ import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/ios/iproxy.dart'; import 'package:flutter_tools/src/ios/iproxy.dart';
import 'package:flutter_tools/src/ios/mac.dart'; import 'package:flutter_tools/src/ios/mac.dart';
import 'package:flutter_tools/src/macos/xcdevice.dart'; import 'package:flutter_tools/src/macos/xcdevice.dart';
import 'package:mockito/mockito.dart'; import 'package:test/fake.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/fake_process_manager.dart'; import '../../src/fake_process_manager.dart';
...@@ -192,13 +194,13 @@ void main() { ...@@ -192,13 +194,13 @@ void main() {
group('.dispose()', () { group('.dispose()', () {
IOSDevice device; IOSDevice device;
MockIOSApp appPackage1; FakeIOSApp appPackage1;
MockIOSApp appPackage2; FakeIOSApp appPackage2;
IOSDeviceLogReader logReader1; IOSDeviceLogReader logReader1;
IOSDeviceLogReader logReader2; IOSDeviceLogReader logReader2;
MockProcess mockProcess1; FakeProcess process1;
MockProcess mockProcess2; FakeProcess process2;
MockProcess mockProcess3; FakeProcess process3;
IOSDevicePortForwarder portForwarder; IOSDevicePortForwarder portForwarder;
ForwardedPort forwardedPort; ForwardedPort forwardedPort;
Cache cache; Cache cache;
...@@ -240,14 +242,12 @@ void main() { ...@@ -240,14 +242,12 @@ void main() {
} }
setUp(() { setUp(() {
appPackage1 = MockIOSApp(); appPackage1 = FakeIOSApp('flutterApp1');
appPackage2 = MockIOSApp(); appPackage2 = FakeIOSApp('flutterApp2');
when(appPackage1.name).thenReturn('flutterApp1'); process1 = FakeProcess();
when(appPackage2.name).thenReturn('flutterApp2'); process2 = FakeProcess();
mockProcess1 = MockProcess(); process3 = FakeProcess();
mockProcess2 = MockProcess(); forwardedPort = ForwardedPort.withContext(123, 456, process3);
mockProcess3 = MockProcess();
forwardedPort = ForwardedPort.withContext(123, 456, mockProcess3);
cache = Cache.test( cache = Cache.test(
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
); );
...@@ -274,8 +274,8 @@ void main() { ...@@ -274,8 +274,8 @@ void main() {
cpuArchitecture: DarwinArch.arm64, cpuArchitecture: DarwinArch.arm64,
interfaceType: IOSDeviceInterface.usb, interfaceType: IOSDeviceInterface.usb,
); );
logReader1 = createLogReader(device, appPackage1, mockProcess1); logReader1 = createLogReader(device, appPackage1, process1);
logReader2 = createLogReader(device, appPackage2, mockProcess2); logReader2 = createLogReader(device, appPackage2, process2);
portForwarder = createPortForwarder(forwardedPort, device); portForwarder = createPortForwarder(forwardedPort, device);
device.setLogReader(appPackage1, logReader1); device.setLogReader(appPackage1, logReader1);
device.setLogReader(appPackage2, logReader2); device.setLogReader(appPackage2, logReader2);
...@@ -283,30 +283,30 @@ void main() { ...@@ -283,30 +283,30 @@ void main() {
await device.dispose(); await device.dispose();
verify(mockProcess1.kill()); expect(process1.killed, true);
verify(mockProcess2.kill()); expect(process2.killed, true);
verify(mockProcess3.kill()); expect(process3.killed, true);
}); });
}); });
}); });
group('polling', () { group('polling', () {
MockXcdevice mockXcdevice; FakeXcdevice xcdevice;
Cache cache; Cache cache;
FakeProcessManager fakeProcessManager; FakeProcessManager fakeProcessManager;
BufferLogger logger; BufferLogger logger;
IOSDeploy iosDeploy; IOSDeploy iosDeploy;
IMobileDevice iMobileDevice; IMobileDevice iMobileDevice;
IOSWorkflow mockIosWorkflow; IOSWorkflow iosWorkflow;
IOSDevice device1; IOSDevice device1;
IOSDevice device2; IOSDevice device2;
setUp(() { setUp(() {
mockXcdevice = MockXcdevice(); xcdevice = FakeXcdevice();
final Artifacts artifacts = Artifacts.test(); final Artifacts artifacts = Artifacts.test();
cache = Cache.test(processManager: FakeProcessManager.any()); cache = Cache.test(processManager: FakeProcessManager.any());
logger = BufferLogger.test(); logger = BufferLogger.test();
mockIosWorkflow = MockIOSWorkflow(); iosWorkflow = FakeIOSWorkflow();
fakeProcessManager = FakeProcessManager.any(); fakeProcessManager = FakeProcessManager.any();
iosDeploy = IOSDeploy( iosDeploy = IOSDeploy(
artifacts: artifacts, artifacts: artifacts,
...@@ -354,39 +354,27 @@ void main() { ...@@ -354,39 +354,27 @@ void main() {
testWithoutContext('start polling without Xcode', () async { testWithoutContext('start polling without Xcode', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: macPlatform, platform: macPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(false); xcdevice.isInstalled = false;
await iosDevices.startPolling(); await iosDevices.startPolling();
verifyNever(mockXcdevice.getAvailableIOSDevices()); expect(xcdevice.getAvailableIOSDevicesCount, 0);
}); });
testWithoutContext('start polling', () async { testWithoutContext('start polling', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: macPlatform, platform: macPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(true); xcdevice.isInstalled = true;
xcdevice.devices
int fetchDevicesCount = 0; ..add(<IOSDevice>[])
when(mockXcdevice.getAvailableIOSDevices()) ..add(<IOSDevice>[device1, device2]);
.thenAnswer((Invocation invocation) {
if (fetchDevicesCount == 0) {
// Initial time, no devices.
fetchDevicesCount++;
return Future<List<IOSDevice>>.value(<IOSDevice>[]);
} else if (fetchDevicesCount == 1) {
// Simulate 2 devices added later.
fetchDevicesCount++;
return Future<List<IOSDevice>>.value(<IOSDevice>[device1, device2]);
}
fail('Too many calls to getAvailableTetheredIOSDevices');
});
int addedCount = 0; int addedCount = 0;
final Completer<void> added = Completer<void>(); final Completer<void> added = Completer<void>();
...@@ -405,16 +393,13 @@ void main() { ...@@ -405,16 +393,13 @@ void main() {
removed.complete(); removed.complete();
}); });
final StreamController<Map<XCDeviceEvent, String>> eventStream = StreamController<Map<XCDeviceEvent, String>>();
when(mockXcdevice.observedDeviceEvents()).thenAnswer((_) => eventStream.stream);
await iosDevices.startPolling(); await iosDevices.startPolling();
verify(mockXcdevice.getAvailableIOSDevices()).called(1); expect(xcdevice.getAvailableIOSDevicesCount, 1);
expect(iosDevices.deviceNotifier.items, isEmpty); expect(iosDevices.deviceNotifier.items, isEmpty);
expect(eventStream.hasListener, isTrue); expect(xcdevice.deviceEventController.hasListener, isTrue);
eventStream.add(<XCDeviceEvent, String>{ xcdevice.deviceEventController.add(<XCDeviceEvent, String>{
XCDeviceEvent.attach: 'd83d5bc53967baa0ee18626ba87b6254b2ab5418' XCDeviceEvent.attach: 'd83d5bc53967baa0ee18626ba87b6254b2ab5418'
}); });
await added.future; await added.future;
...@@ -422,7 +407,7 @@ void main() { ...@@ -422,7 +407,7 @@ void main() {
expect(iosDevices.deviceNotifier.items, contains(device1)); expect(iosDevices.deviceNotifier.items, contains(device1));
expect(iosDevices.deviceNotifier.items, contains(device2)); expect(iosDevices.deviceNotifier.items, contains(device2));
eventStream.add(<XCDeviceEvent, String>{ xcdevice.deviceEventController.add(<XCDeviceEvent, String>{
XCDeviceEvent.detach: 'd83d5bc53967baa0ee18626ba87b6254b2ab5418' XCDeviceEvent.detach: 'd83d5bc53967baa0ee18626ba87b6254b2ab5418'
}); });
await removed.future; await removed.future;
...@@ -430,7 +415,7 @@ void main() { ...@@ -430,7 +415,7 @@ void main() {
// Remove stream will throw over-completion if called more than once // Remove stream will throw over-completion if called more than once
// which proves this is ignored. // which proves this is ignored.
eventStream.add(<XCDeviceEvent, String>{ xcdevice.deviceEventController.add(<XCDeviceEvent, String>{
XCDeviceEvent.detach: 'bogus' XCDeviceEvent.detach: 'bogus'
}); });
...@@ -438,45 +423,37 @@ void main() { ...@@ -438,45 +423,37 @@ void main() {
await iosDevices.stopPolling(); await iosDevices.stopPolling();
expect(eventStream.hasListener, isFalse); expect(xcdevice.deviceEventController.hasListener, isFalse);
}); });
testWithoutContext('polling can be restarted if stream is closed', () async { testWithoutContext('polling can be restarted if stream is closed', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: macPlatform, platform: macPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(true); xcdevice.isInstalled = true;
xcdevice.devices.add(<IOSDevice>[]);
when(mockXcdevice.getAvailableIOSDevices()) xcdevice.devices.add(<IOSDevice>[]);
.thenAnswer((Invocation invocation) => Future<List<IOSDevice>>.value(<IOSDevice>[]));
final StreamController<Map<XCDeviceEvent, String>> eventStream = StreamController<Map<XCDeviceEvent, String>>();
final StreamController<Map<XCDeviceEvent, String>> rescheduledStream = StreamController<Map<XCDeviceEvent, String>>(); final StreamController<Map<XCDeviceEvent, String>> rescheduledStream = StreamController<Map<XCDeviceEvent, String>>();
bool reschedule = false; unawaited(xcdevice.deviceEventController.done.whenComplete(() {
when(mockXcdevice.observedDeviceEvents()).thenAnswer((Invocation invocation) { xcdevice.deviceEventController = rescheduledStream;
if (!reschedule) { }));
reschedule = true;
return eventStream.stream;
}
return rescheduledStream.stream;
});
await iosDevices.startPolling(); await iosDevices.startPolling();
expect(eventStream.hasListener, isTrue); expect(xcdevice.deviceEventController.hasListener, isTrue);
verify(mockXcdevice.getAvailableIOSDevices()).called(1); expect(xcdevice.getAvailableIOSDevicesCount, 1);
// Pretend xcdevice crashed. // Pretend xcdevice crashed.
await eventStream.close(); await xcdevice.deviceEventController.close();
expect(logger.traceText, contains('xcdevice observe stopped')); expect(logger.traceText, contains('xcdevice observe stopped'));
// Confirm a restart still gets streamed events. // Confirm a restart still gets streamed events.
await iosDevices.startPolling(); await iosDevices.startPolling();
expect(eventStream.hasListener, isFalse);
expect(rescheduledStream.hasListener, isTrue); expect(rescheduledStream.hasListener, isTrue);
await iosDevices.stopPolling(); await iosDevices.stopPolling();
...@@ -486,23 +463,19 @@ void main() { ...@@ -486,23 +463,19 @@ void main() {
testWithoutContext('dispose cancels polling subscription', () async { testWithoutContext('dispose cancels polling subscription', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: macPlatform, platform: macPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(true); xcdevice.isInstalled = true;
when(mockXcdevice.getAvailableIOSDevices()) xcdevice.devices.add(<IOSDevice>[]);
.thenAnswer((Invocation invocation) => Future<List<IOSDevice>>.value(<IOSDevice>[]));
final StreamController<Map<XCDeviceEvent, String>> eventStream = StreamController<Map<XCDeviceEvent, String>>();
when(mockXcdevice.observedDeviceEvents()).thenAnswer((_) => eventStream.stream);
await iosDevices.startPolling(); await iosDevices.startPolling();
expect(iosDevices.deviceNotifier.items, isEmpty); expect(iosDevices.deviceNotifier.items, isEmpty);
expect(eventStream.hasListener, isTrue); expect(xcdevice.deviceEventController.hasListener, isTrue);
iosDevices.dispose(); iosDevices.dispose();
expect(eventStream.hasListener, isFalse); expect(xcdevice.deviceEventController.hasListener, isFalse);
}); });
final List<Platform> unsupportedPlatforms = <Platform>[linuxPlatform, windowsPlatform]; final List<Platform> unsupportedPlatforms = <Platform>[linuxPlatform, windowsPlatform];
...@@ -510,11 +483,11 @@ void main() { ...@@ -510,11 +483,11 @@ void main() {
testWithoutContext('pollingGetDevices throws Unsupported Operation exception on ${unsupportedPlatform.operatingSystem}', () async { testWithoutContext('pollingGetDevices throws Unsupported Operation exception on ${unsupportedPlatform.operatingSystem}', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: unsupportedPlatform, platform: unsupportedPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(false); xcdevice.isInstalled = false;
expect( expect(
() async { await iosDevices.pollingGetDevices(); }, () async { await iosDevices.pollingGetDevices(); },
throwsUnsupportedError, throwsUnsupportedError,
...@@ -525,29 +498,28 @@ void main() { ...@@ -525,29 +498,28 @@ void main() {
testWithoutContext('pollingGetDevices returns attached devices', () async { testWithoutContext('pollingGetDevices returns attached devices', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: macPlatform, platform: macPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(true); xcdevice.isInstalled = true;
xcdevice.devices.add(<IOSDevice>[device1]);
when(mockXcdevice.getAvailableIOSDevices())
.thenAnswer((Invocation invocation) => Future<List<IOSDevice>>.value(<IOSDevice>[device1]));
final List<Device> devices = await iosDevices.pollingGetDevices(); final List<Device> devices = await iosDevices.pollingGetDevices();
expect(devices, hasLength(1)); expect(devices, hasLength(1));
expect(identical(devices.first, device1), isTrue); expect(devices.first, same(device1));
}); });
}); });
group('getDiagnostics', () { group('getDiagnostics', () {
MockXcdevice mockXcdevice; FakeXcdevice xcdevice;
IOSWorkflow mockIosWorkflow; IOSWorkflow iosWorkflow;
Logger logger; Logger logger;
setUp(() { setUp(() {
mockXcdevice = MockXcdevice(); xcdevice = FakeXcdevice();
mockIosWorkflow = MockIOSWorkflow(); iosWorkflow = FakeIOSWorkflow();
logger = BufferLogger.test(); logger = BufferLogger.test();
}); });
...@@ -556,11 +528,11 @@ void main() { ...@@ -556,11 +528,11 @@ void main() {
testWithoutContext('throws returns platform diagnostic exception on ${unsupportedPlatform.operatingSystem}', () async { testWithoutContext('throws returns platform diagnostic exception on ${unsupportedPlatform.operatingSystem}', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: unsupportedPlatform, platform: unsupportedPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(false); xcdevice.isInstalled = false;
expect((await iosDevices.getDiagnostics()).first, 'Control of iOS devices or simulators only supported on macOS.'); expect((await iosDevices.getDiagnostics()).first, 'Control of iOS devices or simulators only supported on macOS.');
}); });
} }
...@@ -568,13 +540,12 @@ void main() { ...@@ -568,13 +540,12 @@ void main() {
testWithoutContext('returns diagnostics', () async { testWithoutContext('returns diagnostics', () async {
final IOSDevices iosDevices = IOSDevices( final IOSDevices iosDevices = IOSDevices(
platform: macPlatform, platform: macPlatform,
xcdevice: mockXcdevice, xcdevice: xcdevice,
iosWorkflow: mockIosWorkflow, iosWorkflow: iosWorkflow,
logger: logger, logger: logger,
); );
when(mockXcdevice.isInstalled).thenReturn(true); xcdevice.isInstalled = true;
when(mockXcdevice.getDiagnostics()) xcdevice.diagnostics.add('Generic pairing error');
.thenAnswer((Invocation invocation) => Future<List<String>>.value(<String>['Generic pairing error']));
final List<String> diagnostics = await iosDevices.getDiagnostics(); final List<String> diagnostics = await iosDevices.getDiagnostics();
expect(diagnostics, hasLength(1)); expect(diagnostics, hasLength(1));
...@@ -583,7 +554,46 @@ void main() { ...@@ -583,7 +554,46 @@ void main() {
}); });
} }
class MockIOSApp extends Mock implements IOSApp {} class FakeIOSApp extends Fake implements IOSApp {
class MockIOSWorkflow extends Mock implements IOSWorkflow {} FakeIOSApp(this.name);
class MockXcdevice extends Mock implements XCDevice {}
class MockProcess extends Mock implements Process {} @override
final String name;
}
class FakeIOSWorkflow extends Fake implements IOSWorkflow {}
class FakeXcdevice extends Fake implements XCDevice {
int getAvailableIOSDevicesCount = 0;
final List<List<IOSDevice>> devices = <List<IOSDevice>>[];
final List<String> diagnostics = <String>[];
StreamController<Map<XCDeviceEvent, String>> deviceEventController = StreamController<Map<XCDeviceEvent, String>>();
@override
bool isInstalled = true;
@override
Future<List<String>> getDiagnostics() async {
return diagnostics;
}
@override
Stream<Map<XCDeviceEvent, String>> observedDeviceEvents() {
return deviceEventController.stream;
}
@override
Future<List<IOSDevice>> getAvailableIOSDevices({Duration timeout}) async {
return devices[getAvailableIOSDevicesCount++];
}
}
class FakeProcess extends Fake implements Process {
bool killed = false;
@override
bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) {
killed = true;
return true;
}
}
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