mod testcase;
mod xml;
use std::fs::File;
use std::path::Path;
pub use testcase::Testcase;
use crate::report::ReportError;
use crate::report::junit::xml::{Element, XmlDocument};
use crate::util::path::create_dir_all;
pub fn write_report(
filename: &Path,
testcases: &[Testcase],
secrets: &[&str],
) -> Result<(), ReportError> {
create_dir_all(filename)
.map_err(|e| ReportError::from_io_error(&e, filename, "Issue writing JUnit report"))?;
let mut root = if filename.exists() {
let file = File::open(filename)
.map_err(|e| ReportError::from_io_error(&e, filename, "Issue reading JUnit report"))?;
let doc = XmlDocument::parse(file).unwrap();
doc.root.unwrap()
} else {
Element::new("testsuites")
};
let testsuite = create_testsuite(testcases, secrets);
root = root.add_child(testsuite);
let doc = XmlDocument::new(root);
let file = File::create(filename)
.map_err(|e| ReportError::from_io_error(&e, filename, "Issue writing JUnit report"))?;
doc.write(file).map_err(|e| {
ReportError::from_string(&format!(
"Issue writing JUnit report {} {e}",
filename.display()
))
})?;
Ok(())
}
fn create_testsuite(testcases: &[Testcase], secrets: &[&str]) -> Element {
let mut tests = 0;
let mut errors = 0;
let mut failures = 0;
for cases in testcases.iter() {
tests += 1;
errors += cases.get_error_count();
failures += cases.get_fail_count();
}
let mut element = Element::new("testsuite")
.attr("tests", &tests.to_string())
.attr("errors", &errors.to_string())
.attr("failures", &failures.to_string());
for testcase in testcases.iter() {
let child = testcase.to_xml(secrets);
element = element.add_child(child);
}
element
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use crate::http::HttpError;
use crate::report::junit::xml::XmlDocument;
use crate::report::junit::{Testcase, create_testsuite};
use crate::runner::{EntryResult, HurlResult, RunnerError, RunnerErrorKind};
use hurl_core::ast::SourceInfo;
use hurl_core::input::Input;
use hurl_core::reader::Pos;
use hurl_core::types::Index;
#[test]
fn create_junit_report() {
let content = "GET http://localhost:8000/not_found\n\
HTTP/1.0 200";
let filename = Input::new("test.hurl");
let secrets = [];
let mut testcases = vec![];
let res = HurlResult {
duration: Duration::from_millis(124),
success: true,
..Default::default()
};
let tc = Testcase::from(&res, content, &filename);
testcases.push(tc);
let res = HurlResult {
entries: vec![EntryResult {
entry_index: Index::new(1),
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 35)),
errors: vec![RunnerError::new(
SourceInfo::new(Pos::new(2, 10), Pos::new(2, 13)),
RunnerErrorKind::AssertStatus {
actual: "404".to_string(),
},
true,
)],
..Default::default()
}],
duration: Duration::from_millis(200),
success: true,
..Default::default()
};
let tc = Testcase::from(&res, content, &filename);
testcases.push(tc);
let res = HurlResult {
entries: vec![EntryResult {
entry_index: Index::new(1),
source_info: SourceInfo::new(Pos::new(1, 1), Pos::new(1, 35)),
errors: vec![RunnerError::new(
SourceInfo::new(Pos::new(1, 5), Pos::new(1, 19)),
RunnerErrorKind::Http(HttpError::Libcurl {
code: 6,
description: "Could not resolve host: unknown".to_string(),
}),
false,
)],
..Default::default()
}],
duration: Duration::from_millis(230),
success: true,
..Default::default()
};
let tc = Testcase::from(&res, content, &filename);
testcases.push(tc);
let suite = create_testsuite(&testcases, &secrets);
let doc = XmlDocument::new(suite);
assert_eq!(
doc.dump(),
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
<testsuite tests=\"3\" errors=\"1\" failures=\"1\">\
<testcase id=\"test.hurl\" name=\"test.hurl\" time=\"0.124\" />\
<testcase id=\"test.hurl\" name=\"test.hurl\" time=\"0.200\">\
<failure>Assert status code\n \
--> test.hurl:2:10\n \
|\n \
| GET http://localhost:8000/not_found\n \
2 | HTTP/1.0 200\n \
| ^^^ actual value is <404>\n \
|\
</failure>\
</testcase>\
<testcase id=\"test.hurl\" name=\"test.hurl\" time=\"0.230\">\
<error>HTTP connection\n --> test.hurl:1:5\n |\n 1 | GET http://localhost:8000/not_found\n | ^^^^^^^^^^^^^^ (6) Could not resolve host: unknown\n |\
</error>\
</testcase>\
</testsuite>"
);
}
}