oto/test/oto_application_test.dart

337 lines
8.2 KiB
Dart

import 'dart:io';
import 'package:oto/cli/commands/command_exe.dart';
import 'package:oto/oto/application.dart';
import 'package:test/test.dart';
void main() {
setUp(() {
Application.instance.property = {};
Application.instance.commandStates = {};
Application.instance.dataCommandMap = {};
});
test('build returns failure instead of exiting on invalid yaml', () async {
const invalidYaml = '''
property:
workspace: .
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe: doesNotExist
''';
final result = await Application.instance
.build(BuildType.file, yamlContent: invalidYaml);
expect(result.success, isFalse);
expect(result.exitCode, 10);
expect(result.error, isNotNull);
});
test('file build returns success for print-only pipeline', () async {
const yaml = '''
property:
workspace: .
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isTrue);
expect(result.exitCode, 0);
});
test('file build can run twice in same process', () async {
const yaml = '''
property:
workspace: .
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe: hello
''';
final first =
await Application.instance.build(BuildType.file, yamlContent: yaml);
final second =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(first.success, isTrue);
expect(second.success, isTrue);
});
test('build fails with message when YAML root is not a map', () async {
const yaml = '''
- command: Print
id: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), contains('Build YAML root must be a map'));
});
test('build fails with message when property is not a map', () async {
const yaml = '''
property:
- bad
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), contains('Validate build yaml'));
});
test('build fails with message when command id is not a string', () async {
const yaml = '''
commands:
- command: Print
id: 123
param:
message: hi
pipeline:
id: main
workflow:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), contains('Validate command list'));
});
test('build fails with message when command type is not a string', () async {
const yaml = '''
commands:
- command: 999
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), contains('Validate command list'));
});
test('build fails with validation message when workflow key is not a string',
() async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- 123: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(),
isNot(contains('Converting object to an encodable object failed')));
expect(result.error.toString(), contains('workflow[0]'));
});
test('build fails with validation message when exe-handle branch is missing',
() async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe-handle:
id: hello
on-fail:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(),
contains('exe-handle syntax requires on-success'));
});
// REVIEW_VALIDATE-1: exe command id type guard
test(
'build fails with validation message when exe command id is not a string',
() async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe: 123
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), isNot(contains('is not a subtype')));
expect(result.error.toString(), contains('exe'));
});
// REVIEW_VALIDATE-1: wait-until-string condition type guard
test(
'build fails with validation message when wait-until-string value is not a string',
() async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- wait-until-string: 123
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), isNot(contains('is not a subtype')));
expect(result.error.toString(), contains('wait-until'));
});
// REVIEW_VALIDATE-3: nested pipeline malformed cases
test('build fails with validation message when exe-handle id is not a string',
() async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow:
- exe-handle:
id: 123
on-success:
- exe: hello
on-fail:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), isNot(contains('is not a subtype')));
expect(result.error.toString(), contains('exe-handle'));
expect(result.error.toString(), contains('id'));
});
// REVIEW_REVIEW_VALIDATE-1: pipeline.id validation
test('build fails with validation message when pipeline.id is missing',
() async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
workflow:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), isNot(contains('is not a subtype')));
expect(result.error.toString(), contains('pipeline.id'));
});
test('build fails with validation message when pipeline.id is not a string',
() async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: 123
workflow:
- exe: hello
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), isNot(contains('is not a subtype')));
expect(result.error.toString(), contains('pipeline.id'));
});
test('build fails with validation message when workflow is empty', () async {
const yaml = '''
commands:
- command: Print
id: hello
param:
message: hi
pipeline:
id: main
workflow: []
''';
final result =
await Application.instance.build(BuildType.file, yamlContent: yaml);
expect(result.success, isFalse);
expect(result.error.toString(), isNot(contains('Null check operator')));
expect(result.error.toString(), contains('pipeline.workflow'));
});
test('CommandExe exe -f handles missing file without LateInitializationError',
() async {
final missing =
'/tmp/oto_missing_${DateTime.now().microsecondsSinceEpoch}.yaml';
expect(File(missing).existsSync(), isFalse);
final command = CommandExe();
final priorExitCode = exitCode;
try {
await command.execute(['-f', missing]);
} finally {
exitCode = priorExitCode;
}
});
}