1- import re
21from http import HTTPStatus
32
43import httpx
54import pytest
65from sqlalchemy import text
76from sqlalchemy .ext .asyncio import AsyncConnection
87
9- from tests .users import ApiKey
8+ from core .errors import SetupNotFoundError , TagNotFoundError , TagNotOwnedError
9+ from routers .openml .setups import untag_setup
10+ from tests .users import ADMIN_USER , OWNER_USER , SOME_USER , ApiKey
1011
1112
1213async def test_setup_untag_missing_auth (py_api : httpx .AsyncClient ) -> None :
@@ -16,70 +17,102 @@ async def test_setup_untag_missing_auth(py_api: httpx.AsyncClient) -> None:
1617 assert response .json ()["detail" ] == "No API key provided."
1718
1819
19- async def test_setup_untag_unknown_setup (py_api : httpx .AsyncClient ) -> None :
20- response = await py_api .post (
21- f"/setup/untag?api_key={ ApiKey .SOME_USER } " ,
22- json = {"setup_id" : 999999 , "tag" : "test_tag" },
23- )
24- assert response .status_code == HTTPStatus .NOT_FOUND
25- assert re .match (
26- r"Setup \d+ not found." ,
27- response .json ()["detail" ],
20+ @pytest .mark .mut
21+ async def test_setup_untag_api_success (
22+ py_api : httpx .AsyncClient , expdb_test : AsyncConnection
23+ ) -> None :
24+ tag = "setup_untag_via_http"
25+ await expdb_test .execute (
26+ text ("INSERT INTO setup_tag (id, tag, uploader) VALUES (1, :tag, 2);" ),
27+ parameters = {"tag" : tag },
2828 )
2929
30-
31- async def test_setup_untag_tag_not_found (py_api : httpx .AsyncClient ) -> None :
3230 response = await py_api .post (
3331 f"/setup/untag?api_key={ ApiKey .SOME_USER } " ,
34- json = {"setup_id" : 1 , "tag" : "non_existent_tag_12345" },
32+ json = {"setup_id" : 1 , "tag" : tag },
3533 )
36- assert response .status_code == HTTPStatus .NOT_FOUND
37- assert re .match (
38- r"Setup \d+ does not have tag '\S+'." ,
39- response .json ()["detail" ],
34+
35+ assert response .status_code == HTTPStatus .OK
36+ expected = {"setup_untag" : {"id" : "1" , "tag" : []}}
37+ assert expected == response .json ()
38+
39+ rows = await expdb_test .execute (
40+ text ("SELECT * FROM setup_tag WHERE id = 1 AND tag = :tag" ),
41+ parameters = {"tag" : tag },
4042 )
43+ assert len (rows .all ()) == 0
44+
45+
46+ # ── Direct call tests: untag_setup ──
47+
48+
49+ async def test_setup_untag_unknown_setup (expdb_test : AsyncConnection ) -> None :
50+ with pytest .raises (SetupNotFoundError , match = r"Setup \d+ not found." ):
51+ await untag_setup (
52+ setup_id = 999999 ,
53+ tag = "test_tag" ,
54+ user = SOME_USER ,
55+ expdb_db = expdb_test ,
56+ )
57+
58+
59+ async def test_setup_untag_tag_not_found (expdb_test : AsyncConnection ) -> None :
60+ tag = "non_existent_tag_12345"
61+ with pytest .raises (TagNotFoundError , match = rf"Setup 1 does not have tag '{ tag } '\." ):
62+ await untag_setup (
63+ setup_id = 1 ,
64+ tag = tag ,
65+ user = SOME_USER ,
66+ expdb_db = expdb_test ,
67+ )
4168
4269
4370@pytest .mark .mut
44- async def test_setup_untag_not_owned_by_you (
45- py_api : httpx .AsyncClient , expdb_test : AsyncConnection
46- ) -> None :
71+ async def test_setup_untag_not_owned_by_you (expdb_test : AsyncConnection ) -> None :
72+ tag = "setup_untag_forbidden"
4773 await expdb_test .execute (
48- text ("INSERT INTO setup_tag (id, tag, uploader) VALUES (1, 'test_unit_tag_123', 2);" )
49- )
50- response = await py_api .post (
51- f"/setup/untag?api_key={ ApiKey .OWNER_USER } " ,
52- json = {"setup_id" : 1 , "tag" : "test_unit_tag_123" },
74+ text ("INSERT INTO setup_tag (id, tag, uploader) VALUES (1, :tag, 2);" ),
75+ parameters = {"tag" : tag },
5376 )
54- assert response .status_code == HTTPStatus .FORBIDDEN
55- assert re .match (
56- r"You may not remove tag '\S+' of setup \d+ because it was not created by you." ,
57- response .json ()["detail" ],
77+ with pytest .raises (
78+ TagNotOwnedError ,
79+ match = rf"You may not remove tag '{ tag } ' of setup 1 because it was not created by you\." ,
80+ ):
81+ await untag_setup (
82+ setup_id = 1 ,
83+ tag = tag ,
84+ user = OWNER_USER ,
85+ expdb_db = expdb_test ,
86+ )
87+ rows = await expdb_test .execute (
88+ text ("SELECT * FROM setup_tag WHERE id = 1 AND tag = :tag" ),
89+ parameters = {"tag" : tag },
5890 )
91+ assert len (rows .all ()) == 1
5992
6093
6194@pytest .mark .mut
62- @pytest .mark .parametrize (
63- "api_key" ,
64- [ApiKey .SOME_USER , ApiKey .ADMIN ],
65- ids = ["Owner" , "Administrator" ],
66- )
67- async def test_setup_untag_success (
68- api_key : str , py_api : httpx .AsyncClient , expdb_test : AsyncConnection
95+ async def test_setup_untag_admin_removes_tag_uploaded_by_another_user (
96+ expdb_test : AsyncConnection ,
6997) -> None :
98+ """Administrator can remove a tag uploaded by another user."""
99+ tag = "setup_untag_via_direct"
70100 await expdb_test .execute (
71- text ("INSERT INTO setup_tag (id, tag, uploader) VALUES (1, 'test_success_tag', 2)" )
101+ text ("INSERT INTO setup_tag (id, tag, uploader) VALUES (1, :tag, 2);" ),
102+ parameters = {"tag" : tag },
72103 )
73104
74- response = await py_api .post (
75- f"/setup/untag?api_key={ api_key } " ,
76- json = {"setup_id" : 1 , "tag" : "test_success_tag" },
105+ result = await untag_setup (
106+ setup_id = 1 ,
107+ tag = tag ,
108+ user = ADMIN_USER ,
109+ expdb_db = expdb_test ,
77110 )
78111
79- assert response .status_code == HTTPStatus .OK
80- assert response .json () == {"setup_untag" : {"id" : "1" , "tag" : []}}
112+ assert result == {"setup_untag" : {"id" : "1" , "tag" : []}}
81113
82114 rows = await expdb_test .execute (
83- text ("SELECT * FROM setup_tag WHERE id = 1 AND tag = 'test_success_tag'" )
115+ text ("SELECT * FROM setup_tag WHERE id = 1 AND tag = :tag" ),
116+ parameters = {"tag" : tag },
84117 )
85118 assert len (rows .all ()) == 0
0 commit comments