Merge "Implement purge list for tempest cleanup"

This commit is contained in:
Zuul 2024-05-21 06:13:54 +00:00 committed by Gerrit Code Review
commit e838ec9fa8
11 changed files with 890 additions and 26 deletions

View File

@ -0,0 +1,11 @@
---
features:
- |
A new interface ``--resource-list`` has been introduced in the
``tempest cleanup`` command to remove the resources created by
Tempest. A new config option in the default section, ``record_resources``,
is added to allow the recording of all resources created by Tempest.
A list of these resources will be saved in ``resource_list.json`` file,
which will be appended in case of multiple Tempest runs. This file
is intended to be used with the ``tempest cleanup`` command if it is
used with the newly added option ``--resource-list``.

View File

@ -13,8 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
from oslo_concurrency import lockutils
from tempest import config
from tempest.lib import auth
from tempest.lib.common.rest_client import RestClient
from tempest.lib import exceptions as lib_exc
from tempest.lib.services import clients
@ -35,6 +40,11 @@ class Manager(clients.ServiceClients):
super(Manager, self).__init__(
credentials=credentials, identity_uri=identity_uri, scope=scope,
region=CONF.identity.region)
if CONF.record_resources:
RestClient.lock_dir = os.path.join(
lockutils.get_lock_path(CONF),
'tempest-rec-rw-lock')
RestClient.record_resources = True
# TODO(andreaf) When clients are initialised without the right
# parameters available, the calls below will trigger a KeyError.
# We should catch that and raise a better error.

View File

