ajout de tests
CI - Security, Lint & Tests / validate (push) Failing after 56s

This commit is contained in:
cedrick2711
2026-08-25 15:53:46 -04:00
parent 1549fbaef3
commit d18979a3e9
14 changed files with 1253 additions and 42 deletions
+170
View File
@@ -0,0 +1,170 @@
"""Admin season lifecycle — start/end and gate on team matches.
ADMIN-007. The season_active setting gates regular-season match scheduling
for non-admins. These tests verify start/end season and the gate.
"""
import pytest
from app.extensions import db
from app.models import AppSettings, OrgTeam, TeamMatch, User
NON_ADMIN_ROLES = ['manager', 'coach']
def _redirected(response):
return response.status_code in (301, 302)
# ---------------------------------------------------------------------------
# Season lifecycle
# ---------------------------------------------------------------------------
class TestSeasonLifecycle:
def test_start_season_sets_fields(self, client, as_role):
as_role('admin')
client.post(
'/admin/season/start',
data={'season_name': 'Fall 2026', 'season_start': '2026-09-01'},
follow_redirects=False,
)
with client.application.app_context():
assert AppSettings.get('season_name') == 'Fall 2026'
assert AppSettings.get('season_start') == '2026-09-01'
assert AppSettings.get_bool('season_active', default=False)
def test_cannot_start_season_when_already_active(self, client, as_role):
as_role('admin')
client.post(
'/admin/season/start',
data={'season_name': 'Fall 2026', 'season_start': '2026-09-01'},
)
# Second start should be rejected
response = client.post(
'/admin/season/start',
data={'season_name': 'Spring 2027', 'season_start': '2027-01-01'},
follow_redirects=True,
)
html = response.data.decode()
assert 'already active' in html.lower()
def test_start_season_creates_audit_log(self, client, as_role):
from app.models import AuditLog
as_role('admin')
client.post(
'/admin/season/start',
data={'season_name': 'Fall 2026', 'season_start': '2026-09-01'},
)
with client.application.app_context():
entry = AuditLog.query.filter_by(action='season_started').first()
assert entry is not None
def test_end_season_sets_end_date_and_deactivates(self, client, as_role):
as_role('admin')
client.post(
'/admin/season/start',
data={'season_name': 'Fall 2026', 'season_start': '2026-09-01'},
)
client.post(
'/admin/season/end',
data={'season_end': '2026-12-15'},
follow_redirects=False,
)
with client.application.app_context():
assert AppSettings.get('season_end') == '2026-12-15'
assert not AppSettings.get_bool('season_active', default=False)
def test_cannot_end_season_when_inactive(self, client, as_role):
as_role('admin')
# No season started
response = client.post(
'/admin/season/end',
data={'season_end': '2026-12-15'},
follow_redirects=True,
)
html = response.data.decode()
assert 'no season is currently active' in html.lower()
def test_end_season_creates_audit_log(self, client, as_role):
from app.models import AuditLog
as_role('admin')
client.post(
'/admin/season/start',
data={'season_name': 'Fall 2026', 'season_start': '2026-09-01'},
)
client.post('/admin/season/end', data={'season_end': '2026-12-15'})
with client.application.app_context():
entry = AuditLog.query.filter_by(action='season_ended').first()
assert entry is not None
# ---------------------------------------------------------------------------
# Gate enforcement on team matches
# ---------------------------------------------------------------------------
class TestSeasonGateEnforcement:
@pytest.fixture
def org_team(self, app, client, as_role):
as_role('admin')
client.post(
'/teams/create',
data={'name': 'Varsity Test'},
follow_redirects=False,
)
with app.app_context():
return OrgTeam.query.filter_by(name='Varsity Test').first().id
@pytest.mark.parametrize('role', NON_ADMIN_ROLES)
def test_non_admin_cannot_create_match_when_season_inactive(
self, client, as_role, org_team, role
):
as_role(role)
response = client.get(
f'/team-matches/{org_team}/create',
follow_redirects=True,
)
html = response.data.decode()
assert 'season is not active' in html.lower() or 'begin a season' in html.lower()
@pytest.mark.parametrize('role', NON_ADMIN_ROLES)
def test_non_admin_cannot_delete_match_when_season_inactive(
self, app, client, as_role, org_team, role, make_user
):
# Create a match as admin (season active not required for admin)
as_role('admin')
# Start season so match can be created
client.post(
'/admin/season/start',
data={'season_name': 'Fall', 'season_start': '2026-09-01'},
)
client.post(
f'/team-matches/{org_team}/create',
data={'title': 'Match Test', 'date': '2026-10-01', 'start_time': '10:00'},
follow_redirects=False,
)
with app.app_context():
match_id = TeamMatch.query.filter_by(title='Match Test').first().id
# End season
client.post('/admin/season/end', data={'season_end': '2026-12-15'})
as_role(role)
response = client.post(
f'/team-matches/{match_id}/delete', data={}, follow_redirects=True,
)
html = response.data.decode()
assert 'season is not active' in html.lower() or 'begin a season' in html.lower()
def test_admin_can_always_schedule_match(self, client, as_role, org_team):
as_role('admin')
# No season active
response = client.post(
f'/team-matches/{org_team}/create',
data={'title': 'Admin Match', 'date': '2026-10-01', 'start_time': '10:00'},
follow_redirects=False,
)
assert _redirected(response) # success, not blocked