blob: f27a9d0786afc058f96d1a93d2895c6b0c0e4cea [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use serde::{Deserialize, Serialize};
use serde_json::from_str;
use std::fs;
use std::path::Path;
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TestConfigV1 {
/// Arbitrary tags to identify and categorize the tests.
#[serde(default)]
pub tags: Vec<TestTag>,
/// Specifies requested features for the test.
#[serde(default)]
pub requested_vars: RequestedVars,
/// Defines the configuration that is directly passed to the Host test binary.
#[serde(default)]
pub execution: serde_json::Value,
}
/// Configuration for a test to be executed.
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(tag = "version")]
pub enum TestConfiguration {
#[serde(rename = "0.1")]
V1 {
#[serde(flatten)]
config: TestConfigV1,
},
}
impl From<TestConfigV1> for TestConfiguration {
fn from(config: TestConfigV1) -> Self {
Self::V1 { config }
}
}
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord, Clone)]
pub struct TestTag {
pub key: String,
pub value: String,
}
/// Specifies requested features for the test.
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Default)]
pub struct RequestedVars {
/// List of known env variables which are required by the test.
#[serde(default, alias = "KNOWN_VARS")]
pub known_vars: Vec<String>,
/// Extra variables required by the test.
#[serde(default, alias = "EXTRA_VARS")]
pub extra_vars: Vec<String>,
}
impl TryFrom<&Path> for TestConfiguration {
type Error = anyhow::Error;
fn try_from(file_path: &Path) -> Result<Self, Self::Error> {
// Read JSON data from the file
let json_str = fs::read_to_string(&file_path)?;
// Deserialize JSON data into a TestConfiguration struct
let test_config: TestConfiguration = from_str(&json_str)?;
Ok(test_config)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use std::io::Write;
use tempfile::NamedTempFile;
#[test]
fn test_success() {
let mut temp_file = NamedTempFile::new().unwrap();
let test_data = json!({
"environment": {},
"version": "0.1",
"tags": [
{ "key": "tag1", "value": "value1" },
{ "key": "tag2", "value": "value2" }
],
"requested_vars": {
"KNOWN_VARS": ["FUCHSIA_SDK_TOOL_PATH"],
"EXTRA_VARS": ["FOO", "BAR"]
},
"execution": {
"some_object": { "some_key": "val" },
"some_array": [1, 10],
}
});
temp_file.write_all(test_data.to_string().as_bytes()).unwrap();
let file_path = temp_file.path();
let test_config = TestConfiguration::try_from(file_path).expect("invalid json");
assert_eq!(
test_config,
TestConfigV1 {
tags: vec![
TestTag { key: "tag1".to_string(), value: "value1".to_string() },
TestTag { key: "tag2".to_string(), value: "value2".to_string() },
],
requested_vars: RequestedVars {
known_vars: vec!["FUCHSIA_SDK_TOOL_PATH".into()],
extra_vars: vec!["FOO".into(), "BAR".into()],
},
execution: json!({
"some_object": { "some_key": "val" },
"some_array": [1, 10]
}),
}
.into()
);
temp_file.close().expect("Failed to close temporary file");
}
#[test]
fn test_default() {
let mut temp_file = NamedTempFile::new().unwrap();
let test_data = json!({
"environment": {}, // extra value in config file
"version": "0.1",
});
temp_file.write_all(test_data.to_string().as_bytes()).unwrap();
let file_path = temp_file.path();
let test_config = TestConfiguration::try_from(file_path).expect("invalid json");
assert_eq!(
test_config,
TestConfigV1 {
tags: vec![],
requested_vars: RequestedVars { known_vars: vec![], extra_vars: vec![] },
execution: serde_json::Value::default(),
}
.into()
);
temp_file.close().expect("Failed to close temporary file");
}
#[test]
fn test_invalid_json() {
let mut temp_file = NamedTempFile::new().unwrap();
temp_file.write_all(b"invalid_json_data").unwrap();
let file_path = temp_file.path();
let _err = TestConfiguration::try_from(file_path).expect_err("parsing should error out");
temp_file.close().expect("Failed to close temporary file");
}
#[test]
fn test_empty_config() {
// Create a temporary JSON file with missing "version" field
let mut temp_file = NamedTempFile::new().unwrap();
let test_data = "{}";
temp_file.write_all(test_data.to_string().as_bytes()).unwrap();
let file_path = temp_file.path();
let err = TestConfiguration::try_from(file_path).expect_err("parsing should error out");
let err_str = format!("{}", err);
assert!(err_str.contains("missing field `version`"), "{}", err_str);
temp_file.close().expect("Failed to close temporary file");
}
#[test]
fn test_invalid_version() {
// Create a temporary JSON file with invalid "count" field
let mut temp_file = NamedTempFile::new().unwrap();
let test_data = json!({
"tags": [],
"version": "1.0",
"execution": {}
});
temp_file.write_all(test_data.to_string().as_bytes()).unwrap();
let file_path = temp_file.path();
let err = TestConfiguration::try_from(file_path).expect_err("parsing should error out");
let err_str = format!("{}", err);
assert!(err_str.contains("unknown variant `1.0`, expected `0.1`"), "{}", err_str);
temp_file.close().expect("Failed to close temporary file");
}
}