Test coverage: plugin lifecycle, registry, lockout unlock, contract fleet, seed
Fills the review's highest-value coverage gaps in the framework's own core feature. New tests/test_plugin_lifecycle.py: manager enable/disable dependency guards (beta depends on alpha - enable-beta-first refused, disable-alpha-while-beta-on refused) via synthetic plugins; enable seeds a plugin's RBAC permissions idempotently; registry disable-survives-reload, corrupt-file recovery, and the equipment->machines rename migration; `flask seed settings` idempotency. test_plugin_contract.py: BUNDLED_PLUGINS now covers all bundled plugins incl. geenforce, measuringtools, warranty (was 9, contradicting the CLAUDE.md "all bundled satisfy the contract" claim); the structural checks now run against them. test_authz.py: account lockout auto-unlock path (expired lockeduntil -> correct password logs in and clears the lock state), previously untested. All new tests pass; naming green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -203,6 +203,25 @@ def test_account_locks_after_repeated_bad_logins(client, db, admin_user):
|
||||
assert 'locked' in locked.get_json()['data']['error']['message'].lower()
|
||||
|
||||
|
||||
def test_lockout_auto_unlocks_after_expiry(client, db, admin_user):
|
||||
"""Once lockeduntil is in the past the account unlocks itself: a correct
|
||||
password logs in and clears the lock state."""
|
||||
from datetime import datetime, timezone, timedelta
|
||||
# Simulate an expired lock (naive-UTC to match the column comparisons).
|
||||
admin_user.lockeduntil = (datetime.now(timezone.utc).replace(tzinfo=None)
|
||||
- timedelta(minutes=1))
|
||||
admin_user.failedlogins = 5
|
||||
db.session.commit()
|
||||
|
||||
ok = client.post('/api/auth/login',
|
||||
json={'username': 'testadmin', 'password': 'testpass'})
|
||||
assert ok.status_code == 200, ok.get_json()
|
||||
|
||||
db.session.refresh(admin_user)
|
||||
assert admin_user.lockeduntil is None
|
||||
assert admin_user.failedlogins == 0
|
||||
|
||||
|
||||
def test_successful_login_resets_failed_counter(client, db, admin_user):
|
||||
"""A good login before the threshold clears the failure count."""
|
||||
for _ in range(3):
|
||||
|
||||
Reference in New Issue
Block a user