nextest_runner/config/elements/
junit.rs1use crate::config::elements::ReportSkipPolicy;
5use camino::{Utf8Path, Utf8PathBuf};
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
14#[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))]
15#[serde(rename_all = "kebab-case")]
16#[cfg_attr(test, derive(test_strategy::Arbitrary))]
17pub enum JunitFlakyFailStatus {
18 #[default]
21 Failure,
22
23 Success,
25}
26
27#[derive(Clone, Debug)]
31pub struct JunitConfig<'cfg> {
32 path: Utf8PathBuf,
33 report_name: &'cfg str,
34 store_success_output: bool,
35 store_failure_output: bool,
36 report_skipped: ReportSkipPolicy,
37 flaky_fail_status: JunitFlakyFailStatus,
38}
39
40impl<'cfg> JunitConfig<'cfg> {
41 pub(in crate::config) fn new(
42 store_dir: &Utf8Path,
43 settings: JunitSettings<'cfg>,
44 ) -> Option<Self> {
45 let path = settings.path?;
46 Some(Self {
47 path: store_dir.join(path),
48 report_name: settings.report_name,
49 store_success_output: settings.store_success_output,
50 store_failure_output: settings.store_failure_output,
51 report_skipped: settings.report_skipped,
52 flaky_fail_status: settings.flaky_fail_status,
53 })
54 }
55
56 pub fn path(&self) -> &Utf8Path {
58 &self.path
59 }
60
61 pub fn report_name(&self) -> &'cfg str {
63 self.report_name
64 }
65
66 pub fn store_success_output(&self) -> bool {
68 self.store_success_output
69 }
70
71 pub fn store_failure_output(&self) -> bool {
73 self.store_failure_output
74 }
75
76 pub fn report_skipped(&self) -> ReportSkipPolicy {
79 self.report_skipped
80 }
81
82 pub fn flaky_fail_status(&self) -> JunitFlakyFailStatus {
84 self.flaky_fail_status
85 }
86
87 #[cfg(test)]
90 pub(crate) fn new_for_test(
91 path: Utf8PathBuf,
92 report_name: &'cfg str,
93 report_skipped: ReportSkipPolicy,
94 ) -> Self {
95 Self {
96 path,
97 report_name,
98 store_success_output: false,
99 store_failure_output: false,
100 report_skipped,
101 flaky_fail_status: JunitFlakyFailStatus::Failure,
102 }
103 }
104}
105
106#[derive(Clone, Debug)]
108pub(in crate::config) struct JunitSettings<'cfg> {
109 pub(in crate::config) path: Option<&'cfg Utf8Path>,
110 pub(in crate::config) report_name: &'cfg str,
111 pub(in crate::config) store_success_output: bool,
112 pub(in crate::config) store_failure_output: bool,
113 pub(in crate::config) report_skipped: ReportSkipPolicy,
114 pub(in crate::config) flaky_fail_status: JunitFlakyFailStatus,
115}
116
117#[derive(Clone, Debug)]
118pub(in crate::config) struct DefaultJunitImpl {
119 pub(in crate::config) path: Option<Utf8PathBuf>,
120 pub(in crate::config) report_name: String,
121 pub(in crate::config) store_success_output: bool,
122 pub(in crate::config) store_failure_output: bool,
123 pub(in crate::config) report_skipped: ReportSkipPolicy,
124 pub(in crate::config) flaky_fail_status: JunitFlakyFailStatus,
125}
126
127impl DefaultJunitImpl {
128 pub(crate) fn for_default_profile(data: JunitImpl) -> Self {
130 DefaultJunitImpl {
131 path: data.path,
132 report_name: data
133 .report_name
134 .expect("junit.report present in default profile"),
135 store_success_output: data
136 .store_success_output
137 .expect("junit.store-success-output present in default profile"),
138 store_failure_output: data
139 .store_failure_output
140 .expect("junit.store-failure-output present in default profile"),
141 report_skipped: data
142 .report_skipped
143 .expect("junit.report-skipped present in default profile"),
144 flaky_fail_status: data
145 .flaky_fail_status
146 .expect("junit.flaky-fail-status present in default profile"),
147 }
148 }
149}
150
151#[derive(Clone, Debug, Default, Deserialize)]
152#[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))]
153#[cfg_attr(feature = "config-schema", schemars(deny_unknown_fields))]
154#[serde(rename_all = "kebab-case")]
155pub(in crate::config) struct JunitImpl {
156 #[serde(default)]
159 #[cfg_attr(
160 feature = "config-schema",
161 schemars(schema_with = "String::json_schema")
162 )]
163 pub(in crate::config) path: Option<Utf8PathBuf>,
164 #[serde(default)]
166 pub(in crate::config) report_name: Option<String>,
167 #[serde(default)]
169 pub(in crate::config) store_success_output: Option<bool>,
170 #[serde(default)]
172 pub(in crate::config) store_failure_output: Option<bool>,
173 #[serde(default)]
176 pub(in crate::config) report_skipped: Option<ReportSkipPolicy>,
177 #[serde(default)]
179 pub(in crate::config) flaky_fail_status: Option<JunitFlakyFailStatus>,
180}
181
182#[cfg(test)]
183mod tests {
184 use crate::config::{core::NextestConfig, elements::ReportSkipPolicy, utils::test_helpers::*};
185 use camino_tempfile::tempdir;
186 use indoc::indoc;
187 use nextest_filtering::ParseContext;
188
189 fn report_skipped_for(config_contents: &str, profile: &str) -> ReportSkipPolicy {
190 let workspace_dir = tempdir().unwrap();
191 let graph = temp_workspace(&workspace_dir, config_contents);
192 let pcx = ParseContext::new(&graph);
193 let nextest_config = NextestConfig::from_sources(
194 graph.workspace().root(),
195 &pcx,
196 None,
197 &[][..],
198 &Default::default(),
199 )
200 .expect("config file should parse");
201
202 nextest_config
203 .profile(profile)
204 .expect("profile should exist")
205 .apply_build_platforms(&build_platforms())
206 .junit()
207 .expect("junit config should be present")
208 .report_skipped()
209 }
210
211 #[test]
212 fn report_skipped_defaults_to_none() {
213 let config = indoc! {r#"
216 [profile.default.junit]
217 path = "junit.xml"
218 "#};
219 assert_eq!(
220 report_skipped_for(config, "default"),
221 ReportSkipPolicy::None
222 );
223 }
224
225 #[test]
226 fn report_skipped_can_be_set_to_ignored() {
227 let config = indoc! {r#"
228 [profile.default.junit]
229 path = "junit.xml"
230 report-skipped = "ignored"
231 "#};
232 assert_eq!(
233 report_skipped_for(config, "default"),
234 ReportSkipPolicy::Ignored
235 );
236 }
237
238 #[test]
239 fn report_skipped_can_be_set_to_all() {
240 let config = indoc! {r#"
241 [profile.default.junit]
242 path = "junit.xml"
243 report-skipped = "all"
244 "#};
245 assert_eq!(report_skipped_for(config, "default"), ReportSkipPolicy::All);
246 }
247}