diff --git a/setup.cfg b/setup.cfg index e6c34b29..401df140 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,9 @@ oslo.messaging.notify.drivers = trove.openstack.common.notifier.rpc_notifier = oslo_messaging.notify.messaging:MessagingDriver trove.openstack.common.notifier.test_notifier = oslo_messaging.notify._impl_test:TestDriver +tempest.test_plugins = + trove_tests = trove.tests.tempest.plugin:TroveTempestPlugin + [global] setup-hooks = pbr.hooks.setup_hook diff --git a/trove/tests/tempest/__init__.py b/trove/tests/tempest/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/config.py b/trove/tests/tempest/config.py new file mode 100644 index 00000000..0048b7a7 --- /dev/null +++ b/trove/tests/tempest/config.py @@ -0,0 +1,35 @@ +# Copyright (c) 2016 Hewlett-Packard Development Company, L.P. +# +# 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_config import cfg + +service_option = cfg.BoolOpt('trove', + default=True, + help="Whether or not Trove is expected to be " + "available") + +database_group = cfg.OptGroup(name='database', + title='Database Service Options') + +DatabaseGroup = [ + cfg.StrOpt('catalog_type', + default='database', + help="Catalog type of the Database service."), + cfg.StrOpt('db_flavor_ref', + default="1", + help="Valid primary flavor to use in database tests."), + cfg.StrOpt('db_current_version', + default="v1.0", + help="Current database version to use in database tests."), +] diff --git a/trove/tests/tempest/plugin.py b/trove/tests/tempest/plugin.py new file mode 100644 index 00000000..c739b29c --- /dev/null +++ b/trove/tests/tempest/plugin.py @@ -0,0 +1,41 @@ +# Copyright (c) 2016 Hewlett-Packard Development Company, L.P. +# 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. + +import os + +from tempest.test_discover import plugins + +from trove.tests.tempest import config as trove_config + + +class TroveTempestPlugin(plugins.TempestPlugin): + + def load_tests(self): + base_path = os.path.split(os.path.dirname( + os.path.abspath(__file__)))[0] + base_path = os.path.dirname(os.path.dirname(base_path)) + test_dir = "trove/tests/tempest/tests" + full_test_dir = os.path.join(base_path, test_dir) + return full_test_dir, base_path + + def register_opts(self, conf): + conf.register_group(trove_config.database_group) + conf.register_opts(trove_config.DatabaseGroup, group='database') + conf.register_opt(trove_config.service_option, + group='service_available') + + def get_opt_lists(self): + return [('database', trove_config.DatabaseGroup), + ('service_available', [trove_config.service_option])] diff --git a/trove/tests/tempest/services/__init__.py b/trove/tests/tempest/services/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/services/database/__init__.py b/trove/tests/tempest/services/database/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/services/database/json/__init__.py b/trove/tests/tempest/services/database/json/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/services/database/json/flavors_client.py b/trove/tests/tempest/services/database/json/flavors_client.py new file mode 100644 index 00000000..95ecfdc7 --- /dev/null +++ b/trove/tests/tempest/services/database/json/flavors_client.py @@ -0,0 +1,37 @@ +# Copyright 2014 OpenStack Foundation +# 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 import urllib +from tempest.lib.common import rest_client + + +class DatabaseFlavorsClient(rest_client.RestClient): + + def list_db_flavors(self, params=None): + url = 'flavors' + if params: + url += '?%s' % urllib.parse.urlencode(params) + + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) + + 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) diff --git a/trove/tests/tempest/services/database/json/limits_client.py b/trove/tests/tempest/services/database/json/limits_client.py new file mode 100644 index 00000000..23164a86 --- /dev/null +++ b/trove/tests/tempest/services/database/json/limits_client.py @@ -0,0 +1,31 @@ +# Copyright 2014 OpenStack Foundation +# 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 DatabaseLimitsClient(rest_client.RestClient): + + def list_db_limits(self, params=None): + """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) diff --git a/trove/tests/tempest/services/database/json/versions_client.py b/trove/tests/tempest/services/database/json/versions_client.py new file mode 100644 index 00000000..d7154f27 --- /dev/null +++ b/trove/tests/tempest/services/database/json/versions_client.py @@ -0,0 +1,37 @@ +# Copyright 2014 OpenStack Foundation +# 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 DatabaseVersionsClient(rest_client.RestClient): + + def __init__(self, auth_provider, service, region, **kwargs): + super(DatabaseVersionsClient, self).__init__( + auth_provider, service, region, **kwargs) + self.skip_path() + + def list_db_versions(self, params=None): + """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) diff --git a/trove/tests/tempest/tests/__init__.py b/trove/tests/tempest/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/tests/api/__init__.py b/trove/tests/tempest/tests/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/tests/api/database/__init__.py b/trove/tests/tempest/tests/api/database/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/tests/api/database/base.py b/trove/tests/tempest/tests/api/database/base.py new file mode 100644 index 00000000..a0d58bdc --- /dev/null +++ b/trove/tests/tempest/tests/api/database/base.py @@ -0,0 +1,74 @@ +# Copyright 2014 OpenStack Foundation +# 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 tempest import config +import tempest.test + +from trove.tests.tempest.services.database.json import flavors_client +from trove.tests.tempest.services.database.json import limits_client +from trove.tests.tempest.services.database.json import versions_client + + +CONF = config.CONF + + +class BaseDatabaseTest(tempest.test.BaseTestCase): + """Base test case class for all Database API tests.""" + + credentials = ['primary'] + + @classmethod + def skip_checks(cls): + super(BaseDatabaseTest, cls).skip_checks() + if not CONF.service_available.trove: + skip_msg = ("%s skipped as trove is not available" % cls.__name__) + raise cls.skipException(skip_msg) + + @classmethod + def setup_clients(cls): + super(BaseDatabaseTest, cls).setup_clients() + default_params = config.service_client_config() + + # NOTE: Tempest uses timeout values of compute API if project specific + # timeout values don't exist. + default_params_with_timeout_values = { + 'build_interval': CONF.compute.build_interval, + 'build_timeout': CONF.compute.build_timeout + } + default_params_with_timeout_values.update(default_params) + cls.database_flavors_client = flavors_client.DatabaseFlavorsClient( + cls.os.auth_provider, + CONF.database.catalog_type, + CONF.identity.region, + **default_params_with_timeout_values) + cls.os_flavors_client = cls.os.flavors_client + cls.database_limits_client = limits_client.DatabaseLimitsClient( + cls.os.auth_provider, + CONF.database.catalog_type, + CONF.identity.region, + **default_params_with_timeout_values) + cls.database_versions_client = versions_client.DatabaseVersionsClient( + cls.os.auth_provider, + CONF.database.catalog_type, + CONF.identity.region, + **default_params_with_timeout_values) + + @classmethod + def resource_setup(cls): + super(BaseDatabaseTest, cls).resource_setup() + + cls.catalog_type = CONF.database.catalog_type + cls.db_flavor_ref = CONF.database.db_flavor_ref + cls.db_current_version = CONF.database.db_current_version diff --git a/trove/tests/tempest/tests/api/database/flavors/__init__.py b/trove/tests/tempest/tests/api/database/flavors/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/tests/api/database/flavors/test_flavors.py b/trove/tests/tempest/tests/api/database/flavors/test_flavors.py new file mode 100644 index 00000000..43e3909c --- /dev/null +++ b/trove/tests/tempest/tests/api/database/flavors/test_flavors.py @@ -0,0 +1,88 @@ +# Copyright 2014 OpenStack Foundation +# 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 tempest.lib import decorators +from tempest import test +from testtools import testcase as testtools + +from trove.tests.tempest.tests.api.database import base + + +class DatabaseFlavorsTest(base.BaseDatabaseTest): + + @classmethod + def setup_clients(cls): + super(DatabaseFlavorsTest, cls).setup_clients() + cls.client = cls.database_flavors_client + + @testtools.attr('smoke') + @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.assertEqual(self.db_flavor_ref, str(flavor['id'])) + self.assertIn('ram', flavor) + self.assertIn('links', flavor) + self.assertIn('name', flavor) + + @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']) + # List of all flavors should contain the expected flavor + flavors = self.client.list_db_flavors()['flavors'] + self.assertIn(flavor, flavors) + + def _check_values(self, names, db_flavor, os_flavor, in_db=True): + for name in names: + self.assertIn(name, os_flavor) + if in_db: + self.assertIn(name, db_flavor) + self.assertEqual(str(db_flavor[name]), str(os_flavor[name]), + "DB flavor differs from OS on '%s' value" + % name) + else: + self.assertNotIn(name, db_flavor) + + @testtools.attr('smoke') + @decorators.idempotent_id('afb2667f-4ec2-4925-bcb7-313fdcffb80d') + @test.services('compute') + def test_compare_db_flavors_with_os(self): + db_flavors = self.client.list_db_flavors()['flavors'] + os_flavors = (self.os_flavors_client.list_flavors(detail=True) + ['flavors']) + self.assertEqual(len(os_flavors), len(db_flavors), + "OS flavors %s do not match DB flavors %s" % + (os_flavors, db_flavors)) + for os_flavor in os_flavors: + db_flavor =\ + self.client.show_db_flavor(os_flavor['id'])['flavor'] + if db_flavor['id']: + self.assertIn('id', db_flavor) + self.assertEqual(str(db_flavor['id']), str(os_flavor['id']), + "DB flavor id differs from OS flavor id value" + ) + else: + self.assertIn('str_id', db_flavor) + self.assertEqual(db_flavor['str_id'], str(os_flavor['id']), + "DB flavor id differs from OS flavor id value" + ) + + self._check_values(['name', 'ram', 'vcpus', + 'disk'], db_flavor, os_flavor) + self._check_values(['swap'], db_flavor, os_flavor, + in_db=False) diff --git a/trove/tests/tempest/tests/api/database/flavors/test_flavors_negative.py b/trove/tests/tempest/tests/api/database/flavors/test_flavors_negative.py new file mode 100644 index 00000000..ad208071 --- /dev/null +++ b/trove/tests/tempest/tests/api/database/flavors/test_flavors_negative.py @@ -0,0 +1,36 @@ +# Copyright 2014 OpenStack Foundation +# 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 tempest.lib import decorators +from tempest.lib import exceptions as lib_exc +from testtools import testcase as testtools + +from trove.tests.tempest.tests.api.database import base + + +class DatabaseFlavorsNegativeTest(base.BaseDatabaseTest): + + @classmethod + def setup_clients(cls): + super(DatabaseFlavorsNegativeTest, cls).setup_clients() + cls.client = cls.database_flavors_client + + @testtools.attr('negative') + @decorators.idempotent_id('f8e7b721-373f-4a64-8e9c-5327e975af3e') + 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) diff --git a/trove/tests/tempest/tests/api/database/limits/__init__.py b/trove/tests/tempest/tests/api/database/limits/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/tests/api/database/limits/test_limits.py b/trove/tests/tempest/tests/api/database/limits/test_limits.py new file mode 100644 index 00000000..c58ef6b8 --- /dev/null +++ b/trove/tests/tempest/tests/api/database/limits/test_limits.py @@ -0,0 +1,47 @@ +# Copyright 2014 OpenStack Foundation +# 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 tempest.lib import decorators +from testtools import testcase as testtools + +from trove.tests.tempest.tests.api.database import base + + +class DatabaseLimitsTest(base.BaseDatabaseTest): + + @classmethod + def resource_setup(cls): + super(DatabaseLimitsTest, cls).resource_setup() + cls.client = cls.database_limits_client + + @testtools.attr('smoke') + @decorators.idempotent_id('73024538-f316-4829-b3e9-b459290e137a') + 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'] + expected_abs_limits = ['max_backups', 'max_volumes', + 'max_instances', 'verb'] + absolute_limit = [l for l in limits + if l['verb'] == 'ABSOLUTE'] + self.assertEqual(1, len(absolute_limit), "One ABSOLUTE limit " + "verb is allowed. Fetched %s" + % len(absolute_limit)) + actual_abs_limits = absolute_limit[0].keys() + missing_abs_limit = set(expected_abs_limits) - set(actual_abs_limits) + self.assertEmpty(missing_abs_limit, + "Failed to find the following absolute limit(s)" + " in a fetched list: %s" % + ', '.join(str(a) for a in missing_abs_limit)) diff --git a/trove/tests/tempest/tests/api/database/versions/__init__.py b/trove/tests/tempest/tests/api/database/versions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trove/tests/tempest/tests/api/database/versions/test_versions.py b/trove/tests/tempest/tests/api/database/versions/test_versions.py new file mode 100644 index 00000000..53eb7c32 --- /dev/null +++ b/trove/tests/tempest/tests/api/database/versions/test_versions.py @@ -0,0 +1,41 @@ +# Copyright 2014 OpenStack Foundation +# 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 tempest.lib import decorators +from testtools import testcase as testtools + +from trove.tests.tempest.tests.api.database import base + + +class DatabaseVersionsTest(base.BaseDatabaseTest): + + @classmethod + def setup_clients(cls): + super(DatabaseVersionsTest, cls).setup_clients() + cls.client = cls.database_versions_client + + @testtools.attr('smoke') + @decorators.idempotent_id('6952cd77-90cd-4dca-bb60-8e2c797940cf') + def test_list_db_versions(self): + versions = self.client.list_db_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 + current_versions = list() + for version in versions: + if 'CURRENT' == version['status']: + current_versions.append(version['id']) + self.assertEqual(1, len(current_versions)) + self.assertIn(self.db_current_version, current_versions)