diff --git a/tcms/rpc/api/testcase.py b/tcms/rpc/api/testcase.py index c91983a7d7..b17bd93b2c 100644 --- a/tcms/rpc/api/testcase.py +++ b/tcms/rpc/api/testcase.py @@ -10,12 +10,13 @@ from tcms.rpc import utils from tcms.rpc.api.forms.testcase import NewForm, UpdateForm from tcms.rpc.decorators import permissions_required -from tcms.testcases.models import TestCase +from tcms.testcases.models import TestCase, TestCasePlan __all__ = ( 'create', 'update', 'filter', + 'sortkeys', 'remove', 'add_comment', @@ -280,6 +281,27 @@ def filter(query=None): # pylint: disable=redefined-builtin return TestCase.to_xmlrpc(query) +@permissions_required('testcases.view_testcase') +@rpc_method(name='TestCase.sortkeys') +def sortkeys(query=None): + """ + .. function:: RPC TestCase.sortkeys(query) + + Return information about TestCase position inside TestPlan. + + For example `TestCase.sortkeys({'plan': 3})` + + :param query: Field lookups for :class:`tcms.testcases.models.TestCasePlan` + :type query: dict + :return: Serialized list of :class:`tcms.testcases.models.TestCasePlan` objects. + :rtype: list(dict) + """ + if query is None: + query = {} + + return list(TestCasePlan.objects.filter(**query).values()) + + @permissions_required('testcases.change_testcase') @rpc_method(name='TestCase.update') def update(case_id, values): diff --git a/tcms/rpc/tests/test_testcase.py b/tcms/rpc/tests/test_testcase.py index c568cf7eaf..96c08e8956 100644 --- a/tcms/rpc/tests/test_testcase.py +++ b/tcms/rpc/tests/test_testcase.py @@ -8,7 +8,7 @@ from tcms.core.helpers.comments import get_comments from tcms.management.models import Priority -from tcms.rpc.tests.utils import APITestCase +from tcms.rpc.tests.utils import APITestCase, APIPermissionsTestCase from tcms.testcases.models import Category, TestCase, TestCaseStatus from tcms.tests import remove_perm_from_user from tcms.tests.factories import (CategoryFactory, ComponentFactory, @@ -539,3 +539,45 @@ def test_add_comment_with_pk_as_int(self): first_comment = comments.first() self.assertEqual("Hello World!", first_comment.comment) self.assertEqual("Hello World!", created_comment['comment']) + + +class TestCaseSortkeysPermissions(APIPermissionsTestCase): + permission_label = 'testcases.view_testcase' + + def _fixture_setup(self): + super()._fixture_setup() + + self.plan = TestPlanFactory() + + # add TCs with non-standard sortkeys + self.case_1 = TestCaseFactory() + self.plan.add_case(self.case_1, sortkey=5) + + self.case_2 = TestCaseFactory() + self.plan.add_case(self.case_2, sortkey=15) + + self.case_3 = TestCaseFactory() + self.plan.add_case(self.case_3, sortkey=25) + + def verify_api_with_permission(self): + result = self.rpc_client.TestCase.sortkeys({ + "plan": self.plan.pk, + }) + + for entry in result: + self.assertEqual(entry['plan_id'], self.plan.pk) + + self.assertEqual(result[0]['case_id'], self.case_1.pk) + self.assertEqual(result[0]['sortkey'], 5) + + self.assertEqual(result[1]['case_id'], self.case_2.pk) + self.assertEqual(result[1]['sortkey'], 15) + + self.assertEqual(result[2]['case_id'], self.case_3.pk) + self.assertEqual(result[2]['sortkey'], 25) + + def verify_api_without_permission(self): + with self.assertRaisesRegex(ProtocolError, '403 Forbidden'): + self.rpc_client.TestCase.sortkeys({ + "plan": self.plan.pk, + })