f40b06a8ac
Processes on Windows can take longer to exit, taking longer for directories they use to become available for deletion. Accommodate this potentially lengthy by trying several times to delete temp directories before failing the test. Fixes https://github.com/dart-lang/sdk/issues/47700 TEST=run_test on Windows Change-Id: Id73d6ba3ff981ed59c89ab833f5775eff5375ae6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/226980 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Alexander Aprelev <aam@google.com>
186 lines
5.0 KiB
Dart
186 lines
5.0 KiB
Dart
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
|
// for details. 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:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:pub_semver/pub_semver.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
/// A long [Timeout] is provided for tests that start a process on
|
|
/// `bin/dartdev.dart` as the command is not compiled ahead of time, and each
|
|
/// invocation requires the VM to compile the entire dependency graph.
|
|
const Timeout longTimeout = Timeout(Duration(minutes: 5));
|
|
|
|
/// This version of dart is the last guaranteed pre-null safety language
|
|
/// version:
|
|
const String dartVersionFilePrefix2_9 = '// @dart = 2.9\n';
|
|
|
|
TestProject project(
|
|
{String mainSrc,
|
|
String analysisOptions,
|
|
bool logAnalytics = false,
|
|
String name = TestProject._defaultProjectName,
|
|
VersionConstraint sdkConstraint,
|
|
Map<String, dynamic> pubspec}) =>
|
|
TestProject(
|
|
mainSrc: mainSrc,
|
|
analysisOptions: analysisOptions,
|
|
logAnalytics: logAnalytics,
|
|
sdkConstraint: sdkConstraint,
|
|
pubspec: pubspec);
|
|
|
|
class TestProject {
|
|
static const String _defaultProjectName = 'dartdev_temp';
|
|
|
|
Directory dir;
|
|
|
|
String get dirPath => dir.path;
|
|
|
|
String get mainPath => path.join(dirPath, relativeFilePath);
|
|
|
|
final String name;
|
|
|
|
String get relativeFilePath => 'lib/main.dart';
|
|
|
|
final bool logAnalytics;
|
|
|
|
final VersionConstraint sdkConstraint;
|
|
|
|
final Map<String, dynamic> pubspec;
|
|
|
|
Process _process;
|
|
|
|
TestProject(
|
|
{String mainSrc,
|
|
String analysisOptions,
|
|
this.name = _defaultProjectName,
|
|
this.logAnalytics = false,
|
|
this.sdkConstraint,
|
|
this.pubspec}) {
|
|
dir = Directory.systemTemp.createTempSync('a');
|
|
file(
|
|
'pubspec.yaml',
|
|
pubspec == null
|
|
? '''
|
|
name: $name
|
|
environment:
|
|
sdk: '${sdkConstraint ?? '>=2.10.0 <3.0.0'}'
|
|
|
|
dev_dependencies:
|
|
test: any
|
|
'''
|
|
: json.encode(pubspec));
|
|
if (analysisOptions != null) {
|
|
file('analysis_options.yaml', analysisOptions);
|
|
}
|
|
if (mainSrc != null) {
|
|
file(relativeFilePath, mainSrc);
|
|
}
|
|
}
|
|
|
|
void file(String name, String contents) {
|
|
var file = File(path.join(dir.path, name));
|
|
file.parent.createSync();
|
|
file.writeAsStringSync(contents);
|
|
}
|
|
|
|
void deleteFile(String name) {
|
|
var file = File(path.join(dir.path, name));
|
|
assert(file.existsSync());
|
|
file.deleteSync();
|
|
}
|
|
|
|
Future<void> dispose() async {
|
|
_process?.kill();
|
|
await _process?.exitCode;
|
|
_process = null;
|
|
int deleteAttempts = 5;
|
|
while (dir.existsSync()) {
|
|
try {
|
|
dir.deleteSync(recursive: true);
|
|
} catch (e) {
|
|
if ((--deleteAttempts) <= 0) {
|
|
rethrow;
|
|
}
|
|
await Future.delayed(Duration(milliseconds: 500));
|
|
print('Got $e while deleting $dir. Trying again...');
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<ProcessResult> run(
|
|
List<String> arguments, {
|
|
String workingDir,
|
|
}) async {
|
|
_process = await Process.start(
|
|
Platform.resolvedExecutable,
|
|
[
|
|
'--no-analytics',
|
|
...arguments,
|
|
],
|
|
workingDirectory: workingDir ?? dir.path,
|
|
environment: {if (logAnalytics) '_DARTDEV_LOG_ANALYTICS': 'true'});
|
|
final stdoutContents = _process.stdout.transform(utf8.decoder).join();
|
|
final stderrContents = _process.stderr.transform(utf8.decoder).join();
|
|
final code = await _process.exitCode;
|
|
return ProcessResult(
|
|
_process.pid,
|
|
code,
|
|
await stdoutContents,
|
|
await stderrContents,
|
|
);
|
|
}
|
|
|
|
Future<Process> start(
|
|
List<String> arguments, {
|
|
String workingDir,
|
|
}) {
|
|
return Process.start(
|
|
Platform.resolvedExecutable,
|
|
[
|
|
'--no-analytics',
|
|
...arguments,
|
|
],
|
|
workingDirectory: workingDir ?? dir.path,
|
|
environment: {if (logAnalytics) '_DARTDEV_LOG_ANALYTICS': 'true'})
|
|
..then((p) => _process = p);
|
|
}
|
|
|
|
String _sdkRootPath;
|
|
|
|
/// Return the root of the SDK.
|
|
String get sdkRootPath {
|
|
if (_sdkRootPath == null) {
|
|
// Assumes the script importing this one is somewhere under the SDK.
|
|
String current = path.canonicalize(Platform.script.toFilePath());
|
|
do {
|
|
String tryDir = path.dirname(current);
|
|
if (File(path.join(tryDir, 'pkg', 'dartdev', 'bin', 'dartdev.dart'))
|
|
.existsSync()) {
|
|
_sdkRootPath = tryDir;
|
|
return _sdkRootPath;
|
|
}
|
|
current = tryDir;
|
|
} while (path.dirname(current) != current);
|
|
throw StateError('can not find SDK repository root');
|
|
}
|
|
return _sdkRootPath;
|
|
}
|
|
|
|
String get absolutePathToDartdevFile =>
|
|
path.join(sdkRootPath, 'pkg', 'dartdev', 'bin', 'dartdev.dart');
|
|
|
|
Directory findDirectory(String name) {
|
|
var directory = Directory(path.join(dir.path, name));
|
|
return directory.existsSync() ? directory : null;
|
|
}
|
|
|
|
File findFile(String name) {
|
|
var file = File(path.join(dir.path, name));
|
|
return file.existsSync() ? file : null;
|
|
}
|
|
}
|