| // 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 'dart:convert'; |
| import 'dart:io'; |
| |
| import 'package:flutter_devicelab/framework/devices.dart'; |
| import 'package:flutter_devicelab/framework/framework.dart'; |
| import 'package:flutter_devicelab/framework/task_result.dart'; |
| import 'package:flutter_devicelab/framework/utils.dart'; |
| import 'package:path/path.dart' as path; |
| |
| void main() { |
| task(() async { |
| final Device device = await devices.workingDevice; |
| await device.unlock(); |
| final Directory appDir = dir(path.join(flutterDirectory.path, 'dev/integration_tests/ui')); |
| await inDirectory(appDir, () async { |
| final Completer<void> ready = Completer<void>(); |
| final List<String> stdout = <String>[]; |
| final List<String> stderr = <String>[]; |
| |
| // Uninstall if the app is already installed on the device to get to a clean state. |
| print('uninstalling...'); |
| final Process uninstall = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| <String>['--suppress-analytics', 'install', '--uninstall-only', '-d', device.deviceId], |
| )..stdout |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| print('uninstall:stdout: $line'); |
| })..stderr |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| print('uninstall:stderr: $line'); |
| stderr.add(line); |
| }); |
| if (await uninstall.exitCode != 0) { |
| throw 'flutter install --uninstall-only failed.'; |
| } |
| |
| print('run: starting...'); |
| final Process run = await startProcess( |
| path.join(flutterDirectory.path, 'bin', 'flutter'), |
| <String>['--suppress-analytics', 'run', '--release', '-d', device.deviceId, 'lib/main.dart'], |
| isBot: false, // we just want to test the output, not have any debugging info |
| ); |
| int? runExitCode; |
| run.stdout |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| .listen((String line) { |
| print('run:stdout: $line'); |
| if ( |
| !line.startsWith('Building flutter tool...') && |
| !line.startsWith('Running "flutter pub get" in ui...') && |
| !line.startsWith('Initializing gradle...') && |
| !line.contains('settings_aar.gradle') && |
| !line.startsWith('Resolving dependencies...') && |
| // Catch engine piped output from unrelated concurrent Flutter apps |
| !line.contains(RegExp(r'[A-Z]\/flutter \([0-9]+\):')) && |
| // Empty lines could be due to the progress spinner breaking up. |
| line.length > 1 |
| ) { |
| stdout.add(line); |
| } |
| if (line.contains('Quit (terminate the application on the device).')) { |
| ready.complete(); |
| } |
| }); |
| run.stderr |
| .transform<String>(utf8.decoder) |
| .transform<String>(const LineSplitter()) |
| // TODO(egarciad): Remove once https://github.com/flutter/flutter/issues/95131 is fixed. |
| .skipWhile((String line) => line.contains('Mapping new ns')) |
| .listen((String line) { |
| print('run:stderr: $line'); |
| stderr.add(line); |
| }); |
| unawaited(run.exitCode.then<void>((int exitCode) { runExitCode = exitCode; })); |
| await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]); |
| if (runExitCode != null) { |
| throw 'Failed to run test app; runner unexpected exited, with exit code $runExitCode.'; |
| } |
| run.stdin.write('q'); |
| |
| await run.exitCode; |
| |
| if (stderr.isNotEmpty) { |
| throw 'flutter run --release had output on standard error.'; |
| } |
| |
| _findNextMatcherInList( |
| stdout, |
| (String line) => line.startsWith('Launching lib/main.dart on ') && line.endsWith(' in release mode...'), |
| 'Launching lib/main.dart on', |
| ); |
| |
| _findNextMatcherInList( |
| stdout, |
| (String line) => line.startsWith("Running Gradle task 'assembleRelease'..."), |
| "Running Gradle task 'assembleRelease'...", |
| ); |
| |
| _findNextMatcherInList( |
| stdout, |
| (String line) => line.contains('Built build/app/outputs/flutter-apk/app-release.apk (') && line.contains('MB).'), |
| 'Built build/app/outputs/flutter-apk/app-release.apk', |
| ); |
| |
| _findNextMatcherInList( |
| stdout, |
| (String line) => line.startsWith('Installing build/app/outputs/flutter-apk/app.apk...'), |
| 'Installing build/app/outputs/flutter-apk/app.apk...', |
| ); |
| |
| _findNextMatcherInList( |
| stdout, |
| (String line) => line.contains('Quit (terminate the application on the device).'), |
| 'q Quit (terminate the application on the device)', |
| ); |
| |
| _findNextMatcherInList( |
| stdout, |
| (String line) => line == 'Application finished.', |
| 'Application finished.', |
| ); |
| }); |
| return TaskResult.success(null); |
| }); |
| } |
| |
| void _findNextMatcherInList( |
| List<String> list, |
| bool Function(String testLine) matcher, |
| String errorMessageExpectedLine |
| ) { |
| final List<String> copyOfListForErrorMessage = List<String>.from(list); |
| |
| while (list.isNotEmpty) { |
| final String nextLine = list.first; |
| list.removeAt(0); |
| |
| if (matcher(nextLine)) { |
| return; |
| } |
| } |
| |
| throw ''' |
| Did not find expected line |
| |
| $errorMessageExpectedLine |
| |
| in flutter run --release stdout |
| |
| $copyOfListForErrorMessage |
| '''; |
| } |