mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-14 03:08:27 +03:00
Use pure-Rust XML parsing/serializing for JUnit Report
This commit is contained in:
parent
ac5c87ef78
commit
a17370f9cb
34
Cargo.lock
generated
34
Cargo.lock
generated
@ -373,6 +373,12 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.8"
|
||||
@ -412,6 +418,7 @@ dependencies = [
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"hurl_core",
|
||||
"indexmap",
|
||||
"libflate",
|
||||
"libxml",
|
||||
"md5",
|
||||
@ -423,6 +430,7 @@ dependencies = [
|
||||
"termion",
|
||||
"url",
|
||||
"winres",
|
||||
"xmltree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -458,6 +466,16 @@ dependencies = [
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
@ -1033,3 +1051,19 @@ checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
|
||||
dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
|
||||
[[package]]
|
||||
name = "xmltree"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"xml-rs",
|
||||
]
|
||||
|
@ -30,6 +30,7 @@ glob = "0.3.0"
|
||||
hex = "0.4.3"
|
||||
hex-literal = "0.3.4"
|
||||
hurl_core = { version = "1.6.0-snapshot", path = "../hurl_core" }
|
||||
indexmap = "1.7.0"
|
||||
libflate = "1.1.1"
|
||||
libxml = "0.3.0"
|
||||
md5 = "0.7.0"
|
||||
@ -39,6 +40,7 @@ serde = "1.0.131"
|
||||
serde_json = "1.0.73"
|
||||
sha2 = "0.10.0"
|
||||
url = "2.2.2"
|
||||
xmltree = { version = "0.10", features = ["attribute-order"] }
|
||||
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
|
@ -45,7 +45,7 @@ pub struct CliOptions {
|
||||
pub include: bool,
|
||||
pub insecure: bool,
|
||||
pub interactive: bool,
|
||||
pub junit_file: Option<PathBuf>,
|
||||
pub junit_file: Option<String>,
|
||||
pub max_redirect: Option<usize>,
|
||||
pub no_proxy: Option<String>,
|
||||
pub output: Option<String>,
|
||||
@ -365,12 +365,9 @@ pub fn parse_options(matches: ArgMatches) -> Result<CliOptions, CliError> {
|
||||
let include = matches.is_present("include");
|
||||
let insecure = matches.is_present("insecure");
|
||||
let interactive = matches.is_present("interactive");
|
||||
let junit_file = if let Some(filename) = matches.value_of("junit") {
|
||||
let path = Path::new(filename);
|
||||
Some(path.to_path_buf())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let junit_file = matches
|
||||
.value_of("junit")
|
||||
.map(|filename| filename.to_string());
|
||||
let max_redirect = match matches.value_of("max_redirects") {
|
||||
None => Some(50),
|
||||
Some("-1") => None,
|
||||
|
@ -298,19 +298,7 @@ fn main() {
|
||||
};
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
let doc = if let Ok(doc) = report::create_or_get_junit_report(cli_options.junit_file.clone()) {
|
||||
doc
|
||||
} else {
|
||||
log_error_message(false, "Error creating Junit XML report");
|
||||
std::process::exit(EXIT_ERROR_UNDEFINED);
|
||||
};
|
||||
let mut testsuite = if let Ok(doc) = report::add_testsuite(&doc) {
|
||||
doc
|
||||
} else {
|
||||
log_error_message(false, "Error creating Junit XML report");
|
||||
std::process::exit(EXIT_ERROR_UNDEFINED);
|
||||
};
|
||||
let mut testcases = vec![];
|
||||
|
||||
for (current, filename) in filenames.iter().enumerate() {
|
||||
let contents = match cli::read_to_string(filename) {
|
||||
@ -421,18 +409,17 @@ fn main() {
|
||||
);
|
||||
}
|
||||
if cli_options.junit_file.is_some() {
|
||||
unwrap_or_exit(
|
||||
&log_error_message,
|
||||
report::add_testcase(&doc, &mut testsuite, hurl_result, &lines),
|
||||
);
|
||||
let testcase = report::Testcase::from_hurl_result(&hurl_result, &lines);
|
||||
testcases.push(testcase);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(file_path) = cli_options.junit_file.clone() {
|
||||
log_verbose(format!("Writing Junit report to {}", file_path.display()).as_str());
|
||||
if doc.save_file(&file_path.to_string_lossy()).is_err() {
|
||||
log_error_message(false, format!("Failed to save to {:?}", file_path).as_str());
|
||||
}
|
||||
if let Some(filename) = cli_options.junit_file.clone() {
|
||||
log_verbose(format!("Writing Junit report to {}", filename).as_str());
|
||||
unwrap_or_exit(
|
||||
&log_error_message,
|
||||
report::create_junit_report(filename, testcases),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(dir_path) = cli_options.html_dir {
|
||||
|
@ -54,88 +54,75 @@
|
||||
// </testsuites>
|
||||
//
|
||||
|
||||
use crate::{cli::CliError, runner::HurlResult};
|
||||
use libxml::parser::Parser;
|
||||
use libxml::tree::{Document, Node};
|
||||
use std::fs::File;
|
||||
|
||||
mod result;
|
||||
use xmltree::{Element, XMLNode};
|
||||
|
||||
type JunitError = String;
|
||||
pub use testcase::Testcase;
|
||||
|
||||
///
|
||||
/// Get XML document
|
||||
/// The document is created if it does not exist
|
||||
///
|
||||
pub fn create_or_get_junit_report(
|
||||
file_path: Option<std::path::PathBuf>,
|
||||
) -> Result<Document, CliError> {
|
||||
if let Some(file_path) = file_path {
|
||||
if file_path.exists() {
|
||||
let parser = Parser::default();
|
||||
let doc = parser
|
||||
.parse_string(
|
||||
std::fs::read_to_string(file_path.clone()).map_err(|e| CliError {
|
||||
message: format!("Failed to read file {:?}: {:?}", file_path, e),
|
||||
})?,
|
||||
)
|
||||
.map_err(|e| CliError {
|
||||
message: format!("Failed to parse file {:?}: {:?}", file_path, e),
|
||||
})?;
|
||||
Ok(doc)
|
||||
} else {
|
||||
let mut doc = Document::new().map_err(|e| CliError {
|
||||
message: format!("Failed to produce junit report: {:?}", e),
|
||||
})?;
|
||||
let testsuites =
|
||||
Node::new("testsuites", None, &doc).expect("Could not create testsuites node");
|
||||
doc.set_root_element(&testsuites);
|
||||
Ok(doc)
|
||||
use crate::cli::CliError;
|
||||
|
||||
mod testcase;
|
||||
|
||||
pub fn create_report(filename: String, testcases: Vec<Testcase>) -> Result<(), CliError> {
|
||||
let mut testsuites = vec![];
|
||||
|
||||
let path = std::path::Path::new(&filename);
|
||||
if path.exists() {
|
||||
let s = match std::fs::read_to_string(path) {
|
||||
Ok(s) => s,
|
||||
Err(why) => {
|
||||
return Err(CliError {
|
||||
message: format!("Issue reading {} to string to {:?}", path.display(), why),
|
||||
});
|
||||
}
|
||||
};
|
||||
let root = Element::parse(s.as_bytes()).unwrap();
|
||||
for child in root.children {
|
||||
if let XMLNode::Element(_) = child.clone() {
|
||||
testsuites.push(child.clone());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let mut doc = Document::new().map_err(|e| CliError {
|
||||
}
|
||||
|
||||
let testsuite = create_testsuite(testcases);
|
||||
testsuites.push(testsuite);
|
||||
let report = Element {
|
||||
name: "testsuites".to_string(),
|
||||
prefix: None,
|
||||
namespace: None,
|
||||
namespaces: None,
|
||||
attributes: indexmap::map::IndexMap::new(),
|
||||
children: testsuites,
|
||||
};
|
||||
let file = match File::create(filename) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
return Err(CliError {
|
||||
message: format!("Failed to produce junit report: {:?}", e),
|
||||
});
|
||||
}
|
||||
};
|
||||
match report.write(file) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(CliError {
|
||||
message: format!("Failed to produce junit report: {:?}", e),
|
||||
})?;
|
||||
let testsuites =
|
||||
Node::new("testsuites", None, &doc).expect("Could not create testsuites node");
|
||||
doc.set_root_element(&testsuites);
|
||||
Ok(doc)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Add testsuite to XML document
|
||||
///
|
||||
pub fn add_testsuite(doc: &libxml::tree::Document) -> Result<libxml::tree::Node, JunitError> {
|
||||
let mut testsuite = match Node::new("testsuite", None, doc) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return Err("can not create node testsuite".to_string()),
|
||||
fn create_testsuite(testcases: Vec<Testcase>) -> XMLNode {
|
||||
let children = testcases
|
||||
.iter()
|
||||
.map(|t| XMLNode::Element(t.to_xml()))
|
||||
.collect();
|
||||
let element = Element {
|
||||
name: "testsuite".to_string(),
|
||||
prefix: None,
|
||||
namespace: None,
|
||||
namespaces: None,
|
||||
attributes: indexmap::map::IndexMap::new(),
|
||||
children,
|
||||
};
|
||||
|
||||
let mut testsuites = match doc.get_root_element() {
|
||||
Some(v) => v,
|
||||
None => return Err("can not get root element".to_string()),
|
||||
};
|
||||
match testsuites.add_child(&mut testsuite) {
|
||||
Ok(_) => {}
|
||||
Err(_) => return Err("can not add child".to_string()),
|
||||
}
|
||||
Ok(testsuite)
|
||||
}
|
||||
|
||||
///
|
||||
/// Add Testcase in the testsuite the XML document
|
||||
///
|
||||
pub fn add_testcase(
|
||||
doc: &Document,
|
||||
testsuite: &mut Node,
|
||||
hurl_result: HurlResult,
|
||||
lines: &[String],
|
||||
) -> Result<(), CliError> {
|
||||
let mut testcase = hurl_result.to_testcase(doc, lines)?;
|
||||
if testsuite.add_child(&mut testcase).is_err() {
|
||||
return Err(CliError {
|
||||
message: "can not add child".to_string(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
XMLNode::Element(element)
|
||||
}
|
||||
|
@ -1,190 +0,0 @@
|
||||
/*
|
||||
* hurl (https://hurl.dev)
|
||||
* Copyright (C) 2020 Orange
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use super::JunitError;
|
||||
use crate::cli;
|
||||
use crate::runner::{EntryResult, Error, HurlResult};
|
||||
use libxml::tree::{Document, Node};
|
||||
|
||||
impl HurlResult {
|
||||
///
|
||||
/// Export Hurl result to an XML Junit <testcase>
|
||||
///
|
||||
pub fn to_testcase(
|
||||
&self,
|
||||
doc: &Document,
|
||||
lines: &[String],
|
||||
) -> Result<libxml::tree::Node, JunitError> {
|
||||
let mut node = Node::new("testcase", None, doc).expect("XML Node");
|
||||
node.set_attribute("id", &self.filename)
|
||||
.expect("Set attribute id");
|
||||
let time_in_seconds = format!("{:.3}", self.time_in_ms as f64 / 1000.0);
|
||||
node.set_attribute("time", &time_in_seconds)
|
||||
.expect("Set attribute duration");
|
||||
|
||||
for entry in self.entries.clone() {
|
||||
for mut error in entry.errors(doc, lines, self.filename.clone())? {
|
||||
if node.add_child(&mut error).is_err() {
|
||||
return Err("can not add child".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl EntryResult {
|
||||
///
|
||||
/// Export entry result errors to XML Junit <error>/<failure>
|
||||
///
|
||||
fn errors(
|
||||
&self,
|
||||
doc: &Document,
|
||||
lines: &[String],
|
||||
filename: String,
|
||||
) -> Result<Vec<Node>, JunitError> {
|
||||
let mut errors = vec![];
|
||||
for error in self.errors.clone() {
|
||||
let error = error.to_junit_error(doc, lines, filename.clone())?;
|
||||
errors.push(error);
|
||||
}
|
||||
Ok(errors)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
///
|
||||
/// Export Hurl runner error to an XML Junit <error>/<failure>
|
||||
///
|
||||
fn to_junit_error(
|
||||
&self,
|
||||
doc: &Document,
|
||||
lines: &[String],
|
||||
filename: String,
|
||||
) -> Result<Node, JunitError> {
|
||||
let node_name = if self.assert { "failure" } else { "error" };
|
||||
let mut node = if let Ok(value) = Node::new(node_name, None, doc) {
|
||||
value
|
||||
} else {
|
||||
return Err("Can not create node".to_string());
|
||||
};
|
||||
let message = cli::error_string(lines, filename, self);
|
||||
if node.append_text(message.as_str()).is_err() {
|
||||
return Err("Can not append text".to_string());
|
||||
}
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::runner::{EntryResult, Error, HurlResult, RunnerError};
|
||||
use hurl_core::ast::SourceInfo;
|
||||
use libxml::tree::Document;
|
||||
|
||||
#[test]
|
||||
fn test_create_testcase_success() {
|
||||
let doc = Document::new().unwrap();
|
||||
let lines = vec![];
|
||||
let hurl_result = HurlResult {
|
||||
filename: "test.hurl".to_string(),
|
||||
entries: vec![],
|
||||
time_in_ms: 230,
|
||||
success: true,
|
||||
cookies: vec![],
|
||||
};
|
||||
assert_eq!(
|
||||
doc.node_to_string(&hurl_result.to_testcase(&doc, &lines).unwrap()),
|
||||
r#"<testcase id="test.hurl" time="0.230"/>"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_testcase_failure() {
|
||||
let lines = vec![
|
||||
"GET http://localhost:8000/not_found".to_string(),
|
||||
"HTTP/1.0 200".to_string(),
|
||||
];
|
||||
let doc = Document::new().unwrap();
|
||||
let hurl_result = HurlResult {
|
||||
filename: "test.hurl".to_string(),
|
||||
entries: vec![EntryResult {
|
||||
request: None,
|
||||
response: None,
|
||||
captures: vec![],
|
||||
asserts: vec![],
|
||||
errors: vec![Error {
|
||||
source_info: SourceInfo::init(2, 10, 2, 13),
|
||||
inner: RunnerError::AssertStatus {
|
||||
actual: "404".to_string(),
|
||||
},
|
||||
assert: true,
|
||||
}],
|
||||
time_in_ms: 0,
|
||||
}],
|
||||
time_in_ms: 230,
|
||||
success: true,
|
||||
cookies: vec![],
|
||||
};
|
||||
assert_eq!(
|
||||
doc.node_to_string(&hurl_result.to_testcase(&doc, &lines).unwrap()),
|
||||
r#"<testcase id="test.hurl" time="0.230"><failure>Assert Status
|
||||
--> test.hurl:2:10
|
||||
|
|
||||
2 | HTTP/1.0 200
|
||||
| ^^^ actual value is <404>
|
||||
|</failure></testcase>"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_testcase_error() {
|
||||
let lines = vec!["GET http://unknown".to_string()];
|
||||
let doc = Document::new().unwrap();
|
||||
let hurl_result = HurlResult {
|
||||
filename: "test.hurl".to_string(),
|
||||
entries: vec![EntryResult {
|
||||
request: None,
|
||||
response: None,
|
||||
captures: vec![],
|
||||
asserts: vec![],
|
||||
errors: vec![Error {
|
||||
source_info: SourceInfo::init(1, 5, 1, 19),
|
||||
inner: RunnerError::HttpConnection {
|
||||
url: "http://unknown".to_string(),
|
||||
message: "(6) Could not resolve host: unknown".to_string(),
|
||||
},
|
||||
assert: false,
|
||||
}],
|
||||
time_in_ms: 0,
|
||||
}],
|
||||
time_in_ms: 230,
|
||||
success: true,
|
||||
cookies: vec![],
|
||||
};
|
||||
assert_eq!(
|
||||
doc.node_to_string(&hurl_result.to_testcase(&doc, &lines).unwrap()),
|
||||
r#"<testcase id="test.hurl" time="0.230"><error>Http Connection
|
||||
--> test.hurl:1:5
|
||||
|
|
||||
1 | GET http://unknown
|
||||
| ^^^^^^^^^^^^^^ (6) Could not resolve host: unknown
|
||||
|</error></testcase>"#
|
||||
);
|
||||
}
|
||||
}
|
209
packages/hurl/src/report/junit/testcase.rs
Normal file
209
packages/hurl/src/report/junit/testcase.rs
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* hurl (https://hurl.dev)
|
||||
* Copyright (C) 2020 Orange
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
use crate::cli;
|
||||
use crate::runner::HurlResult;
|
||||
|
||||
use xmltree::{Element, XMLNode};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Testcase {
|
||||
id: String,
|
||||
time_in_ms: u128,
|
||||
failures: Vec<String>,
|
||||
errors: Vec<String>,
|
||||
}
|
||||
|
||||
impl Testcase {
|
||||
///
|
||||
/// create an XML Junit <testcase> from an Hurl result
|
||||
///
|
||||
pub fn from_hurl_result(hurl_result: &HurlResult, lines: &[String]) -> Testcase {
|
||||
let id = hurl_result.filename.clone();
|
||||
let time_in_ms = hurl_result.time_in_ms;
|
||||
let mut failures = vec![];
|
||||
let mut errors = vec![];
|
||||
|
||||
for error in hurl_result.errors().clone() {
|
||||
let message = cli::error_string(lines, hurl_result.filename.clone(), &error);
|
||||
if error.assert {
|
||||
failures.push(message);
|
||||
} else {
|
||||
errors.push(message);
|
||||
};
|
||||
}
|
||||
Testcase {
|
||||
id,
|
||||
time_in_ms,
|
||||
failures,
|
||||
errors,
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize to XML
|
||||
pub fn to_xml(&self) -> xmltree::Element {
|
||||
let name = "testcase".to_string();
|
||||
let mut attributes = indexmap::map::IndexMap::new();
|
||||
attributes.insert("id".to_string(), self.id.clone());
|
||||
let time_in_seconds = format!("{:.3}", self.time_in_ms as f64 / 1000.0);
|
||||
attributes.insert("time".to_string(), time_in_seconds);
|
||||
|
||||
let mut children = vec![];
|
||||
for message in self.failures.clone() {
|
||||
let element = Element {
|
||||
prefix: None,
|
||||
namespace: None,
|
||||
namespaces: None,
|
||||
name: "failure".to_string(),
|
||||
attributes: indexmap::map::IndexMap::new(),
|
||||
children: vec![XMLNode::Text(message)],
|
||||
};
|
||||
children.push(XMLNode::Element(element));
|
||||
}
|
||||
for message in self.errors.clone() {
|
||||
let element = Element {
|
||||
prefix: None,
|
||||
namespace: None,
|
||||
namespaces: None,
|
||||
name: "error".to_string(),
|
||||
attributes: indexmap::map::IndexMap::new(),
|
||||
children: vec![XMLNode::Text(message)],
|
||||
};
|
||||
children.push(XMLNode::Element(element));
|
||||
}
|
||||
Element {
|
||||
name,
|
||||
prefix: None,
|
||||
namespace: None,
|
||||
namespaces: None,
|
||||
attributes,
|
||||
children,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::report::junit::testcase::Testcase;
|
||||
use crate::runner::{EntryResult, Error, HurlResult, RunnerError};
|
||||
use hurl_core::ast::SourceInfo;
|
||||
|
||||
#[test]
|
||||
fn test_create_testcase_success() {
|
||||
let lines = vec![];
|
||||
let hurl_result = HurlResult {
|
||||
filename: "test.hurl".to_string(),
|
||||
entries: vec![],
|
||||
time_in_ms: 230,
|
||||
success: true,
|
||||
cookies: vec![],
|
||||
};
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
Testcase::from_hurl_result(&hurl_result, &lines)
|
||||
.to_xml()
|
||||
.write(&mut buffer)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&buffer).unwrap(),
|
||||
r#"<?xml version="1.0" encoding="UTF-8"?><testcase id="test.hurl" time="0.230" />"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_testcase_failure() {
|
||||
let lines = vec![
|
||||
"GET http://localhost:8000/not_found".to_string(),
|
||||
"HTTP/1.0 200".to_string(),
|
||||
];
|
||||
let hurl_result = HurlResult {
|
||||
filename: "test.hurl".to_string(),
|
||||
entries: vec![EntryResult {
|
||||
request: None,
|
||||
response: None,
|
||||
captures: vec![],
|
||||
asserts: vec![],
|
||||
errors: vec![Error {
|
||||
source_info: SourceInfo::init(2, 10, 2, 13),
|
||||
inner: RunnerError::AssertStatus {
|
||||
actual: "404".to_string(),
|
||||
},
|
||||
assert: true,
|
||||
}],
|
||||
time_in_ms: 0,
|
||||
}],
|
||||
time_in_ms: 230,
|
||||
success: true,
|
||||
cookies: vec![],
|
||||
};
|
||||
let mut buffer = Vec::new();
|
||||
Testcase::from_hurl_result(&hurl_result, &lines)
|
||||
.to_xml()
|
||||
.write(&mut buffer)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&buffer).unwrap(),
|
||||
r#"<?xml version="1.0" encoding="UTF-8"?><testcase id="test.hurl" time="0.230"><failure>Assert Status
|
||||
--> test.hurl:2:10
|
||||
|
|
||||
2 | HTTP/1.0 200
|
||||
| ^^^ actual value is <404>
|
||||
|</failure></testcase>"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_testcase_error() {
|
||||
let lines = vec!["GET http://unknown".to_string()];
|
||||
let hurl_result = HurlResult {
|
||||
filename: "test.hurl".to_string(),
|
||||
entries: vec![EntryResult {
|
||||
request: None,
|
||||
response: None,
|
||||
captures: vec![],
|
||||
asserts: vec![],
|
||||
errors: vec![Error {
|
||||
source_info: SourceInfo::init(1, 5, 1, 19),
|
||||
inner: RunnerError::HttpConnection {
|
||||
url: "http://unknown".to_string(),
|
||||
message: "(6) Could not resolve host: unknown".to_string(),
|
||||
},
|
||||
assert: false,
|
||||
}],
|
||||
time_in_ms: 0,
|
||||
}],
|
||||
time_in_ms: 230,
|
||||
success: true,
|
||||
cookies: vec![],
|
||||
};
|
||||
let mut buffer = Vec::new();
|
||||
Testcase::from_hurl_result(&hurl_result, &lines)
|
||||
.to_xml()
|
||||
.write(&mut buffer)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
std::str::from_utf8(&buffer).unwrap(),
|
||||
r#"<?xml version="1.0" encoding="UTF-8"?><testcase id="test.hurl" time="0.230"><error>Http Connection
|
||||
--> test.hurl:1:5
|
||||
|
|
||||
1 | GET http://unknown
|
||||
| ^^^^^^^^^^^^^^ (6) Could not resolve host: unknown
|
||||
|</error></testcase>"#
|
||||
);
|
||||
}
|
||||
}
|
@ -24,9 +24,8 @@ use super::runner::HurlResult;
|
||||
mod html;
|
||||
mod junit;
|
||||
|
||||
pub use junit::add_testcase;
|
||||
pub use junit::add_testsuite;
|
||||
pub use junit::create_or_get_junit_report;
|
||||
pub use junit::create_report as create_junit_report;
|
||||
pub use junit::Testcase;
|
||||
|
||||
pub fn parse_html(path: PathBuf) -> Result<Vec<HurlResult>, CliError> {
|
||||
if path.exists() {
|
||||
|
Loading…
Reference in New Issue
Block a user