Update mixins to use the base structure for API tests
Update dcmanager's mixins to use the base structure for API tests and validate errors through pecan's abort method. Test plan: All of the tests were created taking into account the output of 'tox -c tox.ini -e cover' command Story: 2007082 Task: 49374 Change-Id: I28fb72a6767d80cdc04092d69afb572708039d8a Signed-off-by: rlima <Raphael.Lima@windriver.com>
This commit is contained in:
parent
df271c0371
commit
30562d0a32
|
@ -1,5 +1,5 @@
|
||||||
# Copyright (c) 2017 Ericsson AB
|
# Copyright (c) 2017 Ericsson AB
|
||||||
# Copyright (c) 2020-2022 Wind River Systems, Inc.
|
# Copyright (c) 2020-2022, 2024 Wind River Systems, Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
@ -15,12 +15,13 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import http.client
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import mock
|
import mock
|
||||||
from six.moves import http_client
|
import pecan
|
||||||
|
|
||||||
from dcmanager.rpc import client as rpc_client
|
from dcmanager.rpc import client as rpc_client
|
||||||
|
|
||||||
from dcmanager.tests import utils
|
from dcmanager.tests import utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,12 +106,12 @@ class PostMixin(object):
|
||||||
'ManagerClient'))
|
'ManagerClient'))
|
||||||
params = self.get_post_params()
|
params = self.get_post_params()
|
||||||
upload_files = self.get_post_upload_files()
|
upload_files = self.get_post_upload_files()
|
||||||
response = self.app.post(self.get_api_prefix(),
|
response = self.app.post(
|
||||||
params=params,
|
self.get_api_prefix(), params=params,
|
||||||
upload_files=upload_files,
|
upload_files=upload_files, headers=self.get_api_headers()
|
||||||
headers=self.get_api_headers())
|
)
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
self.assertEqual(response.status_code, http.client.OK)
|
||||||
self.assert_fields(response.json)
|
self.assert_fields(response.json)
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,29 +119,30 @@ class PostRejectedMixin(object):
|
||||||
# Test that a POST operation is blocked by the API
|
# Test that a POST operation is blocked by the API
|
||||||
# API should return 400 BAD_REQUEST or FORBIDDEN 403
|
# API should return 400 BAD_REQUEST or FORBIDDEN 403
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_create_not_allowed(self, mock_client):
|
@mock.patch.object(pecan, 'abort', wraps=pecan.abort)
|
||||||
params = self.get_post_params()
|
def test_create_not_allowed(self, mock_pecan_abort, _):
|
||||||
upload_files = self.get_post_upload_files()
|
response = self.app.post(
|
||||||
response = self.app.post(self.API_PREFIX,
|
self.API_PREFIX, params=self.get_post_params(),
|
||||||
params=params,
|
upload_files=self.get_post_upload_files(),
|
||||||
upload_files=upload_files,
|
headers=self.get_api_headers(), expect_errors=True
|
||||||
headers=self.get_api_headers(),
|
)
|
||||||
expect_errors=True)
|
|
||||||
self.assertEqual(response.status_code, http_client.FORBIDDEN)
|
self.assertEqual(response.status_code, http.client.FORBIDDEN)
|
||||||
self.assertTrue(response.json['error_message'])
|
mock_pecan_abort.assert_called_once()
|
||||||
self.assertIn("Operation not permitted.",
|
mock_pecan_abort.assert_called_with(
|
||||||
response.json['error_message'])
|
http.client.FORBIDDEN, 'Operation not permitted.'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PostJSONMixin(object):
|
class PostJSONMixin(object):
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_create_success(self, mock_client):
|
def test_create_success(self, _):
|
||||||
# Test that a POST (post_json) operation is supported by the API
|
# Test that a POST (post_json) operation is supported by the API
|
||||||
ndict = self.get_post_object()
|
ndict = self.get_post_object()
|
||||||
response = self.app.post_json(self.get_api_prefix(),
|
response = self.app.post_json(
|
||||||
ndict,
|
self.get_api_prefix(), ndict, headers=self.get_api_headers()
|
||||||
headers=self.get_api_headers())
|
)
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,16 +150,18 @@ class PostJSONRejectedMixin(object):
|
||||||
# Test that a POST (post_json) operation is blocked by the API
|
# Test that a POST (post_json) operation is blocked by the API
|
||||||
# API should return 400 BAD_REQUEST or FORBIDDEN 403
|
# API should return 400 BAD_REQUEST or FORBIDDEN 403
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_create_not_allowed(self, mock_client):
|
@mock.patch.object(pecan, 'abort', wraps=pecan.abort)
|
||||||
ndict = self.get_post_object()
|
def test_create_not_allowed(self, mock_pecan_abort, _):
|
||||||
response = self.app.post_json(self.API_PREFIX,
|
response = self.app.post_json(
|
||||||
ndict,
|
self.API_PREFIX, self.get_post_object(), headers=self.get_api_headers(),
|
||||||
headers=self.get_api_headers(),
|
expect_errors=True
|
||||||
expect_errors=True)
|
)
|
||||||
self.assertEqual(response.status_code, http_client.FORBIDDEN)
|
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertEqual(response.status_code, http.client.FORBIDDEN)
|
||||||
self.assertIn("Operation not permitted.",
|
mock_pecan_abort.assert_called_once()
|
||||||
response.json['error_message'])
|
mock_pecan_abort.assert_called_with(
|
||||||
|
http.client.FORBIDDEN, 'Operation not permitted.'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ------ API GET mixin
|
# ------ API GET mixin
|
||||||
|
@ -182,16 +186,17 @@ class GetMixin(object):
|
||||||
|
|
||||||
def validate_list_response(self, expected_length, response):
|
def validate_list_response(self, expected_length, response):
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
self.assertEqual(response.status_code, http.client.OK)
|
||||||
|
|
||||||
# validate the list length
|
# validate the list length
|
||||||
self.validate_list(expected_length, response.json)
|
self.validate_list(expected_length, response.json)
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_initial_list_size(self, mock_client):
|
def test_initial_list_size(self, _):
|
||||||
# Test that a GET operation for a list is supported by the API
|
# Test that a GET operation for a list is supported by the API
|
||||||
response = self.app.get(self.get_api_prefix(),
|
response = self.app.get(
|
||||||
headers=self.get_api_headers())
|
self.get_api_prefix(), headers=self.get_api_headers()
|
||||||
|
)
|
||||||
# Validate the initial length
|
# Validate the initial length
|
||||||
self.validate_list_response(self.initial_list_size, response)
|
self.validate_list_response(self.initial_list_size, response)
|
||||||
|
|
||||||
|
@ -199,31 +204,36 @@ class GetMixin(object):
|
||||||
context = utils.dummy_context()
|
context = utils.dummy_context()
|
||||||
self._create_db_object(context)
|
self._create_db_object(context)
|
||||||
|
|
||||||
response = self.app.get(self.get_api_prefix(),
|
response = self.app.get(
|
||||||
headers=self.get_api_headers())
|
self.get_api_prefix(), headers=self.get_api_headers()
|
||||||
|
)
|
||||||
self.validate_list_response(self.initial_list_size + 1, response)
|
self.validate_list_response(self.initial_list_size + 1, response)
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_fail_get_single(self, mock_client):
|
@mock.patch.object(pecan, 'abort', wraps=pecan.abort)
|
||||||
|
def test_fail_get_single(self, mock_pecan_abort, _):
|
||||||
# Test that a GET operation for an invalid ID returns the
|
# Test that a GET operation for an invalid ID returns the
|
||||||
# appropriate error results
|
# appropriate error results
|
||||||
response = self.app.get(self.get_single_url(self.invalid_id),
|
response = self.app.get(
|
||||||
headers=self.get_api_headers(),
|
self.get_single_url(self.invalid_id), headers=self.get_api_headers(),
|
||||||
expect_errors=True)
|
expect_errors=True
|
||||||
# Failures will return text rather than json
|
)
|
||||||
self.assertEqual(response.content_type, 'text/plain')
|
|
||||||
self.assertEqual(response.status_code, http_client.NOT_FOUND)
|
self.assertEqual(response.status_code, http.client.NOT_FOUND)
|
||||||
|
mock_pecan_abort.assert_called_once()
|
||||||
|
mock_pecan_abort.assert_called_with(http.client.NOT_FOUND, mock.ANY)
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_get_single(self, mock_client):
|
def test_get_single(self, _):
|
||||||
context = utils.dummy_context()
|
context = utils.dummy_context()
|
||||||
db_obj = self._create_db_object(context)
|
db_obj = self._create_db_object(context)
|
||||||
|
|
||||||
# Test that a GET operation for a valid ID works
|
# Test that a GET operation for a valid ID works
|
||||||
response = self.app.get(self.get_single_url(db_obj.id),
|
response = self.app.get(
|
||||||
headers=self.get_api_headers())
|
self.get_single_url(db_obj.id), headers=self.get_api_headers()
|
||||||
|
)
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
self.assertEqual(response.status_code, http.client.OK)
|
||||||
self.validate_entry(response.json)
|
self.validate_entry(response.json)
|
||||||
|
|
||||||
|
|
||||||
|
@ -235,54 +245,64 @@ class UpdateMixin(object):
|
||||||
self.assertEqual(value, full_obj.get(key))
|
self.assertEqual(value, full_obj.get(key))
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_update_success(self, mock_client):
|
def test_update_success(self, _):
|
||||||
context = utils.dummy_context()
|
context = utils.dummy_context()
|
||||||
single_obj = self._create_db_object(context)
|
single_obj = self._create_db_object(context)
|
||||||
update_data = self.get_update_object()
|
update_data = self.get_update_object()
|
||||||
response = self.app.patch_json(self.get_single_url(single_obj.id),
|
|
||||||
headers=self.get_api_headers(),
|
response = self.app.patch_json(
|
||||||
params=update_data)
|
self.get_single_url(single_obj.id), headers=self.get_api_headers(),
|
||||||
|
params=update_data
|
||||||
|
)
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
self.assertEqual(response.status_code, http.client.OK)
|
||||||
self.validate_updated_fields(update_data, response.json)
|
self.validate_updated_fields(update_data, response.json)
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_update_empty_changeset(self, mock_client):
|
@mock.patch.object(pecan, 'abort', wraps=pecan.abort)
|
||||||
|
def test_update_empty_changeset(self, mock_pecan_abort, _):
|
||||||
context = utils.dummy_context()
|
context = utils.dummy_context()
|
||||||
single_obj = self._create_db_object(context)
|
single_obj = self._create_db_object(context)
|
||||||
update_data = {}
|
|
||||||
response = self.app.patch_json(self.get_single_url(single_obj.id),
|
response = self.app.patch_json(
|
||||||
headers=self.get_api_headers(),
|
self.get_single_url(single_obj.id), headers=self.get_api_headers(),
|
||||||
params=update_data,
|
params={}, expect_errors=True
|
||||||
expect_errors=True)
|
)
|
||||||
# Failures will return text rather than json
|
|
||||||
self.assertEqual(response.content_type, 'text/plain')
|
self.assertEqual(response.status_code, http.client.BAD_REQUEST)
|
||||||
self.assertEqual(response.status_code, http_client.BAD_REQUEST)
|
mock_pecan_abort.assert_called_once()
|
||||||
|
mock_pecan_abort.assert_called_with(http.client.BAD_REQUEST, 'Body required')
|
||||||
|
|
||||||
|
|
||||||
# ------ API Delete Mixin
|
# ------ API Delete Mixin
|
||||||
class DeleteMixin(object):
|
class DeleteMixin(object):
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_delete_success(self, mock_client):
|
def test_delete_success(self, _):
|
||||||
context = utils.dummy_context()
|
context = utils.dummy_context()
|
||||||
single_obj = self._create_db_object(context)
|
single_obj = self._create_db_object(context)
|
||||||
response = self.app.delete(self.get_single_url(single_obj.id),
|
response = self.app.delete(self.get_single_url(single_obj.id),
|
||||||
headers=self.get_api_headers())
|
headers=self.get_api_headers())
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.assertEqual(response.content_type, 'application/json')
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
self.assertEqual(response.status_code, http.client.OK)
|
||||||
|
|
||||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
def test_double_delete(self, mock_client):
|
@mock.patch.object(pecan, 'abort', wraps=pecan.abort)
|
||||||
|
def test_double_delete(self, mock_pecan_abort, _):
|
||||||
context = utils.dummy_context()
|
context = utils.dummy_context()
|
||||||
single_obj = self._create_db_object(context)
|
single_obj = self._create_db_object(context)
|
||||||
response = self.app.delete(self.get_single_url(single_obj.id),
|
|
||||||
headers=self.get_api_headers())
|
response = self.app.delete(
|
||||||
self.assertEqual(response.content_type, 'application/json')
|
self.get_single_url(single_obj.id), headers=self.get_api_headers()
|
||||||
self.assertEqual(response.status_code, http_client.OK)
|
)
|
||||||
|
self.assertEqual(response.status_code, http.client.OK)
|
||||||
|
|
||||||
# delete the same object a second time. this should fail (NOT_FOUND)
|
# delete the same object a second time. this should fail (NOT_FOUND)
|
||||||
response = self.app.delete(self.get_single_url(single_obj.id),
|
response = self.app.delete(
|
||||||
headers=self.get_api_headers(),
|
self.get_single_url(single_obj.id), headers=self.get_api_headers(),
|
||||||
expect_errors=True)
|
expect_errors=True
|
||||||
self.assertEqual(response.content_type, 'text/plain')
|
)
|
||||||
self.assertEqual(response.status_code, http_client.NOT_FOUND)
|
self.assertEqual(response.status_code, http.client.NOT_FOUND)
|
||||||
|
|
||||||
|
mock_pecan_abort.assert_called_once()
|
||||||
|
mock_pecan_abort.assert_called_with(http.client.NOT_FOUND, mock.ANY)
|
||||||
|
|
Loading…
Reference in New Issue