flowey_lib_hvlite/_jobs/
build_and_run_nextest_unit_tests.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Build and run the cargo-nextest based unit tests.
5
6use crate::build_nextest_unit_tests::BuildNextestUnitTestMode;
7use crate::run_cargo_build::common::CommonProfile;
8use crate::run_cargo_nextest_run::NextestProfile;
9use flowey::node::prelude::*;
10use std::collections::BTreeMap;
11
12flowey_request! {
13    pub struct Params {
14        /// Friendly label for report JUnit test results
15        pub junit_test_label: String,
16        /// Build and run unit tests for the specified target
17        pub target: target_lexicon::Triple,
18        /// Build and run unit tests with the specified cargo profile
19        pub profile: CommonProfile,
20        /// Nextest profile to use when running the source code
21        pub nextest_profile: NextestProfile,
22
23        /// Whether the job should fail if any test has failed
24        pub fail_job_on_test_fail: bool,
25        /// If provided, also publish junit.xml test results as an artifact.
26        pub artifact_dir: Option<ReadVar<PathBuf>>,
27        pub done: WriteVar<SideEffect>,
28    }
29}
30
31new_simple_flow_node!(struct Node);
32
33impl SimpleFlowNode for Node {
34    type Request = Params;
35
36    fn imports(ctx: &mut ImportCtx<'_>) {
37        ctx.import::<flowey_lib_common::publish_test_results::Node>();
38        ctx.import::<crate::build_nextest_unit_tests::Node>();
39    }
40
41    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
42        let Params {
43            junit_test_label,
44            target,
45            profile,
46            nextest_profile,
47            fail_job_on_test_fail,
48            artifact_dir,
49            done,
50        } = request;
51
52        let results = ctx.reqv(|v| crate::build_nextest_unit_tests::Request {
53            profile,
54            target,
55            build_mode: BuildNextestUnitTestMode::ImmediatelyRun {
56                nextest_profile,
57                results: v,
58            },
59        });
60
61        let mut side_effects = Vec::new();
62
63        let junit_xml = results.map(ctx, |r| r.junit_xml);
64        let reported_results = ctx.reqv(|v| flowey_lib_common::publish_test_results::Request {
65            junit_xml,
66            test_label: junit_test_label,
67            attachments: BTreeMap::new(),
68            output_dir: artifact_dir,
69            done: v,
70        });
71
72        side_effects.push(reported_results);
73
74        ctx.emit_rust_step("report test results to overall pipeline status", |ctx| {
75            side_effects.claim(ctx);
76            done.claim(ctx);
77
78            let results = results.clone().claim(ctx);
79            move |rt| {
80                let results = rt.read(results);
81                if results.all_tests_passed {
82                    log::info!("all tests passed!");
83                } else {
84                    if fail_job_on_test_fail {
85                        anyhow::bail!("encountered test failures.")
86                    } else {
87                        log::error!("encountered test failures.")
88                    }
89                }
90
91                Ok(())
92            }
93        });
94
95        Ok(())
96    }
97}