Files
Lamont/tests/unit/test_durable_queues.py
Chelsea Lee fbdf33e894
Some checks failed
CI / test (push) Has been cancelled
CI / compose-smoke (push) Has been cancelled
Build reusable bot framework
2026-07-19 21:53:24 -05:00

291 lines
9.1 KiB
Python

"""Focused unit coverage for durable job and outbound-message state changes."""
from datetime import datetime, timezone
import pytest
from core import jobs, outbox
NOW = datetime.now(timezone.utc)
MESSAGE_ID = "00000000-0000-0000-0000-000000000001"
class RecordingCursor:
def __init__(self, one=None, many=None):
self.one = list(one or [])
self.many = list(many or [])
self.executed = []
def execute(self, query, params=None):
self.executed.append((" ".join(query.split()), params))
def fetchone(self):
return self.one.pop(0) if self.one else None
def fetchall(self):
return self.many
@pytest.mark.parametrize("queue", [jobs, outbox])
def test_shared_timestamp_and_positive_validation(queue):
assert queue._timestamp("2026-01-02T03:04:05Z") == datetime(
2026, 1, 2, 3, 4, 5, tzinfo=timezone.utc
)
assert queue._timestamp(datetime(2026, 1, 2, 3, 4, 5)).tzinfo == timezone.utc
with pytest.raises(ValueError, match="datetime"):
queue._timestamp(123)
with pytest.raises(ValueError, match="whole number"):
queue._positive(None, "limit")
with pytest.raises(ValueError, match="at least 1"):
queue._positive(0, "limit")
with pytest.raises(ValueError, match="at most 2"):
queue._positive(3, "limit", 2)
def test_create_get_and_list_jobs_with_parameterized_filters():
created = {"id": "job-one", "status": "pending"}
cursor = RecordingCursor(one=[created])
result = jobs.create_job(
" sample.work ",
{"value": 1},
NOW,
user_uuid="user-one",
max_attempts="4",
idempotency_key="unique-work",
job_id="job-one",
cursor=cursor,
)
assert result == created
params = cursor.executed[0][1]
assert params["job_type"] == "sample.work"
assert params["max_attempts"] == 4
assert params["payload"].adapted == {"value": 1}
with pytest.raises(ValueError, match="job_type"):
jobs.create_job(" ", {}, NOW, cursor=cursor)
cursor = RecordingCursor(one=[created])
assert jobs.get_job("job-one", cursor=cursor) == created
cursor = RecordingCursor(many=[created])
assert jobs.list_jobs(
user_uuid="user-one",
status="pending",
job_type="sample.work",
limit=3,
cursor=cursor,
) == [created]
query, params = cursor.executed[0]
assert "user_uuid = %s" in query and "job_type = %s" in query
assert params == ["user-one", "pending", "sample.work", 3]
def test_job_claim_renew_complete_retry_and_cancel_paths():
claimed = [{"id": "job-one", "status": "running"}]
cursor = RecordingCursor(many=claimed)
assert jobs.claim_due_jobs(
"worker-one",
limit=2,
lease_seconds=60,
job_types="sample.work",
cursor=cursor,
) == claimed
assert len(cursor.executed) == 2
assert cursor.executed[1][1]["job_types"] == ["sample.work"]
assert jobs.claim_due_jobs("worker", job_types=[], cursor=cursor) == []
with pytest.raises(ValueError, match="worker_id"):
jobs.claim_due_jobs("", cursor=cursor)
updated = {"id": "job-one", "status": "running"}
cursor = RecordingCursor(one=[updated, {**updated, "status": "completed"}])
assert jobs.renew_job_lease("job-one", "worker-one", 30, cursor=cursor) == updated
assert jobs.complete_job("job-one", "worker-one", cursor=cursor)[
"status"
] == "completed"
cursor = RecordingCursor(
one=[
{"attempts": 2, "max_attempts": 3},
{"id": "job-one", "status": "pending"},
]
)
retried = jobs.fail_job(
"job-one", "worker-one", "temporary", retry_seconds=10, cursor=cursor
)
assert retried["status"] == "pending"
assert cursor.executed[1][1]["delay"] == 20
assert cursor.executed[1][1]["exhausted"] is False
cursor = RecordingCursor(
one=[
{"attempts": 3, "max_attempts": 3},
{"id": "job-one", "status": "failed"},
]
)
assert jobs.fail_job("job-one", "worker-one", "fatal", cursor=cursor)[
"status"
] == "failed"
assert cursor.executed[1][1]["exhausted"] is True
assert jobs.fail_job(
"missing", "worker-one", "ignored", cursor=RecordingCursor()
) is None
cursor = RecordingCursor(one=[{"id": "job-one", "status": "cancelled"}])
assert jobs.cancel_job("job-one", user_uuid="user-one", cursor=cursor)[
"status"
] == "cancelled"
cursor = RecordingCursor(many=[{"id": "job-two"}])
assert jobs.cancel_jobs(job_type="sample.work", cursor=cursor) == [
{"id": "job-two"}
]
with pytest.raises(ValueError, match="filter"):
jobs.cancel_jobs(cursor=cursor)
def test_enqueue_get_and_list_messages_with_parameterized_filters():
created = {"id": "message-one", "status": "pending"}
cursor = RecordingCursor(one=[created])
result = outbox.enqueue_message(
"user-one",
" discord_dm ",
{"content": "hello"},
"unique-message",
available_at=NOW,
max_attempts=4,
message_id="message-one",
cursor=cursor,
)
assert result == created
params = cursor.executed[0][1]
assert params["channel"] == "discord_dm"
assert params["payload"].adapted == {"content": "hello"}
invalidValues = [
(None, "discord_dm", {}, "key", "user_uuid"),
("user", " ", {}, "key", "channel"),
("user", "discord_dm", {}, None, "idempotency_key"),
("user", "discord_dm", None, "key", "payload"),
]
for userUUID, channel, payload, key, error in invalidValues:
with pytest.raises(ValueError, match=error):
outbox.enqueue_message(
userUUID, channel, payload, key, available_at=NOW, cursor=cursor
)
cursor = RecordingCursor(one=[created])
assert outbox.get_message(MESSAGE_ID, cursor=cursor) == created
assert outbox.get_message("not-a-uuid", cursor=cursor) is None
cursor = RecordingCursor(many=[created])
assert outbox.list_messages(
user_uuid="user-one",
status="pending",
channel="discord_dm",
limit=2,
cursor=cursor,
) == [created]
def test_outbox_claim_renew_delivery_retry_and_cancel_paths():
claimed = [{"id": "message-one", "status": "delivering"}]
cursor = RecordingCursor(many=claimed)
assert outbox.claim_messages(
"worker-one",
channel="discord_dm",
limit=2,
lease_seconds=60,
cursor=cursor,
) == claimed
assert len(cursor.executed) == 2
with pytest.raises(ValueError, match="worker_id"):
outbox.claim_messages(None, cursor=cursor)
cursor = RecordingCursor(
one=[
{"id": "message-one", "status": "delivering"},
{"id": "message-one", "status": "delivered"},
]
)
assert outbox.renew_message_lease(
"message-one", "worker-one", 60, cursor=cursor
)["status"] == "delivering"
delivered = outbox.mark_delivered(
"message-one",
"worker-one",
external_message_id="discord-123",
cursor=cursor,
)
assert delivered["status"] == "delivered"
assert cursor.executed[1][1][0] == "discord-123"
cursor = RecordingCursor(
one=[
{"attempts": 1, "max_attempts": 3},
{"id": "message-one", "status": "pending"},
]
)
retried = outbox.retry_message(
"message-one", "worker-one", "temporary", retry_seconds=15, cursor=cursor
)
assert retried["status"] == "pending"
assert cursor.executed[1][1]["delay"] == 15
cursor = RecordingCursor(
one=[
{"attempts": 3, "max_attempts": 3},
{"id": "message-one", "status": "failed"},
]
)
assert outbox.retry_message(
"message-one", "worker-one", "fatal", cursor=cursor
)["status"] == "failed"
assert outbox.retry_message(
"missing", "worker-one", "ignored", cursor=RecordingCursor()
) is None
cursor = RecordingCursor(one=[{"id": "message-one", "status": "cancelled"}])
assert outbox.cancel_message(
"message-one", user_uuid="user-one", cursor=cursor
)["status"] == "cancelled"
cursor = RecordingCursor(many=[{"id": "message-two"}])
assert outbox.cancel_messages(channel="discord_dm", cursor=cursor) == [
{"id": "message-two"}
]
with pytest.raises(ValueError, match="filter"):
outbox.cancel_messages(cursor=cursor)
def test_retry_backoff_is_capped():
cursor = RecordingCursor(
one=[
{"attempts": 20, "max_attempts": 30},
{"id": "job", "status": "pending"},
]
)
jobs.fail_job(
"job",
"worker",
"retry",
retry_seconds=30,
max_retry_seconds=90,
cursor=cursor,
)
assert cursor.executed[1][1]["delay"] == 90
cursor = RecordingCursor(
one=[
{"attempts": 20, "max_attempts": 30},
{"id": "message", "status": "pending"},
]
)
outbox.retry_message(
"message",
"worker",
"retry",
retry_seconds=30,
max_retry_seconds=90,
cursor=cursor,
)
assert cursor.executed[1][1]["delay"] == 90