Checkpoint: management app redesign, onboarding/signup workflow, and events calendar backend
Large uncommitted body of work accumulated across sessions on this branch -- committing as a checkpoint so it's tracked and future worktree-isolated agents see the real codebase instead of a stale ancestor commit. Covers the management app's dedicated Tailwind theme and templates, the club onboarding requirement/signup workflow (club/services/onboarding.py, requirement/status models, sign-up dashboard), fee/status auto-activation decoupling, referee management, and the new events calendar grid service layer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
from io import StringIO
|
||||
from unittest.mock import patch
|
||||
|
||||
from allauth.mfa.models import Authenticator
|
||||
from celery import shared_task
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.cache import cache
|
||||
from django.core.management import call_command
|
||||
@@ -10,7 +12,8 @@ from waffle import flag_is_active, get_waffle_flag_model
|
||||
|
||||
from club.models import Club
|
||||
|
||||
from .models import Maintenance
|
||||
from .jobs import JOB_REGISTRY
|
||||
from .models import JobRun, Maintenance
|
||||
|
||||
Flag = get_waffle_flag_model()
|
||||
User = get_user_model()
|
||||
@@ -259,3 +262,63 @@ class MaintenanceCommandTests(TestCase):
|
||||
Maintenance.start()
|
||||
|
||||
self.run_command("migrate", "--check") # raises SystemExit only if migrations are pending
|
||||
|
||||
|
||||
@shared_task(name="features.tests.succeed")
|
||||
def _succeed_task():
|
||||
return "did the thing"
|
||||
|
||||
|
||||
@shared_task(name="features.tests.fail")
|
||||
def _fail_task():
|
||||
raise RuntimeError("boom")
|
||||
|
||||
|
||||
@shared_task(name="features.tests.untracked")
|
||||
def _untracked_task():
|
||||
return "quiet"
|
||||
|
||||
|
||||
class JobRunTests(TestCase):
|
||||
"""The Celery signal wiring in features/signals.py, exercised against throwaway tasks
|
||||
(module-level, like any real task -- Celery's registry gets confused if the same task
|
||||
name is redefined per-test) rather than the real billing/club/events ones: what matters
|
||||
here is that a JobRun row appears for anything in JOB_REGISTRY and only for that, not the
|
||||
domain logic of any one scheduled job (each of those has its own tests alongside its
|
||||
management command)."""
|
||||
|
||||
def setUp(self):
|
||||
self.succeed_task, self.fail_task, self.untracked_task = _succeed_task, _fail_task, _untracked_task
|
||||
patcher = patch.dict(JOB_REGISTRY, {"features.tests.succeed": {}, "features.tests.fail": {}})
|
||||
patcher.start()
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
def test_a_successful_run_is_recorded(self):
|
||||
# .apply() runs the task synchronously, in-process, regardless of
|
||||
# CELERY_TASK_ALWAYS_EAGER -- exactly what the task_prerun/task_postrun signal
|
||||
# handlers in features/signals.py are wired to react to either way.
|
||||
self.succeed_task.apply()
|
||||
|
||||
run = JobRun.objects.get(name="features.tests.succeed")
|
||||
self.assertEqual(run.status, JobRun.Status.SUCCESS)
|
||||
self.assertEqual(run.detail, "did the thing")
|
||||
self.assertEqual(run.error, "")
|
||||
self.assertIsNotNone(run.started_at)
|
||||
self.assertIsNotNone(run.finished_at)
|
||||
|
||||
def test_a_failed_run_is_recorded(self):
|
||||
# A real worker never raises a task's exception back into whoever called .delay() --
|
||||
# it's async, the caller is long gone by the time the task runs -- so eager mode
|
||||
# doesn't either (CELERY_TASK_EAGER_PROPAGATES is left at its default False; see
|
||||
# rosterchief/settings.py). The result carries FAILURE instead, same as production.
|
||||
result = self.fail_task.apply()
|
||||
|
||||
self.assertEqual(result.state, "FAILURE")
|
||||
run = JobRun.objects.get(name="features.tests.fail")
|
||||
self.assertEqual(run.status, JobRun.Status.FAILURE)
|
||||
self.assertIn("boom", run.error)
|
||||
|
||||
def test_a_task_outside_the_registry_is_not_tracked(self):
|
||||
self.untracked_task.apply()
|
||||
|
||||
self.assertFalse(JobRun.objects.filter(name="features.tests.untracked").exists())
|
||||
|
||||
Reference in New Issue
Block a user