use async_trait::async_trait;
use foxtive_cron::contracts::{
JobContract, MisfirePolicy, RetryPolicy, Schedule, ValidatedSchedule,
};
use foxtive_cron::{CronError, CronResult};
use std::borrow::Cow;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::time::Duration;
#[allow(dead_code)]
pub struct MockJob {
pub id: String,
pub name: String,
pub schedule: ValidatedSchedule,
pub run_count: Arc<AtomicUsize>,
pub should_fail: bool,
pub start_count: Arc<AtomicUsize>,
pub complete_count: Arc<AtomicUsize>,
pub error_count: Arc<AtomicUsize>,
pub timeout: Option<Duration>,
pub priority: i32,
pub concurrency_limit: Option<usize>,
pub misfire_policy: MisfirePolicy,
pub retry_policy: RetryPolicy,
}
#[allow(dead_code)]
impl MockJob {
pub fn new(id: impl Into<String>, schedule_expr: &str) -> Self {
let id = id.into();
Self {
id: id.clone(),
name: id,
schedule: ValidatedSchedule::parse(schedule_expr).unwrap(),
run_count: Arc::new(AtomicUsize::new(0)),
should_fail: false,
start_count: Arc::new(AtomicUsize::new(0)),
complete_count: Arc::new(AtomicUsize::new(0)),
error_count: Arc::new(AtomicUsize::new(0)),
timeout: None,
priority: 0,
concurrency_limit: None,
misfire_policy: MisfirePolicy::Skip,
retry_policy: RetryPolicy::None,
}
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn with_priority(mut self, priority: i32) -> Self {
self.priority = priority;
self
}
pub fn with_concurrency_limit(mut self, limit: usize) -> Self {
self.concurrency_limit = Some(limit);
self
}
pub fn with_misfire_policy(mut self, policy: MisfirePolicy) -> Self {
self.misfire_policy = policy;
self
}
pub fn with_retry_policy(mut self, policy: RetryPolicy) -> Self {
self.retry_policy = policy;
self
}
pub fn failing(id: impl Into<String>, schedule_expr: &str) -> Self {
Self {
should_fail: true,
..Self::new(id, schedule_expr)
}
}
}
#[async_trait]
impl JobContract for MockJob {
async fn run(&self) -> CronResult<()> {
self.run_count
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
if self.should_fail {
Err(CronError::ExecutionError(anyhow::anyhow!(
"intentional failure"
)))
} else {
Ok(())
}
}
fn id(&self) -> Cow<'_, str> {
Cow::Borrowed(&self.id)
}
fn name(&self) -> Cow<'_, str> {
Cow::Borrowed(&self.name)
}
fn schedule(&self) -> &dyn Schedule {
&self.schedule
}
fn timeout(&self) -> Option<Duration> {
self.timeout
}
fn priority(&self) -> i32 {
self.priority
}
fn concurrency_limit(&self) -> Option<usize> {
self.concurrency_limit
}
fn misfire_policy(&self) -> MisfirePolicy {
self.misfire_policy
}
fn retry_policy(&self) -> RetryPolicy {
self.retry_policy.clone()
}
async fn on_start(&self) {
self.start_count
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
async fn on_complete(&self) {
self.complete_count
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
async fn on_error(&self, _error: &CronError) {
self.error_count
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
}
}