pub mod effect;
pub mod live_folder;
pub mod pulse;
pub mod value_gen;
use tokio::sync::broadcast;
use tokio::task::JoinHandle;
use vantage_diorama::ChangeEvent;
use vantage_vista::Vista;
use vantage_vista::mocks::MockShell;
pub use effect::{FakerCtx, FakerEffect, FifoEffect, StaticEffect};
pub use live_folder::{
EVENT_TYPES, Entry, EntryKind, LiveFolderConfig, LiveFolderSim, PushMode, format_ts,
};
pub use pulse::{PulseConfig, PulseKey, PulseRole, PulseSim};
pub use value_gen::ValueGen;
#[derive(Clone, Debug)]
pub struct FakerColumn {
pub name: String,
pub ty: String,
pub flags: Vec<String>,
}
pub struct FakerTable {
pub vista: Vista,
pub events: broadcast::Sender<ChangeEvent>,
_task: Option<AbortOnDrop>,
}
impl FakerTable {
pub fn build(
name: impl Into<String>,
columns: Vec<FakerColumn>,
id_column: impl Into<String>,
effect: Box<dyn FakerEffect>,
) -> Self {
let shell = MockShell::new();
let (events, _) = broadcast::channel(EVENT_CAPACITY);
let ctx = std::sync::Arc::new(FakerCtx::new(
shell.clone(),
events.clone(),
columns,
id_column.into(),
));
effect.seed(&ctx);
let vista = Vista::new(name, Box::new(shell));
let task = effect.is_live().then(|| {
AbortOnDrop(tokio::spawn(async move {
effect.run(ctx).await;
}))
});
Self {
vista,
events,
_task: task,
}
}
pub fn split(self) -> (Vista, FakerHandle) {
let Self {
vista,
events,
_task,
} = self;
(vista, FakerHandle { events, _task })
}
}
pub struct FakerHandle {
pub events: broadcast::Sender<ChangeEvent>,
_task: Option<AbortOnDrop>,
}
const EVENT_CAPACITY: usize = 1024;
struct AbortOnDrop(JoinHandle<()>);
impl Drop for AbortOnDrop {
fn drop(&mut self) {
self.0.abort();
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
use vantage_dataset::prelude::ReadableValueSet;
fn columns() -> Vec<FakerColumn> {
vec![
FakerColumn {
name: "id".into(),
ty: "string".into(),
flags: vec!["id".into()],
},
FakerColumn {
name: "email".into(),
ty: "string".into(),
flags: vec![],
},
]
}
#[tokio::test]
async fn static_table_seeds_rows_and_has_no_live_task() {
let table = FakerTable::build(
"events",
columns(),
"id",
Box::new(StaticEffect { count: 20 }),
);
let rows = table.vista.list_values().await.unwrap();
assert_eq!(rows.len(), 20);
}
#[tokio::test]
async fn fifo_table_broadcasts_inserts_as_it_runs() {
let table = FakerTable::build(
"events",
columns(),
"id",
Box::new(FifoEffect {
interval: Duration::from_millis(5),
retention_lo: Duration::from_secs(30),
retention_hi: Duration::from_secs(60),
}),
);
let mut rx = table.events.subscribe();
let got_insert = tokio::time::timeout(Duration::from_secs(1), recv_insert(&mut rx))
.await
.expect("expected an Inserted within 1s");
assert!(got_insert);
drop(table);
}
async fn recv_insert(rx: &mut broadcast::Receiver<ChangeEvent>) -> bool {
loop {
match rx.recv().await {
Ok(ChangeEvent::Inserted { .. }) => return true,
Ok(_) => continue,
Err(_) => return false,
}
}
}
}