cteward-ng/cteward_ng/tests/test_views.py

117 lines
3.8 KiB
Python
Raw Normal View History

2026-06-08 20:33:47 +02:00
"""Integration tests for API route handlers (views.py).
Uses Flask test client with mocked database to verify the full request pipeline
without needing a live MSSQL connection.
"""
import base64
from unittest.mock import patch, MagicMock
import pytest
def _bot_auth(user='testbot', passwd='testpassword'):
token = base64.b64encode(f"{user}:{passwd}".encode()).decode()
return {'Authorization': f'Basic {token}'}
class TestMonitor:
@patch('cteward_ng.database.check_backend_okay')
def test_monitor_ok(self, mock_check, client):
mock_check.return_value = None # no exception
resp = client.get('/legacy/monitor')
assert resp.status_code == 200
assert resp.json['status'] == 'OK'
@patch('cteward_ng.database.check_backend_okay')
def test_monitor_broken(self, mock_check, client):
mock_check.side_effect = Exception("DB down")
resp = client.get('/legacy/monitor')
assert resp.status_code == 503
assert resp.json['status'] == 'BROKEN'
class TestStatsEndpoints:
"""Test that stats endpoints reject unauthorized access and pass through correctly."""
@patch('cteward_ng.database.run_query')
def test_stats_members_unauthorized(self, mock_run, client):
resp = client.get('/legacy/stats/members')
assert resp.status_code == 401
@patch('cteward_ng.database.run_query')
def test_stats_members_authorized(self, mock_run, client):
mock_run.return_value = [
{'Year': 2023, 'Month': 1, 'Members': 10},
]
resp = client.get(
'/legacy/stats/members',
headers=_bot_auth(),
)
assert resp.status_code == 200
data = resp.json
assert len(data) == 1
assert data[0]['Year'] == 2023
class TestMemberEndpoint:
@patch('cteward_ng.database.run_query')
def test_member_unauthorized(self, mock_run, client):
resp = client.get('/legacy/member/alice')
assert resp.status_code == 401
@patch('cteward_ng.database.run_query')
def test_member_raw_invalid_type(self, mock_run, client):
resp = client.get(
'/legacy/member/alice/invalid/raw/',
headers=_bot_auth(),
)
assert resp.status_code == 400
class TestMemberMemo:
@patch('cteward_ng.database.run_query')
def test_memo_empty_crewname(self, mock_run, client):
# Empty crewname should be caught by Flask as a routing issue or handled
# The bot doesn't have _board_ flag, so this should 403
resp = client.get(
'/legacy/member/alice/memo',
headers=_bot_auth(),
)
# Bot has no board access → should fail auth
assert resp.status_code in (401, 403)
class TestContributions:
@patch('cteward_ng.database.run_query')
def test_contributions_board_only(self, mock_run, client):
resp = client.get(
'/legacy/member/alice/contributions',
headers=_bot_auth(),
)
# Bot has no board access → 403 or 401
assert resp.status_code in (401, 403)
class TestMemberDetailRaw:
@patch('cteward_ng.database.run_query')
def test_contract_detail(self, mock_run, client):
mock_run.return_value = [{
'VertragNr': '1', 'ArtName': 'Ehren', 'Sollstellung': 'monatlich',
'Betrag': 25,
}]
resp = client.get(
'/legacy/member/alice/contract/raw/',
headers=_bot_auth(),
)
# Bot has no board access → should fail
assert resp.status_code in (401, 403)
@patch('cteward_ng.database.run_query')
def test_invalid_detail_type(self, mock_run, client):
resp = client.get(
'/legacy/member/alice/unknown/raw/',
headers=_bot_auth(),
)
assert resp.status_code == 400