@ -87,6 +87,23 @@ Runtime Arguments
``saved_state.json`` file will be ignored and cleanup will be done based on
the passed prefix only.
* ``--resource-list``: Allows the use of file ``./resource_list.json``, which
contains all resources created by Tempest during all Tempest runs, to
create another method for removing only resources created by Tempest.
List of these resources is created when config option ``record_resources``
in default section is set to true. After using this option for cleanup,
the existing ``./resource_list.json`` is cleared from deleted resources.
When this option is used, ``saved_state.json`` file is not needed (no
need to run with ``--init-saved-state`` first). If there is any
``saved_state.json`` file present and you run the tempest cleanup with
``--resource-list``, the ``saved_state.json`` file will be ignored and
cleanup will be done based on the ``resource_list.json`` only.
If you run tempest cleanup with both ``--prefix`` and ``--resource-list``,
the ``--resource-list`` option will be ignored and cleanup will be done
based on the ``--prefix`` option only.
* ``--help``: Print the help text for the command and parameters.
.. [1] The ``_projects_to_clean`` dictionary in ``dry_run.json`` lists the
@ -122,6 +139,7 @@ from tempest.lib import exceptions
SAVED_STATE_JSON = "saved_state.json"
DRY_RUN_JSON = "dry_run.json"
RESOURCE_LIST_JSON = "resource_list.json"
LOG = logging.getLogger(__name__)
CONF = config.CONF
@ -164,6 +182,7 @@ class TempestCleanup(command.Command):
self.admin_mgr = clients.Manager(
credentials.get_configured_admin_credentials())
self.dry_run_data = {}
self.resource_data = {}
self.json_data = {}
# available services
@ -177,12 +196,20 @@ class TempestCleanup(command.Command):
self._init_state()
return
self._load_json()
if parsed_args.prefix:
return
if parsed_args.resource_list:
self._load_resource_list()
return
self._load_saved_state()
def _cleanup(self):
LOG.info("Begin cleanup")
is_dry_run = self.options.dry_run
is_preserve = not self.options.delete_tempest_conf_objects
is_resource_list = self.options.resource_list
is_save_state = False
cleanup_prefix = self.options.prefix
@ -194,8 +221,10 @@ class TempestCleanup(command.Command):
# they are in saved state json. Therefore is_preserve is False
kwargs = {'data': self.dry_run_data,
'is_dry_run': is_dry_run,
'resource_list_json': self.resource_data,
'saved_state_json': self.json_data,
'is_preserve': False,
'is_resource_list': is_resource_list,
'is_save_state': is_save_state,
'prefix': cleanup_prefix}
project_service = cleanup_service.ProjectService(admin_mgr, **kwargs)
@ -208,8 +237,10 @@ class TempestCleanup(command.Command):
kwargs = {'data': self.dry_run_data,
'is_dry_run': is_dry_run,
'resource_list_json': self.resource_data,
'saved_state_json': self.json_data,
'is_preserve': is_preserve,
'is_resource_list': is_resource_list,
'is_save_state': is_save_state,
'prefix': cleanup_prefix,
'got_exceptions': self.GOT_EXCEPTIONS}
@ -228,11 +259,17 @@ class TempestCleanup(command.Command):
f.write(json.dumps(self.dry_run_data, sort_keys=True,
indent=2, separators=(',', ': ')))
if is_resource_list:
LOG.info("Clearing 'resource_list.json' file.")
with open(RESOURCE_LIST_JSON, 'w') as f:
f.write('{}')
def _clean_project(self, project):
LOG.debug("Cleaning project: %s ", project['name'])
is_dry_run = self.options.dry_run
dry_run_data = self.dry_run_data
is_preserve = not self.options.delete_tempest_conf_objects
is_resource_list = self.options.resource_list
project_id = project['id']
project_name = project['name']
project_data = None
@ -244,7 +281,9 @@ class TempestCleanup(command.Command):
kwargs = {'data': project_data,
'is_dry_run': is_dry_run,
'saved_state_json': self.json_data,
'resource_list_json': self.resource_data,
'is_preserve': is_preserve,
'is_resource_list': is_resource_list,
'is_save_state': False,
'project_id': project_id,
'prefix': cleanup_prefix,
@ -287,6 +326,19 @@ class TempestCleanup(command.Command):
"ignored when --init-saved-state is used so that "
"it can capture the true init state - all "
"resources present at that moment.")
parser.add_argument('--resource-list', action="store_true",
dest='resource_list', default=False,
help="Runs tempest cleanup with generated "
"JSON file: " + RESOURCE_LIST_JSON + " to "
"erase resources created during Tempest run. "
"NOTE: To create " + RESOURCE_LIST_JSON + " "
"set config option record_resources under default "
"section in tempest.conf file to true. This "
"option will be ignored when --init-saved-state "
"is used so that it can capture the true init "
"state - all resources present at that moment. "
"This option will be ignored if passed with "
"--prefix.")
return parser
def get_description(self):
@ -304,6 +356,7 @@ class TempestCleanup(command.Command):
'is_dry_run': False,
'saved_state_json': data,
'is_preserve': False,
'is_resource_list': False,
'is_save_state': True,
# must be None as we want to capture true init state
# (all resources present) thus no filtering based
@ -326,15 +379,31 @@ class TempestCleanup(command.Command):
f.write(json.dumps(data, sort_keys=True,
indent=2, separators=(',', ': ')))
def _load_json(self, saved_state_json=SAVED_STATE_JSON):
def _load_resource_list(self, resource_list_json=RESOURCE_LIST_JSON):
try:
with open(resource_list_json, 'rb') as json_file:
self.resource_data = json.load(json_file)
except IOError as ex:
LOG.exception(
"Failed loading 'resource_list.json', please "
"be sure you created this file by setting config "
"option record_resources in default section to true "
"prior to running tempest. Exception: %s", ex)
sys.exit(ex)
except Exception as ex:
LOG.exception(
"Exception parsing 'resource_list.json' : %s", ex)
sys.exit(ex)
def _load_saved_state(self, saved_state_json=SAVED_STATE_JSON):
try:
with open(saved_state_json, 'rb') as json_file:
self.json_data = json.load(json_file)
except IOError as ex:
LOG.exception("Failed loading saved state, please be sure you"
" have first run cleanup with --init-saved-state "
"flag prior to running tempest. Exception: %s", ex)
LOG.exception(
"Failed loading saved state, please be sure you"
" have first run cleanup with --init-saved-state "
"flag prior to running tempest. Exception: %s", ex)
sys.exit(ex)
except Exception as ex:
LOG.exception("Exception parsing saved state json : %s", ex)

View File

