Commit f92f71fe authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Lock flutter tool while updating artifacts (#4476)

This prevents multiple simultaneous runs of the analyzer from stomping
over each other (e.g. multiple runs of 'update-packages'). Certain
long-lived commands (like analyze, run, logs) are exempted once they've
done enough work to be safe from most stomping action.

This still doesn't make us entirely safe from craziness, e.g. if you're
half way through an 'update-packages' run and you call 'git pull', who
knows what state you'll end up in. But there's only so much one can do.

Fixes https://github.com/flutter/flutter/issues/2762
parent d8c52527
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
artifacts/ artifacts/
dart-sdk/ dart-sdk/
pkg/ pkg/
lockfile
...@@ -30,16 +30,22 @@ DART_SDK_PATH="$FLUTTER_ROOT/bin/cache/dart-sdk" ...@@ -30,16 +30,22 @@ DART_SDK_PATH="$FLUTTER_ROOT/bin/cache/dart-sdk"
DART="$DART_SDK_PATH/bin/dart" DART="$DART_SDK_PATH/bin/dart"
REVISION=`(cd "$FLUTTER_ROOT"; git rev-parse HEAD)` (
if [ ! -f "$SNAPSHOT_PATH" ] || [ ! -f "$STAMP_PATH" ] || [ `cat "$STAMP_PATH"` != "$REVISION" ] || [ "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock" ]; then if hash flock 2>/dev/null; then
"$FLUTTER_ROOT/bin/cache/update_dart_sdk.sh" flock 3 # ensures that we don't simultaneously update Dart in multiple parallel instances
# some platforms (e.g. Mac) don't have flock or any reliable alternative
echo Building flutter tool... fi
FLUTTER_DIR="$FLUTTER_ROOT/packages/flutter" REVISION=`(cd "$FLUTTER_ROOT"; git rev-parse HEAD)`
(cd "$FLUTTER_TOOLS_DIR"; "../../bin/cache/dart-sdk/bin/pub" get --verbosity=warning) if [ ! -f "$SNAPSHOT_PATH" ] || [ ! -f "$STAMP_PATH" ] || [ `cat "$STAMP_PATH"` != "$REVISION" ] || [ "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock" ]; then
"$DART" --snapshot="$SNAPSHOT_PATH" --packages="$FLUTTER_TOOLS_DIR/.packages" "$SCRIPT_PATH" "$FLUTTER_ROOT/bin/cache/update_dart_sdk.sh"
echo $REVISION > "$STAMP_PATH"
fi echo Building flutter tool...
FLUTTER_DIR="$FLUTTER_ROOT/packages/flutter"
(cd "$FLUTTER_TOOLS_DIR"; "../../bin/cache/dart-sdk/bin/pub" get --verbosity=warning)
"$DART" --snapshot="$SNAPSHOT_PATH" --packages="$FLUTTER_TOOLS_DIR/.packages" "$SCRIPT_PATH"
echo $REVISION > "$STAMP_PATH"
fi
) 3< $PROG_NAME
if [ $FLUTTER_DEV ]; then if [ $FLUTTER_DEV ]; then
"$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" -c "$SCRIPT_PATH" "$@" "$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" -c "$SCRIPT_PATH" "$@"
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test: The following assertion was thrown running a test:
Guarded function conflict\. You must use "await" with all Future-returning test APIs\. Guarded function conflict\. You must use "await" with all Future-returning test APIs\.
The guarded "guardedHelper" function was called from .*dev/manual_tests/test_data/test_async_utils_guarded_test\.dart on line [0-9]+\. The guarded "guardedHelper" function was called from .*dev/automated_tests/flutter_test/test_async_utils_guarded_test\.dart on line [0-9]+\.
Then, the "expect" function was called from .*dev/manual_tests/test_data/test_async_utils_guarded_test\.dart on line [0-9]+\. Then, the "expect" function was called from .*dev/automated_tests/flutter_test/test_async_utils_guarded_test\.dart on line [0-9]+\.
The first function \(guardedHelper\) had not yet finished executing at the time that the second function \(expect\) was called\. Since both are guarded, and the second was not a nested call inside the first, the first must complete its execution before the second can be called\. Typically, this is achieved by putting an "await" statement in front of the call to the first\. The first function \(guardedHelper\) had not yet finished executing at the time that the second function \(expect\) was called\. Since both are guarded, and the second was not a nested call inside the first, the first must complete its execution before the second can be called\. Typically, this is achieved by putting an "await" statement in front of the call to the first\.
If you are confident that all test APIs are being called using "await", and this expect\(\) call is not being invoked at the top level but is itself being called from some sort of callback registered before the guardedHelper method was called, then consider using expectSync\(\) instead\. If you are confident that all test APIs are being called using "await", and this expect\(\) call is not being called at the top level but is itself being called from some sort of callback registered before the guardedHelper method was called, then consider using expectSync\(\) instead\.
When the first function \(guardedHelper\) was called, this was the stack: When the first function \(guardedHelper\) was called, this was the stack:
<<skip until matching line>> <<skip until matching line>>
...@@ -14,6 +14,8 @@ When the first function \(guardedHelper\) was called, this was the stack: ...@@ -14,6 +14,8 @@ When the first function \(guardedHelper\) was called, this was the stack:
When the exception was thrown, this was the stack: When the exception was thrown, this was the stack:
<<skip until matching line>> <<skip until matching line>>
\(elided .+\) \(elided .+\)
════════════════════════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════════════════════════
.*(this line has more of the test framework's output)? .*(this line has more of the test framework's output)?
Test failed\. See exception logs above\. Test failed\. See exception logs above\.
......
.*..:.. \+0: - TestAsyncUtils - handling unguarded async helper functions * .*(this line contains the test framework's output with the clock and so forth)?
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test: The following assertion was thrown running a test:
Guarded function conflict\. You must use "await" with all Future-returning test APIs\. Guarded function conflict\. You must use "await" with all Future-returning test APIs\.
The guarded method "pump" from class WidgetTester was called from .*dev/flutter/dev/manual_tests/test_data/test_async_utils_unguarded_test.dart on line [0-9]+\. The guarded method "pump" from class WidgetTester was called from .*dev/automated_tests/flutter_test/test_async_utils_unguarded_test.dart on line [0-9]+\.
Then, it was called again from .*dev/manual_tests/test_data/test_async_utils_unguarded_test.dart on line [0-9]+\. Then, it was called again from .*dev/automated_tests/flutter_test/test_async_utils_unguarded_test.dart on line [0-9]+\.
The first method had not yet finished executing at the time that the second method was called\. Since both are guarded, and the second was not a nested call inside the first, the first must complete its execution before the second can be called\. Typically, this is achieved by putting an "await" statement in front of the call to the first\. The first method had not yet finished executing at the time that the second method was called\. Since both are guarded, and the second was not a nested call inside the first, the first must complete its execution before the second can be called\. Typically, this is achieved by putting an "await" statement in front of the call to the first\.
When the first method was called, this was the stack: When the first method was called, this was the stack:
...@@ -13,6 +13,8 @@ When the first method was called, this was the stack: ...@@ -13,6 +13,8 @@ When the first method was called, this was the stack:
When the exception was thrown, this was the stack: When the exception was thrown, this was the stack:
<<skip until matching line>> <<skip until matching line>>
(elided [0-9]+ frames from .+) (elided [0-9]+ frames from .+)
════════════════════════════════════════════════════════════════════════════════════════════════════ ════════════════════════════════════════════════════════════════════════════════════════════════════
.*..:.. \+0 -1: - TestAsyncUtils - handling unguarded async helper functions * .*..:.. \+0 -1: - TestAsyncUtils - handling unguarded async helper functions *
Test failed. See exception logs above. Test failed. See exception logs above.
......
...@@ -24,6 +24,54 @@ class Cache { ...@@ -24,6 +24,54 @@ class Cache {
// Initialized by FlutterCommandRunner on startup. // Initialized by FlutterCommandRunner on startup.
static String flutterRoot; static String flutterRoot;
static RandomAccessFile _lock;
static bool _lockEnabled = true;
/// Turn off the [lock]/[releaseLockEarly] mechanism.
///
/// This is used by the tests since they run simultaneously and all in one
/// process and so it would be a mess if they had to use the lock.
static void disableLocking() {
_lockEnabled = false;
}
/// Lock the cache directory.
///
/// This happens automatically on startup (see [FlutterCommandRunner.runCommand]).
///
/// Normally the lock will be held until the process exits (this uses normal
/// POSIX flock semantics). Long-lived commands should release the lock by
/// calling [Cache.releaseLockEarly] once they are no longer touching the cache.
static Future<Null> lock() async {
if (!_lockEnabled)
return null;
assert(_lock == null);
_lock = new File(path.join(flutterRoot, 'bin', 'cache', 'lockfile')).openSync(mode: FileMode.WRITE);
bool locked = false;
bool printed = false;
while (!locked) {
try {
await _lock.lock();
locked = true;
} on FileSystemException {
if (!printed) {
printStatus('Waiting to be able to obtain lock of Flutter cache directory...');
printed = true;
}
await new Future/*<Null>*/.delayed(const Duration(milliseconds: 50));
}
}
}
/// Releases the lock. This is not necessary unless the process is long-lived.
static void releaseLockEarly() {
if (!_lockEnabled)
return;
assert(_lock != null);
_lock.closeSync();
_lock = null;
}
static String _engineRevision; static String _engineRevision;
static String get engineRevision { static String get engineRevision {
......
...@@ -190,6 +190,8 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -190,6 +190,8 @@ class AnalyzeCommand extends FlutterCommand {
packages['sky_services'] = path.join(tools.engineBuildPath, 'gen/dart-pkg/sky_services/lib'); packages['sky_services'] = path.join(tools.engineBuildPath, 'gen/dart-pkg/sky_services/lib');
} }
Cache.releaseLockEarly();
if (argResults['preamble']) { if (argResults['preamble']) {
if (dartFiles.length == 1) { if (dartFiles.length == 1) {
logger.printStatus('Analyzing ${path.relative(dartFiles.first.path)}...'); logger.printStatus('Analyzing ${path.relative(dartFiles.first.path)}...');
...@@ -316,6 +318,8 @@ class AnalyzeCommand extends FlutterCommand { ...@@ -316,6 +318,8 @@ class AnalyzeCommand extends FlutterCommand {
server.onAnalyzing.listen((bool isAnalyzing) => _handleAnalysisStatus(server, isAnalyzing)); server.onAnalyzing.listen((bool isAnalyzing) => _handleAnalysisStatus(server, isAnalyzing));
server.onErrors.listen(_handleAnalysisErrors); server.onErrors.listen(_handleAnalysisErrors);
Cache.releaseLockEarly();
await server.start(); await server.start();
final int exitCode = await server.onExit; final int exitCode = await server.onExit;
......
...@@ -10,6 +10,7 @@ import '../android/android_device.dart'; ...@@ -10,6 +10,7 @@ import '../android/android_device.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart'; import '../globals.dart';
import '../ios/devices.dart'; import '../ios/devices.dart';
...@@ -48,6 +49,8 @@ class DaemonCommand extends FlutterCommand { ...@@ -48,6 +49,8 @@ class DaemonCommand extends FlutterCommand {
NotifyingLogger notifyingLogger = new NotifyingLogger(); NotifyingLogger notifyingLogger = new NotifyingLogger();
appContext[Logger] = notifyingLogger; appContext[Logger] = notifyingLogger;
Cache.releaseLockEarly();
return appContext.runInZone(() { return appContext.runInZone(() {
Stream<Map<String, dynamic>> commandStream = stdin Stream<Map<String, dynamic>> commandStream = stdin
.transform(UTF8.decoder) .transform(UTF8.decoder)
......
...@@ -16,6 +16,7 @@ import '../base/logger.dart'; ...@@ -16,6 +16,7 @@ import '../base/logger.dart';
import '../base/os.dart'; import '../base/os.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart';
import '../dart/sdk.dart'; import '../dart/sdk.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart'; import '../globals.dart';
...@@ -135,6 +136,8 @@ class DriveCommand extends RunCommandBase { ...@@ -135,6 +136,8 @@ class DriveCommand extends RunCommandBase {
status.stop(showElapsedTime: true); status.stop(showElapsedTime: true);
} }
Cache.releaseLockEarly();
try { try {
return await testRunner(<String>[testFile]) return await testRunner(<String>[testFile])
.catchError((dynamic error, dynamic stackTrace) { .catchError((dynamic error, dynamic stackTrace) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:async'; import 'dart:async';
import '../application_package.dart'; import '../application_package.dart';
import '../cache.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart'; import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -24,6 +25,8 @@ class InstallCommand extends FlutterCommand { ...@@ -24,6 +25,8 @@ class InstallCommand extends FlutterCommand {
Device device = deviceForCommand; Device device = deviceForCommand;
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform); ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
Cache.releaseLockEarly();
printStatus('Installing $package to $device...'); printStatus('Installing $package to $device...');
return installApp(device, package) ? 0 : 2; return installApp(device, package) ? 0 : 2;
......
...@@ -7,6 +7,7 @@ import 'dart:io'; ...@@ -7,6 +7,7 @@ import 'dart:io';
import '../base/os.dart'; import '../base/os.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../cache.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart'; import '../globals.dart';
import 'run.dart'; import 'run.dart';
...@@ -44,6 +45,8 @@ class ListenCommand extends RunCommandBase { ...@@ -44,6 +45,8 @@ class ListenCommand extends RunCommandBase {
if (watchCommand == null) if (watchCommand == null)
return 1; return 1;
Cache.releaseLockEarly();
printStatus('Listening for changes in ' printStatus('Listening for changes in '
'${directories.map((String name) => "'$name${Platform.pathSeparator}'").join(', ')}' '${directories.map((String name) => "'$name${Platform.pathSeparator}'").join(', ')}'
'.'); '.');
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import '../cache.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart'; import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -39,6 +40,8 @@ class LogsCommand extends FlutterCommand { ...@@ -39,6 +40,8 @@ class LogsCommand extends FlutterCommand {
DeviceLogReader logReader = device.logReader; DeviceLogReader logReader = device.logReader;
Cache.releaseLockEarly();
printStatus('Showing $logReader logs:'); printStatus('Showing $logReader logs:');
Completer<int> exitCompleter = new Completer<int>(); Completer<int> exitCompleter = new Completer<int>();
......
...@@ -9,6 +9,7 @@ import 'package:path/path.dart' as path; ...@@ -9,6 +9,7 @@ import 'package:path/path.dart' as path;
import '../android/android_device.dart'; import '../android/android_device.dart';
import '../application_package.dart'; import '../application_package.dart';
import '../cache.dart';
import '../flx.dart'; import '../flx.dart';
import '../globals.dart'; import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -46,6 +47,8 @@ class RefreshCommand extends FlutterCommand { ...@@ -46,6 +47,8 @@ class RefreshCommand extends FlutterCommand {
return result; return result;
} }
Cache.releaseLockEarly();
AndroidDevice device = deviceForCommand; AndroidDevice device = deviceForCommand;
String activity = argResults['activity']; String activity = argResults['activity'];
......
...@@ -9,6 +9,7 @@ import '../application_package.dart'; ...@@ -9,6 +9,7 @@ import '../application_package.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart'; import '../globals.dart';
import '../observatory.dart'; import '../observatory.dart';
...@@ -109,6 +110,8 @@ class RunCommand extends RunCommandBase { ...@@ -109,6 +110,8 @@ class RunCommand extends RunCommandBase {
); );
} }
Cache.releaseLockEarly();
if (argResults['resident']) { if (argResults['resident']) {
RunAndStayResident runner = new RunAndStayResident( RunAndStayResident runner = new RunAndStayResident(
deviceForCommand, deviceForCommand,
......
...@@ -9,6 +9,7 @@ import 'package:path/path.dart' as path; ...@@ -9,6 +9,7 @@ import 'package:path/path.dart' as path;
import '../base/process.dart'; import '../base/process.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart';
import '../flx.dart' as flx; import '../flx.dart' as flx;
import '../globals.dart'; import '../globals.dart';
import '../run.dart'; import '../run.dart';
...@@ -151,6 +152,8 @@ class RunMojoCommand extends FlutterCommand { ...@@ -151,6 +152,8 @@ class RunMojoCommand extends FlutterCommand {
return result; return result;
} }
Cache.releaseLockEarly();
return await runCommandAndStreamOutput(await _getShellConfig(targetApp)); return await runCommandAndStreamOutput(await _getShellConfig(targetApp));
} }
} }
...@@ -9,6 +9,7 @@ import 'package:path/path.dart' as path; ...@@ -9,6 +9,7 @@ import 'package:path/path.dart' as path;
import 'package:test/src/executable.dart' as executable; // ignore: implementation_imports import 'package:test/src/executable.dart' as executable; // ignore: implementation_imports
import '../base/logger.dart'; import '../base/logger.dart';
import '../cache.dart';
import '../dart/package_map.dart'; import '../dart/package_map.dart';
import '../globals.dart'; import '../globals.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -101,6 +102,9 @@ class TestCommand extends FlutterCommand { ...@@ -101,6 +102,9 @@ class TestCommand extends FlutterCommand {
printError('Cannot find Flutter shell at ${loader.shellPath}'); printError('Cannot find Flutter shell at ${loader.shellPath}');
return 1; return 1;
} }
Cache.releaseLockEarly();
return await _runTests(testArgs, testDir); return await _runTests(testArgs, testDir);
} }
} }
...@@ -8,6 +8,7 @@ import 'dart:io'; ...@@ -8,6 +8,7 @@ import 'dart:io';
import '../base/common.dart'; import '../base/common.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../cache.dart';
import '../globals.dart'; import '../globals.dart';
import '../observatory.dart'; import '../observatory.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
...@@ -57,6 +58,8 @@ class TraceCommand extends FlutterCommand { ...@@ -57,6 +58,8 @@ class TraceCommand extends FlutterCommand {
return 1; return 1;
} }
Cache.releaseLockEarly();
if ((!argResults['start'] && !argResults['stop']) || if ((!argResults['start'] && !argResults['stop']) ||
(argResults['start'] && argResults['stop'])) { (argResults['start'] && argResults['stop'])) {
// Setting neither flags or both flags means do both commands and wait // Setting neither flags or both flags means do both commands and wait
......
...@@ -128,7 +128,7 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -128,7 +128,7 @@ class FlutterCommandRunner extends CommandRunner {
} }
@override @override
Future<int> runCommand(ArgResults globalResults) { Future<int> runCommand(ArgResults globalResults) async {
// Check for verbose. // Check for verbose.
if (globalResults['verbose']) if (globalResults['verbose'])
context[Logger] = new VerboseLogger(); context[Logger] = new VerboseLogger();
...@@ -142,11 +142,13 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -142,11 +142,13 @@ class FlutterCommandRunner extends CommandRunner {
// enginePath's initialiser uses it). // enginePath's initialiser uses it).
Cache.flutterRoot = path.normalize(path.absolute(globalResults['flutter-root'])); Cache.flutterRoot = path.normalize(path.absolute(globalResults['flutter-root']));
await Cache.lock();
if (globalResults['suppress-analytics']) if (globalResults['suppress-analytics'])
flutterUsage.suppressAnalytics = true; flutterUsage.suppressAnalytics = true;
if (!_checkFlutterCopy()) if (!_checkFlutterCopy())
return new Future<int>.value(1); return 1;
if (globalResults.wasParsed('packages')) if (globalResults.wasParsed('packages'))
PackageMap.globalPackagesPath = path.normalize(path.absolute(globalResults['packages'])); PackageMap.globalPackagesPath = path.normalize(path.absolute(globalResults['packages']));
...@@ -173,10 +175,10 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -173,10 +175,10 @@ class FlutterCommandRunner extends CommandRunner {
if (globalResults['version']) { if (globalResults['version']) {
flutterUsage.sendCommand('version'); flutterUsage.sendCommand('version');
printStatus(FlutterVersion.getVersion(Cache.flutterRoot).toString()); printStatus(FlutterVersion.getVersion(Cache.flutterRoot).toString());
return new Future<int>.value(0); return 0;
} }
return super.runCommand(globalResults); return await super.runCommand(globalResults);
} }
String _tryEnginePath(String enginePath) { String _tryEnginePath(String enginePath) {
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
// doesn't support running without symlinks. We can delete these files once that // doesn't support running without symlinks. We can delete these files once that
// fix lands. // fix lands.
import 'package:flutter_tools/src/cache.dart';
import 'adb_test.dart' as adb_test; import 'adb_test.dart' as adb_test;
import 'analytics_test.dart' as analytics_test; import 'analytics_test.dart' as analytics_test;
import 'analyze_duplicate_names_test.dart' as analyze_duplicate_names_test; import 'analyze_duplicate_names_test.dart' as analyze_duplicate_names_test;
...@@ -18,6 +20,7 @@ import 'context_test.dart' as context_test; ...@@ -18,6 +20,7 @@ import 'context_test.dart' as context_test;
import 'create_test.dart' as create_test; import 'create_test.dart' as create_test;
import 'daemon_test.dart' as daemon_test; import 'daemon_test.dart' as daemon_test;
import 'device_test.dart' as device_test; import 'device_test.dart' as device_test;
// import 'devices_test.dart' as devices_test;
import 'drive_test.dart' as drive_test; import 'drive_test.dart' as drive_test;
import 'install_test.dart' as install_test; import 'install_test.dart' as install_test;
import 'listen_test.dart' as listen_test; import 'listen_test.dart' as listen_test;
...@@ -26,11 +29,13 @@ import 'os_utils_test.dart' as os_utils_test; ...@@ -26,11 +29,13 @@ import 'os_utils_test.dart' as os_utils_test;
import 'protocol_discovery_test.dart' as protocol_discovery_test; import 'protocol_discovery_test.dart' as protocol_discovery_test;
import 'run_test.dart' as run_test; import 'run_test.dart' as run_test;
import 'stop_test.dart' as stop_test; import 'stop_test.dart' as stop_test;
import 'test_test.dart' as test_test;
import 'toolchain_test.dart' as toolchain_test; import 'toolchain_test.dart' as toolchain_test;
import 'trace_test.dart' as trace_test; import 'trace_test.dart' as trace_test;
import 'upgrade_test.dart' as upgrade_test; import 'upgrade_test.dart' as upgrade_test;
void main() { void main() {
Cache.disableLocking();
adb_test.main(); adb_test.main();
analytics_test.main(); analytics_test.main();
analyze_duplicate_names_test.main(); analyze_duplicate_names_test.main();
...@@ -42,6 +47,7 @@ void main() { ...@@ -42,6 +47,7 @@ void main() {
create_test.main(); create_test.main();
daemon_test.main(); daemon_test.main();
device_test.main(); device_test.main();
// devices_test.main(); // https://github.com/flutter/flutter/issues/4480
drive_test.main(); drive_test.main();
install_test.main(); install_test.main();
listen_test.main(); listen_test.main();
...@@ -50,6 +56,7 @@ void main() { ...@@ -50,6 +56,7 @@ void main() {
protocol_discovery_test.main(); protocol_discovery_test.main();
run_test.main(); run_test.main();
stop_test.main(); stop_test.main();
test_test.main();
toolchain_test.main(); toolchain_test.main();
trace_test.main(); trace_test.main();
upgrade_test.main(); upgrade_test.main();
......
...@@ -18,16 +18,16 @@ void main() { ...@@ -18,16 +18,16 @@ void main() {
group('test', () { group('test', () {
testUsingContext('TestAsyncUtils guarded function test', () async { testUsingContext('TestAsyncUtils guarded function test', () async {
Cache.flutterRoot = '../..'; Cache.flutterRoot = '../..';
return _testFile('test_async_utils_guarded'); return _testFile('test_async_utils_guarded', 1);
}); });
testUsingContext('TestAsyncUtils unguarded function test', () async { testUsingContext('TestAsyncUtils unguarded function test', () async {
Cache.flutterRoot = '../..'; Cache.flutterRoot = '../..';
return _testFile('test_async_utils_unguarded'); return _testFile('test_async_utils_unguarded', 1);
}); });
}, timeout: new Timeout(const Duration(seconds: 5))); }, timeout: new Timeout(const Duration(seconds: 5)));
} }
Future<Null> _testFile(String testName) async { Future<Null> _testFile(String testName, int wantedExitCode) async {
final String manualTestsDirectory = path.join('..', '..', 'dev', 'automated_tests'); final String manualTestsDirectory = path.join('..', '..', 'dev', 'automated_tests');
final String fullTestName = path.join(manualTestsDirectory, 'flutter_test', '${testName}_test.dart'); final String fullTestName = path.join(manualTestsDirectory, 'flutter_test', '${testName}_test.dart');
final File testFile = new File(fullTestName); final File testFile = new File(fullTestName);
...@@ -40,11 +40,12 @@ Future<Null> _testFile(String testName) async { ...@@ -40,11 +40,12 @@ Future<Null> _testFile(String testName) async {
<String>[ <String>[
path.absolute(path.join('bin', 'flutter_tools.dart')), path.absolute(path.join('bin', 'flutter_tools.dart')),
'test', 'test',
'--no-color',
fullTestName fullTestName
], ],
workingDirectory: manualTestsDirectory workingDirectory: manualTestsDirectory
); );
expect(exec.exitCode, 0); expect(exec.exitCode, wantedExitCode);
final List<String> output = exec.stdout.split('\n'); final List<String> output = exec.stdout.split('\n');
final List<String> expectations = new File(fullTestExpectation).readAsLinesSync(); final List<String> expectations = new File(fullTestExpectation).readAsLinesSync();
bool allowSkip = false; bool allowSkip = false;
......
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