Skip to main content

flowey_lib_hvlite/
build_nextest_vmm_tests.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build the cargo-nextest based VMM tests.
5
6use crate::common::CommonArch;
7use crate::common::CommonProfile;
8use crate::run_cargo_nextest_run::NextestProfile;
9use flowey::node::prelude::*;
10use flowey_lib_common::run_cargo_nextest_run::TestResults;
11use flowey_lib_common::run_cargo_nextest_run::build_params::TestPackages;
12use std::collections::BTreeMap;
13
14/// Type-safe wrapper around a built nextest archive containing VMM tests
15#[derive(Serialize, Deserialize)]
16pub struct NextestVmmTestsArchive {
17    #[serde(rename = "vmm_tests.tar.zst")]
18    pub archive_file: PathBuf,
19}
20
21impl Artifact for NextestVmmTestsArchive {}
22
23/// Build mode to use when building the nextest VMM tests
24#[derive(Serialize, Deserialize)]
25pub enum BuildNextestVmmTestsMode {
26    /// Build and immediate run VMM tests, side-stepping any intermediate
27    /// archiving steps.
28    ///
29    /// NOTE: The caller is responsible for setting `extra_env` and
30    /// `pre_run_deps` to ensure that all tests filtered by
31    /// `nextest_filter_expr` are able to run successfully.
32    ImmediatelyRun {
33        /// Nextest profile to use when running the source code
34        nextest_profile: NextestProfile,
35        /// Nextest test filter expression
36        nextest_filter_expr: Option<String>,
37        /// Additional env vars set when executing the tests.
38        extra_env: ReadVar<BTreeMap<String, String>>,
39        /// Wait for specified side-effects to resolve before building / running
40        /// any tests. (e.g: to allow for some ambient packages / dependencies
41        /// to get installed).
42        pre_run_deps: Vec<ReadVar<SideEffect>>,
43
44        results: WriteVar<TestResults>,
45    },
46    /// Build and archive the tests into a nextest archive file, which can then
47    /// be run via [`crate::test_nextest_vmm_tests_archive`].
48    Archive(WriteVar<NextestVmmTestsArchive>),
49}
50
51flowey_request! {
52    pub struct Request {
53        /// Build and run VMM tests for the specified target
54        pub target: target_lexicon::Triple,
55        /// Build and run VMM tests with the specified cargo profile
56        pub profile: CommonProfile,
57        /// Build mode to use when building the nextest VMM tests
58        pub build_mode: BuildNextestVmmTestsMode,
59    }
60}
61
62new_flow_node!(struct Node);
63
64impl FlowNode for Node {
65    type Request = Request;
66
67    fn imports(ctx: &mut ImportCtx<'_>) {
68        ctx.import::<crate::install_openvmm_rust_build_essential::Node>();
69        ctx.import::<crate::run_cargo_nextest_run::Node>();
70        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
71        ctx.import::<crate::init_openvmm_magicpath_openhcl_sysroot::Node>();
72        ctx.import::<crate::init_cross_build::Node>();
73        ctx.import::<flowey_lib_common::run_cargo_nextest_archive::Node>();
74        ctx.import::<flowey_lib_common::install_dist_pkg::Node>();
75    }
76
77    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
78        let mut ambient_deps = vec![ctx.reqv(crate::install_openvmm_rust_build_essential::Request)];
79
80        // TODO: install build tools for other platforms
81        if matches!(
82            ctx.platform(),
83            FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu)
84        ) {
85            ambient_deps.push(ctx.reqv(|v| {
86                flowey_lib_common::install_dist_pkg::Request::Install {
87                    package_names: vec![
88                        "libssl-dev".into(),
89                        "pkg-config".into(),
90                        "build-essential".into(),
91                    ],
92                    done: v,
93                }
94            }));
95        }
96
97        let ambient_deps = ambient_deps;
98
99        for Request {
100            target,
101            profile,
102            build_mode,
103        } in requests
104        {
105            let mut ambient_deps = ambient_deps.clone();
106
107            let sysroot_arch = CommonArch::from_architecture(target.architecture)?;
108
109            // See comment in `crate::cargo_build` for why this is necessary.
110            //
111            // copied here since this node doesn't actually route through `cargo build`.
112            if matches!(target.environment, target_lexicon::Environment::Musl) {
113                ambient_deps.push(
114                    ctx.reqv(|v| crate::init_openvmm_magicpath_openhcl_sysroot::Request {
115                        arch: sysroot_arch,
116                        path: v,
117                    })
118                    .into_side_effect(),
119                );
120            }
121
122            let injected_env = ctx.reqv(|v| crate::init_cross_build::Request {
123                target: target.clone(),
124                injected_env: v,
125            });
126
127            let build_params =
128                flowey_lib_common::run_cargo_nextest_run::build_params::NextestBuildParams {
129                    packages: ReadVar::from_static(TestPackages::Crates {
130                        crates: vec!["vmm_tests".into()],
131                    }),
132                    features: Default::default(),
133                    no_default_features: false,
134                    target: target.clone(),
135                    profile: profile.into(),
136                    extra_env: injected_env,
137                };
138
139            match build_mode {
140                BuildNextestVmmTestsMode::ImmediatelyRun {
141                    nextest_profile,
142                    nextest_filter_expr,
143                    extra_env,
144                    pre_run_deps,
145                    results,
146                } => {
147                    ambient_deps.extend(pre_run_deps);
148
149                    ctx.req(crate::run_cargo_nextest_run::Request {
150                        friendly_name: "vmm_tests".into(),
151                        run_kind:
152                            flowey_lib_common::run_cargo_nextest_run::NextestRunKind::BuildAndRun(
153                                build_params,
154                            ),
155                        nextest_profile,
156                        nextest_filter_expr,
157                        nextest_working_dir: None,
158                        nextest_config_file: None,
159                        run_ignored: false,
160                        extra_env: Some(extra_env),
161                        pre_run_deps: ambient_deps,
162                        results,
163                    })
164                }
165                BuildNextestVmmTestsMode::Archive(unit_tests_archive) => {
166                    let openvmm_repo_path =
167                        ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
168
169                    let archive_file =
170                        ctx.reqv(|v| flowey_lib_common::run_cargo_nextest_archive::Request {
171                            friendly_label: "vmm_tests".into(),
172                            working_dir: openvmm_repo_path,
173                            build_params,
174                            pre_run_deps: ambient_deps,
175                            archive_file: v,
176                        });
177
178                    ctx.emit_minor_rust_step("report built vmm_tests", |ctx| {
179                        let archive_file = archive_file.claim(ctx);
180                        let unit_tests = unit_tests_archive.claim(ctx);
181                        |rt| {
182                            let archive_file = rt.read(archive_file);
183                            rt.write(unit_tests, &NextestVmmTestsArchive { archive_file });
184                        }
185                    });
186                }
187            }
188        }
189
190        Ok(())
191    }
192}