@ -120,6 +120,13 @@ class BaseService(object):
if item['name'].startswith(self.prefix)]
return items
def _filter_by_resource_list(self, item_list, attr):
if attr not in self.resource_list_json:
return []
items = [item for item in item_list if item['id']
in self.resource_list_json[attr].keys()]
return items
def _filter_out_ids_from_saved(self, item_list, attr):
items = [item for item in item_list if item['id']
not in self.saved_state_json[attr].keys()]
@ -166,8 +173,11 @@ class SnapshotService(BaseService):
def list(self):
client = self.client
snaps = client.list_snapshots()['snapshots']
if self.prefix:
snaps = self._filter_by_prefix(snaps)
elif self.is_resource_list:
snaps = self._filter_by_resource_list(snaps, 'snapshots')
elif not self.is_save_state:
# recreate list removing saved snapshots
snaps = self._filter_out_ids_from_saved(snaps, 'snapshots')
@ -205,8 +215,11 @@ class ServerService(BaseService):
client = self.client
servers_body = client.list_servers()
servers = servers_body['servers']
if self.prefix:
servers = self._filter_by_prefix(servers)
elif self.is_resource_list:
servers = self._filter_by_resource_list(servers, 'servers')
elif not self.is_save_state:
# recreate list removing saved servers
servers = self._filter_out_ids_from_saved(servers, 'servers')
@ -238,9 +251,12 @@ class ServerGroupService(ServerService):
def list(self):
client = self.server_groups_client
sgs = client.list_server_groups()['server_groups']
sgs = client.list_server_groups(all_projects=True)['server_groups']
if self.prefix:
sgs = self._filter_by_prefix(sgs)
elif self.is_resource_list:
sgs = self._filter_by_resource_list(sgs, 'server_groups')
elif not self.is_save_state:
# recreate list removing saved server_groups
sgs = self._filter_out_ids_from_saved(sgs, 'server_groups')
@ -276,8 +292,13 @@ class KeyPairService(BaseService):
def list(self):
client = self.client
keypairs = client.list_keypairs()['keypairs']
if self.prefix:
keypairs = self._filter_by_prefix(keypairs)
elif self.is_resource_list:
keypairs = [keypair for keypair in keypairs
if keypair['keypair']['name']
in self.resource_list_json['keypairs'].keys()]
elif not self.is_save_state:
# recreate list removing saved keypairs
keypairs = [keypair for keypair in keypairs
@ -317,8 +338,11 @@ class VolumeService(BaseService):
def list(self):
client = self.client
vols = client.list_volumes()['volumes']
if self.prefix:
vols = self._filter_by_prefix(vols)
elif self.is_resource_list:
vols = self._filter_by_resource_list(vols, 'volumes')
elif not self.is_save_state:
# recreate list removing saved volumes
vols = self._filter_out_ids_from_saved(vols, 'volumes')
@ -462,8 +486,11 @@ class NetworkService(BaseNetworkService):
client = self.networks_client
networks = client.list_networks(**self.tenant_filter)
networks = networks['networks']
if self.prefix:
networks = self._filter_by_prefix(networks)
elif self.is_resource_list:
networks = self._filter_by_resource_list(networks, 'networks')
else:
if not self.is_save_state:
# recreate list removing saved networks
@ -500,15 +527,17 @@ class NetworkService(BaseNetworkService):
class NetworkFloatingIpService(BaseNetworkService):
def list(self):
if self.prefix:
# this means we're cleaning resources based on a certain prefix,
# this resource doesn't have a name, therefore return empty list
return []
client = self.floating_ips_client
flips = client.list_floatingips(**self.tenant_filter)
flips = flips['floatingips']
if not self.is_save_state:
if self.prefix:
# this means we're cleaning resources based on a certain prefix,
# this resource doesn't have a name, therefore return empty list
return []
elif self.is_resource_list:
flips = self._filter_by_resource_list(flips, 'floatingips')
elif not self.is_save_state:
# recreate list removing saved flips
flips = self._filter_out_ids_from_saved(flips, 'floatingips')
LOG.debug("List count, %s Network Floating IPs", len(flips))
@ -543,8 +572,11 @@ class NetworkRouterService(BaseNetworkService):
client = self.routers_client
routers = client.list_routers(**self.tenant_filter)
routers = routers['routers']
if self.prefix:
routers = self._filter_by_prefix(routers)
elif self.is_resource_list:
routers = self._filter_by_resource_list(routers, 'routers')
else:
if not self.is_save_state:
# recreate list removing saved routers
@ -592,16 +624,19 @@ class NetworkRouterService(BaseNetworkService):
class NetworkMeteringLabelRuleService(NetworkService):
def list(self):
if self.prefix:
# this means we're cleaning resources based on a certain prefix,
# this resource doesn't have a name, therefore return empty list
return []
client = self.metering_label_rules_client
rules = client.list_metering_label_rules()
rules = rules['metering_label_rules']
rules = self._filter_by_tenant_id(rules)
if not self.is_save_state:
if self.prefix:
# this means we're cleaning resources based on a certain prefix,
# this resource doesn't have a name, therefore return empty list
return []
elif self.is_resource_list:
rules = self._filter_by_resource_list(
rules, 'metering_label_rules')
elif not self.is_save_state:
rules = self._filter_out_ids_from_saved(
rules, 'metering_label_rules')
# recreate list removing saved rules
@ -638,8 +673,12 @@ class NetworkMeteringLabelService(BaseNetworkService):
labels = client.list_metering_labels()
labels = labels['metering_labels']
labels = self._filter_by_tenant_id(labels)
if self.prefix:
labels = self._filter_by_prefix(labels)
elif self.is_resource_list:
labels = self._filter_by_resource_list(
labels, 'metering_labels')
elif not self.is_save_state:
# recreate list removing saved labels
labels = self._filter_out_ids_from_saved(
@ -677,8 +716,11 @@ class NetworkPortService(BaseNetworkService):
client.list_ports(**self.tenant_filter)['ports']
if port["device_owner"] == "" or
port["device_owner"].startswith("compute:")]
if self.prefix:
ports = self._filter_by_prefix(ports)
elif self.is_resource_list:
ports = self._filter_by_resource_list(ports, 'ports')
else:
if not self.is_save_state:
# recreate list removing saved ports
@ -717,8 +759,12 @@ class NetworkSecGroupService(BaseNetworkService):
secgroups = [secgroup for secgroup in
client.list_security_groups(**filter)['security_groups']
if secgroup['name'] != 'default']
if self.prefix:
secgroups = self._filter_by_prefix(secgroups)
elif self.is_resource_list:
secgroups = self._filter_by_resource_list(
secgroups, 'security_groups')
else:
if not self.is_save_state:
# recreate list removing saved security_groups
@ -760,8 +806,11 @@ class NetworkSubnetService(BaseNetworkService):
client = self.subnets_client
subnets = client.list_subnets(**self.tenant_filter)
subnets = subnets['subnets']
if self.prefix:
subnets = self._filter_by_prefix(subnets)
elif self.is_resource_list:
subnets = self._filter_by_resource_list(subnets, 'subnets')
else:
if not self.is_save_state:
# recreate list removing saved subnets
@ -797,8 +846,11 @@ class NetworkSubnetPoolsService(BaseNetworkService):
def list(self):
client = self.subnetpools_client
pools = client.list_subnetpools(**self.tenant_filter)['subnetpools']
if self.prefix:
pools = self._filter_by_prefix(pools)
elif self.is_resource_list:
pools = self._filter_by_resource_list(pools, 'subnetpools')
else:
if not self.is_save_state:
# recreate list removing saved subnet pools
@ -838,13 +890,18 @@ class RegionService(BaseService):
self.client = manager.regions_client
def list(self):
client = self.client
regions = client.list_regions()
if self.prefix:
# this means we're cleaning resources based on a certain prefix,
# this resource doesn't have a name, therefore return empty list
return []
client = self.client
regions = client.list_regions()
if not self.is_save_state:
elif self.is_resource_list:
regions = self._filter_by_resource_list(
regions['regions'], 'regions')
return regions
elif not self.is_save_state:
regions = self._filter_out_ids_from_saved(
regions['regions'], 'regions')
LOG.debug("List count, %s Regions", len(regions))
@ -884,8 +941,11 @@ class FlavorService(BaseService):
def list(self):
client = self.client
flavors = client.list_flavors({"is_public": None})['flavors']
if self.prefix:
flavors = self._filter_by_prefix(flavors)
elif self.is_resource_list:
flavors = self._filter_by_resource_list(flavors, 'flavors')
else:
if not self.is_save_state:
# recreate list removing saved flavors
@ -932,8 +992,11 @@ class ImageService(BaseService):
marker = urllib.parse_qs(parsed.query)['marker'][0]
response = client.list_images(params={"marker": marker})
images.extend(response['images'])
if self.prefix:
images = self._filter_by_prefix(images)
elif self.is_resource_list:
images = self._filter_by_resource_list(images, 'images')
else:
if not self.is_save_state:
images = self._filter_out_ids_from_saved(images, 'images')
@ -974,6 +1037,8 @@ class UserService(BaseService):
users = self.client.list_users()['users']
if self.prefix:
users = self._filter_by_prefix(users)
elif self.is_resource_list:
users = self._filter_by_resource_list(users, 'users')
else:
if not self.is_save_state:
users = self._filter_out_ids_from_saved(users, 'users')
@ -1015,8 +1080,11 @@ class RoleService(BaseService):
def list(self):
try:
roles = self.client.list_roles()['roles']
if self.prefix:
roles = self._filter_by_prefix(roles)
elif self.is_resource_list:
roles = self._filter_by_resource_list(roles, 'roles')
elif not self.is_save_state:
# reconcile roles with saved state and never list admin role
roles = self._filter_out_ids_from_saved(roles, 'roles')
@ -1056,8 +1124,11 @@ class ProjectService(BaseService):
def list(self):
projects = self.client.list_projects()['projects']
if self.prefix:
projects = self._filter_by_prefix(projects)
elif self.is_resource_list:
projects = self._filter_by_resource_list(projects, 'projects')
else:
if not self.is_save_state:
projects = self._filter_out_ids_from_saved(
@ -1099,8 +1170,11 @@ class DomainService(BaseService):
def list(self):
client = self.client
domains = client.list_domains()['domains']
if self.prefix:
domains = self._filter_by_prefix(domains)
elif self.is_resource_list:
domains = self._filter_by_resource_list(domains, 'domains')
elif not self.is_save_state:
domains = self._filter_out_ids_from_saved(domains, 'domains')
LOG.debug("List count, %s Domains after reconcile", len(domains))

View File

@ -1309,6 +1309,15 @@ or
"to cleanup only the resources that match the prefix. "
"Make sure this prefix does not match with the resource "
"name you do not want Tempest cleanup CLI to delete."),
cfg.BoolOpt('record_resources',
default=False,
help="Allows to record all resources created by Tempest. "
"These resources are stored in file resource_list.json, "
"which can be later used for resource deletion by "
"command tempest cleanup. The resource_list.json file "
"will be appended in case of multiple Tempest runs, "
"so the file will contain a list of resources created "
"during all Tempest runs."),
]
_opts = [

View File

@ -21,6 +21,7 @@ import time
import urllib
import urllib3
from fasteners import process_lock
import jsonschema
from oslo_log import log as logging
from oslo_log import versionutils
@ -78,6 +79,17 @@ class RestClient(object):
# The version of the API this client implements
api_version = None
# Directory for storing read-write lock
lock_dir = None
# An interprocess lock used when the recording of all resources created by
# Tempest is allowed.
rec_rw_lock = None
# Variable mirrors value in config option 'record_resources' that allows
# the recording of all resources created by Tempest.
record_resources = False
LOG = logging.getLogger(__name__)
def __init__(self, auth_provider, service, region,
@ -297,7 +309,13 @@ class RestClient(object):
and the second the response body
:rtype: tuple
"""
return self.request('POST', url, extra_headers, headers, body, chunked)
resp_header, resp_body = self.request(
'POST', url, extra_headers, headers, body, chunked)
if self.record_resources:
self.resource_record(resp_body)
return resp_header, resp_body
def get(self, url, headers=None, extra_headers=False, chunked=False):
"""Send a HTTP GET request using keystone service catalog and auth
@ -1006,6 +1024,66 @@ class RestClient(object):
"""Returns the primary type of resource this client works with."""
return 'resource'
def resource_update(self, data, res_type, res_dict):
"""Updates resource_list.json file with current resource."""
if not isinstance(res_dict, dict):
return
if not res_type.endswith('s'):
res_type += 's'
if res_type not in data:
data[res_type] = {}
if 'uuid' in res_dict:
data[res_type].update(
{res_dict.get('uuid'): res_dict.get('name')})
elif 'id' in res_dict:
data[res_type].update(
{res_dict.get('id'): res_dict.get('name')})
elif 'name' in res_dict:
data[res_type].update({res_dict.get('name'): ""})
self.rec_rw_lock.acquire_write_lock()
with open("resource_list.json", 'w+') as f:
f.write(json.dumps(data, indent=2, separators=(',', ': ')))
self.rec_rw_lock.release_write_lock()
def resource_record(self, resp_dict):
"""Records resources into resource_list.json file."""
if self.rec_rw_lock is None:
path = self.lock_dir
self.rec_rw_lock = (
process_lock.InterProcessReaderWriterLock(path)
)
self.rec_rw_lock.acquire_read_lock()
try:
with open('resource_list.json', 'rb') as f:
data = json.load(f)
except IOError:
data = {}
self.rec_rw_lock.release_read_lock()
try:
resp_dict = json.loads(resp_dict.decode('utf-8'))
except (AttributeError, TypeError, ValueError):
return
# check if response has any keys
if not resp_dict.keys():
return
resource_type = list(resp_dict.keys())[0]
resource_dict = resp_dict[resource_type]
if isinstance(resource_dict, list):
for resource in resource_dict:
self.resource_update(data, resource_type, resource)
else:
self.resource_update(data, resource_type, resource_dict)
@classmethod
def validate_response(cls, schema, resp, body):
# Only check the response if the status code is a success code

View File

@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from urllib import parse as urllib
from oslo_serialization import jsonutils as json
from tempest.lib.api_schema.response.compute.v2_1 import server_groups \
@ -55,9 +57,14 @@ class ServerGroupsClient(base_compute_client.BaseComputeClient):
self.validate_response(schema.delete_server_group, resp, body)
return rest_client.ResponseBody(resp, body)
def list_server_groups(self):
def list_server_groups(self, **params):
"""List the server-groups."""
resp, body = self.get("os-server-groups")
url = 'os-server-groups'
if params:
url += '?%s' % urllib.urlencode(params)
resp, body = self.get(url)
body = json.loads(body)
schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.list_server_groups, resp, body)

View File

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from unittest import mock
from tempest.cmd import cleanup
@ -20,12 +21,30 @@ from tempest.tests import base
class TestTempestCleanup(base.TestCase):
def test_load_json(self):
def test_load_json_saved_state(self):
# instantiate "empty" TempestCleanup
c = cleanup.TempestCleanup(None, None, 'test')
test_saved_json = 'tempest/tests/cmd/test_saved_state_json.json'
with open(test_saved_json, 'r') as f:
test_saved_json_content = json.load(f)
# test if the file is loaded without any issues/exceptions
c._load_json(test_saved_json)
c.options = mock.Mock()
c.options.init_saved_state = True
c._load_saved_state(test_saved_json)
self.assertEqual(c.json_data, test_saved_json_content)
def test_load_json_resource_list(self):
# instantiate "empty" TempestCleanup
c = cleanup.TempestCleanup(None, None, 'test')
test_resource_list = 'tempest/tests/cmd/test_resource_list.json'
with open(test_resource_list, 'r') as f:
test_resource_list_content = json.load(f)
# test if the file is loaded without any issues/exceptions
c.options = mock.Mock()
c.options.init_saved_state = False
c.options.resource_list = True
c._load_resource_list(test_resource_list)
self.assertEqual(c.resource_data, test_resource_list_content)
@mock.patch('tempest.cmd.cleanup.TempestCleanup.init')
@mock.patch('tempest.cmd.cleanup.TempestCleanup._cleanup')

View File

@ -41,8 +41,10 @@ class TestBaseService(base.TestCase):
def test_base_service_init(self):
kwargs = {'data': {'data': 'test'},
'is_dry_run': False,
'resource_list_json': {'resp': 'data'},
'saved_state_json': {'saved': 'data'},
'is_preserve': False,
'is_resource_list': False,
'is_save_state': True,
'prefix': 'tempest',
'tenant_id': 'project_id',
@ -50,8 +52,10 @@ class TestBaseService(base.TestCase):
base = cleanup_service.BaseService(kwargs)
self.assertEqual(base.data, kwargs['data'])
self.assertFalse(base.is_dry_run)
self.assertEqual(base.resource_list_json, kwargs['resource_list_json'])
self.assertEqual(base.saved_state_json, kwargs['saved_state_json'])
self.assertFalse(base.is_preserve)
self.assertFalse(base.is_resource_list)
self.assertTrue(base.is_save_state)
self.assertEqual(base.tenant_filter['project_id'], kwargs['tenant_id'])
self.assertEqual(base.got_exceptions, kwargs['got_exceptions'])
@ -60,8 +64,10 @@ class TestBaseService(base.TestCase):
def test_not_implemented_ex(self):
kwargs = {'data': {'data': 'test'},
'is_dry_run': False,
'resource_list_json': {'resp': 'data'},
'saved_state_json': {'saved': 'data'},
'is_preserve': False,
'is_resource_list': False,
'is_save_state': False,
'prefix': 'tempest',
'tenant_id': 'project_id',
@ -181,10 +187,20 @@ class BaseCmdServiceTests(MockFunctionsBase):
"subnetpools": {'8acf64c1-43fc': 'saved-subnet-pool'},
"regions": {'RegionOne': {}}
}
resource_list = {
"keypairs": {'saved-key-pair': ""}
}
# Mocked methods
get_method = 'tempest.lib.common.rest_client.RestClient.get'
delete_method = 'tempest.lib.common.rest_client.RestClient.delete'
log_method = 'tempest.cmd.cleanup_service.LOG.exception'
filter_saved_state = 'tempest.cmd.cleanup_service.' \
'BaseService._filter_out_ids_from_saved'
filter_resource_list = 'tempest.cmd.cleanup_service.' \
'BaseService._filter_by_resource_list'
filter_prefix = 'tempest.cmd.cleanup_service.BaseService._filter_by_prefix'
# Override parameters
service_class = 'BaseService'
response = None
@ -192,17 +208,19 @@ class BaseCmdServiceTests(MockFunctionsBase):
def _create_cmd_service(self, service_type, is_save_state=False,
is_preserve=False, is_dry_run=False,
prefix=''):
prefix='', is_resource_list=False):
creds = fake_credentials.FakeKeystoneV3Credentials()
os = clients.Manager(creds)
return getattr(cleanup_service, service_type)(
os,
is_resource_list=is_resource_list,
is_save_state=is_save_state,
is_preserve=is_preserve,
is_dry_run=is_dry_run,
prefix=prefix,
project_id='b8e3ece07bb049138d224436756e3b57',
data={},
resource_list_json=self.resource_list,
saved_state_json=self.saved_state
)
@ -266,6 +284,38 @@ class BaseCmdServiceTests(MockFunctionsBase):
self.assertNotIn(rsp['id'], self.conf_values.values())
self.assertNotIn(rsp['name'], self.conf_values.values())
def _test_prefix_opt_precedence(self, delete_mock):
serv = self._create_cmd_service(
self.service_class, is_resource_list=True, prefix='tempest')
_, fixtures = self.run_function_with_mocks(
serv.run,
delete_mock
)
# Check that prefix was used for filtering
fixtures[2].mock.assert_called_once()
# Check that neither saved_state.json nor resource list was
# used for filtering
fixtures[0].mock.assert_not_called()
fixtures[1].mock.assert_not_called()
def _test_resource_list_opt_precedence(self, delete_mock):
serv = self._create_cmd_service(
self.service_class, is_resource_list=True)
_, fixtures = self.run_function_with_mocks(
serv.run,
delete_mock
)
# Check that resource list was used for filtering
fixtures[1].mock.assert_called_once()
# Check that neither saved_state.json nor prefix was
# used for filtering
fixtures[0].mock.assert_not_called()
fixtures[2].mock.assert_not_called()
class TestSnapshotService(BaseCmdServiceTests):
@ -320,6 +370,24 @@ class TestSnapshotService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestServerService(BaseCmdServiceTests):
@ -378,6 +446,24 @@ class TestServerService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestServerGroupService(BaseCmdServiceTests):
@ -429,6 +515,26 @@ class TestServerGroupService(BaseCmdServiceTests):
(self.validate_response, 'validate', None)
])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.validate_response, 'validate', None),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.validate_response, 'validate', None),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestKeyPairService(BaseCmdServiceTests):
@ -493,6 +599,33 @@ class TestKeyPairService(BaseCmdServiceTests):
(self.validate_response, 'validate', None)
])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.validate_response, 'validate', None),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.validate_response, 'validate', None),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
serv = self._create_cmd_service(
self.service_class, is_resource_list=True)
_, fixtures = self.run_function_with_mocks(
serv.delete,
delete_mock
)
# Check that prefix was not used for filtering
fixtures[0].mock.assert_not_called()
class TestVolumeService(BaseCmdServiceTests):
@ -542,6 +675,24 @@ class TestVolumeService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestVolumeQuotaService(BaseCmdServiceTests):
@ -761,6 +912,24 @@ class TestNetworkService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkFloatingIpService(BaseCmdServiceTests):
@ -823,6 +992,34 @@ class TestNetworkFloatingIpService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
serv = self._create_cmd_service(
self.service_class, is_resource_list=True, prefix='tempest')
_, fixtures = self.run_function_with_mocks(
serv.run,
delete_mock
)
# cleanup returns []
fixtures[0].mock.assert_not_called()
fixtures[1].mock.assert_not_called()
fixtures[2].mock.assert_not_called()
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkRouterService(BaseCmdServiceTests):
@ -937,6 +1134,24 @@ class TestNetworkRouterService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkMeteringLabelRuleService(BaseCmdServiceTests):
@ -978,6 +1193,34 @@ class TestNetworkMeteringLabelRuleService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
serv = self._create_cmd_service(
self.service_class, is_resource_list=True, prefix='tempest')
_, fixtures = self.run_function_with_mocks(
serv.run,
delete_mock
)
# cleanup returns []
fixtures[0].mock.assert_not_called()
fixtures[1].mock.assert_not_called()
fixtures[2].mock.assert_not_called()
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkMeteringLabelService(BaseCmdServiceTests):
@ -1020,6 +1263,24 @@ class TestNetworkMeteringLabelService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkPortService(BaseCmdServiceTests):
@ -1118,6 +1379,24 @@ class TestNetworkPortService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkSecGroupService(BaseCmdServiceTests):
@ -1196,6 +1475,24 @@ class TestNetworkSecGroupService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkSubnetService(BaseCmdServiceTests):
@ -1272,6 +1569,24 @@ class TestNetworkSubnetService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestNetworkSubnetPoolsService(BaseCmdServiceTests):
@ -1340,6 +1655,24 @@ class TestNetworkSubnetPoolsService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
# begin global services
class TestRegionService(BaseCmdServiceTests):
@ -1392,6 +1725,34 @@ class TestRegionService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
serv = self._create_cmd_service(
self.service_class, is_resource_list=True, prefix='tempest')
_, fixtures = self.run_function_with_mocks(
serv.run,
delete_mock
)
# cleanup returns []
fixtures[0].mock.assert_not_called()
fixtures[1].mock.assert_not_called()
fixtures[2].mock.assert_not_called()
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestDomainService(BaseCmdServiceTests):
@ -1445,6 +1806,26 @@ class TestDomainService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None),
(self.mock_update, 'update', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None),
(self.mock_update, 'update', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestProjectsService(BaseCmdServiceTests):
@ -1518,6 +1899,24 @@ class TestProjectsService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestImagesService(BaseCmdServiceTests):
@ -1597,6 +1996,24 @@ class TestImagesService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestFlavorService(BaseCmdServiceTests):
@ -1670,6 +2087,24 @@ class TestFlavorService(BaseCmdServiceTests):
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestRoleService(BaseCmdServiceTests):
@ -1716,6 +2151,24 @@ class TestRoleService(BaseCmdServiceTests):
def test_save_state(self):
self._test_saved_state_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)
class TestUserService(BaseCmdServiceTests):
@ -1782,3 +2235,21 @@ class TestUserService(BaseCmdServiceTests):
"password_expires_at": "1893-11-06T15:32:17.000000",
})
self._test_is_preserve_true([(self.get_method, self.response, 200)])
def test_prefix_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_prefix_opt_precedence(delete_mock)
def test_resource_list_opt_precedence(self):
delete_mock = [(self.filter_saved_state, [], None),
(self.filter_resource_list, [], None),
(self.filter_prefix, [], None),
(self.get_method, self.response, 200),
(self.delete_method, 'error', None),
(self.log_method, 'exception', None)]
self._test_resource_list_opt_precedence(delete_mock)

