use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct TestResult {
pub uuid: Uuid,
pub history_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub test_case_id: Option<String>,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub full_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description_html: Option<String>,
#[serde(default)]
pub links: Vec<Link>,
#[serde(default)]
pub labels: Vec<Label>,
#[serde(default)]
pub parameters: Vec<Parameter>,
#[serde(default)]
pub attachments: Vec<Attachment>,
pub status: Status,
#[serde(skip_serializing_if = "Option::is_none")]
pub status_details: Option<StatusDetails>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stage: Option<Stage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop: Option<i64>,
#[serde(default)]
pub steps: Vec<Step>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Link {
pub r#type: String,
pub name: String,
pub url: url::Url,
}
#[derive(Debug, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct Labels {
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub severity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub owner: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub epic: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub feature: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub story: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_suite: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suite: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sub_suite: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub package: Option<String>,
#[serde(flatten)]
pub labels: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "name", content = "value")]
#[serde(rename_all = "camelCase")]
pub enum Label {
Tag(String),
Severity(String),
Owner(String),
Epic(String),
Feature(String),
Story(String),
ParentSuite(String),
Suite(String),
SubSuite(String),
Package(String),
#[serde(untagged)]
Custom {
name: String,
value: String,
},
}
impl Label {
pub fn custom(name: impl Into<String>, value: impl Into<String>) -> Self {
Label::Custom {
name: name.into(),
value: value.into(),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Parameter {
pub name: String,
pub value: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub excluded: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<ParameterMode>,
}
#[derive(Debug, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ParameterMode {
#[default]
Default,
Masked,
Hidden,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Attachment {
pub name: String,
pub source: String,
pub r#type: String,
}
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
#[serde(rename_all = "lowercase")]
pub enum Status {
Failed,
Broken,
Passed,
Skipped,
#[default]
Unknown,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StatusDetails {
#[serde(skip_serializing_if = "Option::is_none")]
pub known: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub muted: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub flaky: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trace: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Stage {
Scheduled,
Running,
Finished,
Pending,
Interrupted,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Step {
pub name: String,
#[serde(default)]
pub parameters: Vec<Parameter>,
#[serde(default)]
pub attachments: Vec<Attachment>,
pub status: Status,
#[serde(skip_serializing_if = "Option::is_none")]
pub status_details: Option<StatusDetails>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stage: Option<Stage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop: Option<i64>,
#[serde(default)]
pub steps: Vec<Step>,
}
impl TestResult {
pub fn new(name: String) -> Self {
TestResult {
uuid: Uuid::new_v4(),
history_id: String::new(), test_case_id: None,
name,
full_name: None,
description: None,
description_html: None,
links: Default::default(),
labels: Default::default(),
parameters: Default::default(),
attachments: Default::default(),
status: Status::Unknown,
status_details: None,
stage: None,
start: None,
stop: None,
steps: Default::default(),
}
}
pub fn start(&mut self) {
self.start = Some(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64,
);
self.stage = Some(Stage::Running);
}
pub fn stop(&mut self) {
self.stop = Some(
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64,
);
self.stage = Some(Stage::Finished);
}
pub fn set_history_id(&mut self) {
self.history_id = format!("{}-history", self.name);
}
}