use crate::pipeline::FlowHandle;
use crate::testing::stage_journal::StageJournalLookupError;
use obzenflow_core::event::chain_event::ChainEvent;
use obzenflow_core::journal::Journal;
use obzenflow_core::StageId;
use std::collections::HashMap;
use std::sync::Arc;
struct StageJournalMap {
stage_data_journals: HashMap<StageId, Arc<dyn Journal<ChainEvent>>>,
}
impl StageJournalMap {
fn from_stage_list(
stage_data_journals: Vec<(StageId, Arc<dyn Journal<ChainEvent>>)>,
) -> Result<Self, StageJournalLookupError> {
let mut map: HashMap<StageId, Arc<dyn Journal<ChainEvent>>> = HashMap::new();
for (stage_id, journal) in stage_data_journals {
if map.insert(stage_id, journal).is_some() {
return Err(StageJournalLookupError::DuplicateStageJournal(stage_id));
}
}
Ok(Self {
stage_data_journals: map,
})
}
fn get(&self, stage_id: StageId) -> Option<&Arc<dyn Journal<ChainEvent>>> {
self.stage_data_journals.get(&stage_id)
}
}
pub struct FlowTestHarness {
inner: FlowHandle,
stage_journals: StageJournalMap,
}
impl FlowTestHarness {
pub fn from_parts(
inner: FlowHandle,
stage_data_journals: Vec<(StageId, Arc<dyn Journal<ChainEvent>>)>,
) -> Result<Self, StageJournalLookupError> {
let stage_journals = StageJournalMap::from_stage_list(stage_data_journals)?;
Ok(Self {
inner,
stage_journals,
})
}
pub fn stage_journal_for_test(
&self,
stage_name: &str,
) -> Result<(StageId, Arc<dyn Journal<ChainEvent>>), StageJournalLookupError> {
use crate::id_conversions::StageIdExt;
let topology = self
.inner
.topology()
.ok_or(StageJournalLookupError::MissingTopology)?;
let mut matches: Vec<StageId> = topology
.stages()
.filter(|s| s.name == stage_name)
.map(|s| StageId::from_topology_id(s.id))
.collect();
let stage_id = match matches.len() {
0 => {
return Err(StageJournalLookupError::UnknownStage(
stage_name.to_string(),
))
}
1 => matches.remove(0),
_ => {
return Err(StageJournalLookupError::AmbiguousStage(
stage_name.to_string(),
))
}
};
let journal = self
.stage_journals
.get(stage_id)
.ok_or_else(|| StageJournalLookupError::MissingStageJournal(stage_name.to_string()))?;
Ok((stage_id, journal.clone()))
}
pub fn into_inner(self) -> FlowHandle {
self.inner
}
}
impl std::ops::Deref for FlowTestHarness {
type Target = FlowHandle;
fn deref(&self) -> &FlowHandle {
&self.inner
}
}