Commit 1ada132e authored by Todd Volkert's avatar Todd Volkert Committed by GitHub

Add first replay test (#8628)

parent 5571cb11
......@@ -6,6 +6,7 @@ import 'package:path/path.dart' as p;
String flutterRoot = p.dirname(p.dirname(p.dirname(p.fromUri(Platform.script))));
String flutter = p.join(flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter');
String dart = p.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'dart.exe' : 'dart');
String pub = p.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', Platform.isWindows ? 'pub.bat' : 'pub');
String flutterTestArgs = Platform.environment['FLUTTER_TEST_ARGS'];
/// When you call this, you can set FLUTTER_TEST_ARGS to pass custom
......@@ -81,6 +82,9 @@ Future<Null> main() async {
await _runAllDartTests(p.join(flutterRoot, 'packages', 'flutter_tools'),
environment: <String, String>{ 'FLUTTER_ROOT': flutterRoot },
);
await _pubRunTest(p.join(flutterRoot, 'packages', 'flutter_tools'),
testPath: 'test/replay',
);
await _runAllDartTests(p.join(flutterRoot, 'dev', 'devicelab'));
await _runFlutterTest(p.join(flutterRoot, 'dev', 'manual_tests'));
......@@ -93,6 +97,16 @@ Future<Null> main() async {
}
}
Future<Null> _pubRunTest(
String workingDirectory, {
String testPath,
}) {
final List<String> args = <String>['run', 'test'];
if (testPath != null)
args.add(testPath);
return _runCmd(pub, args, workingDirectory: workingDirectory);
}
Future<Null> _runCmd(String executable, List<String> arguments, {
String workingDirectory,
Map<String, String> environment,
......
......@@ -18,7 +18,6 @@ import 'src/base/context.dart';
import 'src/base/file_system.dart';
import 'src/base/io.dart';
import 'src/base/logger.dart';
import 'src/base/os.dart';
import 'src/base/platform.dart';
import 'src/base/process.dart';
import 'src/base/utils.dart';
......@@ -49,7 +48,6 @@ import 'src/devfs.dart';
import 'src/device.dart';
import 'src/doctor.dart';
import 'src/globals.dart';
import 'src/ios/mac.dart';
import 'src/ios/simulators.dart';
import 'src/run_hot.dart';
import 'src/runner/flutter_command.dart';
......@@ -131,11 +129,8 @@ Future<int> run(List<String> args, List<FlutterCommand> subCommands, {
context.putIfAbsent(HotRunnerConfig, () => new HotRunnerConfig());
context.putIfAbsent(Cache, () => new Cache());
context.putIfAbsent(Artifacts, () => new CachedArtifacts());
context.putIfAbsent(OperatingSystemUtils, () => new OperatingSystemUtils());
context.putIfAbsent(Xcode, () => new Xcode());
context.putIfAbsent(IOSSimulatorUtils, () => new IOSSimulatorUtils());
context.putIfAbsent(SimControl, () => new SimControl());
context.putIfAbsent(Usage, () => new Usage());
// Initialize the system locale.
await intl.findSystemLocale();
......@@ -192,14 +187,14 @@ Future<int> _handleToolError(
// We've crashed; emit a log report.
stderr.writeln();
flutterUsage.sendException(error, chain);
if (!reportCrashes) {
// Print the stack trace on the bots - don't write a crash report.
stderr.writeln('$error');
stderr.writeln(chain.terse.toString());
return _exit(1);
} else {
flutterUsage.sendException(error, chain);
if (error is String)
stderr.writeln('Oops; flutter has exited unexpectedly: "$error".');
else
......@@ -208,7 +203,7 @@ Future<int> _handleToolError(
await CrashReportSender.instance.sendReport(
error: error,
stackTrace: chain,
flutterVersion: getFlutterVersion(),
getFlutterVersion: getFlutterVersion,
);
try {
final File file = await _createLocalCrashReport(args, error, chain);
......
......@@ -14,7 +14,7 @@ import 'process.dart';
import 'process_manager.dart';
/// Returns [OperatingSystemUtils] active in the current app context (i.e. zone).
OperatingSystemUtils get os => context[OperatingSystemUtils];
OperatingSystemUtils get os => context.putIfAbsent(OperatingSystemUtils, () => new OperatingSystemUtils());
abstract class OperatingSystemUtils {
factory OperatingSystemUtils() {
......
......@@ -72,7 +72,7 @@ class CrashReportSender {
Future<Null> sendReport({
@required dynamic error,
@required dynamic stackTrace,
@required String flutterVersion,
@required String getFlutterVersion(),
}) async {
try {
// TODO(yjbanov): we only actually send crash reports in tests. When we
......@@ -86,6 +86,7 @@ class CrashReportSender {
printStatus('Sending crash report to Google.');
final String flutterVersion = getFlutterVersion();
final Uri uri = _baseUri.replace(
queryParameters: <String, String>{
'product': _kProductId,
......
......@@ -59,7 +59,7 @@ class Xcode {
}
/// Returns [Xcode] active in the current app context.
static Xcode get instance => context[Xcode];
static Xcode get instance => context.putIfAbsent(Xcode, () => new Xcode());
bool get isInstalledAndMeetsVersionCheck => isInstalled && xcodeVersionSatisfactory;
......
......@@ -38,7 +38,7 @@ class Usage {
}
/// Returns [Usage] active in the current app context.
static Usage get instance => context[Usage];
static Usage get instance => context.putIfAbsent(Usage, () => new Usage());
Analytics _analytics;
......
......@@ -4,8 +4,11 @@
import 'dart:async';
import 'package:file/local.dart';
import 'package:flutter_tools/executable.dart' as tools;
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/base/io.dart' as io;
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:test/test.dart';
import '../src/common.dart';
......@@ -24,11 +27,11 @@ void testReplay(
bool skip,
}) {
setUp(() {
setExitFunctionForTests();
io.setExitFunctionForTests();
});
tearDown(() {
restoreExitFunction();
io.restoreExitFunction();
});
testUsingContext(
......@@ -55,7 +58,27 @@ void testReplay(
/// '--no-resident',
/// ]
/// ```
void expectProcessExits(List<String> command, {dynamic exitCode: 0}) {
final Future<Null> mainFuture = tools.main(command);
expect(mainFuture, throwsProcessExit(exitCode));
void expectProcessExits(
FlutterCommand command, {
List<String> args: const <String>[],
dynamic exitCode: 0,
}) {
final Future<Null> runFuture = tools.run(
<String>[command.name]..addAll(args),
<FlutterCommand>[command],
reportCrashes: false,
flutterVersion: 'test',
);
expect(runFuture, throwsProcessExit(exitCode));
}
/// The base path of the replay tests.
String get replayBase {
return const LocalFileSystem().path.joinAll(<String>[
Cache.flutterRoot,
'packages',
'flutter_tools',
'test',
'replay',
]);
}
https://storage.googleapis.com/flutter_infra/flutter/fonts/13ac995daa9dda0a6ba0a45f1fccc541e616a74c/fonts.zip
https://storage.googleapis.com/flutter_infra/flutter/fonts/13ac995daa9dda0a6ba0a45f1fccc541e616a74c/fonts.zip
\ No newline at end of file
f9c1f5fa539fdfcbcae65a1dd09d1d05949da459
\ No newline at end of file
f9c1f5fa539fdfcbcae65a1dd09d1d05949da459
\ No newline at end of file
{
"numberOfProcessors": 24,
"pathSeparator": "/",
"operatingSystem": "macos",
"localHostname": "flutter-macpro.flutter.io",
"environment": {
"TERM_PROGRAM": "Apple_Terminal",
"SHELL": "/bin/bash",
"TERM": "xterm-256color",
"CLICOLOR": "1",
"TMPDIR": "/var/folders/n5/klvyv2fj5lj2lhn_61080t0m003g3j/T/",
"Apple_PubSub_Socket_Render": "/private/tmp/com.apple.launchd.U3lCTUziZt/Render",
"TERM_PROGRAM_VERSION": "388",
"TERM_SESSION_ID": "33E2EBBF-8ED6-4E02-BBE3-2A71E5E8675D",
"USER": "flutter",
"FLUTTER_ROOT": "/Users/flutter/project/flutter/flutter",
"SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.pOrPDczlgR/Listeners",
"__CF_USER_TEXT_ENCODING": "0x1BC71:0x0:0x0",
"LSCOLORS": "ExGxFxdaCxDADAadhbheFx",
"PATH": "/Users/flutter/homebrew/bin:/Users/flutter/project/flutter/flutter/bin:/Users/flutter/project/flutter/engine/src/third_party/android_tools/sdk/platform-tools:/Users/flutter/project/flutter/flutter/bin/cache/dart-sdk/bin:/Users/flutter/project/depot_tools:/Users/flutter/bin:/usr/local/git/current/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/X11/bin",
"PWD": "/Users/flutter/project/flutter/flutter/examples/hello_world",
"LANG": "en_US.UTF-8",
"XPC_FLAGS": "0x0",
"XPC_SERVICE_NAME": "0",
"SHLVL": "2",
"HOME": "/Users/flutter",
"LOGNAME": "flutter",
"_": "/Users/flutter/project/flutter/flutter/bin/cache/dart-sdk/bin/dart"
},
"executable": "/Users/flutter/project/flutter/flutter/bin/cache/dart-sdk/bin/dart",
"resolvedExecutable": "/Users/flutter/project/flutter/flutter/bin/cache/dart-sdk/bin/dart",
"script": "file:///Users/flutter/project/flutter/flutter/bin/cache/flutter_tools.snapshot",
"executableArguments": [],
"packageRoot": null,
"packageConfig": null,
"version": "1.23.0-dev.2.0 (Tue Feb 28 07:18:56 2017) on \"macos_x64\""
}
Usage: idevice_id [OPTIONS] [UDID]
Prints device name or a list of attached devices.
The UDID is a 40-digit hexadecimal number of the device
for which the name should be retrieved.
-l, --list list UDID of all attached devices
-d, --debug enable communication debugging
-h, --help prints usage information
Homepage: <http://libimobiledevice.org>
{
"devices" : {
"iOS 10.1" : [
{
"state" : "Booted",
"availability" : "(available)",
"name" : "iPhone 6s",
"udid" : "AA8FFDB0-593A-44E4-A927-8E49A138BDA5"
}
]
}
}
Mar 8 11:59:38 flutter-macpro hello_flutter[60434]: Diagnostic server listening on http://127.0.0.1:64939
Mar 8 11:59:38 flutter-macpro hello_flutter[60434]: Observatory listening on http://127.0.0.1:8100/
[
{
"type": "run",
"body": {
"pid": 60403,
"basename": "000.git.60403",
"command": [
"git",
"rev-parse",
"HEAD"
],
"workingDirectory": "/Users/flutter/project/flutter/flutter",
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60404,
"basename": "001.git.60404",
"command": [
"git",
"rev-parse",
"--abbrev-ref",
"HEAD"
],
"workingDirectory": "/Users/flutter/project/flutter/flutter",
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60405,
"basename": "002.defaults.60405",
"command": [
"/usr/bin/defaults",
"read",
"/Applications/Android Studio.app/Contents/Info",
"CFBundleShortVersionString"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "can_run",
"body": {
"executable": "/Applications/Android Studio.app/Contents/gradle/gradle-2.14.1/bin/gradle",
"result": true
}
},
{
"type": "can_run",
"body": {
"executable": "/Users/flutter/Library/Android/sdk/platform-tools/adb",
"result": true
}
},
{
"type": "run",
"body": {
"pid": 60406,
"basename": "005.xcode-select.60406",
"command": [
"xcode-select",
"--print-path"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60407,
"basename": "006.xcodebuild.60407",
"command": [
"xcodebuild",
"-version"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60408,
"basename": "007.clang.60408",
"command": [
"/usr/bin/xcrun",
"clang"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 1
}
},
{
"type": "run",
"body": {
"pid": 60409,
"basename": "008.adb.60409",
"command": [
"/Users/flutter/Library/Android/sdk/platform-tools/adb",
"devices",
"-l"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60410,
"basename": "009.idevice_id.60410",
"command": [
"idevice_id",
"-h"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60411,
"basename": "010.which.60411",
"command": [
"which",
"idevice_id"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60412,
"basename": "011.idevice_id.60412",
"command": [
"/Users/flutter/homebrew/bin/idevice_id",
"-l"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60413,
"basename": "012.simctl.60413",
"command": [
"/usr/bin/xcrun",
"simctl",
"list",
"--json",
"devices"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60414,
"basename": "013.unzip.60414",
"command": [
"unzip",
"-o",
"-q",
"hello_flutter.ipa",
"-d",
"/var/folders/n5/klvyv2fj5lj2lhn_61080t0m003g3j/T/flutter_app_N0zaZx"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60423,
"basename": "014.defaults.60423",
"command": [
"/usr/bin/defaults",
"read",
"/var/folders/n5/klvyv2fj5lj2lhn_61080t0m003g3j/T/flutter_app_N0zaZx/Payload/hello_flutter.app/Info",
"CFBundleIdentifier"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60424,
"basename": "015.simctl.60424",
"command": [
"/usr/bin/xcrun",
"simctl",
"install",
"AA8FFDB0-593A-44E4-A927-8E49A138BDA5",
"/var/folders/n5/klvyv2fj5lj2lhn_61080t0m003g3j/T/flutter_app_N0zaZx/Payload/hello_flutter.app"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60432,
"basename": "016.tail.60432",
"command": [
"tail",
"-n",
"0",
"-F",
"/Users/flutter/Library/Logs/CoreSimulator/AA8FFDB0-593A-44E4-A927-8E49A138BDA5/system.log"
],
"includeParentEnvironment": true,
"runInShell": false,
"mode": "ProcessStartMode.NORMAL",
"daemon": false,
"notResponding": false,
"exitCode": -15
}
},
{
"type": "run",
"body": {
"pid": 60433,
"basename": "017.simctl.60433",
"command": [
"/usr/bin/xcrun",
"simctl",
"launch",
"AA8FFDB0-593A-44E4-A927-8E49A138BDA5",
"io.flutter.HelloFlutter",
"--enable-dart-profiling",
"--enable-checked-mode",
"--observatory-port=8100",
"--diagnostic-port=8101"
],
"includeParentEnvironment": true,
"runInShell": false,
"stdoutEncoding": "system",
"stderrEncoding": "system",
"daemon": false,
"notResponding": false,
"exitCode": 0
}
},
{
"type": "run",
"body": {
"pid": 60435,
"basename": "018.tail.60435",
"command": [
"tail",
"-n",
"0",
"-F",
"/private/var/log/system.log"
],
"includeParentEnvironment": true,
"runInShell": false,
"mode": "ProcessStartMode.NORMAL",
"daemon": false,
"notResponding": false,
"exitCode": -15
}
}
]
// Copyright 2015 The Chromium 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 'package:flutter_tools/src/commands/run.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import '../common.dart';
void main() {
testReplay('runsWithoutError', () async {
final FileSystem fs = const LocalFileSystem();
final String replay = fs.path.join(replayBase, 'osx', 'simulator_application_binary');
expectProcessExits(
new RunCommand(),
args: <String>[
'--no-hot',
'--no-resident',
'--device-id=iPhone',
'--use-application-binary=hello_flutter.ipa',
'--replay-from=$replay',
],
);
});
}
......@@ -108,26 +108,27 @@ void _printBufferedErrors(AppContext testContext) {
String getFlutterRoot() {
Error invalidScript() => new StateError('Invalid script: ${platform.script}');
String toolsPath;
Uri scriptUri;
switch (platform.script.scheme) {
case 'file':
final List<String> parts = fs.path.split(fs.path.fromUri(platform.script));
final int toolsIndex = parts.indexOf('flutter_tools');
if (toolsIndex == -1)
throw invalidScript();
toolsPath = fs.path.joinAll(parts.sublist(0, toolsIndex + 1));
scriptUri = platform.script;
break;
case 'data':
final RegExp flutterTools = new RegExp(r'(file://[^%]*[/\\]flutter_tools)');
final RegExp flutterTools = new RegExp(r'(file://[^%]*[/\\]flutter_tools[^%]+\.dart)%');
final Match match = flutterTools.firstMatch(platform.script.path);
if (match == null)
throw invalidScript();
toolsPath = Uri.parse(match.group(1)).path;
scriptUri = Uri.parse(match.group(1));
break;
default:
throw invalidScript();
}
final List<String> parts = fs.path.split(fs.path.fromUri(scriptUri));
final int toolsIndex = parts.indexOf('flutter_tools');
if (toolsIndex == -1)
throw invalidScript();
final String toolsPath = fs.path.joinAll(parts.sublist(0, toolsIndex + 1));
return fs.path.normalize(fs.path.join(toolsPath, '..', '..'));
}
......
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