Skip to content

Commit 11c8557

Browse files
manuvanegasclaude
andcommitted
Add RedisJobStore tests and fixture
Introduce a pytest fixture for RedisJobStore and add comprehensive tests for Redis-backed job storage. Updates conftest to import RedisJobStore and provide redis_job_store with teardown flushing. Tests cover update/get semantics, overwrite behavior, missing keys, TTL enforcement (using _JOB_TTL_SECONDS), key namespacing, and handling of full success payloads to ensure Redis store correctness. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5a6cce8 commit 11c8557

2 files changed

Lines changed: 66 additions & 2 deletions

File tree

timeseries/app/tests/conftest.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def _find_config_root() -> Path:
2626
os.chdir(_find_config_root())
2727

2828
from app.store.data_reader import DataReader
29-
from app.store.jobs import FileSystemJobStore
29+
from app.store.jobs import FileSystemJobStore, RedisJobStore
3030

3131

3232
# ---------------------------------------------------------------------------
@@ -112,6 +112,13 @@ def fs_job_store(tmp_jobs_dir):
112112
return FileSystemJobStore(directory=tmp_jobs_dir)
113113

114114

115+
@pytest.fixture
116+
def redis_job_store():
117+
store = RedisJobStore(os.environ.get("REDIS_URL", "redis://redis:6379"))
118+
yield store
119+
store._client.flushdb()
120+
121+
115122
# ---------------------------------------------------------------------------
116123
# Data reader mock
117124

timeseries/app/tests/store/test_jobs.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import pytest
66

7-
from app.store.jobs import cleanup_stale_jobs
7+
from app.store.jobs import cleanup_stale_jobs, _JOB_TTL_SECONDS
88

99

1010
# ---------------------------------------------------------------------------
@@ -72,3 +72,60 @@ def test_cleanup_keeps_recent_files(tmp_path, monkeypatch):
7272
cleanup_stale_jobs(max_age_hours=24)
7373

7474
assert recent_file.exists()
75+
76+
77+
# ---------------------------------------------------------------------------
78+
# RedisJobStore
79+
80+
def test_redis_update_job_stores_value(redis_job_store):
81+
redis_job_store.update_job("job-001", {"status": "PENDING"})
82+
raw = redis_job_store._client.get("job:job-001")
83+
assert json.loads(raw) == {"status": "PENDING"}
84+
85+
86+
def test_redis_update_job_overwrites(redis_job_store):
87+
redis_job_store.update_job("job-002", {"status": "PENDING"})
88+
redis_job_store.update_job("job-002", {"status": "SUCCESS", "result": {}})
89+
result = redis_job_store.get_job_status("job-002")
90+
assert result == {"status": "SUCCESS", "result": {}}
91+
92+
93+
def test_redis_get_job_status_existing(redis_job_store):
94+
payload = {"status": "PROCESSING"}
95+
redis_job_store.update_job("job-003", payload)
96+
assert redis_job_store.get_job_status("job-003") == payload
97+
98+
99+
def test_redis_get_job_status_missing_returns_none(redis_job_store):
100+
assert redis_job_store.get_job_status("nonexistent-id") is None
101+
102+
103+
def test_redis_update_job_sets_ttl(redis_job_store):
104+
redis_job_store.update_job("job-004", {"status": "PENDING"})
105+
ttl = redis_job_store._client.ttl("job:job-004")
106+
# TTL should be set and within expected range (allow 1s of drift)
107+
assert 0 < ttl <= _JOB_TTL_SECONDS
108+
109+
110+
def test_redis_update_job_resets_ttl_on_overwrite(redis_job_store):
111+
redis_job_store.update_job("job-005", {"status": "PENDING"})
112+
redis_job_store.update_job("job-005", {"status": "SUCCESS"})
113+
ttl = redis_job_store._client.ttl("job:job-005")
114+
assert 0 < ttl <= _JOB_TTL_SECONDS
115+
116+
117+
def test_redis_key_namespacing(redis_job_store):
118+
redis_job_store.update_job("job-006", {"status": "PENDING"})
119+
# Key must use the 'job:' prefix — bare id should not exist
120+
assert redis_job_store._client.get("job-006") is None
121+
assert redis_job_store._client.get("job:job-006") is not None
122+
123+
124+
def test_redis_full_success_payload(redis_job_store):
125+
payload = {
126+
"status": "SUCCESS",
127+
"result": {"values": [1.0, 2.0, 3.0], "nodata_count": 0},
128+
"base_series": {"timesteps": ["0100", "0101", "0102"]},
129+
}
130+
redis_job_store.update_job("job-007", payload)
131+
assert redis_job_store.get_job_status("job-007") == payload

0 commit comments

Comments
 (0)