Skip to content

Commit

Permalink
test(workflows): FastAPI workflow router
Browse files Browse the repository at this point in the history
  • Loading branch information
davidlougheed committed Nov 20, 2023
1 parent b770083 commit 3affdfa
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 22 deletions.
27 changes: 27 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
from pathlib import Path

from bento_lib import workflows

__all__ = [
"PERMISSION_INGEST_DATA",
"authz_test_case_params",
"authz_test_cases",
"TEST_AUTHZ_VALID_POST_BODY",
"TEST_AUTHZ_HEADERS",
"WDL_DIR",
"WORKFLOW_DEF",
]


PERMISSION_INGEST_DATA = "ingest:data"

# cases: (authz response code, authz response result, test client URL, auth header included, assert final response)
Expand All @@ -20,3 +35,15 @@

TEST_AUTHZ_VALID_POST_BODY = {"test1": "a", "test2": "b"}
TEST_AUTHZ_HEADERS = {"Authorization": "Bearer test"}

WDL_DIR = Path(__file__).parent / "wdls"

WORKFLOW_DEF = wd = workflows.models.WorkflowDefinition(
name="Test Workflow",
type="ingestion",
description="A test workflow",
file="test.wdl",
inputs=[
workflows.models.WorkflowStringInput(id="input1", type="string"),
]
)
43 changes: 37 additions & 6 deletions tests/test_platform_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,23 @@
from bento_lib.auth.exceptions import BentoAuthException
from bento_lib.auth.middleware.constants import RESOURCE_EVERYTHING
from bento_lib.auth.middleware.fastapi import FastApiAuthMiddleware
from bento_lib.auth.permissions import P_INGEST_DATA
from bento_lib.responses.fastapi_errors import (
http_exception_handler_factory,
bento_auth_exception_handler_factory,
validation_exception_handler_factory,
)
from bento_lib.workflows.workflow_set import WorkflowSet
from bento_lib.workflows.fastapi import build_workflow_router

from .common import (
PERMISSION_INGEST_DATA,
authz_test_case_params,
authz_test_cases,
TEST_AUTHZ_VALID_POST_BODY,
TEST_AUTHZ_HEADERS,
WDL_DIR,
WORKFLOW_DEF,
)


Expand Down Expand Up @@ -97,6 +102,11 @@ def get_403():
test_app_auth.exception_handler(BentoAuthException)(bento_auth_exception_handler_factory(logger, auth_middleware))
test_app_auth.exception_handler(RequestValidationError)(validation_exception_handler_factory(auth_middleware))

workflow_set = WorkflowSet(WDL_DIR)
workflow_set.add_workflow("test", WORKFLOW_DEF)

test_app_auth.include_router(build_workflow_router(auth_middleware, workflow_set))

fastapi_client_auth_ = TestClient(test_app_auth)


Expand All @@ -111,22 +121,22 @@ def auth_post_public(body: TestBody):


@test_app_auth.post("/post-private", dependencies=[
auth_middleware.dep_require_permissions_on_resource(frozenset({PERMISSION_INGEST_DATA})),
auth_middleware.dep_require_permissions_on_resource(frozenset({P_INGEST_DATA})),
])
def auth_post_private(body: TestBody):
return JSONResponse(body.model_dump(mode="json"))


@test_app_auth.post("/post-private-no-flag", dependencies=[
auth_middleware.dep_require_permissions_on_resource(frozenset({PERMISSION_INGEST_DATA}), set_authz_flag=False),
auth_middleware.dep_require_permissions_on_resource(frozenset({P_INGEST_DATA}), set_authz_flag=False),
])
def auth_post_private_no_flag(request: Request, body: TestBody):
auth_middleware.mark_authz_done(request)
return JSONResponse(body.model_dump(mode="json"))


