Skip to content

Commit f7bbc75

Browse files
authored
DEVPROD-17564 Generate multiversion binary selection tasks (#99)
1 parent bd69038 commit f7bbc75

12 files changed

+142
-24
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# Changelog
2+
## 3.0.0 - 2025-05-07
3+
* Generate multiversion binary selection tasks
4+
25
## 2.0.0 - 2025-04-23
36
* Allow splitting large tasks on required variants based on total test runtime
47
* Use the AWS-sdk for accessing the s3 bucket of test statistics

Cargo.lock

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "mongo-task-generator"
33
description = "Dynamically split evergreen tasks into subtasks for testing the 10gen/mongo project."
44
license = "Apache-2.0"
5-
version = "2.0.0"
5+
version = "3.0.0"
66
repository = "https://github.com/mongodb/mongo-task-generator"
77
authors = ["DevProd Correctness Team <devprod-correctness-team@mongodb.com>"]
88
edition = "2018"
@@ -23,7 +23,7 @@ serde = { version = "1.0.206", features = ["derive"] }
2323
serde_json = "1.0.124"
2424
serde_yaml = "0.9.33"
2525
shellexpand = "3.1.0"
26-
shrub-rs = "0.5.5"
26+
shrub-rs = "0.6.0"
2727
tokio = { version = "1.39.2", features = ["full"] }
2828
tracing = "0.1.40"
2929
tracing-subscriber = { version = "0.3.18", features = ["json", "fmt", "std"] }

src/evergreen/evg_config_utils.rs

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use lazy_static::lazy_static;
66
use regex::Regex;
77
use shrub_rs::models::commands::EvgCommand::Function;
88
use shrub_rs::models::params::ParamValue;
9+
use shrub_rs::models::task::TaskDependency;
910
use shrub_rs::models::{commands::FunctionCall, task::EvgTask, variant::BuildVariant};
1011

1112
use crate::evergreen_names::{
@@ -101,6 +102,12 @@ pub trait EvgConfigUtils: Sync + Send {
101102
/// List of task names the task depends on.
102103
fn get_task_dependencies(&self, task: &EvgTask) -> Vec<String>;
103104

105+
fn get_task_ref_dependencies(
106+
&self,
107+
task_name: &str,
108+
build_variant: &BuildVariant,
109+
) -> Option<Vec<TaskDependency>>;
110+
104111
/// Lookup the given variable in the vars section of the 'generate resmoke task' func.
105112
///
106113
/// # Arguments
@@ -430,6 +437,20 @@ impl EvgConfigUtils for EvgConfigUtilsImpl {
430437
dependencies.unwrap_or_default()
431438
}
432439

440+
fn get_task_ref_dependencies(
441+
&self,
442+
task_name: &str,
443+
build_variant: &BuildVariant,
444+
) -> Option<Vec<TaskDependency>> {
445+
for task_ref in &build_variant.tasks {
446+
if task_ref.name == task_name {
447+
let dependencies = task_ref.depends_on.clone();
448+
return dependencies;
449+
}
450+
}
451+
None
452+
}
453+
433454
/// Lookup the given variable in the vars section of the 'generate resmoke task' func.
434455
///
435456
/// # Arguments

src/evergreen_names.rs

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pub const BURN_IN_TESTS: &str = "burn_in_tests_gen";
4444
pub const BURN_IN_TAGS: &str = "burn_in_tags_gen";
4545
/// Name of burn_in_tasks task.
4646
pub const BURN_IN_TASKS: &str = "burn_in_tasks_gen";
47+
/// Name of multiversion binary selection task.
48+
pub const MULTIVERSION_BINARY_SELECTION: &str = "select_multiversion_binaries";
4749

4850
// Vars
4951
/// Variable that indicates a task is a fuzzer.

src/lib.rs

+52-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use evergreen::{
2525
};
2626
use evergreen_names::{
2727
BURN_IN_TAGS, BURN_IN_TAG_COMPILE_TASK_DEPENDENCY, BURN_IN_TAG_INCLUDE_BUILD_VARIANTS,
28-
BURN_IN_TASKS, BURN_IN_TESTS, ENTERPRISE_MODULE, GENERATOR_TASKS, UNIQUE_GEN_SUFFIX_EXPANSION,
28+
BURN_IN_TASKS, BURN_IN_TESTS, ENTERPRISE_MODULE, GENERATOR_TASKS,
29+
MULTIVERSION_BINARY_SELECTION, UNIQUE_GEN_SUFFIX_EXPANSION,
2930
};
3031
use generate_sub_tasks_config::GenerateSubTasksConfig;
3132
use resmoke::{
@@ -35,7 +36,7 @@ use resmoke::{
3536
use services::config_extraction::{ConfigExtractionService, ConfigExtractionServiceImpl};
3637
use shrub_rs::models::{
3738
project::EvgProject,
38-
task::{EvgTask, TaskRef},
39+
task::{EvgTask, TaskDependency, TaskRef},
3940
variant::{BuildVariant, DisplayTask},
4041
};
4142
use task_types::{
@@ -708,6 +709,7 @@ impl GenerateTasksService for GenerateTasksServiceImpl {
708709
.infer_build_variant_platform(build_variant);
709710
let mut gen_config = GeneratedConfig::new();
710711
let mut generating_tasks = vec![];
712+
let mut includes_multiversion_tasks = false;
711713
for task in &build_variant.tasks {
712714
if task.name == BURN_IN_TAGS {
713715
if self.gen_burn_in {
@@ -748,12 +750,50 @@ impl GenerateTasksService for GenerateTasksServiceImpl {
748750
gen_config
749751
.display_tasks
750752
.push(generated_task.build_display_task());
753+
754+
// If a task is a multiversion task and it has dependencies overriden on the task
755+
// reference of the build variant, add the MULTIVERSION_BINARY_SELECTION task to
756+
// those overrides too.
757+
let mut task_ref_dependencies = self
758+
.evg_config_utils
759+
.get_task_ref_dependencies(&task.name, build_variant);
760+
761+
if generated_task.is_multiversion() && task_ref_dependencies.is_some() {
762+
task_ref_dependencies = Some(
763+
[
764+
task_ref_dependencies.unwrap(),
765+
vec![TaskDependency {
766+
name: MULTIVERSION_BINARY_SELECTION.to_string(),
767+
variant: None,
768+
}],
769+
]
770+
.concat(),
771+
);
772+
} else {
773+
task_ref_dependencies = None;
774+
}
775+
776+
if generated_task.is_multiversion() {
777+
includes_multiversion_tasks = true;
778+
}
779+
751780
gen_config
752781
.gen_task_specs
753-
.extend(generated_task.build_task_ref(large_distro));
782+
.extend(generated_task.build_task_ref(large_distro, task_ref_dependencies));
754783
}
755784
}
756785

786+
// If any generated task is multiversion, ensure the
787+
// MULTIVERSION_BINARY_SELECTION task is added to the build variant.
788+
if includes_multiversion_tasks {
789+
gen_config.gen_task_specs.push(TaskRef {
790+
name: MULTIVERSION_BINARY_SELECTION.to_string(),
791+
distros: None,
792+
activate: Some(false),
793+
depends_on: None,
794+
});
795+
}
796+
757797
if !generating_tasks.is_empty() {
758798
// Put all the "_gen" tasks into a display task to hide them from view.
759799
gen_config.display_tasks.push(DisplayTask {
@@ -1016,6 +1056,7 @@ pub async fn build_s3_client() -> aws_sdk_s3::Client {
10161056
#[cfg(test)]
10171057
mod tests {
10181058
use rstest::rstest;
1059+
use shrub_rs::models::task::TaskDependency;
10191060

10201061
use crate::{
10211062
evergreen::evg_config_utils::MultiversionGenerateTaskConfig,
@@ -1143,6 +1184,14 @@ mod tests {
11431184
todo!()
11441185
}
11451186

1187+
fn get_task_ref_dependencies(
1188+
&self,
1189+
_task_name: &str,
1190+
_build_variant: &BuildVariant,
1191+
) -> Option<Vec<TaskDependency>> {
1192+
todo!()
1193+
}
1194+
11461195
fn get_gen_task_var<'a>(&self, _task: &'a EvgTask, _var: &str) -> Option<&'a str> {
11471196
todo!()
11481197
}

src/services/config_extraction.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ use crate::{
77
evergreen::evg_config_utils::EvgConfigUtils,
88
evergreen_names::{
99
CONTINUE_ON_FAILURE, FUZZER_PARAMETERS, IDLE_TIMEOUT, LARGE_DISTRO_EXPANSION,
10-
LAST_VERSIONS_EXPANSION, MULTIVERSION, NO_MULTIVERSION_GENERATE_TASKS, NPM_COMMAND,
11-
NUM_FUZZER_FILES, NUM_FUZZER_TASKS, REPEAT_SUITES, RESMOKE_ARGS, RESMOKE_JOBS_MAX,
12-
SHOULD_SHUFFLE_TESTS, UNIQUE_GEN_SUFFIX_EXPANSION, USE_LARGE_DISTRO, USE_XLARGE_DISTRO,
13-
XLARGE_DISTRO_EXPANSION,
10+
LAST_VERSIONS_EXPANSION, MULTIVERSION, MULTIVERSION_BINARY_SELECTION,
11+
NO_MULTIVERSION_GENERATE_TASKS, NPM_COMMAND, NUM_FUZZER_FILES, NUM_FUZZER_TASKS,
12+
REPEAT_SUITES, RESMOKE_ARGS, RESMOKE_JOBS_MAX, SHOULD_SHUFFLE_TESTS,
13+
UNIQUE_GEN_SUFFIX_EXPANSION, USE_LARGE_DISTRO, USE_XLARGE_DISTRO, XLARGE_DISTRO_EXPANSION,
1414
},
1515
generate_sub_tasks_config::GenerateSubTasksConfig,
1616
task_types::{
@@ -127,7 +127,15 @@ impl ConfigExtractionServiceImpl {
127127
///
128128
/// List of tasks that should be included as dependencies.
129129
fn determine_task_dependencies(&self, task_def: &EvgTask) -> Vec<String> {
130-
let depends_on = self.evg_config_utils.get_task_dependencies(task_def);
130+
let mut depends_on = self.evg_config_utils.get_task_dependencies(task_def);
131+
132+
if self
133+
.evg_config_utils
134+
.get_task_tags(task_def)
135+
.contains(MULTIVERSION)
136+
{
137+
depends_on.push(MULTIVERSION_BINARY_SELECTION.to_string());
138+
}
131139

132140
depends_on
133141
.into_iter()
@@ -399,12 +407,14 @@ mod tests {
399407
// Tests for determine_task_dependencies.
400408
#[rstest]
401409
#[case(
402-
vec![], vec![]
410+
vec![], vec![], vec![]
403411
)]
404-
#[case(vec!["dependency_0", "dependency_1"], vec!["dependency_0", "dependency_1"])]
405-
#[case(vec!["dependency_0", "generating_task"], vec!["dependency_0"])]
412+
#[case(vec!["dependency_0", "dependency_1"], vec![], vec!["dependency_0", "dependency_1"])]
413+
#[case(vec!["dependency_0", "generating_task"], vec![], vec!["dependency_0"])]
414+
#[case(vec!["dependency_0", "generating_task"], vec!["multiversion".to_string()], vec!["dependency_0", MULTIVERSION_BINARY_SELECTION])]
406415
fn test_determine_task_dependencies(
407416
#[case] depends_on: Vec<&str>,
417+
#[case] tags: Vec<String>,
408418
#[case] expected_deps: Vec<&str>,
409419
) {
410420
let config_extraction_service = build_mocked_config_extraction_service();
@@ -418,6 +428,7 @@ mod tests {
418428
})
419429
.collect(),
420430
),
431+
tags: Some(tags),
421432
..Default::default()
422433
};
423434

src/task_types/burn_in_tests.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ impl BurnInService for BurnInServiceImpl {
430430

431431
gen_config
432432
.gen_task_specs
433-
.extend(generated_task.build_task_ref(large_distro));
433+
.extend(generated_task.build_task_ref(large_distro, None));
434434
gen_config
435435
.display_tasks
436436
.push(generated_task.build_display_task());
@@ -730,6 +730,14 @@ mod tests {
730730
todo!()
731731
}
732732

733+
fn get_task_ref_dependencies(
734+
&self,
735+
_task_name: &str,
736+
_build_variant: &BuildVariant,
737+
) -> Option<Vec<TaskDependency>> {
738+
todo!()
739+
}
740+
733741
fn get_gen_task_var<'a>(&self, _task: &'a EvgTask, _var: &str) -> Option<&'a str> {
734742
todo!()
735743
}

src/task_types/fuzzer_tasks.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ mod tests {
439439
],
440440
};
441441

442-
let task_refs = fuzzer_task.build_task_ref(Some("distro".to_string()));
442+
let task_refs = fuzzer_task.build_task_ref(Some("distro".to_string()), None);
443443

444444
for task in task_refs {
445445
assert_eq!(task.distros.as_ref(), None);

src/task_types/generated_suite.rs

+25-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use shrub_rs::models::{
2-
task::{EvgTask, TaskRef},
2+
task::{EvgTask, TaskDependency, TaskRef},
33
variant::DisplayTask,
44
};
55

6+
use crate::evergreen_names::MULTIVERSION_BINARY_SELECTION;
7+
68
/// Definition of a generated sub task.
79
#[derive(Clone, Debug, Default)]
810
pub struct GeneratedSubTask {
@@ -48,18 +50,37 @@ pub trait GeneratedSuite: Sync + Send {
4850
}
4951
}
5052

53+
fn is_multiversion(&self) -> bool {
54+
self.sub_tasks()
55+
.iter()
56+
.any(|task| match &task.evg_task.depends_on {
57+
Some(deps) => deps
58+
.iter()
59+
.any(|dep| dep.name == MULTIVERSION_BINARY_SELECTION),
60+
_ => false,
61+
})
62+
}
63+
5164
/// Build a shrub task reference for this generated task.
52-
fn build_task_ref(&self, distro: Option<String>) -> Vec<TaskRef> {
65+
fn build_task_ref(
66+
&self,
67+
distro: Option<String>,
68+
depends_on: Option<Vec<TaskDependency>>,
69+
) -> Vec<TaskRef> {
5370
self.sub_tasks()
5471
.iter()
5572
.map(|sub_task| {
5673
let mut large_distro = None;
5774
if sub_task.use_large_distro || sub_task.use_xlarge_distro {
5875
large_distro = distro.clone();
5976
}
60-
sub_task
77+
let mut task_ref = sub_task
6178
.evg_task
62-
.get_reference(large_distro.map(|d| vec![d]), Some(false))
79+
.get_reference(large_distro.map(|d| vec![d]), Some(false));
80+
81+
task_ref.depends_on = depends_on.clone();
82+
83+
task_ref
6384
})
6485
.collect()
6586
}

src/task_types/resmoke_tasks.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ mod tests {
10531053
.collect(),
10541054
};
10551055

1056-
let task_refs = gen_suite.build_task_ref(Some(distro.clone()));
1056+
let task_refs = gen_suite.build_task_ref(Some(distro.clone()), None);
10571057

10581058
for (i, task) in task_refs.iter().enumerate() {
10591059
assert_eq!(task.name, format!("sub_suite_name_{}", i));

tests/data/evergreen.yml

+3
Original file line numberDiff line numberDiff line change
@@ -7942,6 +7942,9 @@ buildvariants:
79427942
test_flags: >-
79437943
--runAllFeatureFlagTests
79447944
--excludeWithAnyTags=incompatible_with_shard_merge
7945+
depends_on:
7946+
- name: archive_dist_test
7947+
variant: enterprise-rhel-80-64-bit-dynamic-required
79457948
tasks: &enterprise-rhel-80-64-bit-dynamic-all-feature-flags-tasks
79467949
- name: change_streams_per_shard_cursor_passthrough
79477950
- name: cqf

0 commit comments

Comments
 (0)