mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Record/replay test infrastructure. (#8597)
This adds the test harness for record/replay tests.
This commit is contained in:
parent
5e2d3e956a
commit
3d079414ad
|
@ -146,8 +146,8 @@ Future<int> run(List<String> args, List<FlutterCommand> subCommands, {
|
||||||
await _exit(0);
|
await _exit(0);
|
||||||
runCompleter.complete(0);
|
runCompleter.complete(0);
|
||||||
}, onError: (dynamic error, Chain chain) {
|
}, onError: (dynamic error, Chain chain) {
|
||||||
flutterVersion ??= FlutterVersion.getVersionString();
|
String getVersion() => flutterVersion ?? FlutterVersion.getVersionString();
|
||||||
_handleToolError(error, chain, verbose, args, reportCrashes, flutterVersion)
|
_handleToolError(error, chain, verbose, args, reportCrashes, getVersion)
|
||||||
.then(runCompleter.complete, onError: runCompleter.completeError);
|
.then(runCompleter.complete, onError: runCompleter.completeError);
|
||||||
});
|
});
|
||||||
return runCompleter.future;
|
return runCompleter.future;
|
||||||
|
@ -160,7 +160,7 @@ Future<int> _handleToolError(
|
||||||
bool verbose,
|
bool verbose,
|
||||||
List<String> args,
|
List<String> args,
|
||||||
bool reportCrashes,
|
bool reportCrashes,
|
||||||
String flutterVersion,
|
String getFlutterVersion(),
|
||||||
) async {
|
) async {
|
||||||
if (error is UsageException) {
|
if (error is UsageException) {
|
||||||
stderr.writeln(error.message);
|
stderr.writeln(error.message);
|
||||||
|
@ -208,7 +208,7 @@ Future<int> _handleToolError(
|
||||||
await CrashReportSender.instance.sendReport(
|
await CrashReportSender.instance.sendReport(
|
||||||
error: error,
|
error: error,
|
||||||
stackTrace: chain,
|
stackTrace: chain,
|
||||||
flutterVersion: flutterVersion,
|
flutterVersion: getFlutterVersion(),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
final File file = await _createLocalCrashReport(args, error, chain);
|
final File file = await _createLocalCrashReport(args, error, chain);
|
||||||
|
|
|
@ -166,6 +166,13 @@ class BufferLogger extends Logger {
|
||||||
printStatus(message);
|
printStatus(message);
|
||||||
return new Status();
|
return new Status();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clears all buffers.
|
||||||
|
void clear() {
|
||||||
|
_error.clear();
|
||||||
|
_status.clear();
|
||||||
|
_trace.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VerboseLogger extends Logger {
|
class VerboseLogger extends Logger {
|
||||||
|
|
61
packages/flutter_tools/test/replay/common.dart
Normal file
61
packages/flutter_tools/test/replay/common.dart
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// 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 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter_tools/executable.dart' as tools;
|
||||||
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import '../src/common.dart';
|
||||||
|
import '../src/context.dart';
|
||||||
|
|
||||||
|
/// Runs the specified [testMethod] in a minimal `AppContext` that is set up
|
||||||
|
/// to redirect log output to a `BufferLogger` to avoid spamming `stdout`.
|
||||||
|
///
|
||||||
|
/// Test methods will generally want to use [expectProcessExits] in their method
|
||||||
|
/// bodies.
|
||||||
|
void testReplay(
|
||||||
|
String description,
|
||||||
|
dynamic testMethod(), {
|
||||||
|
Timeout timeout,
|
||||||
|
Map<Type, Generator> overrides: const <Type, Generator>{},
|
||||||
|
bool skip,
|
||||||
|
}) {
|
||||||
|
setUp(() {
|
||||||
|
setExitFunctionForTests();
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() {
|
||||||
|
restoreExitFunction();
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext(
|
||||||
|
description,
|
||||||
|
testMethod,
|
||||||
|
timeout: timeout,
|
||||||
|
overrides: overrides,
|
||||||
|
skip: skip,
|
||||||
|
initializeContext: (_) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Expects that the specified [command] to Flutter tools exits with the
|
||||||
|
/// specified [exitCode] (defaults to zero). It is expected that callers will
|
||||||
|
/// be running in a test via [testReplay].
|
||||||
|
///
|
||||||
|
/// [command] should be the list of arguments that are passed to the `flutter`
|
||||||
|
/// command-line tool. For example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// <String>[
|
||||||
|
/// 'run',
|
||||||
|
/// '--no-hot',
|
||||||
|
/// '--no-resident',
|
||||||
|
/// ]
|
||||||
|
/// ```
|
||||||
|
void expectProcessExits(List<String> command, {dynamic exitCode: 0}) {
|
||||||
|
final Future<Null> mainFuture = tools.main(command);
|
||||||
|
expect(mainFuture, throwsProcessExit(exitCode));
|
||||||
|
}
|
|
@ -74,7 +74,7 @@ void testUsingContext(String description, dynamic testMethod(), {
|
||||||
final String flutterRoot = getFlutterRoot();
|
final String flutterRoot = getFlutterRoot();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await testContext.runInZone(() {
|
return await testContext.runInZone(() async {
|
||||||
// Apply the overrides to the test context in the zone since their
|
// Apply the overrides to the test context in the zone since their
|
||||||
// instantiation may reference items already stored on the context.
|
// instantiation may reference items already stored on the context.
|
||||||
overrides.forEach((Type type, dynamic value()) {
|
overrides.forEach((Type type, dynamic value()) {
|
||||||
|
@ -83,23 +83,28 @@ void testUsingContext(String description, dynamic testMethod(), {
|
||||||
// Provide a sane default for the flutterRoot directory. Individual
|
// Provide a sane default for the flutterRoot directory. Individual
|
||||||
// tests can override this.
|
// tests can override this.
|
||||||
Cache.flutterRoot = flutterRoot;
|
Cache.flutterRoot = flutterRoot;
|
||||||
return testMethod();
|
return await testMethod();
|
||||||
|
}, onError: (dynamic error, StackTrace stackTrace) {
|
||||||
|
_printBufferedErrors(testContext);
|
||||||
|
throw error;
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (testContext[Logger] is BufferLogger) {
|
_printBufferedErrors(testContext);
|
||||||
final BufferLogger bufferLogger = testContext[Logger];
|
|
||||||
if (bufferLogger.errorText.isNotEmpty)
|
|
||||||
print(bufferLogger.errorText);
|
|
||||||
}
|
|
||||||
// Previously the following line read "throw error;". This is bad because
|
|
||||||
// it drops the error's actual stacktrace. Use 'rethrow' to preserve
|
|
||||||
// the stacktrace.
|
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
}, timeout: timeout, skip: skip);
|
}, timeout: timeout, skip: skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _printBufferedErrors(AppContext testContext) {
|
||||||
|
if (testContext[Logger] is BufferLogger) {
|
||||||
|
final BufferLogger bufferLogger = testContext[Logger];
|
||||||
|
if (bufferLogger.errorText.isNotEmpty)
|
||||||
|
print(bufferLogger.errorText);
|
||||||
|
bufferLogger.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String getFlutterRoot() {
|
String getFlutterRoot() {
|
||||||
Error invalidScript() => new StateError('Invalid script: ${platform.script}');
|
Error invalidScript() => new StateError('Invalid script: ${platform.script}');
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue