use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::atomic::AtomicBool;
use std::sync::{Mutex, MutexGuard, PoisonError};
use crate::server::Drip;
use crate::{MockNexus, Scenario};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Outcome {
Status(u16),
Reset,
PartialRead { bytes: usize },
Stalled,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReqLog {
pub method: String,
pub path: String,
pub outcome: Outcome,
}
#[derive(Debug)]
pub(crate) struct Shared {
pub(crate) scenario: Scenario,
pub(crate) store: Mutex<HashMap<String, Vec<u8>>>,
pub(crate) log: Mutex<Vec<ReqLog>>,
pub(crate) first_request: Mutex<HashMap<String, u32>>,
pub(crate) first_put: Mutex<HashMap<String, u32>>,
pub(crate) first_get: Mutex<HashMap<String, u32>>,
pub(crate) drift: AtomicBool,
pub(crate) auth_b64: Option<String>,
pub(crate) drip: Option<Drip>,
pub(crate) sizeless: bool,
pub(crate) partial_first_put: Option<usize>,
pub(crate) cut_first_get: Option<(usize, bool)>,
pub(crate) rate_first: Option<(usize, u64)>,
pub(crate) flaky_first: Option<u32>,
pub(crate) members: Vec<SocketAddr>,
}
impl Shared {
pub(crate) fn hosted(scenario: Scenario) -> Self {
let auth_b64 = match &scenario {
Scenario::Auth401 { user, pass } | Scenario::Auth403 { user, pass } => {
Some(crate::base64::encode(format!("{user}:{pass}").as_bytes()))
}
_ => None,
};
let drip = match &scenario {
Scenario::Slow {
chunk_delay_ms,
chunk_size,
} => Some(Drip {
delay_ms: *chunk_delay_ms,
chunk_size: *chunk_size,
}),
_ => None,
};
let sizeless = matches!(&scenario, Scenario::Sizeless);
let (partial_first_put, cut_first_get, rate_first, flaky_first) = match &scenario {
Scenario::PartialPut {
first_attempt_bytes,
} => (Some(*first_attempt_bytes), None, None, None),
Scenario::CutBody {
after_bytes,
fake_length,
} => (None, Some((*after_bytes, *fake_length)), None, None),
Scenario::RateLimit {
first_429s,
retry_after_secs,
} => (None, None, Some((*first_429s, *retry_after_secs)), None),
Scenario::Flaky { first_failures } => (None, None, None, Some(*first_failures)),
_ => (None, None, None, None),
};
Self {
scenario,
store: Mutex::new(HashMap::new()),
log: Mutex::new(Vec::new()),
first_request: Mutex::new(HashMap::new()),
first_put: Mutex::new(HashMap::new()),
first_get: Mutex::new(HashMap::new()),
drift: AtomicBool::new(false),
auth_b64,
drip,
sizeless,
partial_first_put,
cut_first_get,
rate_first,
flaky_first,
members: Vec::new(),
}
}
pub(crate) fn group(members: &[&MockNexus]) -> Self {
Self {
members: members.iter().map(|m| m.addr()).collect(),
..Self::hosted(Scenario::Atomic)
}
}
}
pub(crate) fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
mutex.lock().unwrap_or_else(PoisonError::into_inner)
}