use crate::{error, Result};
use indexmap::IndexMap;
use log::{info, warn};
use ommui_data::filesystem::DeviceBuilder;
use ommui_data::ommui::LoadableDevice as _;
use ommui_data::samplic::LoadableDevice as _;
use ommui_data::LoadableDevice as _;
use snafu::ResultExt;
use std::path::PathBuf;
use structopt::StructOpt;
use uuid::Uuid;
#[derive(StructOpt, Debug)]
pub struct Arguments {
#[structopt(parse(from_os_str), default_value = ".")]
pub path: PathBuf,
#[structopt(parse(from_os_str), long = "junit-file")]
pub junit_file: Option<PathBuf>,
}
impl Arguments {
pub fn run(&self, product_id: &str, company_id: &str) -> Result<()> {
let mut results = TestResults::new();
let name = "device::build";
match DeviceBuilder::new(product_id, company_id)
.base_system_path(&self.path)
.build()
{
Ok(device) => {
results.add_ok(name, name);
let mut check = DeviceCheck {
results: &mut results,
device,
product_id: product_id.to_string(),
company_id: company_id.to_string(),
};
check.run_checks()?;
}
Err(e) => {
results.add_failure(
name,
name,
&format!("{}", e),
&format!("{:?}", e),
);
}
}
if let Some(ref path) = self.junit_file {
let file = std::fs::File::create(path).context(error::Io)?;
let mut writer =
quick_xml::Writer::new_with_indent(file, b' ', 4);
results.build_dom().to_writer(&mut writer).unwrap();
};
Ok(())
}
}
struct DeviceCheck<'a> {
pub results: &'a mut TestResults,
pub device: ommui_data::filesystem::Device,
pub product_id: String,
pub company_id: String,
}
impl DeviceCheck<'_> {
fn run_checks(&mut self) -> Result<()> {
self.check_load()?;
for calibration_id in self
.device
.ommui()
.load_calibration_index()
.context(error::OmmuiData)?
{
self.check_calibration(&calibration_id)?;
}
for sampling_id in self
.device
.load_sampling_index()
.context(error::OmmuiData)?
{
self.check_sampling(&sampling_id)?;
}
for profile_id in self
.device
.ommui()
.load_system_profile_index()
.context(error::OmmuiData)?
{
self.check_profile(profile_id)?;
}
Ok(())
}
fn check_load(&mut self) -> Result<()> {
let name = "device::load";
match self.device.load_device() {
Ok(_) => {
self.results.add_ok(name, name);
}
Err(e) => {
self.results.add_failure(
name,
name,
&format!("{}", e),
&format!("{:?}", e),
);
}
}
Ok(())
}
fn check_calibration(&mut self, calibration_id: &str) -> Result<()> {
let name = format!("calibration::{}", calibration_id);
self.results.add_ok(&name, &name);
Ok(())
}
fn check_sampling(&mut self, sampling_id: &str) -> Result<()> {
let name = format!("sampling::{}", sampling_id);
self.results.add_ok(&name, &name);
Ok(())
}
fn check_profile(&mut self, profile_id: Uuid) -> Result<()> {
let name = format!("profile::{}", profile_id);
let profile = self
.device
.samplic()
.load_system_profile(profile_id)
.context(error::OmmuiData)?;
let sampling = self
.device
.load_sampling(&profile.sampling_id)
.context(error::OmmuiData)?;
{
let name = format!("{}::sampling_exists", name);
self.results.add_ok(&name, &name);
}
for parameter_id in sampling.samplic.parameters.keys() {
let name = format!(
"{}::sampling::{}::parameter_exists::{}",
name, profile.sampling_id, parameter_id
);
if profile.parameters.contains_key(parameter_id) {
self.results.add_ok(&name, &name);
} else {
self.results.add_failure(
&name,
&name,
"Parameter does not exist",
&format!(
"Parameter {:?} of sampling {:?} \
is not present in the profile",
parameter_id, profile.sampling_id
),
);
}
}
self.results.add_ok(&name, &name);
Ok(())
}
}
#[derive(Debug)]
struct TestFailure {
failure_type: String,
details: String,
}
#[derive(Debug)]
struct TestResult {
pub classname: String,
pub failure: Option<TestFailure>,
}
impl TestResult {
fn build_ok(classname: &str) -> Self {
TestResult {
classname: classname.to_string(),
failure: None,
}
}
fn build_failure(classname: &str, failure: TestFailure) -> Self {
TestResult {
classname: classname.to_string(),
failure: Some(failure),
}
}
}
#[derive(Debug)]
struct TestResults {
pub tests: IndexMap<String, TestResult>,
}
impl TestResults {
pub fn new() -> Self {
TestResults {
tests: IndexMap::new(),
}
}
pub fn add_ok(&mut self, name: &str, classname: &str) {
self.add(name, TestResult::build_ok(classname));
}
pub fn add_failure(
&mut self,
name: &str,
classname: &str,
failure_type: &str,
failure_details: &str,
) {
self.add(
name,
TestResult::build_failure(
classname,
TestFailure {
failure_type: failure_type.to_string(),
details: failure_details.to_string(),
},
),
);
}
pub fn add(&mut self, name: &str, result: TestResult) {
match result.failure {
None => info!("OK: {:?}", name),
Some(ref failure) => {
warn!("FAILED: {:?}\n{}", name, failure.details)
}
}
self.tests.insert(name.to_string(), result);
}
pub fn build_dom(&self) -> minidom::Element {
let mut element = minidom::Element::builder("testsuite")
.attr("tests", self.tests.len())
.build();
for (name, test) in self.tests.iter() {
let mut test_node = minidom::Element::builder("testcase")
.attr("classname", &test.classname)
.attr("name", name)
.build();
if let Some(ref details) = test.failure {
let mut failure = minidom::Element::builder("failure")
.attr("type", &details.failure_type)
.build();
failure.append_text_node(&details.details);
test_node.append_child(failure);
}
element.append_child(test_node);
}
element
}
}