Migrate off a global test fixture for build and lint. (flutter/engine#55540)

Partial work towards https://github.com/flutter/flutter/issues/148420, unblocks https://github.com/flutter/engine/pull/55537.

These tests can now be more precise, and changing the fixtures no longer has side-effects on tests across the entire repository. There are about 11 other usages (there were ~50 in these) after this PR that I'll get to, as well as the hard-coded `gn desc` output, before retiring `fixtures.dart`
This commit is contained in:
Matan Lurey 2024-10-01 09:29:51 -07:00 committed by GitHub
parent bfd2fa3e8d
commit 842e2fe8f1
4 changed files with 518 additions and 136 deletions

View File

@ -3,43 +3,20 @@
// found in the LICENSE file.
import 'dart:convert' as convert;
import 'dart:ffi';
import 'package:engine_build_configs/engine_build_configs.dart';
import 'package:engine_tool/src/build_utils.dart';
import 'package:engine_tool/src/commands/command_runner.dart';
import 'package:engine_tool/src/logger.dart';
import 'package:path/path.dart' as path;
import 'package:platform/platform.dart';
import 'package:test/test.dart';
import 'fixtures.dart' as fixtures;
import 'src/test_build_configs.dart';
import 'utils.dart';
void main() {
final linuxTestConfig = BuilderConfig.fromJson(
path: 'ci/builders/linux_test_config.json',
map: convert.jsonDecode(fixtures.testConfig('Linux', Platform.linux))
as Map<String, Object?>,
);
final macTestConfig = BuilderConfig.fromJson(
path: 'ci/builders/mac_test_config.json',
map: convert.jsonDecode(fixtures.testConfig('Mac-12', Platform.macOS))
as Map<String, Object?>,
);
final winTestConfig = BuilderConfig.fromJson(
path: 'ci/builders/win_test_config.json',
map: convert.jsonDecode(fixtures.testConfig('Windows-11', Platform.windows))
as Map<String, Object?>,
);
final configs = <String, BuilderConfig>{
'linux_test_config': linuxTestConfig,
'mac_test_config': macTestConfig,
'win_test_config': winTestConfig,
};
final cannedProcesses = [
CannedProcess(
(command) => command.contains('desc'),
@ -49,21 +26,57 @@ void main() {
test('can find host runnable build', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'macos/host_debug',
dimension: TestDroneDimension.mac,
);
builder.addBuild(
name: 'mac/host_profile',
dimension: TestDroneDimension.mac,
);
builder.addBuild(
name: 'linux/host_debug',
dimension: TestDroneDimension.linux,
);
final configs = {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
};
final result = runnableBuilds(testEnv.environment, configs, true);
expect(result.length, equals(4));
expect(result[0].name, equals('ci/build_name'));
expect(
result.map((r) => r.name),
unorderedEquals(['macos/host_debug', 'mac/host_profile']),
);
});
test('build command invokes gn', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'macos/host_debug',
dimension: TestDroneDimension.mac,
);
final configs = {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
};
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
@ -71,8 +84,10 @@ void main() {
final result = await runner.run([
'build',
'--config',
'ci/build_name',
'host_debug',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory.length, greaterThanOrEqualTo(1));
expect(testEnv.processHistory[0].command[0], contains('gn'));
@ -80,10 +95,22 @@ void main() {
test('build command invokes ninja', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'macos/host_debug',
dimension: TestDroneDimension.mac,
);
final configs = {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
};
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
@ -91,8 +118,10 @@ void main() {
final result = await runner.run([
'build',
'--config',
'ci/build_name',
'host_debug',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory.length, greaterThanOrEqualTo(2));
expect(testEnv.processHistory[1].command[0], contains('ninja'));
@ -100,10 +129,23 @@ void main() {
test('build command invokes generator', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'macos/host_debug',
dimension: TestDroneDimension.mac,
generatorTask: ('gen/script.py', ['--test-param']),
);
final configs = {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
};
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
@ -111,22 +153,36 @@ void main() {
final result = await runner.run([
'build',
'--config',
'ci/build_name',
'host_debug',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory.length, greaterThanOrEqualTo(3));
expect(
testEnv.processHistory[2].command,
containsAllInOrder(['python3', 'gen/script.py']),
testEnv.processHistory.map((p) => p.command),
containsOnce(containsAllInOrder(['python3', 'gen/script.py'])),
);
});
test('build command does not invoke tests', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'macos/host_debug',
dimension: TestDroneDimension.mac,
testTask: ('test/script.py', ['--test-param']),
);
final configs = {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
};
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
@ -134,19 +190,37 @@ void main() {
final result = await runner.run([
'build',
'--config',
'ci/build_name',
'host_debug',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory.length, lessThanOrEqualTo(4));
expect(
testEnv.processHistory.map((p) => p.command),
isNot(contains(containsAllInOrder(['python3', 'gen/script.py']))),
);
});
test('build command runs rbe on an rbe build', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
withRbe: true,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/android_debug_rbe_arm64',
dimension: TestDroneDimension.mac,
enableRbe: true,
);
final configs = {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
};
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
@ -156,50 +230,93 @@ void main() {
'--config',
'ci/android_debug_rbe_arm64',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory[0].command[0],
contains(path.join('tools', 'gn')));
expect(testEnv.processHistory[0].command[2], equals('--rbe'));
expect(testEnv.processHistory[1].command[0],
contains(path.join('reclient', 'bootstrap')));
final [gnCall, reclientCall, ..._] = testEnv.processHistory;
expect(
gnCall.command,
containsAllInOrder([
endsWith('tools/gn'),
contains('--rbe'),
]),
);
expect(
reclientCall.command,
containsAllInOrder([
endsWith('reclient/bootstrap'),
]),
);
});
test('build command plumbs -j to ninja', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
withRbe: true,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/android_debug_arm64',
dimension: TestDroneDimension.mac,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
},
);
final result = await runner.run([
'build',
'--config',
'ci/android_debug_rbe_arm64',
'ci/android_debug_arm64',
'-j',
'500',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory[0].command[0],
contains(path.join('tools', 'gn')));
expect(testEnv.processHistory[0].command[2], equals('--rbe'));
expect(testEnv.processHistory[2].command.contains('500'), isTrue);
print(testEnv.processHistory);
final [_, ninja, ..._] = testEnv.processHistory;
expect(
ninja.command,
containsAllInOrder([
endsWith('ninja/ninja'),
'-j',
'500',
]),
);
});
test('build command fails when rbe is enabled but not supported', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
// Intentionally omit withRbe: true.
// That means the //flutter/build/rbe directory will not be created.
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/android_debug_rbe_arm64',
dimension: TestDroneDimension.mac,
enableRbe: true,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
},
);
final result = await runner.run([
'build',
@ -216,14 +333,28 @@ void main() {
test('build command does not run rbe when disabled', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
withRbe: true,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/android_debug_rbe_arm64',
dimension: TestDroneDimension.mac,
// Intentionally show that RBE is disabled.
// ignore: avoid_redundant_argument_values
enableRbe: false,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
},
);
final result = await runner.run([
'build',
@ -231,36 +362,64 @@ void main() {
'ci/android_debug_rbe_arm64',
'--no-rbe',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory[0].command[0],
contains(path.join('tools', 'gn')));
expect(testEnv.processHistory[0].command, isNot(contains(['--rbe'])));
expect(testEnv.processHistory[1].command[0],
contains(path.join('ninja', 'ninja')));
final [gn, ninja, ..._] = testEnv.processHistory;
expect(gn.command, isNot(contains('--rbe')));
expect(
ninja.command,
containsAllInOrder(
[
endsWith('ninja/ninja'),
],
),
);
});
test('build command does not run rbe when rbe configs do not exist',
() async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/android_debug_rbe_arm64',
dimension: TestDroneDimension.mac,
enableRbe: true,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
},
);
final result = await runner.run([
'build',
'--config',
'ci/android_debug_rbe_arm64',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory[0].command[0],
contains(path.join('tools', 'gn')));
expect(testEnv.processHistory[0].command, isNot(contains(['--rbe'])));
expect(testEnv.processHistory[1].command[0],
contains(path.join('ninja', 'ninja')));
final [gn, ninja, ..._] = testEnv.processHistory;
expect(gn.command, isNot(contains('--rbe')));
expect(
ninja.command,
containsAllInOrder(
[
endsWith('ninja/ninja'),
],
),
);
});
test('mangleConfigName removes the OS and adds ci/ as needed', () {
@ -359,60 +518,108 @@ void main() {
test('build command invokes ninja with the specified target', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/host_debug',
targetDir: 'host_debug',
dimension: TestDroneDimension.mac,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
},
);
final result = await runner.run([
'build',
'--config',
'host_debug',
'ci/host_debug',
'//flutter/fml:fml_arc_unittests',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory, containsCommand((command) {
return command.length > 3 &&
command[0].contains('ninja') &&
command[1].contains('-C') &&
command[2].endsWith('/host_debug') &&
// TODO(matanlurey): Tighten this up to be more specific.
// The reason we need a broad check is because the test fixture
// always returns multiple targets for gn desc, even though that is
// not the actual behavior.
command.sublist(3).contains('flutter/fml:fml_arc_unittests');
}));
final ninjaCmd = testEnv.processHistory.firstWhere(
(p) => p.command.first.endsWith('ninja'),
);
expect(
ninjaCmd.command,
containsAllInOrder(
[
endsWith('ninja'),
'-C',
endsWith('host_debug'),
],
),
);
expect(
ninjaCmd.command,
contains(
contains('flutter/fml:fml_arc_unittests'),
),
);
});
test('build command invokes ninja with all matched targets', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/host_debug',
targetDir: 'host_debug',
dimension: TestDroneDimension.mac,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
},
);
final result = await runner.run([
'build',
'--config',
'host_debug',
'ci/host_debug',
'//flutter/...',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(testEnv.processHistory, containsCommand((command) {
return command.length > 5 &&
command[0].contains('ninja') &&
command[1].contains('-C') &&
command[2].endsWith('/host_debug') &&
command[3] == 'flutter/display_list:display_list_unittests' &&
command[4] == 'flutter/flow:flow_unittests' &&
command[5] == 'flutter/fml:fml_arc_unittests';
}));
final ninjaCmd = testEnv.processHistory.firstWhere(
(p) => p.command.first.endsWith('ninja'),
);
expect(
ninjaCmd.command,
containsAllInOrder(
[
endsWith('ninja'),
'-C',
endsWith('host_debug'),
],
),
);
expect(
ninjaCmd.command,
containsAll([
'flutter/display_list:display_list_unittests',
'flutter/flow:flow_unittests',
'flutter/fml:fml_arc_unittests',
]),
);
});
test('build command gracefully handles no matched targets', () async {
@ -420,27 +627,42 @@ void main() {
CannedProcess(
(command) => command.contains('desc'),
stdout: fixtures.gnDescOutputEmpty(
gnPattern: 'testing/scenario_app:sceario_app'),
gnPattern: 'testing/scenario_app:sceario_app',
),
exitCode: 1,
),
];
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/host_debug',
targetDir: 'host_debug',
dimension: TestDroneDimension.mac,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'mac_test_config': builder.buildConfig(
path: 'ci/builders/mac_test_config.json',
),
},
);
final result = await runner.run([
'build',
'--config',
'host_debug',
'ci/host_debug',
// Intentionally omit the prefix '//flutter/' to trigger the warning.
'//testing/scenario_app',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
expect(
testEnv.testLogs.map((LogRecord r) => r.message).join(),
contains('No targets matched the pattern `testing/scenario_app'),
@ -456,7 +678,7 @@ void main() {
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {},
help: true,
);
final result = await runner.run([
@ -474,21 +696,74 @@ void main() {
);
});
test('verbose "et help build" contains CI builds', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
verbose: true,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/linux_android_debug',
dimension: TestDroneDimension.mac,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: {
'linux_test_config': builder.buildConfig(
path: 'ci/builders/linux_test_config.json',
)
},
help: true,
);
final result = await runner.run([
'--verbose',
'help',
'build',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
// Avoid a degenerate case where nothing is logged.
expect(testEnv.testLogs, isNotEmpty, reason: 'No logs were emitted');
print(testEnv.testLogs);
expect(
testEnv.testLogs.map((LogRecord r) => r.message),
contains(contains('[ci/')),
);
});
test('non-verbose "et help build" does not contain ci builds', () async {
final testEnv = TestEnvironment.withTestEngine(
abi: Abi.macosArm64,
cannedProcesses: cannedProcesses,
);
addTearDown(testEnv.cleanup);
final builder = TestBuilderConfig();
builder.addBuild(
name: 'ci/linux_android_debug',
dimension: TestDroneDimension.mac,
);
final runner = ToolCommandRunner(
environment: testEnv.environment,
configs: configs,
configs: {
'linux_test_config': builder.buildConfig(
path: 'ci/builders/linux_test_config.json',
)
},
help: true,
);
final result = await runner.run([
'help',
'build',
]);
printOnFailure(testEnv.testLogs.map((r) => r.message).join('\n'));
expect(result, equals(0));
// Avoid a degenerate case where nothing is logged.
@ -496,7 +771,8 @@ void main() {
expect(
testEnv.testLogs.map((LogRecord r) => r.message),
isNot(contains('[ci/')),
isNot(contains(contains('[ci/'))),
reason: 'The log should not contain CI-prefixed builds',
);
});
}

View File

@ -2,11 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert' as convert;
import 'dart:ffi' as ffi show Abi;
import 'dart:io' as io;
import 'package:engine_build_configs/engine_build_configs.dart';
import 'package:engine_repo_tools/engine_repo_tools.dart';
import 'package:engine_tool/src/commands/command_runner.dart';
import 'package:engine_tool/src/environment.dart';
@ -16,56 +14,25 @@ import 'package:process_fakes/process_fakes.dart';
import 'package:process_runner/process_runner.dart';
import 'package:test/test.dart';
import 'fixtures.dart' as fixtures;
void main() {
final Engine engine;
try {
engine = Engine.findWithin();
} catch (e) {
io.stderr.writeln(e);
io.exitCode = 1;
return;
}
final BuilderConfig linuxTestConfig = BuilderConfig.fromJson(
path: 'ci/builders/linux_test_config.json',
map: convert.jsonDecode(fixtures.testConfig('Linux', Platform.linux))
as Map<String, Object?>,
);
final BuilderConfig macTestConfig = BuilderConfig.fromJson(
path: 'ci/builders/mac_test_config.json',
map: convert.jsonDecode(fixtures.testConfig('Mac-12', Platform.macOS))
as Map<String, Object?>,
);
final BuilderConfig winTestConfig = BuilderConfig.fromJson(
path: 'ci/builders/win_test_config.json',
map: convert.jsonDecode(fixtures.testConfig('Windows-11', Platform.windows))
as Map<String, Object?>,
);
final Map<String, BuilderConfig> configs = <String, BuilderConfig>{
'linux_test_config': linuxTestConfig,
'mac_test_config': macTestConfig,
'win_test_config': winTestConfig,
};
final engine = Engine.findWithin();
(Environment, List<List<String>>) macEnv(Logger logger) {
final List<List<String>> runHistory = <List<String>>[];
final runHistory = <List<String>>[];
return (
Environment(
abi: ffi.Abi.macosArm64,
engine: engine,
platform: FakePlatform(
operatingSystem: Platform.macOS,
resolvedExecutable: io.Platform.resolvedExecutable,
pathSeparator: '/'),
operatingSystem: Platform.macOS,
resolvedExecutable: io.Platform.resolvedExecutable,
pathSeparator: '/',
),
processRunner: ProcessRunner(
processManager: FakeProcessManager(onStart: (List<String> command) {
processManager: FakeProcessManager(onStart: (command) {
runHistory.add(command);
return FakeProcess();
}, onRun: (List<String> command) {
}, onRun: (command) {
// Should not be executed.
assert(false);
return io.ProcessResult(81, 1, '', '');
@ -81,7 +48,7 @@ void main() {
final (Environment env, List<List<String>> runHistory) = macEnv(logger);
final ToolCommandRunner runner = ToolCommandRunner(
environment: env,
configs: configs,
configs: {},
);
final int result = await runner.run(<String>['lint']);
expect(result, equals(0));

View File

@ -0,0 +1,138 @@
// Copyright 2013 The Flutter 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 'package:engine_build_configs/engine_build_configs.dart';
/// Builds a test [BuilderConfig].
///
/// Many tests will involve exactly one build configuration, or a small number
/// of build configurations. Instead of constructing these configurations ahead
/// of time, this builder is used to create them on-the-fly, with convenient
/// methods for setting up and cloning configurations.
///
/// This builder exists in order to avoid global fixtures in tests that do not
/// isolate elements of the test environment relevant to their test. Prior to
/// the builder, 100s of lines of static configuration were used to setup and
/// instrument tests across multiple files; instead, this builder is used to
/// precisely configure the test environment for each test.
///
/// See <https://github.com/flutter/flutter/issues/148420> for more information.
final class TestBuilderConfig {
final _builds = <Map<String, Object?>>[];
/// Appends a build to the configuration.
void addBuild({
required String name,
required TestDroneDimension dimension,
bool enableRbe = false,
String description = 'A default description.',
String? targetDir,
(String, List<String>)? generatorTask,
(String, List<String>)? testTask,
}) {
_builds.add({
'archives': [],
'drone_dimensions': [
dimension._dimension,
],
'gclient_variables': <String, Object?>{},
'gn': [
if (enableRbe) '--rbe',
],
'name': name,
'description': description,
'ninja': <String, Object?>{
if (targetDir case final targetDir?) ...{
'config': targetDir,
'targets': ['ninja_target'],
}
},
'tests': _testTask(testTask),
'generators': _generatorTask(generatorTask),
});
}
static List<Object?> _testTask((String, List<String>)? task) {
if (task == null) {
return [];
}
final (script, args) = task;
return [
{
'name': 'test_task',
'language': 'python',
'scripts': [script],
'parameters': args,
'contexts': ['context'],
},
];
}
static Map<String, Object?> _generatorTask((String, List<String>)? task) {
if (task == null) {
return {};
}
final (script, args) = task;
return {
'tasks': [
{
'name': 'generator_task',
'language': 'python',
'scripts': [script],
'parameters': args,
},
],
};
}
/// Copies the state of `this` as a new [TestBuilderConfig].
TestBuilderConfig clone() {
final clone = TestBuilderConfig();
clone._builds.addAll(_builds);
return clone;
}
/// Creates and returns a [BuilderConfig] capturing the current builder state.
///
/// [path] is the path to the configuration file that would be read from disk.
///
/// After creation, the builder state remains, and changes can be made to the
/// builder to create a new configuration without affecting the previous one
/// created.
BuilderConfig buildConfig({
required String path,
}) {
final config = BuilderConfig.fromJson(map: buildJson(), path: path);
if (config.check(path) case final errors when errors.isNotEmpty) {
throw StateError('Invalid configuration:\n${errors.join('\n')}');
}
return config;
}
/// Creates and returns the JSON serialized format of a [BuilderConfig].
///
/// Most of the time, use [build] instead of this method.
///
/// It is undefined behavior to mutate the returned map.
Map<String, Object?> buildJson() {
return {
'builds': _builds,
};
}
}
/// Fixed set of dimensions for [TestBuilderConfig.addBuild].
enum TestDroneDimension {
/// Runs on Linux.
linux('os=Linux'),
/// Runs on macOS.
mac('os=Mac-12'),
/// Runs on Windows.
win('os=Windows-11');
const TestDroneDimension(this._dimension);
final String _dimension;
}

View File

@ -69,10 +69,10 @@ class TestEnvironment {
abi: abi,
engine: engine,
platform: FakePlatform(
operatingSystem: _operatingSystemForAbi(abi),
resolvedExecutable: io.Platform.resolvedExecutable,
pathSeparator: _pathSeparatorForAbi(abi),
numberOfProcessors: 32,
operatingSystem: _operatingSystemForAbi(abi),
resolvedExecutable: io.Platform.resolvedExecutable,
pathSeparator: _pathSeparatorForAbi(abi),
numberOfProcessors: 32,
),
processRunner: ProcessRunner(
processManager: FakeProcessManager(onStart: (List<String> command) {
@ -84,7 +84,8 @@ class TestEnvironment {
return processResult;
}, onRun: (List<String> command) {
final io.ProcessResult result = _getCannedProcessResult(
command, cannedProcesses,
command,
cannedProcesses,
);
processHistory.add(ExecutedProcess(
command,