use durare::{
DurableContext, DurableEngine, Error, ErrorCode, InMemoryProvider, Result, WorkflowOptions,
WorkflowQueue,
};
use std::sync::Arc;
use std::time::Duration;
#[tokio::test]
async fn builder_builds_a_runnable_engine() -> Result<()> {
let provider = Arc::new(InMemoryProvider::new());
let mut b = DurableEngine::builder(provider);
b.app_version("9.9.9");
b.register("add", |_ctx: DurableContext, n: i64| async move {
Ok::<_, Error>(n + 1)
});
let engine = b.build().await?;
assert_eq!(engine.app_version(), "9.9.9");
engine.launch().await?;
let out: i64 = engine
.start("add", 41_i64, WorkflowOptions::with_id("wf-b1"))
.await?
.result()
.await?;
assert_eq!(out, 42);
engine.shutdown(Duration::from_secs(1)).await?;
Ok(())
}
#[tokio::test]
async fn builder_rejects_duplicate_names() -> Result<()> {
let provider = Arc::new(InMemoryProvider::new());
let mut b = DurableEngine::builder(provider);
b.register("dup", |_ctx: DurableContext, _: ()| async move {
Ok::<_, Error>(1_i64)
});
b.register("dup", |_ctx: DurableContext, _: ()| async move {
Ok::<_, Error>(2_i64)
});
let Err(err) = b.build().await else {
panic!("duplicate name must error");
};
assert_eq!(err.code(), ErrorCode::ConflictingRegistration);
assert!(err.to_string().contains("dup"));
Ok(())
}
#[tokio::test]
async fn builder_configured_instances_do_not_conflict() -> Result<()> {
let provider = Arc::new(InMemoryProvider::new());
let mut b = DurableEngine::builder(provider);
b.register_configured("greet", "en", |_ctx: DurableContext, _: ()| async move {
Ok::<_, Error>("hi".to_string())
});
b.register_configured("greet", "fr", |_ctx: DurableContext, _: ()| async move {
Ok::<_, Error>("salut".to_string())
});
let engine = b.build().await?;
engine.shutdown(Duration::from_secs(1)).await?;
let provider = Arc::new(InMemoryProvider::new());
let mut b2 = DurableEngine::builder(provider);
b2.register_configured("greet", "en", |_ctx: DurableContext, _: ()| async move {
Ok::<_, Error>("a".to_string())
});
b2.register_configured("greet", "en", |_ctx: DurableContext, _: ()| async move {
Ok::<_, Error>("b".to_string())
});
let Err(err) = b2.build().await else {
panic!("same config twice must error");
};
assert_eq!(err.code(), ErrorCode::ConflictingRegistration);
Ok(())
}
#[tokio::test]
async fn builder_rejects_duplicate_queue_names() -> Result<()> {
let provider = Arc::new(InMemoryProvider::new());
let mut b = DurableEngine::builder(provider);
b.register_queue(WorkflowQueue::new("orders"));
b.register_queue(WorkflowQueue::new("orders"));
let Err(err) = b.build().await else {
panic!("duplicate queue name must error");
};
assert_eq!(err.code(), ErrorCode::ConflictingRegistration);
assert!(err.to_string().contains("orders"));
Ok(())
}
#[tokio::test]
async fn builder_rejects_reserved_queue_name() -> Result<()> {
let provider = Arc::new(InMemoryProvider::new());
let mut b = DurableEngine::builder(provider);
b.register_queue(WorkflowQueue::new("_dbos_internal_queue"));
let Err(err) = b.build().await else {
panic!("reserved queue name must error");
};
assert_eq!(err.code(), ErrorCode::ConflictingRegistration);
Ok(())
}
#[tokio::test]
async fn builder_rejects_reserved_debouncer_workflow_name() -> Result<()> {
let provider = Arc::new(InMemoryProvider::new());
let mut b = DurableEngine::builder(provider);
b.register(
"_dbos_debouncer",
|_ctx: DurableContext, _: ()| async move { Ok::<_, Error>(()) },
);
let Err(err) = b.build().await else {
panic!("reserved workflow name must error");
};
assert_eq!(err.code(), ErrorCode::ConflictingRegistration);
Ok(())
}
#[tokio::test]
async fn connect_dispatches_by_scheme() -> Result<()> {
let mut b = DurableEngine::connect("memory:").await?;
b.register("noop", |_ctx: DurableContext, _: ()| async move {
Ok::<_, Error>(())
});
let engine = b.build().await?;
engine.launch().await?;
let () = engine
.start("noop", (), WorkflowOptions::with_id("wf-c1"))
.await?
.result()
.await?;
engine.shutdown(Duration::from_secs(1)).await?;
assert!(
DurableEngine::connect("mysql://nope").await.is_err(),
"an unrecognized scheme is rejected"
);
Ok(())
}