Create base class for client to avoid code duplication

Implementing listing or showing resource in every client leads to
a lot of duplicated code. This change adds a base client class
which implements common helpers.

Removes "Database" prefix from class names and "db" infix
from method signatures for alignment with standards from the rest
of the community.

Also, adds doseq option by URL encoding to handle sequence field
values.

Change-Id: I580405e2cb8a15e5735ae413ad2186c620f018bc
Co-Authored-By: Przemyslaw Godek <p.godek@partner.samsung.com>
Co-Authored-By: Krzysztof Opasiak <k.opasiak@samsung.com>
Signed-off-by: Bartosz Zurkowski <b.zurkowski@samsung.com>
This commit is contained in:
Bartosz Zurkowski 2018-07-06 21:01:54 +02:00
parent 58fe807f4b
commit 0dea14df86
9 changed files with 79 additions and 54 deletions

View File

@ -0,0 +1,47 @@
# Copyright 2018 Samsung Electronics
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_serialization import jsonutils as json
from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
class BaseClient(rest_client.RestClient):
def show_resource(self, uri, expected_status_code=200, **fields):
if fields:
# Encode provided dict of fields into a series of key=value pairs
# separated by '&' characters.
#
# The field value can be a sequence. Setting option doseq to True
# enforces producing individual key-value pair for each element of
# the sequence under the same key.
#
# e.g. {'foo': 'bar', 'baz': ['test1', 'test2']}
# => foo=bar&baz=test1&baz=test2
uri += '?' + urllib.urlencode(fields, doseq=True)
resp, body = self.get(uri)
self.expected_success(expected_status_code, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_resources(self, uri, expected_status_code=200, **filters):
if filters:
uri += '?' + urllib.urlencode(filters, doseq=True)
resp, body = self.get(uri)
self.expected_success(expected_status_code, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)

View File

@ -13,25 +13,16 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_serialization import jsonutils as json
from six.moves import urllib
from tempest.lib.common import rest_client
from trove_tempest_plugin.services.database.json import base_client
class DatabaseFlavorsClient(rest_client.RestClient):
class FlavorsClient(base_client.BaseClient):
def list_db_flavors(self, params=None):
url = 'flavors'
if params:
url += '?%s' % urllib.parse.urlencode(params)
uri = '/flavors'
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def list_flavors(self):
return self.list_resources(self.uri)
def show_db_flavor(self, db_flavor_id):
resp, body = self.get("flavors/%s" % db_flavor_id)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
def show_flavor(self, flavor_id):
uri = '%s/%s' % (self.uri, flavor_id)
return self.show_resource(uri)

View File

@ -13,19 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_serialization import jsonutils as json
from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
from trove_tempest_plugin.services.database.json import base_client
class DatabaseLimitsClient(rest_client.RestClient):
class LimitsClient(base_client.BaseClient):
def list_db_limits(self, params=None):
uri = '/limits'
def list_limits(self):
"""List all limits."""
url = 'limits'
if params:
url += '?%s' % urllib.urlencode(params)
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
return self.list_resources(self.uri)

View File

@ -13,25 +13,18 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_serialization import jsonutils as json
from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
from trove_tempest_plugin.services.database.json import base_client
class DatabaseVersionsClient(rest_client.RestClient):
class VersionsClient(base_client.BaseClient):
uri = ''
def __init__(self, auth_provider, service, region, **kwargs):
super(DatabaseVersionsClient, self).__init__(
super(VersionsClient, self).__init__(
auth_provider, service, region, **kwargs)
self.skip_path()
def list_db_versions(self, params=None):
def list_versions(self):
"""List all versions."""
url = ''
if params:
url += '?%s' % urllib.urlencode(params)
resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
return self.list_resources(self.uri)

View File

@ -48,18 +48,18 @@ class BaseDatabaseTest(tempest.test.BaseTestCase):
'build_timeout': CONF.compute.build_timeout
}
default_params_with_timeout_values.update(default_params)
cls.database_flavors_client = flavors_client.DatabaseFlavorsClient(
cls.database_flavors_client = flavors_client.FlavorsClient(
cls.os_primary.auth_provider,
CONF.database.catalog_type,
CONF.identity.region,
**default_params_with_timeout_values)
cls.os_flavors_client = cls.os_primary.flavors_client
cls.database_limits_client = limits_client.DatabaseLimitsClient(
cls.database_limits_client = limits_client.LimitsClient(
cls.os_primary.auth_provider,
CONF.database.catalog_type,
CONF.identity.region,
**default_params_with_timeout_values)
cls.database_versions_client = versions_client.DatabaseVersionsClient(
cls.database_versions_client = versions_client.VersionsClient(
cls.os_primary.auth_provider,
CONF.database.catalog_type,
CONF.identity.region,

View File

@ -31,7 +31,7 @@ class DatabaseFlavorsTest(base.BaseDatabaseTest):
@decorators.idempotent_id('c94b825e-0132-4686-8049-8a4a2bc09525')
def test_get_db_flavor(self):
# The expected flavor details should be returned
flavor = (self.client.show_db_flavor(self.db_flavor_ref)
flavor = (self.client.show_flavor(self.db_flavor_ref)
['flavor'])
self.assertEqual(self.db_flavor_ref, str(flavor['id']))
self.assertIn('ram', flavor)
@ -41,10 +41,10 @@ class DatabaseFlavorsTest(base.BaseDatabaseTest):
@testtools.attr('smoke')
@decorators.idempotent_id('685025d6-0cec-4673-8a8d-995cb8e0d3bb')
def test_list_db_flavors(self):
flavor = (self.client.show_db_flavor(self.db_flavor_ref)
flavor = (self.client.show_flavor(self.db_flavor_ref)
['flavor'])
# List of all flavors should contain the expected flavor
flavors = self.client.list_db_flavors()['flavors']
flavors = self.client.list_flavors()['flavors']
self.assertIn(flavor, flavors)
def _check_values(self, names, db_flavor, os_flavor, in_db=True):
@ -62,7 +62,7 @@ class DatabaseFlavorsTest(base.BaseDatabaseTest):
@decorators.idempotent_id('afb2667f-4ec2-4925-bcb7-313fdcffb80d')
@utils.services('compute')
def test_compare_db_flavors_with_os(self):
db_flavors = self.client.list_db_flavors()['flavors']
db_flavors = self.client.list_flavors()['flavors']
os_flavors = (self.os_flavors_client.list_flavors(detail=True)
['flavors'])
self.assertEqual(len(os_flavors), len(db_flavors),
@ -70,7 +70,7 @@ class DatabaseFlavorsTest(base.BaseDatabaseTest):
(os_flavors, db_flavors))
for os_flavor in os_flavors:
db_flavor =\
self.client.show_db_flavor(os_flavor['id'])['flavor']
self.client.show_flavor(os_flavor['id'])['flavor']
if db_flavor['id']:
self.assertIn('id', db_flavor)
self.assertEqual(str(db_flavor['id']), str(os_flavor['id']),

View File

@ -33,4 +33,4 @@ class DatabaseFlavorsNegativeTest(base.BaseDatabaseTest):
def test_get_non_existent_db_flavor(self):
# flavor details are not returned for non-existent flavors
self.assertRaises(lib_exc.NotFound,
self.client.show_db_flavor, -1)
self.client.show_flavor, -1)

View File

@ -31,7 +31,7 @@ class DatabaseLimitsTest(base.BaseDatabaseTest):
def test_absolute_limits(self):
# Test to verify if all absolute limit parameters are
# present when verb is ABSOLUTE
limits = self.client.list_db_limits()['limits']
limits = self.client.list_limits()['limits']
expected_abs_limits = ['max_backups', 'max_volumes',
'max_instances', 'verb']
absolute_limit = [l for l in limits

View File

@ -29,7 +29,7 @@ class DatabaseVersionsTest(base.BaseDatabaseTest):
@testtools.attr('smoke')
@decorators.idempotent_id('6952cd77-90cd-4dca-bb60-8e2c797940cf')
def test_list_db_versions(self):
versions = self.client.list_db_versions()['versions']
versions = self.client.list_versions()['versions']
self.assertTrue(len(versions) > 0, "No database versions found")
# List of all versions should contain the current version, and there
# should only be one 'current' version