From 6e0867bdddfebbbbfdcef637bad1596f7885bb31 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 11 Jun 2024 11:13:58 -0500 Subject: [PATCH 1/3] Rest Framework Tests: Isolate tests by request type --- unittests/test_rest_framework.py | 566 +++++++++++++++---------------- 1 file changed, 271 insertions(+), 295 deletions(-) diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index 32e527b8d97..8c01dc56fcc 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -175,20 +175,6 @@ def wrapper(self, *args, **kwargs): return decorate -# def testIsBroken(method): -# return tag("broken")(method) - - -def check_response_valid(expected_code, response): - def _data_to_str(response): - if hasattr(response, "data"): - return response.data - return None - - assert response.status_code == expected_code, \ - f"Response invalid, returned with code {response.status_code}\nResponse Data:\n{_data_to_str(response)}" - - def format_url(path): return f"{BASE_API_URL}{path}" @@ -367,29 +353,29 @@ def setUp(self): self.url = reverse(self.viewname + '-list') self.schema = open_api3_json_schema + def setUp_not_authorized(self): + testuser = User.objects.get(id=3) + token = Token.objects.get(user=testuser) + self.client = APIClient() + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) + + def setUp_global_reader(self): + testuser = User.objects.get(id=5) + token = Token.objects.get(user=testuser) + self.client = APIClient() + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) + + def setUp_global_owner(self): + testuser = User.objects.get(id=6) + token = Token.objects.get(user=testuser) + self.client = APIClient() + self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) + def check_schema(self, schema, obj): schema_checker = SchemaChecker(self.schema["components"]) # print(vars(schema_checker)) schema_checker.check(self.schema, obj) - # def get_valid_object_id(self): - # response = self.client.get(format_url(f"/{self.viewname}/")) - # check_response_valid(status.HTTP_200_OK, response) - # if len(response.data["results"]) == 0: - # return None - - # return response.data["results"][0].get('id', None) - - def get_endpoint_schema(self, path, method): - paths = self.schema["paths"] - methods = paths.get(path, None) - assert methods is not None, f"{path} not found in {list(paths.keys())}" - - endpoint = methods.get(method, None) - assert endpoint is not None, f"Method {method} not found in {list(methods.keys())}" - - return endpoint - def check_schema_response(self, method, status_code, response, detail=False): detail_path = '{id}/' if detail else '' endpoints_schema = self.schema["paths"][format_url(f"/{self.endpoint_path}/{detail_path}")] @@ -397,64 +383,7 @@ def check_schema_response(self, method, status_code, response, detail=False): obj = response.data self.check_schema(schema, obj) - @skipIfNotSubclass(ListModelMixin) - def test_list(self): - # print(open_api3_json_schema) - # validator = ResponseValidator(spec) - - check_for_tags = False - if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): - # create a new instance first to make sure there's at least 1 instance with tags set by payload to trigger tag handling code - logger.debug('creating model with endpoints: %s', self.payload) - response = self.client.post(self.url, self.payload) - self.assertEqual(201, response.status_code, response.content[:1000]) - - # print('response:', response.content[:1000]) - check_for_id = response.data['id'] - # print('id: ', check_for_id) - check_for_tags = self.payload.get('tags', None) - - response = self.client.get(self.url, format='json') - # print('response') - # print(vars(response)) - - # print('response.data') - # print(response.data) - # tags must be present in last entry, the one we created - if check_for_tags: - tags_found = False - for result in response.data['results']: - if result['id'] == check_for_id: - # logger.debug('result.tags: %s', result.get('tags', '')) - self.assertEqual(len(check_for_tags), len(result.get('tags', None))) - for tag in check_for_tags: - # logger.debug('looking for tag %s in tag list %s', tag, result['tags']) - self.assertIn(tag, result['tags']) - tags_found = True - self.assertTrue(tags_found) - - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('get', '200', response) - - @skipIfNotSubclass(CreateModelMixin) - def test_create(self): - length = self.endpoint_model.objects.count() - response = self.client.post(self.url, self.payload) - logger.debug('test_create_response:') - logger.debug(response) - logger.debug(response.data) - self.assertEqual(201, response.status_code, response.content[:1000]) - self.assertEqual(self.endpoint_model.objects.count(), length + 1) - - if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): - self.assertEqual(len(self.payload.get('tags')), len(response.data.get('tags', None))) - for tag in self.payload.get('tags'): - # logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) - self.assertIn(tag, response.data['tags']) - - self.check_schema_response('post', '201', response) - + class RetrieveRequestTest(RESTEndpointTest): @skipIfNotSubclass(RetrieveModelMixin) def test_detail(self): current_objects = self.client.get(self.url, format='json').data @@ -469,80 +398,6 @@ def test_detail(self): self.check_schema_response('get', '200', response, detail=True) - @skipIfNotSubclass(DestroyModelMixin) - def test_delete(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/'.format(current_objects['results'][-1]['id']) - response = self.client.delete(relative_url) - self.assertEqual(204, response.status_code, response.content[:1000]) - - @skipIfNotSubclass(UpdateModelMixin) - def test_update(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) - response = self.client.patch(relative_url, self.update_fields) - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('patch', '200', response, detail=True) - - for key, value in self.update_fields.items(): - # some exception as push_to_jira has been implemented strangely in the update methods in the api - if key not in ['push_to_jira', 'ssh', 'password', 'api_key']: - # Convert data to sets to avoid problems with lists - if isinstance(value, list): - value = set(value) - if isinstance(response.data[key], list): - response_data = set(response.data[key]) - else: - response_data = response.data[key] - self.assertEqual(value, response_data) - - self.assertNotIn('push_to_jira', response.data) - self.assertNotIn('ssh', response.data) - self.assertNotIn('password', response.data) - self.assertNotIn('api_key', response.data) - - if hasattr(self.endpoint_model, 'tags') and self.update_fields and self.update_fields.get('tags', None): - self.assertEqual(len(self.update_fields.get('tags')), len(response.data.get('tags', None))) - for tag in self.update_fields.get('tags'): - logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) - self.assertIn(tag, response.data['tags']) - - response = self.client.put( - relative_url, self.payload) - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('put', '200', response, detail=True) - - @skipIfNotSubclass(DeletePreviewModelMixin) - def test_delete_preview(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/delete_preview/'.format(current_objects['results'][0]['id']) - response = self.client.get(relative_url) - # print('delete_preview response.data') - - self.assertEqual(200, response.status_code, response.content[:1000]) - - self.check_schema_response('get', '200', response, detail=True) - - self.assertNotIn('push_to_jira', response.data) - self.assertNotIn('password', response.data) - self.assertNotIn('ssh', response.data) - self.assertNotIn('api_key', response.data) - - self.assertIsInstance(response.data['results'], list) - self.assertGreater(len(response.data['results']), 0, "Length: {}".format(len(response.data['results']))) - - for obj in response.data['results']: - self.assertIsInstance(obj, dict) - self.assertEqual(len(obj), 3) - self.assertIsInstance(obj['model'], str) - if obj['id']: # It needs to be None or int - self.assertIsInstance(obj['id'], int) - self.assertIsInstance(obj['name'], str) - - self.assertEqual(self.deleted_objects, len(response.data['results']), response.content[:1000]) - @skipIfNotSubclass(PrefetchRetrieveMixin) def test_detail_prefetch(self): # print("=======================================================") @@ -571,6 +426,71 @@ def test_detail_prefetch(self): # TODO add schema check + @skipIfNotSubclass(RetrieveModelMixin) + def test_detail_object_not_authorized(self): + if not self.test_type == TestType.OBJECT_PERMISSIONS: + self.skipTest('Authorization is not object based') + + self.setUp_not_authorized() + + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' + response = self.client.get(relative_url) + self.assertEqual(404, response.status_code, response.content[:1000]) + + @skipIfNotSubclass(RetrieveModelMixin) + def test_detail_configuration_not_authorized(self): + if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: + self.skipTest('Authorization is not configuration based') + + self.setUp_not_authorized() + + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' + response = self.client.get(relative_url) + self.assertEqual(403, response.status_code, response.content[:1000]) + + class ListRequestTest(RESTEndpointTest): + @skipIfNotSubclass(ListModelMixin) + def test_list(self): + # print(open_api3_json_schema) + # validator = ResponseValidator(spec) + + check_for_tags = False + if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): + # create a new instance first to make sure there's at least 1 instance with tags set by payload to trigger tag handling code + logger.debug('creating model with endpoints: %s', self.payload) + response = self.client.post(self.url, self.payload) + self.assertEqual(201, response.status_code, response.content[:1000]) + + # print('response:', response.content[:1000]) + check_for_id = response.data['id'] + # print('id: ', check_for_id) + check_for_tags = self.payload.get('tags', None) + + response = self.client.get(self.url, format='json') + # print('response') + # print(vars(response)) + + # print('response.data') + # print(response.data) + # tags must be present in last entry, the one we created + if check_for_tags: + tags_found = False + for result in response.data['results']: + if result['id'] == check_for_id: + # logger.debug('result.tags: %s', result.get('tags', '')) + self.assertEqual(len(check_for_tags), len(result.get('tags', None))) + for tag in check_for_tags: + # logger.debug('looking for tag %s in tag list %s', tag, result['tags']) + self.assertIn(tag, result['tags']) + tags_found = True + self.assertTrue(tags_found) + + self.assertEqual(200, response.status_code, response.content[:1000]) + + self.check_schema_response('get', '200', response) + @skipIfNotSubclass(PrefetchListMixin) def test_list_prefetch(self): prefetchable_fields = [x[0] for x in _get_prefetchable_fields(self.viewset.serializer_class)] @@ -600,24 +520,6 @@ def test_list_prefetch(self): # TODO add schema check - def setUp_not_authorized(self): - testuser = User.objects.get(id=3) - token = Token.objects.get(user=testuser) - self.client = APIClient() - self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) - - def setUp_global_reader(self): - testuser = User.objects.get(id=5) - token = Token.objects.get(user=testuser) - self.client = APIClient() - self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) - - def setUp_global_owner(self): - testuser = User.objects.get(id=6) - token = Token.objects.get(user=testuser) - self.client = APIClient() - self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key) - @skipIfNotSubclass(ListModelMixin) def test_list_object_not_authorized(self): if not self.test_type == TestType.OBJECT_PERMISSIONS: @@ -629,17 +531,34 @@ def test_list_object_not_authorized(self): self.assertFalse(response.data['results']) self.assertEqual(200, response.status_code, response.content[:1000]) - @skipIfNotSubclass(RetrieveModelMixin) - def test_detail_object_not_authorized(self): - if not self.test_type == TestType.OBJECT_PERMISSIONS: - self.skipTest('Authorization is not object based') + @skipIfNotSubclass(ListModelMixin) + def test_list_configuration_not_authorized(self): + if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: + self.skipTest('Authorization is not configuration based') self.setUp_not_authorized() - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' - response = self.client.get(relative_url) - self.assertEqual(404, response.status_code, response.content[:1000]) + response = self.client.get(self.url, format='json') + self.assertEqual(403, response.status_code, response.content[:1000]) + + class CreateRequestTest(RESTEndpointTest): + @skipIfNotSubclass(CreateModelMixin) + def test_create(self): + length = self.endpoint_model.objects.count() + response = self.client.post(self.url, self.payload) + logger.debug('test_create_response:') + logger.debug(response) + logger.debug(response.data) + self.assertEqual(201, response.status_code, response.content[:1000]) + self.assertEqual(self.endpoint_model.objects.count(), length + 1) + + if hasattr(self.endpoint_model, 'tags') and self.payload and self.payload.get('tags', None): + self.assertEqual(len(self.payload.get('tags')), len(response.data.get('tags', None))) + for tag in self.payload.get('tags'): + # logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) + self.assertIn(tag, response.data['tags']) + + self.check_schema_response('post', '201', response) @skipIfNotSubclass(CreateModelMixin) @patch('dojo.api_v2.permissions.user_has_permission') @@ -655,28 +574,54 @@ def test_create_object_not_authorized(self, mock): ANY, self.permission_create) - @skipIfNotSubclass(DestroyModelMixin) - @patch('dojo.api_v2.permissions.user_has_permission') - def test_delete_object_not_authorized(self, mock): - if not self.test_type == TestType.OBJECT_PERMISSIONS: - self.skipTest('Authorization is not object based') + @skipIfNotSubclass(CreateModelMixin) + def test_create_configuration_not_authorized(self): + if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: + self.skipTest('Authorization is not configuration based') - mock.return_value = False + self.setUp_not_authorized() + + response = self.client.post(self.url, self.payload) + self.assertEqual(403, response.status_code, response.content[:1000]) + class UpdateRequestTest(RESTEndpointTest): + @skipIfNotSubclass(UpdateModelMixin) + def test_update(self): current_objects = self.client.get(self.url, format='json').data relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) - self.client.delete(relative_url) + response = self.client.patch(relative_url, self.update_fields) + self.assertEqual(200, response.status_code, response.content[:1000]) - if self.endpoint_model == Endpoint_Status: - permission_object = Endpoint.objects.get(id=current_objects['results'][0]['endpoint']) - elif self.endpoint_model == JIRA_Issue: - permission_object = Finding.objects.get(id=current_objects['results'][0]['finding']) - else: - permission_object = self.permission_check_class.objects.get(id=current_objects['results'][0]['id']) + self.check_schema_response('patch', '200', response, detail=True) - mock.assert_called_with(User.objects.get(username='admin'), - permission_object, - self.permission_delete) + for key, value in self.update_fields.items(): + # some exception as push_to_jira has been implemented strangely in the update methods in the api + if key not in ['push_to_jira', 'ssh', 'password', 'api_key']: + # Convert data to sets to avoid problems with lists + if isinstance(value, list): + value = set(value) + if isinstance(response.data[key], list): + response_data = set(response.data[key]) + else: + response_data = response.data[key] + self.assertEqual(value, response_data) + + self.assertNotIn('push_to_jira', response.data) + self.assertNotIn('ssh', response.data) + self.assertNotIn('password', response.data) + self.assertNotIn('api_key', response.data) + + if hasattr(self.endpoint_model, 'tags') and self.update_fields and self.update_fields.get('tags', None): + self.assertEqual(len(self.update_fields.get('tags')), len(response.data.get('tags', None))) + for tag in self.update_fields.get('tags'): + logger.debug('looking for tag %s in tag list %s', tag, response.data['tags']) + self.assertIn(tag, response.data['tags']) + + response = self.client.put( + relative_url, self.payload) + self.assertEqual(200, response.status_code, response.content[:1000]) + + self.check_schema_response('put', '200', response, detail=True) @skipIfNotSubclass(UpdateModelMixin) @patch('dojo.api_v2.permissions.user_has_permission') @@ -708,52 +653,84 @@ def test_update_object_not_authorized(self, mock): permission_object, self.permission_update) - @skipIfNotSubclass(ListModelMixin) - def test_list_configuration_not_authorized(self): + @skipIfNotSubclass(UpdateModelMixin) + def test_update_configuration_not_authorized(self): if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: self.skipTest('Authorization is not configuration based') self.setUp_not_authorized() - response = self.client.get(self.url, format='json') + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' + + response = self.client.patch(relative_url, self.update_fields) self.assertEqual(403, response.status_code, response.content[:1000]) - @skipIfNotSubclass(RetrieveModelMixin) - def test_detail_configuration_not_authorized(self): - if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: - self.skipTest('Authorization is not configuration based') + response = self.client.put(relative_url, self.payload) + self.assertEqual(403, response.status_code, response.content[:1000]) - self.setUp_not_authorized() + class DeleteRequestTest(RESTEndpointTest): + @skipIfNotSubclass(DestroyModelMixin) + def test_delete(self): + current_objects = self.client.get(self.url, format='json').data + relative_url = self.url + '{}/'.format(current_objects['results'][-1]['id']) + response = self.client.delete(relative_url) + self.assertEqual(204, response.status_code, response.content[:1000]) - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' + @skipIfNotSubclass(DeletePreviewModelMixin) + def test_delete_preview(self): + current_objects = self.client.get(self.url, format='json').data + relative_url = self.url + '{}/delete_preview/'.format(current_objects['results'][0]['id']) response = self.client.get(relative_url) - self.assertEqual(403, response.status_code, response.content[:1000]) + # print('delete_preview response.data') - @skipIfNotSubclass(CreateModelMixin) - def test_create_configuration_not_authorized(self): - if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: - self.skipTest('Authorization is not configuration based') + self.assertEqual(200, response.status_code, response.content[:1000]) - self.setUp_not_authorized() + self.check_schema_response('get', '200', response, detail=True) - response = self.client.post(self.url, self.payload) - self.assertEqual(403, response.status_code, response.content[:1000]) + self.assertNotIn('push_to_jira', response.data) + self.assertNotIn('password', response.data) + self.assertNotIn('ssh', response.data) + self.assertNotIn('api_key', response.data) + + self.assertIsInstance(response.data['results'], list) + self.assertGreater(len(response.data['results']), 0, "Length: {}".format(len(response.data['results']))) + + for obj in response.data['results']: + self.assertIsInstance(obj, dict) + self.assertEqual(len(obj), 3) + self.assertIsInstance(obj['model'], str) + if obj['id']: # It needs to be None or int + self.assertIsInstance(obj['id'], int) + self.assertIsInstance(obj['name'], str) + + self.assertEqual(self.deleted_objects, len(response.data['results']), response.content[:1000]) @skipIfNotSubclass(DestroyModelMixin) - def test_delete_configuration_not_authorized(self): - if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: - self.skipTest('Authorization is not configuration based') + @patch('dojo.api_v2.permissions.user_has_permission') + def test_delete_object_not_authorized(self, mock): + if not self.test_type == TestType.OBJECT_PERMISSIONS: + self.skipTest('Authorization is not object based') - self.setUp_not_authorized() + mock.return_value = False - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' - response = self.client.delete(relative_url) - self.assertEqual(403, response.status_code, response.content[:1000]) + current_objects = self.client.get(self.url, format='json').data + relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) + self.client.delete(relative_url) - @skipIfNotSubclass(UpdateModelMixin) - def test_update_configuration_not_authorized(self): + if self.endpoint_model == Endpoint_Status: + permission_object = Endpoint.objects.get(id=current_objects['results'][0]['endpoint']) + elif self.endpoint_model == JIRA_Issue: + permission_object = Finding.objects.get(id=current_objects['results'][0]['finding']) + else: + permission_object = self.permission_check_class.objects.get(id=current_objects['results'][0]['id']) + + mock.assert_called_with(User.objects.get(username='admin'), + permission_object, + self.permission_delete) + + @skipIfNotSubclass(DestroyModelMixin) + def test_delete_configuration_not_authorized(self): if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: self.skipTest('Authorization is not configuration based') @@ -761,17 +738,19 @@ def test_update_configuration_not_authorized(self): current_objects = self.endpoint_model.objects.all() relative_url = self.url + f'{current_objects[0].id}/' - - response = self.client.patch(relative_url, self.update_fields) - self.assertEqual(403, response.status_code, response.content[:1000]) - - response = self.client.put(relative_url, self.payload) + response = self.client.delete(relative_url) self.assertEqual(403, response.status_code, response.content[:1000]) - class MemberEndpointTest(RESTEndpointTest): - def __init__(self, *args, **kwargs): - BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) + class BaseClassTest( + RetrieveRequestTest, + ListRequestTest, + CreateRequestTest, + UpdateRequestTest, + DeleteRequestTest, + ): + pass + class MemberEndpointTest(BaseClassTest): def test_update(self): current_objects = self.client.get(self.url, format='json').data relative_url = self.url + '{}/'.format(current_objects['results'][0]['id']) @@ -800,10 +779,7 @@ def test_update_object_not_authorized(self, mock): self.permission_check_class.objects.get(id=current_objects['results'][0]['id']), self.permission_update) - class AuthenticatedViewTest(RESTEndpointTest): - def __init__(self, *args, **kwargs): - BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) - + class AuthenticatedViewTest(BaseClassTest): @skipIfNotSubclass(ListModelMixin) def test_list_configuration_not_authorized(self): if not self.test_type == TestType.CONFIGURATION_PERMISSIONS: @@ -827,7 +803,7 @@ def test_detail_configuration_not_authorized(self): self.assertEqual(200, response.status_code, response.content[:1000]) -class AppAnalysisTest(BaseClass.RESTEndpointTest): +class AppAnalysisTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -856,7 +832,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class EndpointStatusTest(BaseClass.RESTEndpointTest): +class EndpointStatusTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -947,7 +923,7 @@ def test_update_put_unsuccessful(self): self.assertIn('This endpoint-finding relation already exists', response.content.decode("utf-8")) -class EndpointTest(BaseClass.RESTEndpointTest): +class EndpointTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -974,7 +950,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class EngagementTest(BaseClass.RESTEndpointTest): +class EngagementTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1005,7 +981,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class RiskAcceptanceTest(BaseClass.RESTEndpointTest): +class RiskAcceptanceTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1149,7 +1125,7 @@ def test_request_response_get(self): self.assertEqual(200, response.status_code) -class FindingsTest(BaseClass.RESTEndpointTest): +class FindingsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1262,7 +1238,7 @@ def test_severity_validation(self): assert result.json()["severity"] == ["Severity must be one of the following: ['Info', 'Low', 'Medium', 'High', 'Critical']"] -class FindingMetadataTest(BaseClass.RESTEndpointTest): +class FindingMetadataTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1324,7 +1300,7 @@ def test_delete(self): assert len(result) == 0, "Metadata not deleted correctly" -class FindingTemplatesTest(BaseClass.RESTEndpointTest): +class FindingTemplatesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1347,7 +1323,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class JiraInstancesTest(BaseClass.RESTEndpointTest): +class JiraInstancesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1377,7 +1353,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class JiraIssuesTest(BaseClass.RESTEndpointTest): +class JiraIssuesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1400,7 +1376,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class JiraProjectTest(BaseClass.RESTEndpointTest): +class JiraProjectTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1427,7 +1403,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class SonarqubeIssueTest(BaseClass.RESTEndpointTest): +class SonarqubeIssueTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1446,7 +1422,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class SonarqubeIssuesTransitionTest(BaseClass.RESTEndpointTest): +class SonarqubeIssuesTransitionTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1465,7 +1441,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class Product_API_Scan_ConfigurationTest(BaseClass.RESTEndpointTest): +class Product_API_Scan_ConfigurationTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1488,7 +1464,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ProductTest(BaseClass.RESTEndpointTest): +class ProductTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1515,7 +1491,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class StubFindingsTest(BaseClass.RESTEndpointTest): +class StubFindingsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1546,7 +1522,7 @@ def test_severity_validation(self): assert result.json()["severity"] == ["Severity must be one of the following: ['Info', 'Low', 'Medium', 'High', 'Critical']"] -class TestsTest(BaseClass.RESTEndpointTest): +class TestsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1580,7 +1556,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ToolConfigurationsTest(BaseClass.RESTEndpointTest): +class ToolConfigurationsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1606,7 +1582,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ToolProductSettingsTest(BaseClass.RESTEndpointTest): +class ToolProductSettingsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1632,7 +1608,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ToolTypesTest(BaseClass.RESTEndpointTest): +class ToolTypesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1650,7 +1626,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class NoteTypesTest(BaseClass.RESTEndpointTest): +class NoteTypesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1671,7 +1647,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class NotesTest(BaseClass.RESTEndpointTest): +class NotesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1690,7 +1666,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class UsersTest(BaseClass.RESTEndpointTest): +class UsersTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1735,7 +1711,7 @@ def test_update_user_other_permissions_will_not_leak_and_stay_untouched(self): self.assertEqual(set(user_permissions), set(payload['configuration_permissions'] + [26, 28])) -class UserContactInfoTest(BaseClass.RESTEndpointTest): +class UserContactInfoTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -1776,7 +1752,7 @@ def test_user_should_not_have_access_to_product_3_in_detail(self): self.assertEqual(response.status_code, 404) -class ImportScanTest(BaseClass.RESTEndpointTest): +class ImportScanTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2408,7 +2384,7 @@ def test_create_not_authorized_product_name_engagement_name_scan_type_title(self reimporter_mock.assert_not_called() -class ProductTypeTest(BaseClass.RESTEndpointTest): +class ProductTypeTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2449,7 +2425,7 @@ def test_create_authorized_owner(self): self.assertEqual(201, response.status_code, response.content[:1000]) -class DojoGroupsTest(BaseClass.RESTEndpointTest): +class DojoGroupsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2539,7 +2515,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class RolesTest(BaseClass.RESTEndpointTest): +class RolesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2551,7 +2527,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class GlobalRolesTest(BaseClass.RESTEndpointTest): +class GlobalRolesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2589,7 +2565,7 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Type_Manage_Members self.permission_delete = Permissions.Product_Type_Member_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) class ProductMemberTest(BaseClass.MemberEndpointTest): @@ -2612,7 +2588,7 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Manage_Members self.permission_delete = Permissions.Product_Member_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) class ProductTypeGroupTest(BaseClass.MemberEndpointTest): @@ -2635,7 +2611,7 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Type_Group_Edit self.permission_delete = Permissions.Product_Type_Group_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) class ProductGroupTest(BaseClass.MemberEndpointTest): @@ -2658,10 +2634,10 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Product_Group_Edit self.permission_delete = Permissions.Product_Group_Delete self.deleted_objects = 1 - BaseClass.MemberEndpointTest.__init__(self, *args, **kwargs) + BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class LanguageTypeTest(BaseClass.RESTEndpointTest): +class LanguageTypeTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2680,7 +2656,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class LanguageTest(BaseClass.RESTEndpointTest): +class LanguageTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2708,7 +2684,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ImportLanguagesTest(BaseClass.RESTEndpointTest): +class ImportLanguagesTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2729,7 +2705,7 @@ def __del__(self: object): self.payload['file'].close() def test_create(self): - BaseClass.RESTEndpointTest.test_create(self) + BaseClass.CreateRequestTest.test_create(self) languages = Languages.objects.filter(product=1).order_by('language') @@ -2750,7 +2726,7 @@ def test_create(self): self.assertEqual(languages[1].code, 51056) -class NotificationsTest(BaseClass.RESTEndpointTest): +class NotificationsTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2838,7 +2814,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ConfigurationPermissionTest(BaseClass.RESTEndpointTest): +class ConfigurationPermissionTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2850,7 +2826,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class CredentialMappingTest(BaseClass.RESTEndpointTest): +class CredentialMappingTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2873,7 +2849,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class CredentialTest(BaseClass.RESTEndpointTest): +class CredentialTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): @@ -2895,7 +2871,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class TextQuestionTest(BaseClass.RESTEndpointTest): +class TextQuestionTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2908,7 +2884,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ChoiceQuestionTest(BaseClass.RESTEndpointTest): +class ChoiceQuestionTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2921,7 +2897,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class TextAnswerTest(BaseClass.RESTEndpointTest): +class TextAnswerTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2934,7 +2910,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class ChoiceAnswerTest(BaseClass.RESTEndpointTest): +class ChoiceAnswerTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2947,7 +2923,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class GeneralSurveyTest(BaseClass.RESTEndpointTest): +class GeneralSurveyTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2960,7 +2936,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class EngagementSurveyTest(BaseClass.RESTEndpointTest): +class EngagementSurveyTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2973,7 +2949,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class AnsweredSurveyTest(BaseClass.RESTEndpointTest): +class AnsweredSurveyTest(BaseClass.BaseClassTest): fixtures = ['questionnaire_testdata.json'] def __init__(self, *args, **kwargs): @@ -2986,7 +2962,7 @@ def __init__(self, *args, **kwargs): BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) -class AnnouncementTest(BaseClass.RESTEndpointTest): +class AnnouncementTest(BaseClass.BaseClassTest): fixtures = ['dojo_testdata.json'] def __init__(self, *args, **kwargs): From 9187573188abccdc4fa5742cf716b42b800e911d Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 11 Jun 2024 15:23:16 -0500 Subject: [PATCH 2/3] Add explicit ID to be deleted --- unittests/test_rest_framework.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index 8c01dc56fcc..92122add4ab 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -672,15 +672,22 @@ def test_update_configuration_not_authorized(self): class DeleteRequestTest(RESTEndpointTest): @skipIfNotSubclass(DestroyModelMixin) def test_delete(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/'.format(current_objects['results'][-1]['id']) + if delete_id := getattr(self, "delete_id", ""): + relative_url = f"{self.url}{delete_id}/" + else: + current_objects = self.client.get(self.url, format='json').data + relative_url = f"{self.url}{current_objects['results'][0]['id']}/" response = self.client.delete(relative_url) self.assertEqual(204, response.status_code, response.content[:1000]) @skipIfNotSubclass(DeletePreviewModelMixin) def test_delete_preview(self): - current_objects = self.client.get(self.url, format='json').data - relative_url = self.url + '{}/delete_preview/'.format(current_objects['results'][0]['id']) + if delete_id := getattr(self, "delete_id", ""): + relative_url = f"{self.url}{delete_id}/delete_preview/" + else: + current_objects = self.client.get(self.url, format='json').data + relative_url = f"{self.url}{current_objects['results'][0]['id']}/delete_preview/" + response = self.client.get(relative_url) # print('delete_preview response.data') @@ -704,7 +711,7 @@ def test_delete_preview(self): self.assertIsInstance(obj['id'], int) self.assertIsInstance(obj['name'], str) - self.assertEqual(self.deleted_objects, len(response.data['results']), response.content[:1000]) + self.assertEqual(self.deleted_objects, len(response.data['results']), response.content) @skipIfNotSubclass(DestroyModelMixin) @patch('dojo.api_v2.permissions.user_has_permission') @@ -736,8 +743,11 @@ def test_delete_configuration_not_authorized(self): self.setUp_not_authorized() - current_objects = self.endpoint_model.objects.all() - relative_url = self.url + f'{current_objects[0].id}/' + if delete_id := getattr(self, "delete_id", ""): + relative_url = self.url + f'{delete_id}/' + else: + current_objects = self.endpoint_model.objects.all() + relative_url = self.url + f'{current_objects[0].id}/' response = self.client.delete(relative_url) self.assertEqual(403, response.status_code, response.content[:1000]) @@ -1553,6 +1563,7 @@ def __init__(self, *args, **kwargs): self.permission_update = Permissions.Test_Edit self.permission_delete = Permissions.Test_Delete self.deleted_objects = 5 + self.delete_id = 55 BaseClass.RESTEndpointTest.__init__(self, *args, **kwargs) From 02fc9fd4be2aefa1d5f54eb6ae896e0e99a89764 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:09:57 -0500 Subject: [PATCH 3/3] Typing issue --- unittests/test_rest_framework.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unittests/test_rest_framework.py b/unittests/test_rest_framework.py index 92122add4ab..ce1ad77da16 100644 --- a/unittests/test_rest_framework.py +++ b/unittests/test_rest_framework.py @@ -672,17 +672,17 @@ def test_update_configuration_not_authorized(self): class DeleteRequestTest(RESTEndpointTest): @skipIfNotSubclass(DestroyModelMixin) def test_delete(self): - if delete_id := getattr(self, "delete_id", ""): + if delete_id := getattr(self, "delete_id", None): relative_url = f"{self.url}{delete_id}/" else: current_objects = self.client.get(self.url, format='json').data - relative_url = f"{self.url}{current_objects['results'][0]['id']}/" + relative_url = f"{self.url}{current_objects['results'][-1]['id']}/" response = self.client.delete(relative_url) self.assertEqual(204, response.status_code, response.content[:1000]) @skipIfNotSubclass(DeletePreviewModelMixin) def test_delete_preview(self): - if delete_id := getattr(self, "delete_id", ""): + if delete_id := getattr(self, "delete_id", None): relative_url = f"{self.url}{delete_id}/delete_preview/" else: current_objects = self.client.get(self.url, format='json').data @@ -743,7 +743,7 @@ def test_delete_configuration_not_authorized(self): self.setUp_not_authorized() - if delete_id := getattr(self, "delete_id", ""): + if delete_id := getattr(self, "delete_id", None): relative_url = self.url + f'{delete_id}/' else: current_objects = self.endpoint_model.objects.all()