File size: 3,861 Bytes
5687d37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
"""Regression test for question ordering returned by the admin endpoint.

Locks in the guarantee that ``Test.questions`` is loaded ordered by
``Question.order_index`` (declared on the relationship in
``app.models.models``). If that ``order_by`` is ever removed, this test will
fail — protecting the ``get_questions`` endpoint which relies on it after the
optimization that removed an in-Python ``sorted(...)`` call.
"""

import unittest

from fastapi import FastAPI
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

from app.api.deps import require_admin
from app.api.routes.admin import router
from app.core.database import Base, get_db
from app.models.models import Question, QuestionType, Test, User, UserRole


class AdminGetQuestionsOrderingTests(unittest.TestCase):
    def setUp(self):
        self.engine = create_engine(
            "sqlite:///:memory:",
            connect_args={"check_same_thread": False},
            poolclass=StaticPool,
        )
        # Creates the full schema including Question.order_index, since the
        # production model is imported above and Base is the shared metadata.
        Base.metadata.create_all(self.engine)
        self.SessionLocal = sessionmaker(bind=self.engine)

        # Seed an admin user and a Test with questions inserted in REVERSE
        # order_index so a missing ORDER BY would produce [5, 3, 1].
        db = self.SessionLocal()
        try:
            self.admin = User(
                email="admin@example.com",
                full_name="Admin",
                role=UserRole.admin,
            )
            self.test = Test(
                title="Ordering test", created_by=1, total_marks=0.0
            )
            db.add_all([self.admin, self.test])
            db.commit()
            db.refresh(self.admin)
            db.refresh(self.test)
            self.test_id = self.test.id

            for order_index, text in [(5, "Q-five"), (1, "Q-one"), (3, "Q-three")]:
                db.add(
                    Question(
                        test_id=self.test_id,
                        question_type=QuestionType.mcq,
                        question_text=text,
                        options=["A", "B", "C", "D"],
                        correct_answer="A",
                        marks=1.0,
                        negative_marks=0.0,
                        order_index=order_index,
                    )
                )
            db.commit()
        finally:
            db.close()

        app = FastAPI()
        app.include_router(router)

        def override_get_db():
            session = self.SessionLocal()
            try:
                yield session
            finally:
                session.close()

        def override_require_admin():
            return self.admin

        app.dependency_overrides[get_db] = override_get_db
        app.dependency_overrides[require_admin] = override_require_admin
        self.client = TestClient(app, raise_server_exceptions=False)

    def test_get_questions_returns_questions_sorted_by_order_index(self):
        response = self.client.get(f"/admin/tests/{self.test_id}/questions")

        self.assertEqual(response.status_code, 200)
        payload = response.json()
        self.assertEqual(len(payload), 3)
        self.assertEqual(
            [item["order_index"] for item in payload],
            [1, 3, 5],
        )
        self.assertEqual(
            [item["question_text"] for item in payload],
            ["Q-one", "Q-three", "Q-five"],
        )

    def test_get_questions_returns_404_for_unknown_test(self):
        response = self.client.get("/admin/tests/9999/questions")
        self.assertEqual(response.status_code, 404)


if __name__ == "__main__":
    unittest.main()