Skip to content

Commit c93ea35

Browse files
committed
fix: unit tests working with only one set up
1 parent f5c8796 commit c93ea35

File tree

2 files changed

+114
-88
lines changed

2 files changed

+114
-88
lines changed

tests/conftest.py

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from httpx import ASGITransport, AsyncClient
1010

1111
from src import load_test_db
12-
from src.auth.crud import create_user_session
12+
from src.auth.crud import create_user_session, remove_user_session
1313
from src.database import SQLALCHEMY_TEST_DATABASE_URL, DatabaseSessionManager
1414
from src.main import app
1515

@@ -21,22 +21,7 @@ def suppress_sqlalchemy_logs():
2121
yield
2222
logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
2323

24-
@pytest.fixture(scope="session")
25-
def event_loop(request):
26-
loop = asyncio.get_event_loop_policy().new_event_loop()
27-
yield loop
28-
loop.close()
29-
30-
31-
@pytest.fixture(scope="function")
32-
async def client() -> AsyncGenerator[Any, None]:
33-
# base_url is just a random placeholder url
34-
# ASGITransport is just telling the async client to pass all requests to app
35-
# `async with` syntax used so that the connecton will automatically be closed once done
36-
async with AsyncClient(transport=ASGITransport(app), base_url="http://test") as client:
37-
yield client
38-
39-
@pytest_asyncio.fixture(scope="module")
24+
@pytest_asyncio.fixture(scope="session", loop_scope="session")
4025
async def database_setup():
4126
# reset the database again, just in case
4227
print("Resetting DB...")
@@ -47,24 +32,25 @@ async def database_setup():
4732
yield sessionmanager
4833
await sessionmanager.close()
4934

50-
@pytest_asyncio.fixture(scope="function")
51-
async def db_transaction(database_setup):
52-
async with database_setup.session() as session:
53-
try:
54-
await session.begin()
55-
yield session
56-
finally:
57-
await session.rollback()
35+
@pytest_asyncio.fixture(scope="function", loop_scope="session")
36+
async def client() -> AsyncGenerator[Any, None]:
37+
# base_url is just a random placeholder url
38+
# ASGITransport is just telling the async client to pass all requests to app
39+
# `async with` syntax used so that the connecton will automatically be closed once done
40+
async with AsyncClient(transport=ASGITransport(app), base_url="http://test") as client:
41+
yield client
5842

59-
@pytest_asyncio.fixture(scope="function")
60-
async def db_session(db_transaction):
61-
yield db_transaction
43+
@pytest_asyncio.fixture(scope="function", loop_scope="session")
44+
async def db_session(database_setup):
45+
async with database_setup.session() as session:
46+
yield session
6247

63-
@pytest_asyncio.fixture(scope="function")
48+
@pytest_asyncio.fixture(scope="function", loop_scope="session")
6449
async def admin_session(database_setup):
6550
session_id = "temp_id_" + load_test_db.SYSADMIN_COMPUTING_ID
66-
async with database_setup.session() as db_session:
67-
await create_user_session(db_session, session_id, load_test_db.SYSADMIN_COMPUTING_ID)
68-
yield
51+
async with database_setup.session() as session:
52+
await create_user_session(session, session_id, load_test_db.SYSADMIN_COMPUTING_ID)
53+
yield
54+
await remove_user_session(session, session_id)
6955

7056

tests/integration/test_officers.py

Lines changed: 96 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from datetime import date, timedelta
44

55
import pytest
6+
from httpx import AsyncClient
67

78
from src import load_test_db
89
from src.officers.constants import OfficerPositionEnum
@@ -11,76 +12,108 @@
1112
# TODO: setup a database on the CI machine & run this as a unit test then (since
1213
# this isn't really an integration test)
1314

