Skip to main content

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#[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))]
14#[serde(rename_all = "kebab-case")]
15#[cfg_attr(test, derive(test_strategy::Arbitrary))]
16pub enum JunitFlakyFailStatus {
17    /// Report flaky-fail tests as failures with `<failure>` and
18    /// `<flakyFailure>` elements.
19    #[default]
20    Failure,
21
22    /// Report flaky-fail tests as successes, identical to flaky-pass tests.
23    Success,
24}
25
26/// Global JUnit configuration stored within a profile.
27///
28/// Returned by an [`EvaluatableProfile`](crate::config::core::EvaluatableProfile).
29#[derive(Clone, Debug)]
30pub struct JunitConfig<'cfg> {
31    path: Utf8PathBuf,
32    report_name: &'cfg str,
33    store_success_output: bool,
34    store_failure_output: bool,
35    flaky_fail_status: JunitFlakyFailStatus,
36}
37
38impl<'cfg> JunitConfig<'cfg> {
39    pub(in crate::config) fn new(
40        store_dir: &Utf8Path,
41        settings: JunitSettings<'cfg>,
42    ) -> Option<Self> {
43        let path = settings.path?;
44        Some(Self {
45            path: store_dir.join(path),
46            report_name: settings.report_name,
47            store_success_output: settings.store_success_output,
48            store_failure_output: settings.store_failure_output,
49            flaky_fail_status: settings.flaky_fail_status,
50        })
51    }
52
53    /// Returns the absolute path to the JUnit report.
54    pub fn path(&self) -> &Utf8Path {
55        &self.path
56    }
57
58    /// Returns the name of the JUnit report.
59    pub fn report_name(&self) -> &'cfg str {
60        self.report_name
61    }
62
63    /// Returns true if success output should be stored.
64    pub fn store_success_output(&self) -> bool {
65        self.store_success_output
66    }
67
68    /// Returns true if failure output should be stored.
69    pub fn store_failure_output(&self) -> bool {
70        self.store_failure_output
71    }
72
73    /// Returns the flaky-fail status for JUnit reporting.
74    pub fn flaky_fail_status(&self) -> JunitFlakyFailStatus {
75        self.flaky_fail_status
76    }
77}
78
79/// Pre-resolved JUnit settings from the profile inheritance chain.
80#[derive(Clone, Debug)]
81pub(in crate::config) struct JunitSettings<'cfg> {
82    pub(in crate::config) path: Option<&'cfg Utf8Path>,
83    pub(in crate::config) report_name: &'cfg str,
84    pub(in crate::config) store_success_output: bool,
85    pub(in crate::config) store_failure_output: bool,
86    pub(in crate::config) flaky_fail_status: JunitFlakyFailStatus,
87}
88
89#[derive(Clone, Debug)]
90pub(in crate::config) struct DefaultJunitImpl {
91    pub(in crate::config) path: Option<Utf8PathBuf>,
92    pub(in crate::config) report_name: String,
93    pub(in crate::config) store_success_output: bool,
94    pub(in crate::config) store_failure_output: bool,
95    pub(in crate::config) flaky_fail_status: JunitFlakyFailStatus,
96}
97
98impl DefaultJunitImpl {
99    // Default values have all fields defined on them.
100    pub(crate) fn for_default_profile(data: JunitImpl) -> Self {
101        DefaultJunitImpl {
102            path: data.path,
103            report_name: data
104                .report_name
105                .expect("junit.report present in default profile"),
106            store_success_output: data
107                .store_success_output
108                .expect("junit.store-success-output present in default profile"),
109            store_failure_output: data
110                .store_failure_output
111                .expect("junit.store-failure-output present in default profile"),
112            flaky_fail_status: data
113                .flaky_fail_status
114                .expect("junit.flaky-fail-status present in default profile"),
115        }
116    }
117}
118
119#[derive(Clone, Debug, Default, Deserialize)]
120#[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))]
121#[cfg_attr(feature = "config-schema", schemars(deny_unknown_fields))]
122#[serde(rename_all = "kebab-case")]
123pub(in crate::config) struct JunitImpl {
124    /// Path to write the JUnit XML report to. If unset, JUnit support is
125    /// disabled.
126    #[serde(default)]
127    #[cfg_attr(
128        feature = "config-schema",
129        schemars(schema_with = "String::json_schema")
130    )]
131    pub(in crate::config) path: Option<Utf8PathBuf>,
132    /// Name for the JUnit report.
133    #[serde(default)]
134    pub(in crate::config) report_name: Option<String>,
135    /// Whether to store successful test output in the JUnit XML report.
136    #[serde(default)]
137    pub(in crate::config) store_success_output: Option<bool>,
138    /// Whether to store failed test output in the JUnit XML report.
139    #[serde(default)]
140    pub(in crate::config) store_failure_output: Option<bool>,
141    /// How flaky-fail tests are reported in the JUnit XML report.
142    #[serde(default)]
143    pub(in crate::config) flaky_fail_status: Option<JunitFlakyFailStatus>,
144}