use reddb_server::storage::schema::Value;
use reddb_server::{RedDBOptions, RedDBRuntime};
fn runtime() -> RedDBRuntime {
RedDBRuntime::with_options(RedDBOptions::in_memory()).expect("runtime boots")
}
fn exec(rt: &RedDBRuntime, sql: &str) {
rt.execute_query(sql)
.unwrap_or_else(|err| panic!("{sql}: {err:?}"));
}
fn delivery_ids(result: &reddb_server::RuntimeQueryResult) -> Vec<String> {
result
.result
.records
.iter()
.map(|rec| match rec.get("delivery_id") {
Some(Value::Text(s)) => s.to_string(),
other => panic!("expected text delivery_id, got {other:?}"),
})
.collect()
}
#[test]
fn queue_claim_acquires_deliveries_and_locks_them() {
let rt = runtime();
exec(&rt, "CREATE QUEUE qclaim");
exec(&rt, "QUEUE PUSH qclaim 'job-1'");
exec(&rt, "QUEUE PUSH qclaim 'job-2'");
exec(&rt, "QUEUE PUSH qclaim 'job-3'");
let first = rt
.execute_query(
"UPDATE qclaim SET status = 'processing' WHERE status = 'pending' \
CLAIM LIMIT 2 ORDER BY enqueued_at ASC",
)
.expect("queue claim succeeds");
assert_eq!(first.affected_rows, 2, "claims up to the requested limit");
let first_ids = delivery_ids(&first);
assert_eq!(
first_ids.len(),
2,
"each claimed message carries a delivery_id"
);
let second = rt
.execute_query(
"UPDATE qclaim SET status = 'processing' CLAIM LIMIT 5 ORDER BY enqueued_at ASC",
)
.expect("second queue claim succeeds");
assert_eq!(
second.affected_rows, 1,
"the two pending deliveries stay locked; only one message is left"
);
}
#[test]
fn queue_claim_delivery_id_is_a_real_lifecycle_handle() {
let rt = runtime();
exec(&rt, "CREATE QUEUE qack");
exec(&rt, "QUEUE PUSH qack 'payload-1'");
let claimed = rt
.execute_query(
"UPDATE qack SET status = 'processing' CLAIM LIMIT 1 ORDER BY enqueued_at ASC",
)
.expect("queue claim succeeds");
assert_eq!(claimed.affected_rows, 1);
let delivery_id = delivery_ids(&claimed)
.into_iter()
.next()
.expect("a delivery was acquired");
exec(
&rt,
&format!("QUEUE ACK qack WITH delivery_id = '{delivery_id}'"),
);
let empty = rt
.execute_query(
"UPDATE qack SET status = 'processing' CLAIM LIMIT 5 ORDER BY enqueued_at ASC",
)
.expect("claim on drained queue succeeds");
assert_eq!(empty.affected_rows, 0, "acked delivery is not re-claimable");
}
#[test]
fn queue_claim_descending_order_is_rejected() {
let rt = runtime();
exec(&rt, "CREATE QUEUE qdesc");
exec(&rt, "QUEUE PUSH qdesc 'job-1'");
let err = rt
.execute_query(
"UPDATE qdesc SET status = 'processing' \
CLAIM LIMIT 1 ORDER BY enqueued_at DESC",
)
.expect_err("descending ORDER BY conflicts with FIFO delivery");
let msg = format!("{err:?}");
assert!(
msg.contains("cannot be expressed") && msg.contains("FIFO"),
"expected a clear InvalidOperation about FIFO delivery order, got: {msg}"
);
}
#[test]
fn queue_claim_exact_is_rejected() {
let rt = runtime();
exec(&rt, "CREATE QUEUE qexact");
exec(&rt, "QUEUE PUSH qexact 'job-1'");
let err = rt
.execute_query(
"UPDATE qexact SET status = 'processing' CLAIM EXACT 3 ORDER BY enqueued_at ASC",
)
.expect_err("CLAIM EXACT cannot be expressed through queue delivery");
let msg = format!("{err:?}");
assert!(
msg.contains("CLAIM EXACT") && msg.contains("cannot be expressed"),
"expected a clear InvalidOperation about CLAIM EXACT, got: {msg}"
);
}