14-
# TODO: switch to mark.anyio
15-
@pytest.mark.asyncio
16-
async def test__read_execs(database_setup):
17-
async with database_setup.session() as db_session:
18-
# test that reads from the database succeeded as expected
19-
print(type(db_session))
20-
assert (await get_active_officer_terms(db_session, "blarg")) == []
21-
assert (await get_active_officer_terms(db_session, "abc22")) != []
22-
23-
abc11_officer_terms = await get_active_officer_terms(db_session, "abc11")
24-
assert len(abc11_officer_terms) == 1
25-
assert abc11_officer_terms[0].computing_id == "abc11"
26-
assert abc11_officer_terms[0].position == OfficerPositionEnum.EXECUTIVE_AT_LARGE
27-
assert abc11_officer_terms[0].start_date is not None
28-
assert abc11_officer_terms[0].nickname == "the holy A"
29-
assert abc11_officer_terms[0].favourite_course_0 == "CMPT 361"
30-
assert abc11_officer_terms[0].biography == "Hi! I'm person A and I want school to be over ; _ ;"
31-
32-
current_exec_team = await current_officers(db_session)
33-
assert current_exec_team is not None
34-
assert len(current_exec_team) == 3
35-
# assert next(iter(current_exec_team)) == OfficerPositionEnum.EXECUTIVE_AT_LARGE
36-
# assert next(iter(current_exec_team))["favourite_course_0"] == "CMPT 361"
37-
# assert next(iter(current_exec_team.values()))[0].csss_email == OfficerPosition.to_email(OfficerPositionEnum.EXECUTIVE_AT_LARGE)
38-
# assert next(iter(current_exec_team.values()))[0].private_data is None
39-
40-
current_exec_team = await current_officers(db_session)
41-
assert current_exec_team is not None
42-
assert len(current_exec_team) == 3
43-
# assert next(iter(current_exec_team.keys())) == OfficerPositionEnum.EXECUTIVE_AT_LARGE
44-
# assert next(iter(current_exec_team.values()))[0].favourite_course_0 == "CMPT 361"
45-
# assert next(iter(current_exec_team.values()))[0].csss_email == OfficerPosition.to_email(OfficerPositionEnum.EXECUTIVE_AT_LARGE)
46-
# assert next(iter(current_exec_team.values()))[0].private_data is not None
47-
# assert next(iter(current_exec_team.values()))[0].private_data.computing_id == "abc11"
48-
49-
all_terms = await all_officers(db_session, include_future_terms=False)
50-
assert len(all_terms) == 8
15+
pytestmark = pytest.mark.asyncio(loop_scope="session")
16+
17+
async def test__read_execs(db_session):
18+
# test that reads from the database succeeded as expected
19+
print(type(db_session))
20+
assert (await get_active_officer_terms(db_session, "blarg")) == []
21+
assert (await get_active_officer_terms(db_session, "abc22")) != []
22+
23+
abc11_officer_terms = await get_active_officer_terms(db_session, "abc11")
24+
assert len(abc11_officer_terms) == 1
25+
assert abc11_officer_terms[0].computing_id == "abc11"
26+
assert abc11_officer_terms[0].position == OfficerPositionEnum.EXECUTIVE_AT_LARGE
27+
assert abc11_officer_terms[0].start_date is not None
28+
assert abc11_officer_terms[0].nickname == "the holy A"
29+
assert abc11_officer_terms[0].favourite_course_0 == "CMPT 361"
30+
assert abc11_officer_terms[0].biography == "Hi! I'm person A and I want school to be over ; _ ;"
31+
32+
current_exec_team = await current_officers(db_session)
33+
assert current_exec_team is not None
34+
assert len(current_exec_team) == 3
35+
# assert next(iter(current_exec_team)) == OfficerPositionEnum.EXECUTIVE_AT_LARGE
36+
# assert next(iter(current_exec_team))["favourite_course_0"] == "CMPT 361"
37+
# assert next(iter(current_exec_team.values()))[0].csss_email == OfficerPosition.to_email(OfficerPositionEnum.EXECUTIVE_AT_LARGE)
38+
# assert next(iter(current_exec_team.values()))[0].private_data is None
39+
40+
current_exec_team = await current_officers(db_session)
41+
assert current_exec_team is not None
42+
assert len(current_exec_team) == 3
43+
# assert next(iter(current_exec_team.keys())) == OfficerPositionEnum.EXECUTIVE_AT_LARGE
44+
# assert next(iter(current_exec_team.values()))[0].favourite_course_0 == "CMPT 361"
45+
# assert next(iter(current_exec_team.values()))[0].csss_email == OfficerPosition.to_email(OfficerPositionEnum.EXECUTIVE_AT_LARGE)
46+
# assert next(iter(current_exec_team.values()))[0].private_data is not None
47+
# assert next(iter(current_exec_team.values()))[0].private_data.computing_id == "abc11"
48+
49+
all_terms = await all_officers(db_session, include_future_terms=False)
50+
assert len(all_terms) == 8
5151

5252

5353
#async def test__update_execs(database_setup):
5454
# # TODO: the second time an update_officer_info call occurs, the user should be updated with info
5555
# pass
5656

57-
@pytest.mark.asyncio
58-
async def test__endpoints(client):
57+
async def test__get_officers(client):
58+
# private data shoudn't be leaked
59+
print(f"[DEBUG] Loop ID in {__name__}: {id(asyncio.get_running_loop())}")
5960
response = await client.get("/officers/current")
6061
assert response.status_code == 200
6162
assert response.json() != {}
6263
assert len(response.json().values()) == 3
63-
assert not response.json()["executive at large"]["computing_id"]
64+
assert "computing_id" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
65+
assert "discord_id" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
66+
assert "discord_name" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
67+
assert "discord_nickname" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
68+
assert "phone_number" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
69+
assert "github_username" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
70+
assert "google_drive_email" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
71+
assert "photo_url" not in response.json()[OfficerPositionEnum.EXECUTIVE_AT_LARGE]
72+
73+
assert "computing_id" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
74+
assert "discord_id" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
75+
assert "discord_name" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
76+
assert "discord_nickname" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
77+
assert "phone_number" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
78+
assert "github_username" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
79+
assert "google_drive_email" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
80+
assert "photo_url" not in response.json()[OfficerPositionEnum.DIRECTOR_OF_ARCHIVES]
81+
82+
assert "computing_id" not in response.json()[OfficerPositionEnum.PRESIDENT]
83+
assert "discord_id" not in response.json()[OfficerPositionEnum.PRESIDENT]
84+
assert "discord_name" not in response.json()[OfficerPositionEnum.PRESIDENT]
85+
assert "discord_nickname" not in response.json()[OfficerPositionEnum.PRESIDENT]
86+
assert "phone_number" not in response.json()[OfficerPositionEnum.PRESIDENT]
87+
assert "github_username" not in response.json()[OfficerPositionEnum.PRESIDENT]
88+
assert "google_drive_email" not in response.json()[OfficerPositionEnum.PRESIDENT]
89+
assert "photo_url" not in response.json()[OfficerPositionEnum.PRESIDENT]
6490

