mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
151 lines
5.6 KiB
Dart
151 lines
5.6 KiB
Dart
// 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:path/path.dart' as path;
|
|
import 'package:flutter_devicelab/framework/adb.dart';
|
|
import 'package:flutter_devicelab/framework/framework.dart';
|
|
import 'package:flutter_devicelab/framework/utils.dart';
|
|
|
|
Future<void> testReload(Process process, { Future<void> Function() onListening }) async {
|
|
section('Testing hot reload, restart and quit');
|
|
final Completer<void> listening = Completer<void>();
|
|
final Completer<void> ready = Completer<void>();
|
|
final Completer<void> reloaded = Completer<void>();
|
|
final Completer<void> restarted = Completer<void>();
|
|
final Completer<void> finished = Completer<void>();
|
|
final List<String> stdout = <String>[];
|
|
final List<String> stderr = <String>[];
|
|
|
|
if (onListening == null)
|
|
listening.complete();
|
|
|
|
int exitCode;
|
|
process.stdout
|
|
.transform<String>(utf8.decoder)
|
|
.transform<String>(const LineSplitter())
|
|
.listen((String line) {
|
|
print('attach:stdout: $line');
|
|
stdout.add(line);
|
|
if (line.contains('Waiting') && onListening != null)
|
|
listening.complete(onListening());
|
|
if (line.contains('To detach, press "d"; to quit, press "q".'))
|
|
ready.complete();
|
|
if (line.contains('Reloaded '))
|
|
reloaded.complete();
|
|
if (line.contains('Restarted application in '))
|
|
restarted.complete();
|
|
if (line.contains('Application finished'))
|
|
finished.complete();
|
|
});
|
|
process.stderr
|
|
.transform<String>(utf8.decoder)
|
|
.transform<String>(const LineSplitter())
|
|
.listen((String line) {
|
|
print('run:stderr: $line');
|
|
stdout.add(line);
|
|
});
|
|
|
|
process.exitCode.then<void>((int processExitCode) { exitCode = processExitCode; });
|
|
|
|
Future<dynamic> eventOrExit(Future<void> event) {
|
|
return Future.any<dynamic>(<Future<dynamic>>[ event, process.exitCode ]);
|
|
}
|
|
|
|
await eventOrExit(listening.future);
|
|
await eventOrExit(ready.future);
|
|
|
|
if (exitCode != null)
|
|
throw 'Failed to attach to test app; command unexpected exited, with exit code $exitCode.';
|
|
|
|
process.stdin.write('r');
|
|
process.stdin.flush();
|
|
await eventOrExit(reloaded.future);
|
|
process.stdin.write('R');
|
|
process.stdin.flush();
|
|
await eventOrExit(restarted.future);
|
|
process.stdin.write('q');
|
|
process.stdin.flush();
|
|
await eventOrExit(finished.future);
|
|
|
|
await process.exitCode;
|
|
|
|
if (stderr.isNotEmpty)
|
|
throw 'flutter attach had output on standard error.';
|
|
|
|
if (exitCode != 0)
|
|
throw 'exit code was not 0';
|
|
}
|
|
|
|
void main() {
|
|
const String kAppId = 'com.yourcompany.integration_ui';
|
|
const String kActivityId = '$kAppId/com.yourcompany.integration_ui.MainActivity';
|
|
|
|
task(() async {
|
|
final AndroidDevice device = await devices.workingDevice as AndroidDevice;
|
|
await device.unlock();
|
|
final Directory appDir = dir(path.join(flutterDirectory.path, 'dev/integration_tests/ui'));
|
|
await inDirectory(appDir, () async {
|
|
section('Building');
|
|
final String buildStdout = await eval(
|
|
path.join(flutterDirectory.path, 'bin', 'flutter'),
|
|
<String>['--suppress-analytics', 'build', 'apk', '--debug', 'lib/main.dart'],
|
|
);
|
|
final String lastLine = buildStdout.split('\n').last;
|
|
final RegExp builtRegExp = RegExp(r'Built (.+)( \(|\.$)');
|
|
final String apkPath = builtRegExp.firstMatch(lastLine)[1];
|
|
|
|
section('Installing $apkPath');
|
|
|
|
await device.adb(<String>['install', '-r', apkPath]);
|
|
|
|
try {
|
|
section('Launching `flutter attach`');
|
|
Process attachProcess = await startProcess(
|
|
path.join(flutterDirectory.path, 'bin', 'flutter'),
|
|
<String>['--suppress-analytics', 'attach', '-d', device.deviceId],
|
|
isBot: false, // we just want to test the output, not have any debugging info
|
|
);
|
|
|
|
await testReload(attachProcess, onListening: () async {
|
|
await device.shellExec('am', <String>['start', '-n', kActivityId]);
|
|
});
|
|
|
|
// Give the device the time to really shut down the app.
|
|
await Future<void>.delayed(const Duration(milliseconds: 200));
|
|
// After the delay, force-stopping it shouldn't do anything, but doesn't hurt.
|
|
await device.shellExec('am', <String>['force-stop', kAppId]);
|
|
|
|
final String currentTime = (await device.shellEval('date', <String>['"+%F %R:%S.000"'])).trim();
|
|
print('Start time on device: $currentTime');
|
|
section('Relaunching application');
|
|
await device.shellExec('am', <String>['start', '-n', kActivityId]);
|
|
|
|
// If the next line fails, your device may not support regexp search.
|
|
final String observatoryLine = await device.adb(<String>['logcat', '-e', 'Observatory listening on http:', '-m', '1', '-T', currentTime]);
|
|
print('Found observatory line: $observatoryLine');
|
|
final String observatoryUri = RegExp('Observatory listening on ((http|\/\/)[a-zA-Z0-9:/=_\\-\.\\[\\]]+)').firstMatch(observatoryLine)[1];
|
|
print('Extracted observatory port: $observatoryUri');
|
|
|
|
section('Launching attach with given port');
|
|
attachProcess = await startProcess(
|
|
path.join(flutterDirectory.path, 'bin', 'flutter'),
|
|
<String>['--suppress-analytics', 'attach', '--debug-uri',
|
|
observatoryUri, '-d', device.deviceId],
|
|
isBot: false, // we just want to test the output, not have any debugging info
|
|
);
|
|
await testReload(attachProcess);
|
|
|
|
} finally {
|
|
section('Uninstalling');
|
|
await device.adb(<String>['uninstall', kAppId]);
|
|
}
|
|
});
|
|
return TaskResult.success(null);
|
|
});
|
|
}
|