65c4d768f1
Changes are reformatting and using the nullable list element operator. Change-Id: Iea1f4d2fcb06056f14804c8fe8b33c0b4d9037f2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/477561 Commit-Queue: Sigurd Meldgaard <sigurdm@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com>
188 lines
6.8 KiB
Dart
188 lines
6.8 KiB
Dart
// Copyright (c) 2021, 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:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:dartdev/src/commands/create.dart';
|
|
import 'package:dartdev/src/templates.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:test/test.dart';
|
|
|
|
import '../utils.dart';
|
|
|
|
void main() {
|
|
ensureRunFromSdkBinDart();
|
|
|
|
group('create integration', defineCreateTests, timeout: longTimeout);
|
|
}
|
|
|
|
void defineCreateTests() {
|
|
// Create tests for each template.
|
|
for (String templateId in CreateCommand.legalTemplateIds(
|
|
includeDeprecated: true,
|
|
)) {
|
|
test(templateId, () async {
|
|
const projectName = 'template_project';
|
|
final p = project();
|
|
final templateGenerator = getGenerator(templateId)!;
|
|
|
|
print('$templateId: creating template');
|
|
ProcessResult createResult = await p.run([
|
|
'create',
|
|
'--force',
|
|
'--template',
|
|
templateId,
|
|
projectName,
|
|
]);
|
|
printOnFailure(createResult.stdout);
|
|
printOnFailure(createResult.stderr);
|
|
expect(createResult.exitCode, 0, reason: createResult.stderr);
|
|
|
|
// Validate that the project analyzes cleanly.
|
|
print('$templateId: analyzing generated project');
|
|
ProcessResult analyzeResult = await p.runAnalyze([
|
|
'--fatal-infos',
|
|
projectName,
|
|
], workingDir: p.dir.path);
|
|
expect(analyzeResult.exitCode, 0, reason: analyzeResult.stdout);
|
|
|
|
// Validate that the code is well formatted.
|
|
print('$templateId: checking formatting');
|
|
ProcessResult formatResult = await p.run([
|
|
'format',
|
|
'--output',
|
|
'none',
|
|
'--set-exit-if-changed',
|
|
projectName,
|
|
]);
|
|
expect(formatResult.exitCode, 0, reason: formatResult.stdout);
|
|
|
|
// Process the execution instructions provided by the template.
|
|
final runCommands = templateGenerator
|
|
.getInstallInstructions(projectName, scriptPath: projectName)
|
|
.split('\n')
|
|
// Remove directory change instructions.
|
|
.sublist(1)
|
|
.map((command) => command.trim())
|
|
.map((command) {
|
|
final commandParts = command.split(' ');
|
|
if (command.startsWith('dart ')) {
|
|
return commandParts.sublist(1);
|
|
}
|
|
return commandParts;
|
|
})
|
|
.toList();
|
|
|
|
print('$templateId: running the following commands:');
|
|
for (final command in runCommands) {
|
|
print(' $command');
|
|
}
|
|
|
|
final isServerTemplate = templateGenerator.categories.contains('server');
|
|
final isWebTemplate = templateGenerator.categories.contains('web');
|
|
final workingDir = path.join(p.dirPath, projectName);
|
|
|
|
// Execute the templates run instructions.
|
|
for (int i = 0; i < runCommands.length; ++i) {
|
|
// The last command is always the command to execute the code generated
|
|
// by the template.
|
|
final isLastCommand = i == runCommands.length - 1;
|
|
final command = runCommands[i];
|
|
Process process;
|
|
print('[${i + 1} / ${runCommands.length}] Running "$command"...');
|
|
if (isLastCommand && isWebTemplate) {
|
|
// The web template uses `webdev` to execute, not `dart`, so don't
|
|
// run the test through the project utility method.
|
|
process = await Process.start(
|
|
path.join(
|
|
p.pubCacheBinPath,
|
|
Platform.isWindows ? '${command.first}.bat' : command.first,
|
|
),
|
|
[
|
|
...command.sublist(1),
|
|
'web:0', // Allow for binding to a random available port.
|
|
],
|
|
workingDirectory: workingDir,
|
|
environment: {
|
|
'PUB_CACHE': p.pubCachePath,
|
|
'PATH':
|
|
path.dirname(Platform.resolvedExecutable) +
|
|
(Platform.isWindows ? ';' : ':') +
|
|
Platform.environment['PATH']!,
|
|
},
|
|
);
|
|
} else {
|
|
process = await p.start(command, workingDir: workingDir);
|
|
}
|
|
|
|
if (isLastCommand && (isServerTemplate || isWebTemplate)) {
|
|
final completer = Completer<void>();
|
|
late final StreamSubscription<String> stdoutSub;
|
|
late final StreamSubscription<String> stderrSub;
|
|
// Listen for well-known output from specific templates to determine
|
|
// if they've executed correctly. These templates won't exit on their
|
|
// own, so we'll need to terminate the process once we've verified it
|
|
// runs correctly.
|
|
var hasError = false;
|
|
stdoutSub = process.stdout.transform(utf8.decoder).listen((e) {
|
|
print('stdout: $e');
|
|
if (e.contains('[SEVERE]') ||
|
|
(isServerTemplate && e.contains('Server listening on port')) ||
|
|
(isWebTemplate && e.contains('Built with build_runner'))) {
|
|
if (e.contains('[SEVERE]')) {
|
|
hasError = true;
|
|
}
|
|
stderrSub.cancel();
|
|
stdoutSub.cancel();
|
|
process.kill();
|
|
completer.complete();
|
|
}
|
|
});
|
|
stderrSub = process.stderr.transform(utf8.decoder).listen((e) {
|
|
print('stderr: $e');
|
|
hasError = true;
|
|
stderrSub.cancel();
|
|
stdoutSub.cancel();
|
|
process.kill();
|
|
completer.complete();
|
|
});
|
|
await completer.future;
|
|
expect(hasError, isFalse, reason: 'Command $command failed.');
|
|
|
|
// Since we had to terminate the process manually, we aren't certain
|
|
// as to what the exit code will be on all platforms (should be -15
|
|
// for POSIX systems), so we'll just wait for the process to exit
|
|
// here.
|
|
await process.exitCode;
|
|
} else {
|
|
final output = <String>[];
|
|
final errors = <String>[];
|
|
process.stdout.transform(utf8.decoder).listen(output.add);
|
|
process.stderr.transform(utf8.decoder).listen(errors.add);
|
|
|
|
// If the sample should exit on its own, it should always result in
|
|
// an exit code of 0.
|
|
final duration = const Duration(seconds: 60);
|
|
final exitCode = await process.exitCode.timeout(
|
|
duration,
|
|
onTimeout: () {
|
|
print('Command $command timed out');
|
|
return -1;
|
|
},
|
|
);
|
|
if (exitCode != 0) {
|
|
print('Command $command exited with code $exitCode');
|
|
print('Output: \n${output.join('\n')}');
|
|
print('Errors: \n${errors.join('\n')}');
|
|
}
|
|
expect(exitCode, 0);
|
|
}
|
|
print('[${i + 1} / ${runCommands.length}] Done "$command".');
|
|
}
|
|
});
|
|
}
|
|
}
|