Skip to content

Commit 19fdce8

Browse files
authored
add endpoint for getting monthly workflow (#141)
* add endpoint for getting monthly workflow
1 parent 02a28f1 commit 19fdce8

File tree

2 files changed

+111
-45
lines changed

2 files changed

+111
-45
lines changed

src/argowrapper/routes/routes.py

+34-20
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,10 @@ def check_user_info_for_billing_id_and_workflow_limit(request):
252252
return None, None
253253

254254

255-
def check_user_reached_monthly_workflow_cap(request_token, billing_id, custom_limit):
255+
def check_user_monthly_workflow_cap(request_token, billing_id, custom_limit):
256256
"""
257-
Query Argo service to see how many successful run user already
258-
have in the current calendar month. If the number is greater than
259-
the threshold, return error.
257+
Query Argo service to see how many workflow runs user already
258+
have in the current calendar month. Return number of workflow runs and limit
260259
"""
261260

262261
try:
@@ -271,21 +270,7 @@ def check_user_reached_monthly_workflow_cap(request_token, billing_id, custom_li
271270
limit = GEN3_NON_VA_WORKFLOW_MONTHLY_CAP
272271
else:
273272
limit = GEN3_DEFAULT_WORKFLOW_MONTHLY_CAP
274-
275-
if len(current_month_workflows) >= limit:
276-
logger.warn(
277-
"This user {} already executed {} workflows this month and cannot create new ones anymore. The currently monthly cap for this user is {}.".format(
278-
username, len(current_month_workflows), limit
279-
)
280-
)
281-
return True
282-
else:
283-
logger.info(
284-
"This user {} executed {} workflows this month. The currently monthly cap for this user is {}.".format(
285-
username, len(current_month_workflows), limit
286-
)
287-
)
288-
return False
273+
return len(current_month_workflows), limit
289274
except Exception as e:
290275
logger.error(e)
291276
traceback.print_exc()
@@ -316,10 +301,12 @@ def submit_workflow(
316301
)
317302

318303
# if user has billing_id (non-VA user), check if they already reached the monthly cap
319-
reached_monthly_cap = check_user_reached_monthly_workflow_cap(
304+
workflow_run, workflow_limit = check_user_monthly_workflow_cap(
320305
request.headers.get("Authorization"), billing_id, workflow_limit
321306
)
322307

308+
reached_monthly_cap = workflow_run >= workflow_limit
309+
323310
# submit workflow:
324311
if not reached_monthly_cap:
325312
return argo_engine.workflow_submission(
@@ -448,3 +435,30 @@ def get_workflow_logs(
448435
content="Unexpected Error Occurred",
449436
status_code=HTTP_500_INTERNAL_SERVER_ERROR,
450437
)
438+
439+
440+
@router.get("/workflows/user-monthly", status_code=HTTP_200_OK)
441+
def get_user_monthly_workflow(
442+
request: Request,
443+
) -> Dict[str, any]:
444+
"""
445+
Query Argo service to see how many successful run user already
446+
have in the current calendar month. Return workflow numbers and workflow cap
447+
"""
448+
449+
try:
450+
billing_id, workflow_limit = check_user_info_for_billing_id_and_workflow_limit(
451+
request
452+
)
453+
454+
# if user has billing_id (non-VA user), check if they already reached the monthly cap
455+
workflow_run, workflow_limit = check_user_monthly_workflow_cap(
456+
request.headers.get("Authorization"), billing_id, workflow_limit
457+
)
458+
459+
result = {"workflow_run": workflow_run, "workflow_limit": workflow_limit}
460+
return result
461+
except Exception as e:
462+
logger.error(e)
463+
traceback.print_exc()
464+
raise e

test/test_routes.py

+77-25
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,15 @@
88
from fastapi.testclient import TestClient
99
from argowrapper.constants import *
1010
from test.constants import EXAMPLE_AUTH_HEADER
11-
from argowrapper.routes.routes import router, check_user_reached_monthly_workflow_cap
12-
from argowrapper.constants import GEN3_NON_VA_WORKFLOW_MONTHLY_CAP
11+
from argowrapper.routes.routes import (
12+
router,
13+
check_user_monthly_workflow_cap,
14+
get_user_monthly_workflow,
15+
)
16+
from argowrapper.constants import (
17+
GEN3_NON_VA_WORKFLOW_MONTHLY_CAP,
18+
GEN3_DEFAULT_WORKFLOW_MONTHLY_CAP,
19+
)
1320

1421
variables = [
1522
{"variable_type": "concept", "concept_id": "2000000324"},
@@ -110,13 +117,13 @@ def test_submit_workflow(client):
110117
) as mock_check_billing_id, patch(
111118
"requests.get"
112119
) as mock_requests, patch(
113-
"argowrapper.routes.routes.check_user_reached_monthly_workflow_cap"
120+
"argowrapper.routes.routes.check_user_monthly_workflow_cap"
114121
) as mock_check_monthly_cap:
115122
mock_auth.return_value = True
116123
mock_engine.return_value = "workflow_123"
117124
mock_check_billing_id.return_value = None, None
118125
mock_requests.side_effect = mocked_requests_get
119-
mock_check_monthly_cap.return_value = False
126+
mock_check_monthly_cap.return_value = 1, 3
120127

121128
response = client.post(
122129
"/submit",
@@ -558,9 +565,9 @@ def test_submit_workflow_with_user_billing_id(client):
558565
data["user_tags"] = {"tags": {"othertag1": "tag1", "billing_id": "1234"}}
559566

560567
with patch(
561-
"argowrapper.routes.routes.check_user_reached_monthly_workflow_cap"
568+
"argowrapper.routes.routes.check_user_monthly_workflow_cap"
562569
) as mock_check_monthly_cap:
563-
mock_check_monthly_cap.return_value = False
570+
mock_check_monthly_cap.return_value = 1, 3
564571
response = client.post(
565572
"/submit",
566573
data=json.dumps(data),
@@ -584,7 +591,7 @@ def test_submit_workflow_with_user_billing_id(client):
584591
assert response.status_code == 500
585592

586593

587-
def test_check_user_reached_monthly_workflow_cap():
594+
def test_check_user_monthly_workflow_cap():
588595
headers = {
589596
"Content-Type": "application/json",
590597
"Authorization": EXAMPLE_AUTH_HEADER,
@@ -600,16 +607,14 @@ def test_check_user_reached_monthly_workflow_cap():
600607

601608
# Test Under Default Limit
602609
assert (
603-
check_user_reached_monthly_workflow_cap(
604-
headers["Authorization"], None, None
605-
)
606-
== False
610+
check_user_monthly_workflow_cap(headers["Authorization"], None, None) == 2,
611+
GEN3_NON_VA_WORKFLOW_MONTHLY_CAP,
607612
)
608613

609614
# Test Custom Limit
610615
assert (
611-
check_user_reached_monthly_workflow_cap(headers["Authorization"], None, 2)
612-
== True
616+
check_user_monthly_workflow_cap(headers["Authorization"], None, 2) == 2,
617+
2,
613618
)
614619

615620
# Test Billing Id User Exceeding Limit
@@ -619,10 +624,9 @@ def test_check_user_reached_monthly_workflow_cap():
619624
mock_get_workflow.return_value = workflows
620625

621626
assert (
622-
check_user_reached_monthly_workflow_cap(
623-
headers["Authorization"], "1234", None
624-
)
625-
== True
627+
check_user_monthly_workflow_cap(headers["Authorization"], "1234", None)
628+
== GEN3_NON_VA_WORKFLOW_MONTHLY_CAP + 1,
629+
GEN3_NON_VA_WORKFLOW_MONTHLY_CAP,
626630
)
627631

628632
# Test VA User Exceeding Limit
@@ -631,10 +635,9 @@ def test_check_user_reached_monthly_workflow_cap():
631635
workflows.append({"wf_name": "workflow" + str(index)})
632636
mock_get_workflow.return_value = workflows
633637
assert (
634-
check_user_reached_monthly_workflow_cap(
635-
headers["Authorization"], None, None
636-
)
637-
== True
638+
check_user_monthly_workflow_cap(headers["Authorization"], None, None)
639+
== GEN3_DEFAULT_WORKFLOW_MONTHLY_CAP + 1,
640+
GEN3_DEFAULT_WORKFLOW_MONTHLY_CAP,
638641
)
639642

640643

@@ -646,14 +649,14 @@ def test_submit_workflow_with_billing_id_and_over_monthly_cap(client):
646649
) as mock_log, patch(
647650
"argowrapper.routes.routes.check_user_info_for_billing_id_and_workflow_limit"
648651
) as mock_check_billing_id, patch(
649-
"argowrapper.routes.routes.check_user_reached_monthly_workflow_cap"
652+
"argowrapper.routes.routes.check_user_monthly_workflow_cap"
650653
) as mock_check_monthly_cap, patch(
651654
"requests.get"
652655
) as mock_requests:
653656
mock_auth.return_value = True
654657
mock_engine.return_value = "workflow_123"
655658
mock_check_billing_id.return_value = "1234", None
656-
mock_check_monthly_cap.return_value = True
659+
mock_check_monthly_cap.return_value = 1, 1
657660
mock_requests.side_effect = mocked_requests_get
658661

659662
response = client.post(
@@ -675,14 +678,14 @@ def test_submit_workflow_over_monthly_cap(client):
675678
) as mock_log, patch(
676679
"argowrapper.routes.routes.check_user_info_for_billing_id_and_workflow_limit"
677680
) as mock_check_billing_id, patch(
678-
"argowrapper.routes.routes.check_user_reached_monthly_workflow_cap"
681+
"argowrapper.routes.routes.check_user_monthly_workflow_cap"
679682
) as mock_check_monthly_cap, patch(
680683
"requests.get"
681684
) as mock_requests:
682685
mock_auth.return_value = True
683686
mock_engine.return_value = "workflow_123"
684687
mock_check_billing_id.return_value = None, None
685-
mock_check_monthly_cap.return_value = True
688+
mock_check_monthly_cap.return_value = 1, 1
686689
mock_requests.side_effect = mocked_requests_get
687690

688691
response = client.post(
@@ -722,3 +725,52 @@ def test_submit_workflow_with_non_team_project_cohort(client):
722725
},
723726
)
724727
assert response.status_code == 400
728+
729+
730+
def test_get_user_monthly_workflow(client):
731+
with patch(
732+
"argowrapper.engine.argo_engine.ArgoEngine.get_user_workflows_for_current_month"
733+
) as mock_get_workflow, patch(
734+
"argowrapper.routes.routes.check_user_info_for_billing_id_and_workflow_limit"
735+
) as mock_check_billing_id:
736+
mock_get_workflow.return_value = [
737+
{"wf_name": "workflow1"},
738+
{"wf_name": "workflow2"},
739+
]
740+
mock_check_billing_id.return_value = None, None
741+
742+
response = client.get(
743+
"/workflows/user-monthly",
744+
headers={
745+
"Content-Type": "application/json",
746+
"Authorization": EXAMPLE_AUTH_HEADER,
747+
},
748+
)
749+
750+
assert response.status_code == 200
751+
assert response.content.decode(
752+
"utf-8"
753+
) == '{{"workflow_run":2,"workflow_limit":{}}}'.format(
754+
GEN3_DEFAULT_WORKFLOW_MONTHLY_CAP
755+
)
756+
757+
mock_get_workflow.return_value = [
758+
{"wf_name": "workflow1"},
759+
{"wf_name": "workflow2"},
760+
{"wf_name": "workflow3"},
761+
]
762+
mock_check_billing_id.return_value = "1234", None
763+
764+
response = client.get(
765+
"/workflows/user-monthly",
766+
headers={
767+
"Content-Type": "application/json",
768+
"Authorization": EXAMPLE_AUTH_HEADER,
769+
},
770+
)
771+
772+
assert response.content.decode(
773+
"utf-8"
774+
) == '{{"workflow_run":3,"workflow_limit":{}}}'.format(
775+
GEN3_NON_VA_WORKFLOW_MONTHLY_CAP
776+
)

0 commit comments

Comments
 (0)