use std::time::Duration;
use serde::{Deserialize, Serialize};
use crate::EffectKind;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "mode")]
pub enum VerificationContract {
None,
Authoritative,
EventuallyConsistent {
settle: Duration,
},
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ExecutionContract {
pub format_version: u32,
pub kind: EffectKind,
pub remote_idempotency: bool,
pub verification: VerificationContract,
pub handler_version: String,
pub adapter: Option<String>,
pub require_approval: bool,
pub automatic_retry: bool,
pub max_attempts: u32,
}
impl ExecutionContract {
pub fn new(kind: EffectKind, max_attempts: u32) -> Self {
Self {
format_version: 1,
kind,
remote_idempotency: false,
verification: VerificationContract::None,
handler_version: "1".into(),
adapter: None,
require_approval: false,
automatic_retry: true,
max_attempts,
}
}
pub fn permits(&self, requested: &Self) -> bool {
if self.format_version != 1 || requested.format_version != 1 {
return false;
}
self == requested
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn compatibility_never_grants_changed_execution_assumptions(
remote in any::<bool>(), approval in any::<bool>(),
automatic in any::<bool>(), attempts in any::<u32>(),
format in 2_u32..u32::MAX,
) {
let mut stored = ExecutionContract::new(EffectKind::IrreversibleWrite, attempts);
stored.remote_idempotency = remote;
stored.require_approval = approval;
stored.automatic_retry = automatic;
prop_assert!(stored.permits(&stored));
let mut changed = stored.clone();
changed.remote_idempotency = !remote;
prop_assert!(!stored.permits(&changed));
changed = stored.clone();
changed.require_approval = !approval;
prop_assert!(!stored.permits(&changed));
changed = stored.clone();
changed.automatic_retry = !automatic;
prop_assert!(!stored.permits(&changed));
changed = stored.clone();
changed.format_version = format;
prop_assert!(!stored.permits(&changed));
prop_assert!(!changed.permits(&changed));
}
}
}