use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use umbral::plugin::{AppContext, Plugin, PluginError};
use umbral::{App, Settings};
#[derive(Clone, Debug)]
struct SeedingPlugin {
fired: Arc<AtomicUsize>,
}
impl Plugin for SeedingPlugin {
fn name(&self) -> &'static str {
"seeding"
}
fn on_ready(&self, _ctx: &AppContext) -> Result<(), PluginError> {
self.fired.fetch_add(1, Ordering::SeqCst);
Ok(())
}
}
async fn deferred_app() -> (App, Arc<AtomicUsize>) {
let settings = Settings::from_env().expect("figment defaults always load");
let pool = umbral::db::connect_sqlite("sqlite::memory:")
.await
.expect("in-memory sqlite connects");
let fired = Arc::new(AtomicUsize::new(0));
let app = App::builder()
.settings(settings)
.database("default", pool)
.plugin(SeedingPlugin {
fired: fired.clone(),
})
.build_deferred()
.expect("App::build_deferred");
(app, fired)
}
#[allow(dead_code)]
fn argv(args: &[&str]) -> Vec<std::ffi::OsString> {
std::iter::once("umbral".into())
.chain(args.iter().map(|a| std::ffi::OsString::from(*a)))
.collect()
}
#[tokio::test]
async fn a_command_that_runs_against_live_data_fires_on_ready() {
let (app, fired) = deferred_app().await;
let out = std::env::temp_dir().join("umbral_on_ready_lifecycle_dump.json");
let _ = umbral_cli::dispatch_with_argv(
app,
argv(&[
"dumpdata",
"--output",
out.to_str().expect("utf-8 temp path"),
]),
)
.await;
let _ = std::fs::remove_file(&out);
assert_eq!(
fired.load(Ordering::SeqCst),
1,
"dumpdata runs against a migrated database, so on_ready must fire first",
);
}