use std::sync::Arc;
use std::sync::Mutex;
use std::sync::PoisonError;
use std::time::Duration;
use leptoskit_db::Db;
use leptoskit_db::Timestamp;
use crate::server::jobs::Clock;
use crate::server::jobs::Faults;
use crate::server::jobs::JobRow;
use crate::server::jobs::Settings;
pub struct TestJobs {
db: Db,
settings: Settings,
faults: Arc<Faults>,
cron_from: Mutex<Timestamp>,
}
impl TestJobs {
pub fn new(db: &Db) -> Self {
let clock = Clock::manual();
let faults = Arc::new(Faults::default());
let mut settings = Settings::new(clock.clone());
settings.faults = Some(Arc::clone(&faults));
Self {
db: db.clone(),
cron_from: Mutex::new(clock.now()),
settings,
faults,
}
}
#[must_use]
pub fn lease(mut self, lease: Duration) -> Self {
self.settings.lease = lease;
self
}
#[must_use]
pub fn queue(mut self, queue: impl Into<String>, concurrency: usize) -> Self {
Arc::make_mut(&mut self.settings.queues).insert(queue.into(), concurrency.max(1));
self
}
pub fn now(&self) -> Timestamp {
self.settings.clock.now()
}
pub async fn advance(&self, by: Duration) {
self.settings.clock.advance(by);
let until = self.now();
let from = *self
.cron_from
.lock()
.unwrap_or_else(PoisonError::into_inner);
crate::server::jobs::enqueue_cron(&self.db, from, until)
.await
.expect("cron jobs enqueue");
*self
.cron_from
.lock()
.unwrap_or_else(PoisonError::into_inner) = until;
}
pub async fn run_jobs_until_idle(&self) -> usize {
let mut runs = 0;
loop {
if crate::server::jobs::run_one(&self.db, &self.settings, false)
.await
.expect("jobs claim and run")
{
runs += 1;
continue;
}
let swept = crate::server::jobs::sweep_failures(&self.db)
.await
.expect("on_failure runs");
if swept == 0 {
return runs;
}
runs += swept;
}
}
pub fn kill_in_step(&self, name: &str) {
self.faults.kill_in(name);
}
pub async fn sweep_again(&self, id: leptoskit_db::Id<JobRow>) {
JobRow::update()
.filter(|job| job.id.eq(id) & job.state.eq(crate::server::jobs::JobState::Failed))
.set(|job| job.failure_pending, true)
.run(&self.db.system("sweep a job again in a test"))
.await
.expect("the job updates");
}
pub async fn prune(&self, age: Duration) -> u64 {
crate::server::jobs::worker_prune_at(&self.db, self.now(), age)
.await
.expect("finished jobs prune")
}
pub async fn all(&self) -> Vec<JobRow> {
JobRow::query()
.order_by(|job| job.created_at.asc())
.all(&self.db.system("read jobs in a test"))
.await
.expect("jobs read")
}
}
#[cfg(feature = "live")]
#[derive(Clone)]
pub struct LiveClients {
pipe: crate::server::live::memory::Pipe,
}
#[cfg(feature = "live")]
impl LiveClients {
#[must_use]
pub fn new(live: &crate::server::Live) -> Self {
Self {
pipe: crate::server::live::memory::Pipe::new(live),
}
}
pub fn header(&self, name: &str, value: Option<&str>) {
self.pipe.header(name, value);
}
#[must_use]
pub fn client(&self, config: &crate::client::ClientConfig) -> crate::client::LiveClient {
crate::client::LiveClient::new(config, Arc::new(self.pipe.clone()))
}
pub fn install(&self, config: &crate::client::ClientConfig) -> bool {
crate::client::live::install_client(self.client(config))
}
pub fn outage(&self, offline: bool) {
self.pipe.outage(offline);
}
}