use std::collections::BTreeMap;
use thiserror::Error;
use uuid::Uuid;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TemplateParameterSpec {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RouteTemplateSpec {
pub id: String,
pub parameters: Vec<TemplateParameterSpec>,
pub route: serde_json::Value,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TemplatedRouteSpec {
pub route_template_ref: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub route_id: Option<String>,
pub parameters: BTreeMap<String, String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TemplateInstanceRecord {
pub template_id: String,
pub instance_id: Uuid,
pub route_id: String,
pub parameters: BTreeMap<String, String>,
}
#[derive(Debug, Clone, Error)]
#[non_exhaustive]
pub enum TemplateError {
#[error("missing required parameter: {0}")]
MissingParameter(String),
#[error("unknown parameter: {0}")]
UnknownParameter(String),
#[error("template already registered: {0}")]
AlreadyRegistered(String),
#[error("invalid template body: {0}")]
InvalidBody(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn template_error_converts_to_camel_error() {
use crate::error::CamelError;
let err = TemplateError::MissingParameter("host".into());
let camel: CamelError = err.into();
assert!(matches!(camel, CamelError::Config(_)));
}
#[test]
fn template_parameter_spec_serializes() {
let spec = TemplateParameterSpec {
name: "host".into(),
default_value: Some("localhost".into()),
description: Some("The target host".into()),
};
let json = serde_json::to_string(&spec).unwrap();
assert!(json.contains("host"));
assert!(json.contains("localhost"));
}
#[test]
fn template_parameter_spec_roundtrip() {
let spec = TemplateParameterSpec {
name: "port".into(),
default_value: None,
description: None,
};
let json = serde_json::to_string(&spec).unwrap();
let round: TemplateParameterSpec = serde_json::from_str(&json).unwrap();
assert_eq!(round.name, "port");
assert!(round.default_value.is_none());
assert!(round.description.is_none());
}
#[test]
fn route_template_spec_serializes() {
let tpl = RouteTemplateSpec {
id: "http-route".into(),
parameters: vec![TemplateParameterSpec {
name: "path".into(),
default_value: None,
description: None,
}],
route: serde_json::json!({"from": {"uri": "rest:{{path}}"}}),
};
let json = serde_json::to_string(&tpl).unwrap();
assert!(json.contains("http-route"));
assert!(json.contains("path"));
}
#[test]
fn templated_route_spec_serializes() {
let spec = TemplatedRouteSpec {
route_template_ref: "http-route".into(),
route_id: Some("my-route".into()),
parameters: [("path".into(), "/api".into())].into_iter().collect(),
};
let json = serde_json::to_string(&spec).unwrap();
assert!(json.contains("http-route"));
assert!(json.contains("/api"));
}
#[test]
fn template_instance_record_serializes() {
let instance = TemplateInstanceRecord {
template_id: "http-route".into(),
instance_id: Uuid::nil(),
route_id: "my-route".into(),
parameters: [("path".into(), "/api".into())].into_iter().collect(),
};
let json = serde_json::to_string(&instance).unwrap();
assert!(json.contains("http-route"));
assert!(json.contains("my-route"));
}
#[test]
fn template_error_display_messages() {
let cases: Vec<(TemplateError, &str)> = vec![
(
TemplateError::MissingParameter("x".into()),
"missing required parameter: x",
),
(
TemplateError::UnknownParameter("y".into()),
"unknown parameter: y",
),
(
TemplateError::AlreadyRegistered("z".into()),
"template already registered: z",
),
(
TemplateError::InvalidBody("d".into()),
"invalid template body: d",
),
];
for (err, expected) in cases {
assert_eq!(format!("{err}"), expected);
}
}
#[test]
fn template_error_is_clone() {
let err = TemplateError::MissingParameter("host".into());
let cloned = err.clone();
assert!(matches!(cloned, TemplateError::MissingParameter(_)));
}
}