133 lines
4.3 KiB
Python
133 lines
4.3 KiB
Python
import asyncio
|
|
import inspect
|
|
from datetime import datetime, timezone
|
|
|
|
from fastapi.params import Depends
|
|
|
|
from app.api.v1.session import SubmitAnswerResponse
|
|
from app.core.auth import AuthContext, get_auth_context
|
|
from app.routers import admin as admin_router
|
|
from app.routers import reports as reports_router
|
|
from app.routers import wordpress as wordpress_router
|
|
from app.schemas.session import SessionCompleteResponse, UserAnswerOutput
|
|
from app.services.reporting import AggregatePerformanceStats, StudentPerformanceReport
|
|
|
|
|
|
def _depends_on_auth(callable_obj, parameter_name: str = "auth") -> bool:
|
|
parameter = inspect.signature(callable_obj).parameters[parameter_name]
|
|
default = parameter.default
|
|
return isinstance(default, Depends) and default.dependency is get_auth_context
|
|
|
|
|
|
def test_admin_actions_require_signed_auth_context():
|
|
assert _depends_on_auth(admin_router.admin_trigger_calibration)
|
|
assert _depends_on_auth(admin_router.admin_toggle_ai_generation)
|
|
assert _depends_on_auth(admin_router.admin_reset_normalization)
|
|
|
|
|
|
def test_wordpress_user_lookup_routes_require_signed_auth_context():
|
|
assert _depends_on_auth(wordpress_router.get_website_users)
|
|
assert _depends_on_auth(wordpress_router.get_user_endpoint)
|
|
|
|
|
|
def test_wordpress_roles_map_to_api_admin_roles():
|
|
assert wordpress_router._api_role_from_wordpress_roles(["subscriber"]) == "student"
|
|
assert wordpress_router._api_role_from_wordpress_roles(["administrator"]) == "admin"
|
|
assert wordpress_router._api_role_from_wordpress_roles(["super_admin"]) == "system_admin"
|
|
|
|
|
|
def test_adaptive_submit_response_does_not_expose_answer_key_or_correctness():
|
|
payload = SubmitAnswerResponse(theta=0.12, theta_se=0.8).model_dump()
|
|
|
|
assert "is_correct" not in payload
|
|
assert "correct_answer" not in payload
|
|
assert "explanation" not in payload
|
|
|
|
|
|
def test_session_completion_answer_output_does_not_expose_correctness():
|
|
answer_payload = UserAnswerOutput(
|
|
id=1,
|
|
item_id=10,
|
|
response="A",
|
|
time_spent=12,
|
|
bobot_earned=0.5,
|
|
scoring_mode_used="ctt",
|
|
).model_dump()
|
|
|
|
assert "is_correct" not in answer_payload
|
|
|
|
response_payload = SessionCompleteResponse(
|
|
id=1,
|
|
session_id="s-1",
|
|
wp_user_id="wp-1",
|
|
website_id=2,
|
|
tryout_id="tryout-1",
|
|
start_time=datetime.now(timezone.utc),
|
|
end_time=datetime.now(timezone.utc),
|
|
is_completed=True,
|
|
scoring_mode_used="ctt",
|
|
total_benar=1,
|
|
total_bobot_earned=0.5,
|
|
NM=500,
|
|
NN=500,
|
|
rataan_used=500,
|
|
sb_used=100,
|
|
user_answers=[
|
|
UserAnswerOutput(
|
|
id=1,
|
|
item_id=10,
|
|
response="A",
|
|
time_spent=12,
|
|
bobot_earned=0.5,
|
|
scoring_mode_used="ctt",
|
|
)
|
|
],
|
|
).model_dump()
|
|
|
|
assert "is_correct" not in response_payload["user_answers"][0]
|
|
|
|
|
|
def test_student_performance_report_is_scoped_to_student_user(monkeypatch):
|
|
captured = {}
|
|
|
|
async def fake_generate_student_performance_report(**kwargs):
|
|
captured.update(kwargs)
|
|
return StudentPerformanceReport(
|
|
generated_at=datetime.now(timezone.utc),
|
|
tryout_id=kwargs["tryout_id"],
|
|
website_id=kwargs["website_id"],
|
|
date_range=kwargs["date_range"],
|
|
aggregate=AggregatePerformanceStats(
|
|
tryout_id=kwargs["tryout_id"],
|
|
participant_count=0,
|
|
avg_nm=None,
|
|
std_nm=None,
|
|
min_nm=None,
|
|
max_nm=None,
|
|
median_nm=None,
|
|
avg_nn=None,
|
|
std_nn=None,
|
|
avg_theta=None,
|
|
pass_rate=0.0,
|
|
avg_time_spent=0.0,
|
|
),
|
|
individual_records=[],
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
reports_router,
|
|
"generate_student_performance_report",
|
|
fake_generate_student_performance_report,
|
|
)
|
|
|
|
asyncio.run(
|
|
reports_router.get_student_performance_report(
|
|
tryout_id="tryout-1",
|
|
db=object(),
|
|
auth=AuthContext(website_id=5, role="student", wp_user_id="wp-1"),
|
|
)
|
|
)
|
|
|
|
assert captured["website_id"] == 5
|
|
assert captured["wp_user_id"] == "wp-1"
|