diff --git a/awx/api/views.py b/awx/api/views.py index f502576da3..8ffe05aa4d 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -2916,6 +2916,7 @@ class WorkflowJobTemplateDetail(RetrieveUpdateDestroyAPIView): always_allow_superuser = False new_in_310 = True + class WorkflowJobTemplateCopy(GenericAPIView): model = WorkflowJobTemplate @@ -2999,7 +3000,7 @@ class WorkflowJobRelaunch(GenericAPIView): def post(self, request, *args, **kwargs): obj = self.get_object() new_workflow_job = obj.create_relaunch_workflow_job() - result = new_workflow_job.signal_start() + new_workflow_job.signal_start() data = WorkflowJobSerializer(new_workflow_job, context=self.get_serializer_context()).data headers = {'Location': new_workflow_job.get_absolute_url()} diff --git a/awx/main/access.py b/awx/main/access.py index 4b41da80ba..934c907ad6 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -341,8 +341,6 @@ class BaseAccess(object): # Aliases for going form UI language to API language if display_method == 'edit': method = 'change' - elif display_method == 'copy': - method = 'add' elif display_method == 'adhoc': method = 'run_ad_hoc_commands' else: @@ -368,7 +366,7 @@ class BaseAccess(object): access_method = getattr(self, "can_%s" % method) if method in ['change']: # 3 args user_capabilities[display_method] = access_method(obj, data) - elif method in ['delete', 'run_ad_hoc_commands']: + elif method in ['delete', 'run_ad_hoc_commands', 'copy']: user_capabilities[display_method] = access_method(obj) elif method in ['start']: user_capabilities[display_method] = access_method(obj, validate_license=False) diff --git a/awx/main/tests/unit/models/test_workflow_unit.py b/awx/main/tests/unit/models/test_workflow_unit.py index 54f29ea583..5661eb7b81 100644 --- a/awx/main/tests/unit/models/test_workflow_unit.py +++ b/awx/main/tests/unit/models/test_workflow_unit.py @@ -3,7 +3,7 @@ import pytest from awx.main.models.jobs import JobTemplate from awx.main.models import Inventory, Credential, Project from awx.main.models.workflow import ( - WorkflowJobTemplate, WorkflowJobTemplateNode, WorkflowJobInheritNodesMixin, + WorkflowJobTemplate, WorkflowJobTemplateNode, WorkflowJobOptions, WorkflowJob, WorkflowJobNode ) import mock @@ -22,9 +22,9 @@ class TestWorkflowJobInheritNodesMixin(): def test__create_workflow_job_nodes(self, mocker, job_template_nodes): workflow_job_node_create = mocker.patch('awx.main.models.WorkflowJobTemplateNode.create_workflow_job_node') - mixin = WorkflowJobInheritNodesMixin() - mixin._create_workflow_job_nodes(job_template_nodes) - + mixin = WorkflowJobOptions() + mixin._create_workflow_nodes(job_template_nodes) + for job_template_node in job_template_nodes: workflow_job_node_create.assert_any_call(workflow_job=mixin) @@ -37,22 +37,30 @@ class TestWorkflowJobInheritNodesMixin(): def job_nodes(self): return [WorkflowJobNode(id=i) for i in range(100, 120)] - def test__map_workflow_job_nodes(self, job_template_nodes, job_nodes): - mixin = WorkflowJobInheritNodesMixin() + def test__map_workflow_job_nodes(self, job_template_nodes, job_nodes, mocker): + mixin = WorkflowJob() + wj_node = WorkflowJobNode() + mocker.patch('awx.main.models.workflow.WorkflowJobTemplateNode.create_workflow_job_node', + return_value=wj_node) - node_ids_map = mixin._map_workflow_job_nodes(job_template_nodes, job_nodes) + node_ids_map = mixin._create_workflow_nodes(job_template_nodes, user=None) assert len(node_ids_map) == len(job_template_nodes) for i, job_template_node in enumerate(job_template_nodes): - assert node_ids_map[job_template_node.id] == job_nodes[i].id + assert node_ids_map[job_template_node.id] == wj_node class TestInheritRelationship(): @pytest.fixture def job_template_nodes(self, mocker): - nodes = [mocker.MagicMock(id=i) for i in range(0, 10)] + nodes = [mocker.MagicMock(id=i, pk=i) for i in range(0, 10)] for i in range(0, 9): - nodes[i].success_nodes = [mocker.MagicMock(id=i + 1)] + nodes[i].success_nodes = mocker.MagicMock( + all=mocker.MagicMock(return_value=[mocker.MagicMock(id=i + 1, pk=i + 1)])) + nodes[i].always_nodes = mocker.MagicMock(all=mocker.MagicMock(return_value=[])) + nodes[i].failure_nodes = mocker.MagicMock(all=mocker.MagicMock(return_value=[])) + new_wj_node = mocker.MagicMock(success_nodes=mocker.MagicMock()) + nodes[i].create_workflow_job_node = mocker.MagicMock(return_value=new_wj_node) return nodes @@ -70,18 +78,13 @@ class TestWorkflowJobInheritNodesMixin(): def test__inherit_relationship(self, mocker, job_template_nodes, job_nodes, job_nodes_dict): - mixin = WorkflowJobInheritNodesMixin() + wj = WorkflowJob() - mixin._get_workflow_job_node_by_id = lambda x: job_nodes_dict[x] - mixin._get_all_by_type = lambda x,node_type: x.success_nodes + node_ids_map = wj._create_workflow_nodes(job_template_nodes) + wj._inherit_node_relationships(job_template_nodes, node_ids_map) - node_ids_map = mixin._map_workflow_job_nodes(job_template_nodes, job_nodes) - - for i, job_template_node in enumerate(job_template_nodes): - mixin._inherit_relationship(job_template_node, job_nodes[i], node_ids_map, 'success_nodes') - - for i in range(0, 9): - job_nodes[i].success_nodes.add.assert_any_call(job_nodes[i + 1]) + for i in range(0, 8): + node_ids_map[i].success_nodes.add.assert_any_call(node_ids_map[i + 1]) @pytest.fixture diff --git a/awx/main/tests/unit/test_access.py b/awx/main/tests/unit/test_access.py index 5dc3a5e57b..8a6687ba2f 100644 --- a/awx/main/tests/unit/test_access.py +++ b/awx/main/tests/unit/test_access.py @@ -258,8 +258,8 @@ def test_user_capabilities_method(): def can_change(self, obj, data): return 'bar' - def can_add(self, data): - return 'foobar' + def can_copy(self, obj): + return 'foo' user = User(username='auser') foo_access = FooAccess(user) @@ -267,7 +267,7 @@ def test_user_capabilities_method(): foo_capabilities = foo_access.get_user_capabilities(foo, ['edit', 'copy']) assert foo_capabilities == { 'edit': 'bar', - 'copy': 'foobar' + 'copy': 'foo' }