use crate::dyndns_service::DynDnsProvider; use fqdn::FQDN; use serde::{Deserialize, Serialize}; use serde_with::DisplayFromStr; use serde_with::serde_as; use strum::Display; #[derive(Debug, Deserialize, Serialize)] #[serde(transparent)] struct Config { wans: Vec } #[derive(Debug, Deserialize, Serialize)] struct WanConfig { interface: Option, #[serde(flatten)] dns_record: DnsRecord, providers: Vec, } #[derive(Debug, Display, Deserialize, Serialize)] #[derive(PartialEq)] pub enum DnsRecordType { A, AAAA } #[serde_as] #[derive(Debug, Deserialize, Serialize)] struct DnsRecord { #[serde_as(as = "DisplayFromStr")] fqdn: FQDN, #[serde(default = "default_ttl")] ttl: u32, #[serde(default = "default_record_type")] record_type: DnsRecordType, } fn default_record_type() -> DnsRecordType { DnsRecordType::A } fn default_ttl() -> u32 { 300 } #[cfg(test)] mod tests { use std::error::Error; use std::fs::{read_dir, File}; use std::io::BufReader; use super::*; use serde_json::json; use std::str::FromStr; use crate::dyndns_service::DynDnsProvider::GANDI; use crate::dyndns_service::gandi::Gandi; #[test] fn check_minimal_config() { let input = json!({ "fqdn": "dyn.domain.com", "providers": [ { "type": "GANDI", "api_key": "SOME-API-KEY", } ] }); let wan_config = serde_json::from_value::(input).unwrap(); assert_eq!( wan_config.dns_record.fqdn, FQDN::from_str("dyn.domain.com").unwrap() ); assert_eq!(wan_config.interface, None); assert_eq!(wan_config.providers.len(), 1); let expected = Gandi::new("SOME-API-KEY".to_string()); let actual = wan_config.providers.get(0).unwrap(); assert_eq!(&GANDI(expected), actual); } #[test] fn check_defaults_on_dns_record_deserialization() { let input = json!({ "fqdn": "dyn.mydomain.com", }); let dns_record = serde_json::from_value::(input).unwrap(); assert_eq!(dns_record.record_type, default_record_type()); assert_eq!(dns_record.ttl, default_ttl()); assert_eq!(dns_record.fqdn, FQDN::from_str("dyn.mydomain.com").unwrap()); } #[test] fn check_file_configs() -> Result<(), Box> { let path = std::path::Path::new("test"); for entry in read_dir(path)? { let entry = entry?; let test_file_path = entry.path(); if test_file_path.extension().unwrap_or_default() != "json" { continue; } let file = File::open(test_file_path)?; let reader = BufReader::new(file); let actual: Config = serde_json::from_reader(reader)?; assert_eq!(actual.wans.len(), 2); } Ok(()) } }