@test_app_auth.post("/post-private-no-token", dependencies=[
auth_middleware.dep_require_permissions_on_resource(frozenset({PERMISSION_INGEST_DATA}), require_token=False),
auth_middleware.dep_require_permissions_on_resource(frozenset({P_INGEST_DATA}), require_token=False),
])
def auth_post_private_no_token(body: TestBody):
return JSONResponse(body.model_dump(mode="json"))
Expand Down Expand Up @@ -164,7 +174,7 @@ async def auth_post_with_token_evaluate_one(request: Request, body: TestTokenBod
return JSONResponse({"payload": await auth_middleware.async_evaluate_one(
request,
RESOURCE_EVERYTHING,
PERMISSION_INGEST_DATA,
P_INGEST_DATA,
require_token=True,
headers_getter=(lambda _r: {"Authorization": f"Bearer {token}"}),
)})
Expand All @@ -178,7 +188,7 @@ async def auth_post_with_token_evaluate_to_dict(request: Request, body: TestToke
return JSONResponse({"payload": await auth_middleware.async_evaluate_to_dict(
request,
(RESOURCE_EVERYTHING,),
(PERMISSION_INGEST_DATA,),
(P_INGEST_DATA,),
require_token=True,
headers_getter=(lambda _r: {"Authorization": f"Bearer {token}"}),
)})
Expand Down Expand Up @@ -215,7 +225,7 @@ def auth_disabled_post_public(body: TestBody):


@test_app_auth_disabled.post("/post-private", dependencies=[
auth_middleware_disabled.dep_require_permissions_on_resource(frozenset({PERMISSION_INGEST_DATA})),
auth_middleware_disabled.dep_require_permissions_on_resource(frozenset({P_INGEST_DATA})),
])
def auth_disabled_post_private(body: TestBody):
return JSONResponse(body.model_dump(mode="json"))
Expand Down Expand Up @@ -358,3 +368,24 @@ async def test_fastapi_auth_disabled(aioresponse: aioresponses, fastapi_client_a
frozenset({PERMISSION_INGEST_DATA}),
{"everything": True},
) is None


def test_fastapi_get_workflows(fastapi_client_auth: TestClient):
r = fastapi_client_auth.get("/workflows")
assert r.status_code == 200
assert len(r.json()["ingestion"]) == 1 # 1 ingestion workflow

r = fastapi_client_auth.get("/workflows/") # trailing slash should be OK too
assert r.status_code == 200
assert len(r.json()["ingestion"]) == 1 # 1 ingestion workflow

r = fastapi_client_auth.get("/workflows/test")
assert r.status_code == 200 # workflow metadata
r = fastapi_client_auth.get("/workflows/test.wdl")
assert r.status_code == 200 # workflow WDL file

# no workflow with the ID "test2"
r = fastapi_client_auth.get("/workflows/test2")
assert r.status_code == 404
r = fastapi_client_auth.get("/workflows/test2.wdl")
assert r.status_code == 404
20 changes: 4 additions & 16 deletions tests/test_workflows.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import pytest
from pathlib import Path

from bento_lib import workflows

WDL_DIR = Path(__file__).parent / "wdls"
from .common import WDL_DIR, WORKFLOW_DEF


def test_namespaced_input():
Expand All @@ -17,27 +15,17 @@ def test_workflow_set():
assert ws.get_workflow("test") is None
assert ws.get_workflow_resource("test") is None

wd = workflows.models.WorkflowDefinition(
name="Test Workflow",
type="ingestion",
description="A test workflow",
file="test.wdl",
inputs=[
workflows.models.WorkflowStringInput(id="input1", type="string"),
]
)

ws.add_workflow("test", wd)
ws.add_workflow("test", WORKFLOW_DEF)
assert ws.workflow_exists("test")
assert ws.get_workflow("test") == wd
assert ws.get_workflow("test") == WORKFLOW_DEF
assert ws.get_workflow_resource("test") == "test.wdl"
assert ws.get_workflow_wdl_path("test") == WDL_DIR / "test.wdl"

assert ws.workflow_dicts_by_type_and_id()["ingestion"]["test"]["name"] == "Test Workflow"
assert ws.workflow_dicts_by_id()["test"]["name"] == "Test Workflow"

with pytest.raises(ValueError):
ws.add_workflow("test", wd) # already exists
ws.add_workflow("test", WORKFLOW_DEF) # already exists

wd2 = workflows.models.WorkflowDefinition(
name="Test Workflow 2",
Expand Down

0 comments on commit 3affdfa

Please sign in to comment.