use serde::{Deserialize, Serialize};
use crate::error::AxError;
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(untagged)]
pub enum ProviderDegraded {
Refused(AxError),
VaultFellBack(VaultFellBack),
}
impl<'de> Deserialize<'de> for ProviderDegraded {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let line = serde_json::Value::deserialize(deserializer)?;
AxError::deserialize(&line)
.map(Self::Refused)
.or_else(|as_refusal| {
VaultFellBack::deserialize(&line)
.map(Self::VaultFellBack)
.map_err(|as_fallback| {
serde::de::Error::custom(format!(
"neither a provider refusal ({as_refusal}) nor a vault fallback \
({as_fallback})"
))
})
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct VaultFellBack {
pub component: String,
pub fallback: String,
pub persistence: String,
pub reason: String,
}
#[cfg(test)]
#[allow(clippy::unwrap_used, reason = "test code")]
mod tests {
use super::*;
use crate::event::Payload;
#[test]
fn a_vault_line_keeps_the_bytes_its_ledger_already_holds() {
let line = r#"{"component":"vault","fallback":"session-memory","persistence":"this-process","reason":"probe reference unparsable"}"#;
let read: ProviderDegraded = serde_json::from_str::<Payload>(line)
.unwrap()
.read()
.unwrap();
assert!(matches!(read, ProviderDegraded::VaultFellBack(_)));
assert_eq!(
serde_json::to_string(&Payload::of(&read).unwrap()).unwrap(),
line
);
}
#[test]
fn a_line_that_is_neither_shape_names_what_each_shape_missed() {
let line = r#"{"code":"E_PROVIDER","component":"vault"}"#;
let err = serde_json::from_str::<Payload>(line)
.unwrap()
.read::<ProviderDegraded>()
.unwrap_err()
.to_string();
assert!(
err.contains("neither a provider refusal (missing field `action`)")
&& err.contains("nor a vault fallback (missing field `fallback`)"),
"{err}"
);
}
}