Improve unit test coverage for dcmanager's APIs (subcloud_group)
Improves unit test coverage for dcmanager's subcloud_group API from 77% to 98%. Test plan: All of the tests were created taking into account the output of 'tox -c tox.ini -e cover' command Story: 2007082 Task: 49641 Change-Id: I4f8a87379c770409590ed84b0d2cd50c06110199 Signed-off-by: rlima <Raphael.Lima@windriver.com>
This commit is contained in:
parent
a7f0e617e0
commit
2fe10ca74d
|
@ -1,5 +1,5 @@
|
|||
# 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.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
|
@ -15,22 +15,21 @@
|
|||
# under the License.
|
||||
#
|
||||
|
||||
import mock
|
||||
from six.moves import http_client
|
||||
import http.client
|
||||
|
||||
import mock
|
||||
from oslo_messaging import RemoteError
|
||||
|
||||
from dcmanager.api.controllers.v1 import subcloud_group
|
||||
from dcmanager.common import consts
|
||||
from dcmanager.db.sqlalchemy import api as db_api
|
||||
from dcmanager.rpc import client as rpc_client
|
||||
|
||||
from dcmanager.tests.unit.api import test_root_controller as testroot
|
||||
from dcmanager.tests.unit.api.test_root_controller import DCManagerApiTest
|
||||
from dcmanager.tests.unit.api.v1.controllers.mixins import APIMixin
|
||||
from dcmanager.tests.unit.api.v1.controllers.mixins import DeleteMixin
|
||||
from dcmanager.tests.unit.api.v1.controllers.mixins import GetMixin
|
||||
from dcmanager.tests.unit.api.v1.controllers.mixins import PostJSONMixin
|
||||
from dcmanager.tests.unit.api.v1.controllers.mixins import UpdateMixin
|
||||
from dcmanager.tests.unit.api.v1.controllers.test_subclouds \
|
||||
import FAKE_SUBCLOUD_DATA
|
||||
from dcmanager.tests import utils
|
||||
from dcmanager.tests.unit.common import fake_subcloud
|
||||
|
||||
SAMPLE_SUBCLOUD_GROUP_NAME = 'GroupX'
|
||||
SAMPLE_SUBCLOUD_GROUP_DESCRIPTION = 'A Group of mystery'
|
||||
|
@ -39,42 +38,31 @@ SAMPLE_SUBCLOUD_GROUP_MAX_PARALLEL_SUBCLOUDS = 3
|
|||
|
||||
|
||||
class SubcloudGroupAPIMixin(APIMixin):
|
||||
|
||||
API_PREFIX = '/v1.0/subcloud-groups'
|
||||
RESULT_KEY = 'subcloud_groups'
|
||||
EXPECTED_FIELDS = ['id',
|
||||
'name',
|
||||
'description',
|
||||
'max_parallel_subclouds',
|
||||
'update_apply_type',
|
||||
'created-at',
|
||||
'updated-at']
|
||||
EXPECTED_FIELDS = [
|
||||
'id', 'name', 'description', 'max_parallel_subclouds', 'update_apply_type',
|
||||
'created-at', 'updated-at'
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(SubcloudGroupAPIMixin, self).setUp()
|
||||
self.fake_rpc_client.some_method = mock.MagicMock()
|
||||
super().setUp()
|
||||
|
||||
def _get_test_subcloud_group_dict(self, **kw):
|
||||
# id should not be part of the structure
|
||||
group = {
|
||||
return {
|
||||
'name': kw.get('name', SAMPLE_SUBCLOUD_GROUP_NAME),
|
||||
'description': kw.get('description',
|
||||
SAMPLE_SUBCLOUD_GROUP_DESCRIPTION),
|
||||
'description': kw.get('description', SAMPLE_SUBCLOUD_GROUP_DESCRIPTION),
|
||||
'update_apply_type': kw.get(
|
||||
'update_apply_type',
|
||||
SAMPLE_SUBCLOUD_GROUP_UPDATE_APPLY_TYPE),
|
||||
'update_apply_type', SAMPLE_SUBCLOUD_GROUP_UPDATE_APPLY_TYPE
|
||||
),
|
||||
'max_parallel_subclouds': kw.get(
|
||||
'max_parallel_subclouds',
|
||||
SAMPLE_SUBCLOUD_GROUP_MAX_PARALLEL_SUBCLOUDS)
|
||||
SAMPLE_SUBCLOUD_GROUP_MAX_PARALLEL_SUBCLOUDS
|
||||
)
|
||||
}
|
||||
return group
|
||||
|
||||
def _post_get_test_subcloud_group(self, **kw):
|
||||
post_body = self._get_test_subcloud_group_dict(**kw)
|
||||
return post_body
|
||||
|
||||
# The following methods are required for subclasses of APIMixin
|
||||
|
||||
def get_api_prefix(self):
|
||||
return self.API_PREFIX
|
||||
|
||||
|
@ -92,227 +80,484 @@ class SubcloudGroupAPIMixin(APIMixin):
|
|||
return db_api.subcloud_group_create(context, **creation_fields)
|
||||
|
||||
def get_post_object(self):
|
||||
return self._post_get_test_subcloud_group()
|
||||
return self._get_test_subcloud_group_dict()
|
||||
|
||||
def get_update_object(self):
|
||||
update_object = {
|
||||
'description': 'Updated description'
|
||||
}
|
||||
return update_object
|
||||
return {"description": "Updated description"}
|
||||
|
||||
|
||||
# Combine Subcloud Group API with mixins to test post, get, update and delete
|
||||
class TestSubcloudGroupPost(testroot.DCManagerApiTest,
|
||||
SubcloudGroupAPIMixin,
|
||||
PostJSONMixin):
|
||||
def setUp(self):
|
||||
super(TestSubcloudGroupPost, self).setUp()
|
||||
|
||||
def verify_post_failure(self, response):
|
||||
# Failures will return text rather than json
|
||||
self.assertEqual(response.content_type, 'text/plain')
|
||||
self.assertEqual(response.status_code, http_client.BAD_REQUEST)
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_create_with_numerical_name_fails(self, mock_client):
|
||||
# A numerical name is not permitted. otherwise the 'get' operations
|
||||
# which support getting by either name or ID could become confused
|
||||
# if a name for one group was the same as an ID for another.
|
||||
ndict = self.get_post_object()
|
||||
ndict['name'] = '123'
|
||||
response = self.app.post_json(self.get_api_prefix(),
|
||||
ndict,
|
||||
headers=self.get_api_headers(),
|
||||
expect_errors=True)
|
||||
self.verify_post_failure(response)
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_create_with_blank_name_fails(self, mock_client):
|
||||
# An empty name is not permitted
|
||||
ndict = self.get_post_object()
|
||||
ndict['name'] = ''
|
||||
response = self.app.post_json(self.get_api_prefix(),
|
||||
ndict,
|
||||
headers=self.get_api_headers(),
|
||||
expect_errors=True)
|
||||
self.verify_post_failure(response)
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_create_with_default_name_fails(self, mock_client):
|
||||
# A name that is the same as the 'Default' group is not permitted.
|
||||
# This would be a duplicate, and names must be unique.
|
||||
ndict = self.get_post_object()
|
||||
ndict['name'] = 'Default'
|
||||
response = self.app.post_json(self.get_api_prefix(),
|
||||
ndict,
|
||||
headers=self.get_api_headers(),
|
||||
expect_errors=True)
|
||||
self.verify_post_failure(response)
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_create_with_empty_description_fails(self, mock_client):
|
||||
# An empty description is considered invalid
|
||||
ndict = self.get_post_object()
|
||||
ndict['description'] = ''
|
||||
response = self.app.post_json(self.get_api_prefix(),
|
||||
ndict,
|
||||
headers=self.get_api_headers(),
|
||||
expect_errors=True)
|
||||
self.verify_post_failure(response)
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_create_with_bad_apply_type(self, mock_client):
|
||||
# update_apply_type must be either 'serial' or 'parallel'
|
||||
ndict = self.get_post_object()
|
||||
ndict['update_apply_type'] = 'something_invalid'
|
||||
response = self.app.post_json(self.get_api_prefix(),
|
||||
ndict,
|
||||
headers=self.get_api_headers(),
|
||||
expect_errors=True)
|
||||
self.verify_post_failure(response)
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_create_with_bad_max_parallel_subclouds(self, mock_client):
|
||||
# max_parallel_subclouds must be an integer between 1 and 500
|
||||
ndict = self.get_post_object()
|
||||
# All the entries in bad_values should be considered invalid
|
||||
bad_values = [0, 501, -1, 'abc']
|
||||
for bad_value in bad_values:
|
||||
ndict['max_parallel_subclouds'] = bad_value
|
||||
response = self.app.post_json(self.get_api_prefix(),
|
||||
ndict,
|
||||
headers=self.get_api_headers(),
|
||||
expect_errors=True)
|
||||
self.verify_post_failure(response)
|
||||
|
||||
|
||||
class TestSubcloudGroupGet(testroot.DCManagerApiTest,
|
||||
SubcloudGroupAPIMixin,
|
||||
GetMixin):
|
||||
class BaseTestSubcloudGroupController(DCManagerApiTest, SubcloudGroupAPIMixin):
|
||||
"""Base class for testing the SubcloudGroupController"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestSubcloudGroupGet, self).setUp()
|
||||
super().setUp()
|
||||
|
||||
self.url = self.API_PREFIX
|
||||
|
||||
self._mock_rpc_client()
|
||||
|
||||
|
||||
class TestSubcloudGroupController(BaseTestSubcloudGroupController):
|
||||
"""Test class for SubcloudGroupController"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
def test_unmapped_method(self):
|
||||
"""Test requesting an unmapped method results in success with null content"""
|
||||
|
||||
self.method = self.app.put
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
self.assertEqual(response.text, "null")
|
||||
|
||||
|
||||
class TestSubcloudGroupPost(BaseTestSubcloudGroupController, PostJSONMixin):
|
||||
"""Test class for post requests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.method = self.app.post_json
|
||||
self.params = self.get_post_object()
|
||||
|
||||
def test_post_fails_without_params(self):
|
||||
"""Test post fails without params"""
|
||||
|
||||
self.params = {}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Body required"
|
||||
)
|
||||
|
||||
def test_post_fails_with_numerical_name(self):
|
||||
"""Test post fails with numerical name
|
||||
|
||||
A numerical name is not permitted, otherwise the 'get' operations
|
||||
which support getting by either name or ID could become confusing
|
||||
if a group's name was the same as the id of another.
|
||||
"""
|
||||
|
||||
self.params["name"] = "999"
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group name"
|
||||
)
|
||||
|
||||
def test_post_fails_with_empty_name(self):
|
||||
"""Test post fails with empty name"""
|
||||
|
||||
self.params["name"] = ""
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group name"
|
||||
)
|
||||
|
||||
def test_post_fails_with_default_name(self):
|
||||
"""Test post fails with default name
|
||||
|
||||
The name 'Default' is not permitted because it would be a duplicate, but it
|
||||
should be unique
|
||||
"""
|
||||
|
||||
self.params["name"] = consts.DEFAULT_SUBCLOUD_GROUP_NAME
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group name"
|
||||
|
||||
)
|
||||
|
||||
def test_post_fails_with_invalid_description(self):
|
||||
"""Test post fails with invalid description"""
|
||||
|
||||
invalid_values = [
|
||||
"", "a" * (subcloud_group.MAX_SUBCLOUD_GROUP_DESCRIPTION_LEN + 1)
|
||||
]
|
||||
|
||||
for index, invalid_value in enumerate(invalid_values, start=1):
|
||||
self.params["description"] = invalid_value
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group description",
|
||||
call_count=index
|
||||
)
|
||||
|
||||
def test_post_fails_with_invalid_update_apply_type(self):
|
||||
"""Test post fails with invalid update apply type
|
||||
|
||||
The update apply type should be either serial or parallel
|
||||
"""
|
||||
|
||||
self.params["update_apply_type"] = "fake"
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group update_apply_type"
|
||||
)
|
||||
|
||||
def test_post_fails_without_update_apply_type(self):
|
||||
"""Test post fails without update apply type"""
|
||||
|
||||
del self.params["update_apply_type"]
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group update_apply_type"
|
||||
)
|
||||
|
||||
def test_post_fails_with_invalid_max_parallel_subclouds(self):
|
||||
"""Test post fails with invalid max parallel subclouds
|
||||
|
||||
The acceptable range is between 1 and 500
|
||||
"""
|
||||
|
||||
invalid_values = [0, 501, -1, "fake"]
|
||||
|
||||
for index, invalid_value in enumerate(invalid_values, start=1):
|
||||
self.params["max_parallel_subclouds"] = invalid_value
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
"Invalid group max_parallel_subclouds", call_count=index
|
||||
)
|
||||
|
||||
def test_post_fails_with_db_api_duplicate_entry(self):
|
||||
"""Test post fails with db api duplicate entry"""
|
||||
|
||||
self._create_db_object(self.ctx)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
"A subcloud group with this name already exists"
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, "subcloud_group_create")
|
||||
def test_post_fails_with_db_api_remote_error(self, mock_db_api):
|
||||
"""Test post fails with db api remote error"""
|
||||
|
||||
mock_db_api.side_effect = RemoteError("msg", "value")
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.UNPROCESSABLE_ENTITY, "value"
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, "subcloud_group_create")
|
||||
def test_post_fails_with_db_api_generic_exception(self, mock_db_api):
|
||||
"""Test post fails with db api generic exception"""
|
||||
|
||||
mock_db_api.side_effect = Exception()
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.INTERNAL_SERVER_ERROR,
|
||||
"Unable to create subcloud group"
|
||||
)
|
||||
|
||||
|
||||
class BaseTestSubcloudGroupGet(BaseTestSubcloudGroupController):
|
||||
"""Base test class for get requests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.subcloud_group = db_api.subcloud_group_get(self.ctx, 1)
|
||||
|
||||
self.url = f"{self.url}/{self.subcloud_group.id}"
|
||||
self.method = self.app.get
|
||||
|
||||
|
||||
class TestSubcloudGroupGet(BaseTestSubcloudGroupGet, GetMixin):
|
||||
"""Test class for get requests"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# Override initial_list_size. Default group is setup during db sync
|
||||
self.initial_list_size = 1
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_get_single_by_name(self, mock_client):
|
||||
# create a group
|
||||
context = utils.dummy_context()
|
||||
# todo(abailey) make this a generic method
|
||||
group_name = 'TestGroup'
|
||||
self._create_db_object(context, name=group_name)
|
||||
def test_get_succeeds_with_id(self):
|
||||
"""Test get succeeds with id"""
|
||||
|
||||
# Test that a GET operation for a valid ID works
|
||||
response = self.app.get(self.get_single_url(group_name),
|
||||
headers=self.get_api_headers())
|
||||
self.assertEqual(response.content_type, 'application/json')
|
||||
self.assertEqual(response.status_code, http_client.OK)
|
||||
self.validate_entry(response.json)
|
||||
response = self._send_request()
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_list_subclouds_empty(self, mock_client):
|
||||
# API GET on: subcloud-groups/<uuid>/subclouds
|
||||
uuid = 1 # The Default Subcloud Group is always ID=1
|
||||
url = '%s/%s/subclouds' % (self.get_api_prefix(), uuid)
|
||||
response = self.app.get(url,
|
||||
headers=self.get_api_headers())
|
||||
self._assert_response(response)
|
||||
|
||||
def test_get_succeeds_with_name(self):
|
||||
"""Test get succeeds with name"""
|
||||
|
||||
self.url = f"{self.API_PREFIX}/{self.subcloud_group.name}"
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
|
||||
|
||||
class TestSubcloudGroupGetSubclouds(BaseTestSubcloudGroupGet):
|
||||
"""Test class for get requests with subclouds verb"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.url = f"{self.url}/subclouds"
|
||||
|
||||
def test_get_subclouds_succeeds(self):
|
||||
"""Test get subclouds succeeds
|
||||
|
||||
The list size is 0 because there isn't a subcloud associated to the group
|
||||
"""
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
# This API returns 'subclouds' rather than 'subcloud-groups'
|
||||
self.assertIn('subclouds', response.json)
|
||||
# no subclouds exist yet, so this length should be zero
|
||||
result_list = response.json.get('subclouds')
|
||||
self.assertEqual(0, len(result_list))
|
||||
self.assertEqual(0, len(response.json.get('subclouds')))
|
||||
|
||||
def _create_subcloud_db_object(self, context):
|
||||
creation_fields = {
|
||||
'name': FAKE_SUBCLOUD_DATA.get('name'),
|
||||
'description': FAKE_SUBCLOUD_DATA.get('description'),
|
||||
'location': FAKE_SUBCLOUD_DATA.get('location'),
|
||||
'software_version': FAKE_SUBCLOUD_DATA.get('software_version'),
|
||||
'management_subnet': FAKE_SUBCLOUD_DATA.get('management_subnet'),
|
||||
'management_gateway_ip':
|
||||
FAKE_SUBCLOUD_DATA.get('management_gateway_ip'),
|
||||
'management_start_ip':
|
||||
FAKE_SUBCLOUD_DATA.get('management_start_ip'),
|
||||
'management_end_ip': FAKE_SUBCLOUD_DATA.get('management_end_ip'),
|
||||
'systemcontroller_gateway_ip':
|
||||
FAKE_SUBCLOUD_DATA.get('systemcontroller_gateway_ip'),
|
||||
'deploy_status': FAKE_SUBCLOUD_DATA.get('deploy_status'),
|
||||
'error_description': FAKE_SUBCLOUD_DATA.get('error_description'),
|
||||
'region_name': FAKE_SUBCLOUD_DATA.get('region_name'),
|
||||
'openstack_installed':
|
||||
FAKE_SUBCLOUD_DATA.get('openstack_installed'),
|
||||
'group_id': FAKE_SUBCLOUD_DATA.get('group_id', 1)
|
||||
}
|
||||
return db_api.subcloud_create(context, **creation_fields)
|
||||
def test_get_subclouds_succeeds_with_subcloud_in_group(self):
|
||||
"""Test get subclouds succeeds with subcloud in group
|
||||
|
||||
When a subcloud is created, it is associated with the Default group
|
||||
"""
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_list_subclouds_populated(self, mock_client):
|
||||
# subclouds are to Default group by default (unless specified)
|
||||
context = utils.dummy_context()
|
||||
self._create_subcloud_db_object(context)
|
||||
fake_subcloud.create_fake_subcloud(self.ctx)
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
# API GET on: subcloud-groups/<uuid>/subclouds
|
||||
uuid = 1 # The Default Subcloud Group is always ID=1
|
||||
url = '%s/%s/subclouds' % (self.get_api_prefix(), uuid)
|
||||
response = self.app.get(url,
|
||||
headers=self.get_api_headers())
|
||||
# This API returns 'subclouds' rather than 'subcloud-groups'
|
||||
self.assertIn('subclouds', response.json)
|
||||
# the subcloud created earlier will have been queried
|
||||
result_list = response.json.get('subclouds')
|
||||
self.assertEqual(1, len(result_list))
|
||||
self.assertEqual(1, len(response.json.get('subclouds')))
|
||||
|
||||
|
||||
class TestSubcloudGroupUpdate(testroot.DCManagerApiTest,
|
||||
SubcloudGroupAPIMixin,
|
||||
UpdateMixin):
|
||||
class TestSubcloudGroupPatch(BaseTestSubcloudGroupController, UpdateMixin):
|
||||
"""Test class for patch requests"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestSubcloudGroupUpdate, self).setUp()
|
||||
super().setUp()
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_update_invalid_apply_type(self, mock_client):
|
||||
context = utils.dummy_context()
|
||||
single_obj = self._create_db_object(context)
|
||||
update_data = {
|
||||
'update_apply_type': 'something_bad'
|
||||
self.subcloud_group = db_api.subcloud_group_get(self.ctx, 1)
|
||||
|
||||
self.method = self.app.patch_json
|
||||
self.url = f"{self.url}/{self.subcloud_group.id}"
|
||||
|
||||
def test_patch_succeeds_with_name_and_max_parallel_subclouds(self):
|
||||
"""Test patch succeeds with name and max parallel subclouds"""
|
||||
|
||||
self.subcloud_group = self._create_db_object(self.ctx)
|
||||
|
||||
self.url = f"{self.API_PREFIX}/{self.subcloud_group.id}"
|
||||
|
||||
self.params = {"name": "new name", "max_parallel_subclouds": 2}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_response(response)
|
||||
|
||||
def test_patch_fails_with_group_not_found(self):
|
||||
"""Test patch fails with group not found"""
|
||||
|
||||
self.url = f"{self.API_PREFIX}/999"
|
||||
self.params = {"update_apply_type": "fake"}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.NOT_FOUND, "Subcloud Group not found"
|
||||
)
|
||||
|
||||
def test_patch_fails_with_invalid_property_to_update(self):
|
||||
"""Test patch fails with invalid property to update"""
|
||||
|
||||
self.params = {"fake": "value"}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "nothing to update"
|
||||
)
|
||||
|
||||
def test_patch_fails_with_invalid_name(self):
|
||||
"""Test patch fails with invalid name"""
|
||||
|
||||
self.params = {"name": consts.DEFAULT_SUBCLOUD_GROUP_NAME}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group name"
|
||||
)
|
||||
|
||||
def test_patch_fails_with_new_name_for_default_group(self):
|
||||
"""Test patch fails with new name for default group"""
|
||||
|
||||
self.params = {"name": "new name"}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Default group name cannot be changed"
|
||||
)
|
||||
|
||||
def test_patch_fails_with_invalid_update_apply_type(self):
|
||||
"""Test patch fails with invalid update apply type"""
|
||||
|
||||
self.params = {"update_apply_type": "fake"}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group update_apply_type"
|
||||
)
|
||||
|
||||
def test_patch_fails_with_invalid_max_parallel_subclouds(self):
|
||||
"""Test patch fails with invalid max parallel subclouds"""
|
||||
|
||||
invalid_values = [0, 501, -1, "fake"]
|
||||
|
||||
for index, invalid_value in enumerate(invalid_values, start=1):
|
||||
self.params = {"max_parallel_subclouds": str(invalid_value)}
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
"Invalid group max_parallel_subclouds", call_count=index
|
||||
)
|
||||
|
||||
def test_patch_fails_with_invalid_description(self):
|
||||
"""Test patch fails with invalid description"""
|
||||
|
||||
self.params = {
|
||||
"description":
|
||||
"a" * (subcloud_group.MAX_SUBCLOUD_GROUP_DESCRIPTION_LEN + 1)
|
||||
}
|
||||
response = self.app.patch_json(self.get_single_url(single_obj.id),
|
||||
headers=self.get_api_headers(),
|
||||
params=update_data,
|
||||
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)
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_update_invalid_max_parallel(self, mock_client):
|
||||
context = utils.dummy_context()
|
||||
single_obj = self._create_db_object(context)
|
||||
update_data = {
|
||||
'max_parallel_subclouds': -1
|
||||
}
|
||||
response = self.app.patch_json(self.get_single_url(single_obj.id),
|
||||
headers=self.get_api_headers(),
|
||||
params=update_data,
|
||||
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)
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST, "Invalid group description",
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, "subcloud_group_update")
|
||||
def test_patch_fails_with_db_api_remote_error(self, mock_db_api):
|
||||
"""Test patch fails with db api remote error"""
|
||||
|
||||
self.params = {"update_apply_type": "serial"}
|
||||
|
||||
mock_db_api.side_effect = RemoteError("msg", "value")
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.UNPROCESSABLE_ENTITY, "value"
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, "subcloud_group_update")
|
||||
def test_patch_fails_with_db_api_generic_exception(self, mock_db_api):
|
||||
"""Test patch fails with db api generic exception"""
|
||||
|
||||
self.params = {"update_apply_type": "serial"}
|
||||
|
||||
mock_db_api.side_effect = Exception()
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.INTERNAL_SERVER_ERROR,
|
||||
"Unable to update subcloud group"
|
||||
)
|
||||
|
||||
|
||||
class TestSubcloudGroupDelete(testroot.DCManagerApiTest,
|
||||
SubcloudGroupAPIMixin,
|
||||
DeleteMixin):
|
||||
class TestSubcloudGroupDelete(BaseTestSubcloudGroupController, DeleteMixin):
|
||||
"""Test class for delete requests"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestSubcloudGroupDelete, self).setUp()
|
||||
super().setUp()
|
||||
|
||||
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||
def test_delete_default_fails(self, mock_client):
|
||||
default_zone_id = 1
|
||||
response = self.app.delete(self.get_single_url(default_zone_id),
|
||||
headers=self.get_api_headers(),
|
||||
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.subcloud_group = db_api.subcloud_group_get(self.ctx, 1)
|
||||
|
||||
self.method = self.app.delete
|
||||
self.url = f"{self.url}/{self.subcloud_group.id}"
|
||||
|
||||
def test_delete_fails_for_default(self):
|
||||
"""Test delete fails for default
|
||||
|
||||
The default subcloud group can't be deleted
|
||||
"""
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.BAD_REQUEST,
|
||||
"Default Subcloud Group may not be deleted"
|
||||
)
|
||||
|
||||
def test_delete_fails_with_subcloud_in_group(self):
|
||||
"""Test delete fails with subcloud in group"""
|
||||
|
||||
subcloud_group = self._create_db_object(self.ctx)
|
||||
fake_subcloud.create_fake_subcloud(
|
||||
self.ctx, group_id=subcloud_group.id
|
||||
)
|
||||
|
||||
self.url = f"{self.API_PREFIX}/{subcloud_group.id}"
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.INTERNAL_SERVER_ERROR,
|
||||
"Unable to delete subcloud group", call_count=2
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, "subcloud_group_destroy")
|
||||
def test_delete_fails_with_db_api_remote_error(self, mock_db_api):
|
||||
"""Test delete fails with db api remote error"""
|
||||
|
||||
self.subcloud_group = self._create_db_object(self.ctx)
|
||||
|
||||
self.url = f"{self.API_PREFIX}/{self.subcloud_group.id}"
|
||||
|
||||
mock_db_api.side_effect = RemoteError("msg", "value")
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.UNPROCESSABLE_ENTITY, "value"
|
||||
)
|
||||
|
||||
@mock.patch.object(db_api, "subcloud_group_destroy")
|
||||
def test_delete_fails_with_db_api_generic_exception(self, mock_db_api):
|
||||
"""Test delete fails with db api generic exception"""
|
||||
|
||||
self.subcloud_group = self._create_db_object(self.ctx)
|
||||
|
||||
self.url = f"{self.API_PREFIX}/{self.subcloud_group.id}"
|
||||
|
||||
mock_db_api.side_effect = Exception()
|
||||
|
||||
response = self._send_request()
|
||||
|
||||
self._assert_pecan_and_response(
|
||||
response, http.client.INTERNAL_SERVER_ERROR,
|
||||
"Unable to delete subcloud group"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue