// 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. // @dart = 2.8 import 'dart:async'; import 'package:dds/dds.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/test/font_config_manager.dart'; import 'package:flutter_tools/src/test/flutter_tester_device.dart'; import 'package:meta/meta.dart'; import 'package:mockito/mockito.dart'; import 'package:stream_channel/stream_channel.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; import '../src/common.dart'; import '../src/context.dart'; import '../src/fake_process_manager.dart'; void main() { FakePlatform platform; FileSystem fileSystem; FakeProcessManager processManager; FlutterTesterTestDevice device; setUp(() { fileSystem = MemoryFileSystem.test(); // Not Windows. platform = FakePlatform( operatingSystem: 'linux', environment: {}, ); processManager = FakeProcessManager.any(); }); FlutterTesterTestDevice createDevice({ List dartEntrypointArgs = const [], bool enableObservatory = false, }) => TestFlutterTesterDevice( platform: platform, fileSystem: fileSystem, processManager: processManager, enableObservatory: enableObservatory, dartEntrypointArgs: dartEntrypointArgs, ); group('The FLUTTER_TEST environment variable is passed to the test process', () { setUp(() { processManager = FakeProcessManager.list([]); device = createDevice(); fileSystem .file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion":2,"packages":[]}'); }); FakeCommand flutterTestCommand(String expectedFlutterTestValue) { return FakeCommand(command: const [ '/', '--disable-observatory', '--ipv6', '--enable-checked-mode', '--verify-entry-points', '--enable-software-rendering', '--skia-deterministic-rendering', '--enable-dart-profiling', '--non-interactive', '--use-test-fonts', '--packages=.dart_tool/package_config.json', 'example.dill' ], environment: { 'FLUTTER_TEST': expectedFlutterTestValue, 'FONTCONFIG_FILE': device.fontConfigManager.fontConfigFile.path, 'SERVER_PORT': 'null', 'APP_NAME': '', }); } testUsingContext('as true when not originally set', () async { processManager.addCommand(flutterTestCommand('true')); await device.start('example.dill'); expect(processManager.hasRemainingExpectations, isFalse); }); testUsingContext('as true when set to true', () async { platform.environment = {'FLUTTER_TEST': 'true'}; processManager.addCommand(flutterTestCommand('true')); await device.start('example.dill'); expect(processManager.hasRemainingExpectations, isFalse); }); testUsingContext('as false when set to false', () async { platform.environment = {'FLUTTER_TEST': 'false'}; processManager.addCommand(flutterTestCommand('false')); await device.start('example.dill'); expect(processManager.hasRemainingExpectations, isFalse); }); testUsingContext('unchanged when set', () async { platform.environment = {'FLUTTER_TEST': 'neither true nor false'}; processManager.addCommand(flutterTestCommand('neither true nor false')); await device.start('example.dill'); expect(processManager.hasRemainingExpectations, isFalse); }); testUsingContext('as null when set to null', () async { platform.environment = {'FLUTTER_TEST': null}; processManager.addCommand(flutterTestCommand(null)); await device.start('example.dill'); expect(processManager.hasRemainingExpectations, isFalse); }); }); group('Dart Entrypoint Args', () { setUp(() { processManager = FakeProcessManager.list([ const FakeCommand( command: [ '/', '--disable-observatory', '--ipv6', '--enable-checked-mode', '--verify-entry-points', '--enable-software-rendering', '--skia-deterministic-rendering', '--enable-dart-profiling', '--non-interactive', '--use-test-fonts', '--packages=.dart_tool/package_config.json', '--foo', '--bar', 'example.dill' ], stdout: 'success', stderr: 'failure', exitCode: 0, ) ]); device = createDevice(dartEntrypointArgs: ['--foo', '--bar']); }); testUsingContext('Can pass additional arguments to tester binary', () async { await device.start('example.dill'); expect(processManager, hasNoRemainingExpectations); }); }); group('DDS', () { setUp(() { processManager = FakeProcessManager.list([ const FakeCommand( command: [ '/', '--observatory-port=0', '--ipv6', '--enable-checked-mode', '--verify-entry-points', '--enable-software-rendering', '--skia-deterministic-rendering', '--enable-dart-profiling', '--non-interactive', '--use-test-fonts', '--packages=.dart_tool/package_config.json', 'example.dill' ], stdout: 'Observatory listening on http://localhost:1234', stderr: 'failure', exitCode: 0, ) ]); device = createDevice(enableObservatory: true); }); testUsingContext('skips setting observatory port and uses the input port for for DDS instead', () async { await device.start('example.dill'); await device.observatoryUri; final Uri uri = await (device as TestFlutterTesterDevice).ddsServiceUriFuture(); expect(uri.port, 1234); }); }); } /// A Flutter Tester device. /// /// Uses a mock HttpServer. We don't want to bind random ports in our CI hosts. class TestFlutterTesterDevice extends FlutterTesterTestDevice { TestFlutterTesterDevice({ @required Platform platform, @required FileSystem fileSystem, @required ProcessManager processManager, @required bool enableObservatory, @required List dartEntrypointArgs, }) : super( id: 999, shellPath: '/', platform: platform, fileSystem: fileSystem, processManager: processManager, logger: BufferLogger.test(), debuggingOptions: DebuggingOptions.enabled( const BuildInfo( BuildMode.debug, '', treeShakeIcons: false, packagesPath: '.dart_tool/package_config.json', ), startPaused: false, disableDds: false, disableServiceAuthCodes: false, hostVmServicePort: 1234, nullAssertions: false, dartEntrypointArgs: dartEntrypointArgs, ), enableObservatory: enableObservatory, machine: false, host: InternetAddress.loopbackIPv6, buildTestAssets: false, flutterProject: null, icudtlPath: null, compileExpression: null, fontConfigManager: FontConfigManager(), ); final Completer _ddsServiceUriCompleter = Completer(); Future ddsServiceUriFuture() => _ddsServiceUriCompleter.future; @override Future startDds(Uri uri) async { _ddsServiceUriCompleter.complete(uri); final MockDartDevelopmentService mock = MockDartDevelopmentService(); when(mock.uri).thenReturn(Uri.parse('http://localhost:${debuggingOptions.hostVmServicePort}')); return mock; } @override Future bind(InternetAddress host, int port) async => MockHttpServer(); @override Future> get remoteChannel async => StreamChannelController().foreign; } class MockDartDevelopmentService extends Mock implements DartDevelopmentService {} class MockHttpServer extends Mock implements HttpServer {}