Skip to content

Commit ae58c78

Browse files
committed
test task submission authz
1 parent f547bef commit ae58c78

1 file changed

Lines changed: 121 additions & 0 deletions

File tree

tests/unit_tests/service/test_authorization.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
from blueapi.config import OIDCConfig, OpaConfig, ServiceAccount
99
from blueapi.service.authorization import (
1010
OpaClient,
11+
OpaUserClient,
1112
opa,
13+
submit_permission,
1214
validate_tiled_config,
1315
)
16+
from blueapi.service.model import TaskRequest
1417

1518
# Reusable client patch decorator
1619
patch_client_session = patch(
@@ -25,6 +28,7 @@ def opa_config() -> OpaConfig:
2528
return OpaConfig(
2629
root=HttpUrl("http://auth.example.com"),
2730
submit_task_check="/auth/submit",
31+
admin_check="/auth/admin",
2832
tiled_service_account_check="/auth/tiled",
2933
)
3034

@@ -108,6 +112,105 @@ async def test_opa_adds_input_fields(session: MagicMock, opa_config: OpaConfig):
108112
)
109113

110114

115+
@pytest.mark.parametrize(
116+
"result,context",
117+
[(True, nullcontext()), (False, pytest.raises(HTTPException, match="403"))],
118+
)
119+
@patch_client_session
120+
async def test_require_submit_task(
121+
session: MagicMock,
122+
opa_config: OpaConfig,
123+
result: bool,
124+
context: AbstractContextManager,
125+
):
126+
session.return_value.post = AsyncMock(
127+
return_value=MagicMock(json=AsyncMock(return_value={"result": result}))
128+
)
129+
130+
client = OpaClient(instrument="p99", config=opa_config)
131+
132+
session.assert_called_once_with(base_url="http://auth.example.com/")
133+
with context:
134+
await client.require_submit_task(
135+
instrument_session="cm12345-1", token="foo_bar"
136+
)
137+
138+
session().post.assert_called_once_with(
139+
"/auth/submit",
140+
json={
141+
"input": {
142+
"token": "foo_bar",
143+
"beamline": "p99",
144+
"audience": "account",
145+
"visit": 1,
146+
"proposal": 12345,
147+
}
148+
},
149+
)
150+
151+
152+
@patch_client_session
153+
async def test_opa_require_submit_task_invalid_session(
154+
session: MagicMock, opa_config: OpaConfig
155+
):
156+
client = OpaClient(instrument="p45", config=opa_config)
157+
158+
with pytest.raises(ValueError):
159+
await client.require_submit_task(
160+
instrument_session="not a session", token="foo_bar"
161+
)
162+
163+
164+
@pytest.mark.parametrize("result", [True, False])
165+
@patch_client_session
166+
async def test_opa_is_admin(session: MagicMock, opa_config: OpaConfig, result: bool):
167+
session.return_value.post = AsyncMock(
168+
return_value=MagicMock(json=AsyncMock(return_value={"result": result}))
169+
)
170+
client = OpaClient(instrument="p45", config=opa_config)
171+
172+
admin = await client.is_admin("foo_bar")
173+
174+
assert admin == result
175+
176+
session().post.assert_called_once_with(
177+
"/auth/admin",
178+
json={"input": {"token": "foo_bar", "beamline": "p45", "audience": "account"}},
179+
)
180+
181+
182+
@pytest.mark.parametrize(
183+
"result,context",
184+
[
185+
(None, nullcontext()),
186+
(HTTPException(status_code=403), pytest.raises(HTTPException, match="403")),
187+
],
188+
)
189+
async def test_user_client_can_submit_task(result, context: AbstractContextManager):
190+
opa = MagicMock(spec=OpaUserClient)
191+
opa.require_submit_task = AsyncMock(side_effect=result)
192+
193+
user_client = OpaUserClient(opa, "foo_bar")
194+
195+
with context:
196+
await user_client.can_submit_task(
197+
TaskRequest(name="foo", params={}, instrument_session="cm12345-1")
198+
)
199+
opa.require_submit_task.assert_called_once_with("cm12345-1", "foo_bar")
200+
201+
202+
@pytest.mark.parametrize("result", [True, False])
203+
async def test_user_client_admin(result: bool):
204+
opa = MagicMock(spec=OpaUserClient)
205+
opa.is_admin = AsyncMock(return_value=result)
206+
207+
user_client = OpaUserClient(opa, "foo_bar")
208+
209+
admin = await user_client.admin()
210+
211+
assert admin == result
212+
213+
111214
async def test_validate_tiled_config():
112215
opa = MagicMock(spec=OpaClient)
113216
tiled = ServiceAccount()
@@ -177,3 +280,21 @@ async def test_opa_dependency_without_authz(token):
177280
del request.app.state.authz
178281
user_client = await opa(request, token)
179282
assert user_client is None
283+
284+
285+
@pytest.mark.parametrize(
286+
"result,context",
287+
[
288+
(None, nullcontext()),
289+
(HTTPException(status_code=403), pytest.raises(HTTPException, match="403")),
290+
],
291+
)
292+
async def test_submit_permission_dependency(result, context: AbstractContextManager):
293+
opa = MagicMock(spec=OpaUserClient)
294+
opa.can_submit_task.side_effect = result
295+
with context:
296+
await submit_permission(opa, Mock())
297+
298+
299+
async def test_submit_permission_dependency_without_opa():
300+
assert await submit_permission(None, Mock()) is None

0 commit comments

Comments
 (0)