sts-sponsors team mailing list archive
-
sts-sponsors team
-
Mailing list archive
-
Message #08199
[Merge] ~ack/maas-site-manager:api-tests-grouping into maas-site-manager:main
Alberto Donato has proposed merging ~ack/maas-site-manager:api-tests-grouping into maas-site-manager:main.
Commit message:
group API tests by handler, add more tests
Requested reviews:
MAAS Lander (maas-lander): unittests
MAAS Committers (maas-committers)
For more details, see:
https://code.launchpad.net/~ack/maas-site-manager/+git/site-manager/+merge/442485
--
Your team MAAS Committers is requested to review the proposed merge of ~ack/maas-site-manager:api-tests-grouping into maas-site-manager:main.
diff --git a/backend/tests/user_api/test_handlers.py b/backend/tests/user_api/test_handlers.py
index bf62306..79314da 100644
--- a/backend/tests/user_api/test_handlers.py
+++ b/backend/tests/user_api/test_handlers.py
@@ -32,414 +32,220 @@ def duration_format(time: timedelta, time_format: str) -> str:
@pytest.mark.asyncio
-async def test_root(user_app_client: AsyncClient) -> None:
- response = await user_app_client.get("/")
- assert response.status_code == 200
- assert response.json() == {"version": "0.0.1"}
+class TestRootHandler:
+ async def test_get(self, user_app_client: AsyncClient) -> None:
+ response = await user_app_client.get("/")
+ assert response.status_code == 200
+ assert response.json() == {"version": "0.0.1"}
-
-@pytest.mark.asyncio
-async def test_root_as_auth(
- authenticated_user_app_client: AuthAsyncClient,
-) -> None:
- response = await authenticated_user_app_client.get("/")
- assert response.status_code == 200
- assert response.json() == {"version": "0.0.1"}
+ async def test_get_authenticated(
+ self,
+ authenticated_user_app_client: AuthAsyncClient,
+ ) -> None:
+ response = await authenticated_user_app_client.get("/")
+ assert response.status_code == 200
+ assert response.json() == {"version": "0.0.1"}
@pytest.mark.asyncio
-async def test_sites_get(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- site1 = {
- "name": "LondonHQ",
- "city": "London",
- "country": "gb",
- "latitude": "51.509865",
- "longitude": "-0.118092",
- "note": "the first site",
- "region": "Blue Fin Bldg",
- "street": "110 Southwark St",
- "timezone": "Europe/London",
- "url": "https://londoncalling.example.com",
- "accepted": True,
- }
- site2 = site1.copy()
- site2.update(
- {
- "name": "BerlinHQ",
- "timezone": "Europe/Berlin",
- "city": "Berlin",
- "country": "de",
+class TestSitesHandler:
+ async def test_get(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ site1 = {
+ "name": "LondonHQ",
+ "city": "London",
+ "country": "gb",
+ "latitude": "51.509865",
+ "longitude": "-0.118092",
+ "note": "the first site",
+ "region": "Blue Fin Bldg",
+ "street": "110 Southwark St",
+ "timezone": "Europe/London",
+ "url": "https://londoncalling.example.com",
+ "accepted": True,
}
- )
- sites = await fixture.create("site", [site1, site2])
- for site in sites:
- site["stats"] = None
- del site["created"]
- del site["accepted"]
-
- page1 = await authenticated_user_app_client.get("/sites")
- assert page1.status_code == 200
- assert page1.json() == {
- "page": 1,
- "size": 20,
- "total": 2,
- "items": sites,
- }
- filtered = await authenticated_user_app_client.get(
- "/sites?city=onDo"
- ) # vs London
- assert filtered.status_code == 200
- assert filtered.json() == {
- "page": 1,
- "size": 20,
- "total": 1,
- "items": [sites[0]],
- }
- paginated = await authenticated_user_app_client.get("/sites?page=2&size=1")
- assert paginated.status_code == 200
- assert paginated.json() == {
- "page": 2,
- "size": 1,
- "total": 2,
- "items": [sites[1]],
- }
-
-
-@pytest.mark.asyncio
-async def test_sites_get_only_accepted(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- site1 = {
- "name": "LondonHQ",
- "city": "London",
- "country": "gb",
- "latitude": "51.509865",
- "longitude": "-0.118092",
- "note": "the first site",
- "region": "Blue Fin Bldg",
- "street": "110 Southwark St",
- "timezone": "Europe/London",
- "url": "https://londoncalling.example.com",
- "accepted": True,
- }
- site2 = site1.copy()
- site2.update(
- {
- "name": "BerlinHQ",
- "timezone": "Europe/Berlin",
- "city": "Berlin",
- "country": "de",
- "accepted": False,
+ site2 = site1.copy()
+ site2.update(
+ {
+ "name": "BerlinHQ",
+ "timezone": "Europe/Berlin",
+ "city": "Berlin",
+ "country": "de",
+ }
+ )
+ sites = await fixture.create("site", [site1, site2])
+ for site in sites:
+ site["stats"] = None
+ del site["created"]
+ del site["accepted"]
+
+ page1 = await authenticated_user_app_client.get("/sites")
+ assert page1.status_code == 200
+ assert page1.json() == {
+ "page": 1,
+ "size": 20,
+ "total": 2,
+ "items": sites,
}
- )
- created_site, _ = await fixture.create("site", [site1, site2])
- created_site["stats"] = None
- del created_site["created"]
- del created_site["accepted"]
-
- page1 = await authenticated_user_app_client.get("/sites")
- assert page1.status_code == 200
- assert page1.json() == {
- "page": 1,
- "size": 20,
- "total": 1,
- "items": [created_site],
- }
-
-
-@pytest.mark.asyncio
-async def test_sites_get_filter_timezone(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- site1 = {
- "name": "LondonHQ",
- "city": "London",
- "country": "gb",
- "latitude": "51.509865",
- "longitude": "-0.118092",
- "note": "the first site",
- "region": "Blue Fin Bldg",
- "street": "110 Southwark St",
- "timezone": "Europe/London",
- "url": "https://londoncalling.example.com",
- "accepted": True,
- }
- site2 = site1.copy()
- site2.update(
- {
- "name": "BerlinHQ",
- "timezone": "Europe/Berlin",
- "city": "Berlin",
- "country": "de",
+ filtered = await authenticated_user_app_client.get(
+ "/sites?city=onDo"
+ ) # vs London
+ assert filtered.status_code == 200
+ assert filtered.json() == {
+ "page": 1,
+ "size": 20,
+ "total": 1,
+ "items": [sites[0]],
+ }
+ paginated = await authenticated_user_app_client.get(
+ "/sites?page=2&size=1"
+ )
+ assert paginated.status_code == 200
+ assert paginated.json() == {
+ "page": 2,
+ "size": 1,
+ "total": 2,
+ "items": [sites[1]],
}
- )
- [created_site, _] = await fixture.create("site", [site1, site2])
- created_site["stats"] = None
- del created_site["created"]
- del created_site["accepted"]
- page1 = await authenticated_user_app_client.get(
- "/sites?timezone=Europe/London"
- )
- assert page1.status_code == 200
- assert page1.json() == {
- "page": 1,
- "size": 20,
- "total": 1,
- "items": [created_site],
- }
-
-@pytest.mark.asyncio
-async def test_sites_get_with_stats(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- [site] = await fixture.create(
- "site",
- [
- {
- "name": "LondonHQ",
- "city": "London",
- "country": "gb",
- "latitude": "51.509865",
- "longitude": "-0.118092",
- "note": "the first site",
- "region": "Blue Fin Bldg",
- "street": "110 Southwark St",
- "timezone": "Europe/London",
- "url": "https://londoncalling.example.com",
- "accepted": True,
- }
- ],
- )
- [site_data] = await fixture.create(
- "site_data",
- [
+ async def test_get_only_accepted(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ site1 = {
+ "name": "LondonHQ",
+ "city": "London",
+ "country": "gb",
+ "latitude": "51.509865",
+ "longitude": "-0.118092",
+ "note": "the first site",
+ "region": "Blue Fin Bldg",
+ "street": "110 Southwark St",
+ "timezone": "Europe/London",
+ "url": "https://londoncalling.example.com",
+ "accepted": True,
+ }
+ site2 = site1.copy()
+ site2.update(
{
- "site_id": site["id"],
- "allocated_machines": 10,
- "deployed_machines": 20,
- "ready_machines": 30,
- "error_machines": 40,
- "last_seen": datetime.utcnow(),
+ "name": "BerlinHQ",
+ "timezone": "Europe/Berlin",
+ "city": "Berlin",
+ "country": "de",
+ "accepted": False,
}
- ],
- )
- del site_data["id"]
- del site_data["site_id"]
- site_data["last_seen"] = site_data["last_seen"].isoformat()
- site["stats"] = site_data
- del site["created"]
- del site["accepted"]
-
- page = await authenticated_user_app_client.get("/sites")
- assert page.status_code == 200
- assert page.json() == {
- "page": 1,
- "size": 20,
- "total": 1,
- "items": [site],
- }
-
-
-@pytest.mark.asyncio
-async def test_pending_sites_get(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- site1 = {
- "name": "LondonHQ",
- "city": "London",
- "country": "gb",
- "latitude": "51.509865",
- "longitude": "-0.118092",
- "note": "the first site",
- "region": "Blue Fin Bldg",
- "street": "110 Southwark St",
- "timezone": "Europe/London",
- "url": "https://londoncalling.example.com",
- "accepted": True,
- }
- site2 = site1.copy()
- site2.update(
- {
- "name": "BerlinHQ",
- "timezone": "Europe/Berlin",
- "city": "Berlin",
- "country": "de",
- "accepted": False,
+ )
+ created_site, _ = await fixture.create("site", [site1, site2])
+ created_site["stats"] = None
+ del created_site["created"]
+ del created_site["accepted"]
+
+ page1 = await authenticated_user_app_client.get("/sites")
+ assert page1.status_code == 200
+ assert page1.json() == {
+ "page": 1,
+ "size": 20,
+ "total": 1,
+ "items": [created_site],
}
- )
- _, pending_site = await fixture.create("site", [site1, site2])
-
- response = await authenticated_user_app_client.get("/requests")
- assert response.status_code == 200
- assert response.json() == {
- "page": 1,
- "size": 20,
- "total": 1,
- "items": [
- {
- "id": pending_site["id"],
- "name": pending_site["name"],
- "url": pending_site["url"],
- "created": pending_site["created"].isoformat(),
- },
- ],
- }
-
-
-@pytest.mark.asyncio
-async def test_pending_sites_post_accept(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- site = {
- "name": "LondonHQ",
- "url": "https://londoncalling.example.com",
- "accepted": False,
- }
- [pending_site] = await fixture.create("site", [site])
-
- response = await authenticated_user_app_client.post(
- "/requests",
- json={"ids": [pending_site["id"]], "accept": True},
- )
- assert response.status_code == 204
- [created_site] = await fixture.get("site")
- assert created_site["accepted"]
-
-
-@pytest.mark.asyncio
-async def test_pending_sites_post_reject(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- site = {
- "name": "LondonHQ",
- "url": "https://londoncalling.example.com",
- "accepted": False,
- }
- [pending_site] = await fixture.create("site", [site])
-
- response = await authenticated_user_app_client.post(
- "/requests",
- json={"ids": [pending_site["id"]], "accept": False},
- )
- assert response.status_code == 204
- assert await fixture.get("site") == []
-
-@pytest.mark.asyncio
-async def test_pending_sites_post_invalid_ids(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- site = {
- "name": "LondonHQ",
- "url": "https://londoncalling.example.com",
- "accepted": True,
- }
- [site] = await fixture.create("site", [site])
- # unknown IDs and IDs for non-pending sites are invalid
- ids = [site["id"], 10000]
- response = await authenticated_user_app_client.post(
- "/requests",
- json={"ids": ids, "accept": True},
- )
- assert response.status_code == 400
- assert response.json() == {
- "detail": {"message": "Unknown pending sites", "ids": ids}
- }
-
-
-@pytest.mark.asyncio
-@pytest.mark.parametrize("time_format", ["ISO 8601", "Float"])
-async def test_token_time_format(
- time_format: str, authenticated_user_app_client: AuthAsyncClient
-) -> None:
- seconds = 100
- expiry = timedelta(seconds=seconds)
- formatted_expiry = duration_format(expiry, time_format)
-
- response = await authenticated_user_app_client.post(
- "/tokens", json={"count": 5, "duration": formatted_expiry}
- )
- assert response.status_code == 200
- result = response.json()
- assert datetime.fromisoformat(result["expired"]) < (
- datetime.utcnow() + timedelta(seconds=seconds)
- )
- assert len(result["tokens"]) == 5
-
-
-@pytest.mark.asyncio
-async def test_tokens_get(
- authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
-) -> None:
- tokens = await fixture.create(
- "token",
- [
- {
- "site_id": None,
- "value": "c54e5ba6-d214-40dd-b601-01ebb1019c07",
- "expired": datetime.fromisoformat(
- "2023-02-23T09:09:51.103703"
- ),
- "created": datetime.fromisoformat(
- "2023-02-22T03:14:15.926535"
- ),
- },
+ async def test_get_filter_timezone(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ site1 = {
+ "name": "LondonHQ",
+ "city": "London",
+ "country": "gb",
+ "latitude": "51.509865",
+ "longitude": "-0.118092",
+ "note": "the first site",
+ "region": "Blue Fin Bldg",
+ "street": "110 Southwark St",
+ "timezone": "Europe/London",
+ "url": "https://londoncalling.example.com",
+ "accepted": True,
+ }
+ site2 = site1.copy()
+ site2.update(
{
- "site_id": None,
- "value": "b67c449e-fcf6-4014-887d-909859f9fb70",
- "expired": datetime.fromisoformat(
- "2023-02-23T11:28:54.382456"
- ),
- "created": datetime.fromisoformat(
- "2023-02-22T03:14:15.926535"
- ),
- },
- ],
- )
- for token in tokens:
- token["expired"] = token["expired"].isoformat()
- token["created"] = token["created"].isoformat()
- token["value"] = str(token["value"])
- response = await authenticated_user_app_client.get("/tokens")
- assert response.status_code == 200
- assert response.json()["total"] == 2
- assert response.json()["items"] == tokens
+ "name": "BerlinHQ",
+ "timezone": "Europe/Berlin",
+ "city": "Berlin",
+ "country": "de",
+ }
+ )
+ [created_site, _] = await fixture.create("site", [site1, site2])
+ created_site["stats"] = None
+ del created_site["created"]
+ del created_site["accepted"]
+ page1 = await authenticated_user_app_client.get(
+ "/sites?timezone=Europe/London"
+ )
+ assert page1.status_code == 200
+ assert page1.json() == {
+ "page": 1,
+ "size": 20,
+ "total": 1,
+ "items": [created_site],
+ }
+ async def test_get_with_stats(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ [site] = await fixture.create(
+ "site",
+ [
+ {
+ "name": "LondonHQ",
+ "city": "London",
+ "country": "gb",
+ "latitude": "51.509865",
+ "longitude": "-0.118092",
+ "note": "the first site",
+ "region": "Blue Fin Bldg",
+ "street": "110 Southwark St",
+ "timezone": "Europe/London",
+ "url": "https://londoncalling.example.com",
+ "accepted": True,
+ }
+ ],
+ )
+ [site_data] = await fixture.create(
+ "site_data",
+ [
+ {
+ "site_id": site["id"],
+ "allocated_machines": 10,
+ "deployed_machines": 20,
+ "ready_machines": 30,
+ "error_machines": 40,
+ "last_seen": datetime.utcnow(),
+ }
+ ],
+ )
+ del site_data["id"]
+ del site_data["site_id"]
+ site_data["last_seen"] = site_data["last_seen"].isoformat()
+ site["stats"] = site_data
+ del site["created"]
+ del site["accepted"]
-@pytest.mark.asyncio
-async def test_login_post_fails_with_wrong_password(
- user_app_client: AsyncClient, fixture: Fixture
-) -> None:
- phash = "$2b$12$F5sgrhRNtWAOehcoVO.XK.oSvupmcg8.0T2jCHOTg15M8N8LrpRwS"
- userdata = {
- "id": 1,
- "email": "admin@xxxxxxxxxxx",
- "full_name": "Admin",
- "password": phash,
- }
- await fixture.create("user", userdata)
-
- fail_response = await user_app_client.post(
- "/login",
- json={"username": userdata["email"], "password": "incorrect_pass"},
- )
- assert fail_response.status_code == 401, "Expected authentication error."
-
- fail_response = await user_app_client.post(
- "/login", json={"username": userdata["email"], "password": "admin"}
- )
- assert fail_response.status_code == 200, "Expected user login."
+ page = await authenticated_user_app_client.get("/sites")
+ assert page.status_code == 200
+ assert page.json() == {
+ "page": 1,
+ "size": 20,
+ "total": 1,
+ "items": [site],
+ }
@pytest.mark.asyncio
-async def test_sites_get_unauthenticated(
- user_app_client: AsyncClient, fixture: Fixture
-) -> None:
- site = [
- {
+class TestPendingSitesHandler:
+ async def test_get(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ site1 = {
"name": "LondonHQ",
"city": "London",
"country": "gb",
@@ -452,17 +258,210 @@ async def test_sites_get_unauthenticated(
"url": "https://londoncalling.example.com",
"accepted": True,
}
- ]
- await fixture.create("site", site)
- page1 = await user_app_client.get("/sites")
- assert page1.status_code == 401, "Expected authentication error."
+ site2 = site1.copy()
+ site2.update(
+ {
+ "name": "BerlinHQ",
+ "timezone": "Europe/Berlin",
+ "city": "Berlin",
+ "country": "de",
+ "accepted": False,
+ }
+ )
+ _, pending_site = await fixture.create("site", [site1, site2])
+
+ response = await authenticated_user_app_client.get("/requests")
+ assert response.status_code == 200
+ assert response.json() == {
+ "page": 1,
+ "size": 20,
+ "total": 1,
+ "items": [
+ {
+ "id": pending_site["id"],
+ "name": pending_site["name"],
+ "url": pending_site["url"],
+ "created": pending_site["created"].isoformat(),
+ },
+ ],
+ }
+
+ async def test_post_accept(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ site = {
+ "name": "LondonHQ",
+ "url": "https://londoncalling.example.com",
+ "accepted": False,
+ }
+ [pending_site] = await fixture.create("site", [site])
+
+ response = await authenticated_user_app_client.post(
+ "/requests",
+ json={"ids": [pending_site["id"]], "accept": True},
+ )
+ assert response.status_code == 204
+ [created_site] = await fixture.get("site")
+ assert created_site["accepted"]
+
+ async def test_post_reject(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ site = {
+ "name": "LondonHQ",
+ "url": "https://londoncalling.example.com",
+ "accepted": False,
+ }
+ [pending_site] = await fixture.create("site", [site])
+
+ response = await authenticated_user_app_client.post(
+ "/requests",
+ json={"ids": [pending_site["id"]], "accept": False},
+ )
+ assert response.status_code == 204
+ assert await fixture.get("site") == []
+
+ async def test_post_invalid_ids(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ site = {
+ "name": "LondonHQ",
+ "url": "https://londoncalling.example.com",
+ "accepted": True,
+ }
+ [site] = await fixture.create("site", [site])
+ # unknown IDs and IDs for non-pending sites are invalid
+ ids = [site["id"], 10000]
+ response = await authenticated_user_app_client.post(
+ "/requests",
+ json={"ids": ids, "accept": True},
+ )
+ assert response.status_code == 400
+ assert response.json() == {
+ "detail": {"message": "Unknown pending sites", "ids": ids}
+ }
@pytest.mark.asyncio
-async def test_token_get_unauthenticated(user_app_client: AsyncClient) -> None:
- seconds = 100
+class TestTokensHandler:
+ @pytest.mark.parametrize("time_format", ["ISO 8601", "Float"])
+ async def test_token_time_format(
+ self, time_format: str, authenticated_user_app_client: AuthAsyncClient
+ ) -> None:
+ seconds = 100
+ expiry = timedelta(seconds=seconds)
+ formatted_expiry = duration_format(expiry, time_format)
+
+ response = await authenticated_user_app_client.post(
+ "/tokens", json={"count": 5, "duration": formatted_expiry}
+ )
+ assert response.status_code == 200
+ result = response.json()
+ assert datetime.fromisoformat(result["expired"]) < (
+ datetime.utcnow() + timedelta(seconds=seconds)
+ )
+ assert len(result["tokens"]) == 5
+
+ async def test_tokens_get(
+ self, authenticated_user_app_client: AuthAsyncClient, fixture: Fixture
+ ) -> None:
+ tokens = await fixture.create(
+ "token",
+ [
+ {
+ "site_id": None,
+ "value": "c54e5ba6-d214-40dd-b601-01ebb1019c07",
+ "expired": datetime.fromisoformat(
+ "2023-02-23T09:09:51.103703"
+ ),
+ "created": datetime.fromisoformat(
+ "2023-02-22T03:14:15.926535"
+ ),
+ },
+ {
+ "site_id": None,
+ "value": "b67c449e-fcf6-4014-887d-909859f9fb70",
+ "expired": datetime.fromisoformat(
+ "2023-02-23T11:28:54.382456"
+ ),
+ "created": datetime.fromisoformat(
+ "2023-02-22T03:14:15.926535"
+ ),
+ },
+ ],
+ )
+ for token in tokens:
+ token["expired"] = token["expired"].isoformat()
+ token["created"] = token["created"].isoformat()
+ token["value"] = str(token["value"])
+ response = await authenticated_user_app_client.get("/tokens")
+ assert response.status_code == 200
+ assert response.json()["total"] == 2
+ assert response.json()["items"] == tokens
- response = await user_app_client.post(
- "/tokens", json={"count": 5, "duration": seconds}
- )
- assert response.status_code == 401, "Expected authentication error."
+
+@pytest.mark.asyncio
+class TestLoginHandler:
+ async def test_post(
+ self, user_app_client: AsyncClient, fixture: Fixture
+ ) -> None:
+ phash = "$2b$12$F5sgrhRNtWAOehcoVO.XK.oSvupmcg8.0T2jCHOTg15M8N8LrpRwS"
+ userdata = {
+ "id": 1,
+ "email": "admin@xxxxxxxxxxx",
+ "full_name": "Admin",
+ "password": phash,
+ }
+ await fixture.create("user", userdata)
+ response = await user_app_client.post(
+ "/login",
+ json={"username": userdata["email"], "password": "admin"},
+ )
+ assert response.status_code == 200
+ assert response.json()["token_type"] == "bearer"
+
+ async def test_post_fails_with_wrong_password(
+ self, user_app_client: AsyncClient, fixture: Fixture
+ ) -> None:
+ phash = "$2b$12$F5sgrhRNtWAOehcoVO.XK.oSvupmcg8.0T2jCHOTg15M8N8LrpRwS"
+ userdata = {
+ "id": 1,
+ "email": "admin@xxxxxxxxxxx",
+ "full_name": "Admin",
+ "password": phash,
+ }
+ await fixture.create("user", userdata)
+
+ fail_response = await user_app_client.post(
+ "/login",
+ json={"username": userdata["email"], "password": "incorrect_pass"},
+ )
+ assert (
+ fail_response.status_code == 401
+ ), "Expected authentication error."
+
+ fail_response = await user_app_client.post(
+ "/login", json={"username": userdata["email"], "password": "admin"}
+ )
+ assert fail_response.status_code == 200, "Expected user login."
+
+
+@pytest.mark.asyncio
+@pytest.mark.parametrize(
+ "method,url",
+ [
+ ("GET", "/sites"),
+ ("GET", "/requests"),
+ ("POST", "/requests"),
+ ("GET", "/tokens"),
+ ("POST", "/tokens"),
+ ("GET", "/users/me"),
+ ],
+)
+async def test_handler_auth_required(
+ user_app_client: AsyncClient, method: str, url: str
+) -> None:
+ response = await user_app_client.request(method, url)
+ assert (
+ response.status_code == 401
+ ), f"Auth should be required for {method} {url}"