infrasynth-backend-kit/tests/test_scheduler/test_views.py
jcv-dev 551b42eab5 feat: production-hardening pass across the kit
Close the gaps between the documented contract (API-STANDARD, TENANCY,
ENTITLEMENTS) and the implementation, and remove committed build artifacts.

Security:
- verify + process inbound webhooks (HMAC/handler verify, size limit,
  timestamp tolerance, idempotency via InboundEvent.external_id)
- real 2FA login flow (pre-auth challenge; tokens only after verify/recovery)
- wire HybridPermission into security/audit views; add API-key rotate and
  users/<id>/permissions|roles endpoints
- tenant-scoped throttling on by default; webhook replay protection
- verify MercadoPago webhook signatures
- login brute-force guard, configurable password policy, real ALTCHA PoW

Correctness:
- apply verified billing webhooks idempotently (subscription/entitlement/
  invoice/PaymentTransaction); scheduled payment lifecycle jobs
- capture audit update diffs automatically; add audit retention purge
- working notification retries, per-channel rate limits, log retention
- pluggable virus scanner, upload-size limit, pipeline toggle
- feature rollout %/environment targeting; settings-driven registrations
- workflow guards (instance cap, route depth, self-assignment, clone on re-entry)
- wire every previously-dead INFRASYNTH_* setting; drop truly dead ones

Delivery:
- README + CHANGELOG; CI format check + coverage gate
- keep test media out of the tree; untrack .coverage, __pycache__,
  egg-info, docs/ and invoice artifacts
2026-09-24 10:41:21 -05:00

125 lines
4.8 KiB
Python

from unittest import mock
import pytest
from infrasynth.features.models import FeatureFlag
from infrasynth.scheduler.models import ScheduledTask, TaskExecution
pytestmark = pytest.mark.django_db
TASKS_URL = "/api/v1/scheduler/tasks/"
EXECUTIONS_URL = "/api/v1/scheduler/executions/"
STATUS_URL = "/api/v1/scheduler/status/"
@pytest.fixture
def task():
return ScheduledTask.objects.create(
name="cleanup",
task_path="os.getpid",
schedule_type=ScheduledTask.ScheduleType.CRON,
schedule_config={"cron": "0 2 * * *"},
)
@pytest.fixture
def execution(task):
return TaskExecution.objects.create(
task=task,
status=TaskExecution.Status.SUCCESS,
started_at="2026-01-01T00:00:00Z",
completed_at="2026-01-01T00:00:01Z",
)
class TestScheduledTaskViewSet:
def test_list_tasks(self, authenticated_client, task):
response = authenticated_client.get(TASKS_URL)
assert response.status_code == 200
assert response.data["count"] == 1
assert response.data["results"][0]["name"] == "cleanup"
def test_requires_auth(self, api_client, task):
assert api_client.get(TASKS_URL).status_code == 401
def test_create_task(self, authenticated_client):
response = authenticated_client.post(
TASKS_URL,
{
"name": "backup",
"task_path": "os.getpid",
"schedule_type": "interval",
"schedule_config": {"interval": 3600},
},
format="json",
)
assert response.status_code == 201
assert ScheduledTask.objects.filter(name="backup").exists()
def test_retrieve_update_delete(self, authenticated_client, task):
response = authenticated_client.get(f"{TASKS_URL}{task.id}/")
assert response.status_code == 200
response = authenticated_client.patch(f"{TASKS_URL}{task.id}/", {"name": "renamed"}, format="json")
assert response.status_code == 200
task.refresh_from_db()
assert task.name == "renamed"
response = authenticated_client.delete(f"{TASKS_URL}{task.id}/")
assert response.status_code == 204
assert not ScheduledTask.objects.filter(pk=task.pk).exists()
def test_run_action(self, authenticated_client, task):
response = authenticated_client.post(f"{TASKS_URL}{task.id}/run/")
assert response.status_code == 200
assert response.data["status"] == "triggered"
assert TaskExecution.objects.filter(task=task).exists()
def test_toggle_action(self, authenticated_client, task):
response = authenticated_client.post(f"{TASKS_URL}{task.id}/toggle/")
assert response.status_code == 200
assert response.data["is_active"] is False
response = authenticated_client.post(f"{TASKS_URL}{task.id}/toggle/")
assert response.data["is_active"] is True
def test_disabled_feature_returns_404(self, authenticated_client):
FeatureFlag.objects.create(slug="scheduler", name="Scheduler", is_active=False)
assert authenticated_client.get(TASKS_URL).status_code == 404
class TestTaskExecutionViewSet:
def test_list_executions(self, authenticated_client, execution):
response = authenticated_client.get(EXECUTIONS_URL)
assert response.status_code == 200
assert response.data["count"] == 1
assert response.data["results"][0]["task_info"]["name"] == "cleanup"
def test_retrieve_execution(self, authenticated_client, execution):
response = authenticated_client.get(f"{EXECUTIONS_URL}{execution.id}/")
assert response.status_code == 200
assert response.data["status"] == "success"
def test_requires_auth(self, api_client, execution):
assert api_client.get(EXECUTIONS_URL).status_code == 401
class TestSchedulerStatusViewSet:
def test_queue_status(self, authenticated_client):
with mock.patch("celery.current_app") as app:
inspect = app.control.inspect()
inspect.active.return_value = {}
inspect.scheduled.return_value = {}
inspect.reserved.return_value = {}
response = authenticated_client.get(f"{STATUS_URL}queue_status/")
assert response.status_code == 200
assert response.data["total_active"] == 0
def test_workers(self, authenticated_client):
with mock.patch("celery.current_app") as app:
inspect = app.control.inspect()
inspect.stats.return_value = {}
inspect.active.return_value = {}
response = authenticated_client.get(f"{STATUS_URL}workers/")
assert response.status_code == 200
assert response.data == []
def test_requires_auth(self, api_client):
assert api_client.get(f"{STATUS_URL}queue_status/").status_code == 401