nextest_runner/config/elements/
junit.rs

1// Copyright (c) The nextest Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use camino::{Utf8Path, Utf8PathBuf};
5use serde::{Deserialize, Serialize};
6
7/// Controls how flaky-fail tests are reported in JUnit XML output.
8///
9/// Flaky-fail tests are tests that eventually passed on retry but are configured
10/// with `flaky-result = "fail"`. This setting controls whether they appear as
11/// failures or successes in the JUnit report.
12#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
13#[serde(rename_all = "kebab-case")]
14#[cfg_attr(test, derive(test_strategy::Arbitrary))]
15pub enum JunitFlakyFailStatus {
16    /// Report flaky-fail tests as failures with `<failure>` and
17    /// `<flakyFailure>` elements.
18    #[default]
19    Failure,
20
21    /// Report flaky-fail tests as successes, identical to flaky-pass tests.
22    Success,
23}
24
25/// Global JUnit configuration stored within a profile.
26///
27/// Returned by an [`EvaluatableProfile`](crate::config::core::EvaluatableProfile).
28#[derive(Clone, Debug)]
29pub struct JunitConfig<'cfg> {
30    path: Utf8PathBuf,
31    report_name: &'cfg str,
32    store_success_output: bool,
33    store_failure_output: bool,
34    flaky_fail_status: JunitFlakyFailStatus,
35}
36
37impl<'cfg> JunitConfig<'cfg> {
38    pub(in crate::config) fn new(
39        store_dir: &Utf8Path,
40        settings: JunitSettings<'cfg>,
41    ) -> Option<Self> {
42        let path = settings.path?;
43        Some(Self {
44            path: store_dir.join(path),
45            report_name: settings.report_name,
46            store_success_output: settings.store_success_output,
47            store_failure_output: settings.store_failure_output,
48            flaky_fail_status: settings.flaky_fail_status,
49        })
50    }
51
52    /// Returns the absolute path to the JUnit report.
53    pub fn path(&self) -> &Utf8Path {
54        &self.path
55    }
56
57    /// Returns the name of the JUnit report.
58    pub fn report_name(&self) -> &'cfg str {
59        self.report_name
60    }
61
62    /// Returns true if success output should be stored.
63    pub fn store_success_output(&self) -> bool {
64        self.store_success_output
65    }
66
67    /// Returns true if failure output should be stored.
68    pub fn store_failure_output(&self) -> bool {
69        self.store_failure_output
70    }
71
72    /// Returns the flaky-fail status for JUnit reporting.
73    pub fn flaky_fail_status(&self) -> JunitFlakyFailStatus {
74        self.flaky_fail_status
75    }
76}
77
78/// Pre-resolved JUnit settings from the profile inheritance chain.
79#[derive(Clone, Debug)]
80pub(in crate::config) struct JunitSettings<'cfg> {
81    pub(in crate::config) path: Option<&'cfg Utf8Path>,
82    pub(in crate::config) report_name: &'cfg str,
83    pub(in crate::config) store_success_output: bool,
84    pub(in crate::config) store_failure_output: bool,
85    pub(in crate::config) flaky_fail_status: JunitFlakyFailStatus,
86}
87
88#[derive(Clone, Debug)]
89pub(in crate::config) struct DefaultJunitImpl {
90    pub(in crate::config) path: Option<Utf8PathBuf>,
91    pub(in crate::config) report_name: String,
92    pub(in crate::config) store_success_output: bool,
93    pub(in crate::config) store_failure_output: bool,
94    pub(in crate::config) flaky_fail_status: JunitFlakyFailStatus,
95}
96
97impl DefaultJunitImpl {
98    // Default values have all fields defined on them.
99    pub(crate) fn for_default_profile(data: JunitImpl) -> Self {
100        DefaultJunitImpl {
101            path: data.path,
102            report_name: data
103                .report_name
104                .expect("junit.report present in default profile"),
105            store_success_output: data
106                .store_success_output
107                .expect("junit.store-success-output present in default profile"),
108            store_failure_output: data
109                .store_failure_output
110                .expect("junit.store-failure-output present in default profile"),
111            flaky_fail_status: data
112                .flaky_fail_status
113                .expect("junit.flaky-fail-status present in default profile"),
114        }
115    }
116}
117
118#[derive(Clone, Debug, Default, Deserialize)]
119#[serde(rename_all = "kebab-case")]
120pub(in crate::config) struct JunitImpl {
121    #[serde(default)]
122    pub(in crate::config) path: Option<Utf8PathBuf>,
123    #[serde(default)]
124    pub(in crate::config) report_name: Option<String>,
125    #[serde(default)]
126    pub(in crate::config) store_success_output: Option<bool>,
127    #[serde(default)]
128    pub(in crate::config) store_failure_output: Option<bool>,
129    #[serde(default)]
130    pub(in crate::config) flaky_fail_status: Option<JunitFlakyFailStatus>,
131}