diff --git a/CHANGES/+workflow-in-filter.feature b/CHANGES/+workflow-in-filter.feature new file mode 100644 index 0000000..46694e7 --- /dev/null +++ b/CHANGES/+workflow-in-filter.feature @@ -0,0 +1,2 @@ +Added an `in` lookup to the `WorkflowRun` `workflow` filter (`workflow__in`) so the runs for +several workflows can be fetched in a single list request. diff --git a/pulp_workflow/app/viewsets.py b/pulp_workflow/app/viewsets.py index ec419d2..9b5b6f8 100644 --- a/pulp_workflow/app/viewsets.py +++ b/pulp_workflow/app/viewsets.py @@ -275,14 +275,15 @@ class WorkflowRunFilter(BaseFilterSet): Shared by the nested (``/workflow/workflows//runs/``) and flat (``/workflow/workflow-runs/``) run endpoints. The ``workflow`` filter is primarily useful on - the flat endpoint to scope to a single workflow's run history; on the nested endpoint the + the flat endpoint to scope to a single workflow's run history (or, via ``workflow__in``, to + batch-fetch the runs for several workflows in one request); on the nested endpoint the workflow is already implied by the URL. """ class Meta: model = WorkflowRun fields = { - "workflow": ["exact"], + "workflow": ["exact", "in"], "state": ["exact", "in", "ne"], "pulp_created": DATETIME_FILTER_OPTIONS, "started_at": DATETIME_FILTER_OPTIONS, diff --git a/pulp_workflow/tests/unit/test_viewsets.py b/pulp_workflow/tests/unit/test_viewsets.py index 405d1c3..3f4a88b 100644 --- a/pulp_workflow/tests/unit/test_viewsets.py +++ b/pulp_workflow/tests/unit/test_viewsets.py @@ -1,5 +1,11 @@ +import pytest + +from pulpcore.plugin.util import get_url + +from pulp_workflow.app.models import Workflow, WorkflowRun from pulp_workflow.app.viewsets import ( CallbackServiceViewSet, + WorkflowRunFilter, WorkflowRunListViewSet, WorkflowRunViewSet, WorkflowViewSet, @@ -99,6 +105,30 @@ def test_flat_run_list_viewset_is_list_only(): assert getattr(WorkflowRunListViewSet, "parent_viewset", None) is None +@pytest.mark.django_db +def test_workflow_run_filter_workflow_in_returns_union(): + """The ``workflow__in`` lookup returns the runs of every listed workflow and no others. + + pulpcore resolves ``in`` values against related resources by href, so the filter is fed the + workflow hrefs (as a client would send them), not raw pks. + """ + wf1 = Workflow.objects.create(name="wf-in-1") + wf2 = Workflow.objects.create(name="wf-in-2") + wf3 = Workflow.objects.create(name="wf-in-3") + run1 = WorkflowRun.objects.create(workflow=wf1) + run2 = WorkflowRun.objects.create(workflow=wf2) + # A run belonging to a workflow that is not in the filter must be excluded. + WorkflowRun.objects.create(workflow=wf3) + + filterset = WorkflowRunFilter( + data={"workflow__in": f"{get_url(wf1)},{get_url(wf2)}"}, + queryset=WorkflowRun.objects.all(), + ) + + assert filterset.is_valid(), filterset.errors + assert set(filterset.qs.values_list("pk", flat=True)) == {run1.pk, run2.pk} + + def test_flat_run_list_access_policy_requires_view_and_only_lists(): """The flat run list only allows list, gated on view_workflowrun.""" policy = WorkflowRunListViewSet.DEFAULT_ACCESS_POLICY