6591
response = await client.get("/officers/all?include_future_terms=false")
6692
assert response.status_code == 200
6793
assert response.json() != []
68-
assert len(response.json()) == 6
69-
assert response.json()[0]["private_data"] is None
94+
assert len(response.json()) == 8
95+
assert "computing_id" not in response.json()[0]
96+
assert "discord_id" not in response.json()[0]
97+
assert "discord_name" not in response.json()[0]
98+
assert "discord_nickname" not in response.json()[0]
99+
assert "phone_number" not in response.json()[0]
100+
assert "github_username" not in response.json()[0]
101+
assert "google_drive_email" not in response.json()[0]
102+
assert "photo_url" not in response.json()[0]
70103

71104
response = await client.get("/officers/all?include_future_terms=true")
72105
assert response.status_code == 401
73106

107+
async def test__get_officer_terms(client: AsyncClient):
74108
response = await client.get(f"/officers/terms/{load_test_db.SYSADMIN_COMPUTING_ID}?include_future_terms=false")
75109
assert response.status_code == 200
76-
assert response.json() != []
77110
assert len(response.json()) == 2
78111
assert response.json()[0]["nickname"] == "G2"
79112
assert response.json()[1]["nickname"] == "G1"
80113

81114
response = await client.get("/officers/terms/balargho?include_future_terms=false")
82115
assert response.status_code == 200
83-
assert response.json() == []
116+
assert len(response.json()) == 0
84117

85118
response = await client.get("/officers/terms/abc11?include_future_terms=true")
86119
assert response.status_code == 401
@@ -90,28 +123,35 @@ async def test__endpoints(client):
90123
response = await client.get(f"/officers/info/{load_test_db.SYSADMIN_COMPUTING_ID}")
91124
assert response.status_code == 401
92125

93-
response = await client.post("officers/term", content=json.dumps([{
126+
async def test__post_officer_terms(client: AsyncClient):
127+
# Only admins can create new terms
128+
response = await client.post("officers/term", json=[{
94129
"computing_id": "ehbc12",
95130
"position": OfficerPositionEnum.DIRECTOR_OF_MULTIMEDIA,
96-
"start_date": "2025-12-29"
97-
}]))
131+
"start_date": "2025-12-29",
132+
"legal_name": "Eh Bc"
133+
}])
98134
assert response.status_code == 401
99135

100-
response = await client.post("officers/term", content=json.dumps([{
136+
# Position must be one of the enum positions
137+
response = await client.post("officers/term", json=[{
101138
"computing_id": "ehbc12",
102139
"position": "balargho",
103-
"start_date": "2025-12-29"
104-
}]))
105-
assert response.status_code == 400
140+
"start_date": "2025-12-29",
141+
"legal_name": "Eh Bc"
142+
}])
143+
assert response.status_code == 422
106144

107-
response = await client.patch("officers/info/abc11", content=json.dumps({
145+
async def test__patch_officer_terms(client: AsyncClient):
146+
# Only admins can update new terms
147+
response = await client.patch("officers/info/abc11", json={
108148
"legal_name": "fancy name",
109149
"phone_number": None,
110150
"discord_name": None,
111151
"github_username": None,
112152
"google_drive_email": None,
113-
}))
114-
assert response.status_code == 401
153+
})
154+
assert response.status_code == 403
115155

116156
response = await client.patch("officers/term/1", content=json.dumps({
117157
"computing_id": "abc11",
@@ -127,12 +167,12 @@ async def test__endpoints(client):
127167
"favourite_pl_1": "5",
128168
"biography": "hello"
129169
}))
130-
assert response.status_code == 401
170+
assert response.status_code == 403
131171

132172
response = await client.delete("officers/term/1")
133173
assert response.status_code == 401
134174

135-
@pytest.mark.asyncio
175+
@pytest.mark.skip
136176
async def test__endpoints_admin(client, database_setup, admin_session):
137177
# login as website admin
138178
session_id = "temp_id_" + load_test_db.SYSADMIN_COMPUTING_ID

0 commit comments

Comments
 (0)