View File

@ -0,0 +1,11 @@
{
"project": {
"ce4e7edf051c439d8b81c4bfe581c5ef": "test"
},
"keypairs": {
"tempest-keypair-1215039183": ""
},
"users": {
"74463c83f9d640fe84c4376527ceff26": "test"
}
}

View File

@ -13,6 +13,7 @@
# under the License.
import copy
from unittest import mock
import fixtures
import jsonschema
@ -749,6 +750,110 @@ class TestExpectedSuccess(BaseRestClientTestClass):
expected_code, read_code)
class TestRecordResources(BaseRestClientTestClass):
def setUp(self):
self.fake_http = fake_http.fake_httplib2()
super(TestRecordResources, self).setUp()
def _cleanup_test_resource_record(self):
# clear resource_list.json file
with open('resource_list.json', 'w') as f:
f.write('{}')
def test_post_record_resources(self):
self.rest_client.record_resources = True
__, return_dict = self.rest_client.post(self.url, {}, {})
self.assertEqual({}, return_dict['headers'])
self.assertEqual({}, return_dict['body'])
def test_resource_record_no_top_key(self):
test_body_no_key = b'{}'
self.rest_client.resource_record(test_body_no_key)
def test_resource_record_dict(self):
test_dict_body = b'{"project": {"id": "test-id", "name": ""}}\n'
self.rest_client.resource_record(test_dict_body)
with open('resource_list.json', 'r') as f:
content = f.read()
resource_list_content = json.loads(content)
test_resource_list = {
"projects": {"test-id": ""}
}
self.assertEqual(resource_list_content, test_resource_list)
# cleanup
self._cleanup_test_resource_record()
def test_resource_record_list(self):
test_list_body = '''{
"user": [
{
"id": "test-uuid",
"name": "test-name"
},
{
"id": "test-uuid2",
"name": "test-name2"
}
]
}'''
test_list_body = test_list_body.encode('utf-8')
self.rest_client.resource_record(test_list_body)
with open('resource_list.json', 'r') as f:
content = f.read()
resource_list_content = json.loads(content)
test_resource_list = {
"users": {
"test-uuid": "test-name",
"test-uuid2": "test-name2"
}
}
self.assertEqual(resource_list_content, test_resource_list)
# cleanup
self._cleanup_test_resource_record()
def test_resource_update_id(self):
data = {}
res_dict = {'id': 'test-uuid', 'name': 'test-name'}
self.rest_client.rec_rw_lock = mock.MagicMock()
self.rest_client.resource_update(data, 'user', res_dict)
result = {'users': {'test-uuid': 'test-name'}}
self.assertEqual(data, result)
def test_resource_update_name(self):
data = {'keypairs': {}}
res_dict = {'name': 'test-keypair'}
self.rest_client.rec_rw_lock = mock.MagicMock()
self.rest_client.resource_update(data, 'keypair', res_dict)
result = {'keypairs': {'test-keypair': ""}}
self.assertEqual(data, result)
def test_resource_update_no_id(self):
data = {}
res_dict = {'type': 'test', 'description': 'example'}
self.rest_client.rec_rw_lock = mock.MagicMock()
self.rest_client.resource_update(data, 'projects', res_dict)
result = {'projects': {}}
self.assertEqual(data, result)
def test_resource_update_not_dict(self):
data = {}
res_dict = 'test-string'
self.rest_client.rec_rw_lock = mock.MagicMock()
self.rest_client.resource_update(data, 'user', res_dict)
self.assertEqual(data, {})
class TestResponseBody(base.TestCase):
def test_str(self):