diff --git a/nimble/tests/tempest/__init__.py b/nimble/tests/tempest/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nimble/tests/tempest/api/__init__.py b/nimble/tests/tempest/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nimble/tests/tempest/api/base.py b/nimble/tests/tempest/api/base.py new file mode 100644 index 00000000..1c29c79d --- /dev/null +++ b/nimble/tests/tempest/api/base.py @@ -0,0 +1,64 @@ +# +# Copyright 2016 Huawei Technologies Co., Ltd. +# +# 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 +from tempest.lib import exceptions as lib_exc +import tempest.test + +from nimble.tests.tempest.service import client + +CONF = config.CONF + + +class BaseBaremetalComputeTest(tempest.test.BaseTestCase): + """Base test case class for all Baremetal Compute API tests.""" + + credentials = ['primary'] + client_manager = client.Manager + + @classmethod + def skip_checks(cls): + super(BaseBaremetalComputeTest, cls).skip_checks() + if not CONF.service_available.nimble_plugin: + raise cls.skipException("Nimble support is required") + + @classmethod + def setup_clients(cls): + super(BaseBaremetalComputeTest, cls).setup_clients() + cls.baremetal_compute_client = cls.os.baremetal_compute_client + + @classmethod + def resource_setup(cls): + super(BaseBaremetalComputeTest, cls).resource_setup() + cls.type_ids = [] + cls.instance_ids = [] + + @staticmethod + def cleanup_resources(method, list_of_ids): + for resource_id in list_of_ids: + try: + method(resource_id) + except lib_exc.NotFound: + pass + + @classmethod + def resource_cleanup(cls): + cls.cleanup_resources( + cls.baremetal_compute_client.delete_instance_type, cls.type_ids) + # TODO(liusheng) + # cls.cleanup_resources(cls.baremetal_compute_client.delete_instance, + # cls.instance_ids) + super(BaseBaremetalComputeTest, cls).resource_cleanup() diff --git a/nimble/tests/tempest/api/test_instance_types.py b/nimble/tests/tempest/api/test_instance_types.py new file mode 100644 index 00000000..f37e94d9 --- /dev/null +++ b/nimble/tests/tempest/api/test_instance_types.py @@ -0,0 +1,75 @@ +# +# Copyright 2016 Huawei Technologies Co., Ltd. +# +# 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 six + +from tempest.common.utils import data_utils +from tempest.lib import exceptions as lib_exc +from tempest import test + +from nimble.tests.tempest.api import base + + +class BaremetalComputeAPITest(base.BaseBaremetalComputeTest): + + @classmethod + def resource_setup(cls): + super(BaremetalComputeAPITest, cls).resource_setup() + for i in six.moves.xrange(3): + body = {"name": data_utils.rand_name('nimble_instance_type'), + "description": "nimble instance type description", + 'is_public': bool(data_utils.rand_int_id(0, 1))} + resp = cls.baremetal_compute_client.create_instance_type(**body) + cls.type_ids.append(resp['uuid']) + + @test.idempotent_id('4b256d35-47a9-4195-8f7e-56ceb4ce4737') + def test_type_list(self): + # List instance types + type_list = self.baremetal_compute_client.list_instance_types() + + # Verify created instance type in the list + fetched_ids = [t['uuid'] for t in type_list] + missing_types = [a for a in self.type_ids if a not in fetched_ids] + self.assertEqual(0, len(missing_types), + "Failed to find the following created" + " instance_type(s) in a fetched list: %s" % + ', '.join(str(t) for t in missing_types)) + + @test.idempotent_id('f6ad64af-abc9-456c-9109-bc27cd9af635') + def test_type_create_show_delete(self): + # Create an instance type + body = {"name": 'nimble_type_create', + "description": "nimble instance type description", + 'is_public': True} + resp = self.baremetal_compute_client.create_instance_type(**body) + self.assertEqual('nimble_type_create', resp['name']) + self.assertEqual('nimble instance type description', + resp['description']) + self.assertEqual(True, resp['is_public']) + self.assertIn('uuid', resp) + self.assertIn('extra_specs', resp) + self.assertIn('links', resp) + resp = self.baremetal_compute_client.show_instance_type(resp['uuid']) + self.assertEqual('nimble_type_create', resp['name']) + self.assertEqual('nimble instance type description', + resp['description']) + self.assertEqual(True, resp['is_public']) + self.assertIn('uuid', resp) + self.assertIn('extra_specs', resp) + self.assertIn('links', resp) + self.baremetal_compute_client.delete_instance_type(resp['uuid']) + self.assertRaises(lib_exc.NotFound, + self.baremetal_compute_client.show_instance_type, + resp['uuid']) diff --git a/nimble/tests/tempest/config.py b/nimble/tests/tempest/config.py new file mode 100644 index 00000000..b819d23a --- /dev/null +++ b/nimble/tests/tempest/config.py @@ -0,0 +1,40 @@ +# +# Copyright 2012 OpenStack Foundation +# +# 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_available_group = cfg.OptGroup(name="service_available", + title="Available OpenStack Services") + +ServiceAvailableGroup = [ + cfg.BoolOpt("nimble_plugin", + default=True, + help="Whether or not Nimble is expected to be available"), +] + +baremetal_compute_group = cfg.OptGroup( + name='baremetal_compute_plugin', title='Baremetal compute Service Options') + +BaremetalComputeGroup = [ + cfg.StrOpt('catalog_type', + default='baremetal_compute', + help="Catalog type of the baremetal_compute service."), + cfg.StrOpt('endpoint_type', + default='publicURL', + choices=['public', 'admin', 'internal', + 'publicURL', 'adminURL', 'internalURL'], + help="The endpoint type to use for the baremetal_compute" + " service."), +] diff --git a/nimble/tests/tempest/plugin.py b/nimble/tests/tempest/plugin.py new file mode 100644 index 00000000..be800b8c --- /dev/null +++ b/nimble/tests/tempest/plugin.py @@ -0,0 +1,43 @@ +# +# Copyright 2015 NEC Corporation. +# +# 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 import config +from tempest.test_discover import plugins + +import nimble +from nimble.tests.tempest import config as tempest_config + + +class NimbleTempestPlugin(plugins.TempestPlugin): + def load_tests(self): + base_path = os.path.split(os.path.dirname( + os.path.abspath(nimble.__file__)))[0] + test_dir = "nimble/tests/tempest" + full_test_dir = os.path.join(base_path, test_dir) + return full_test_dir, base_path + + def register_opts(self, conf): + config.register_opt_group(conf, + tempest_config.service_available_group, + tempest_config.ServiceAvailableGroup) + config.register_opt_group(conf, + tempest_config.baremetal_compute_group, + tempest_config.BaremetalComputeGroup) + + def get_opt_lists(self): + return [(tempest_config.baremetal_compute_group.name, + tempest_config.BaremetalComputeGroup)] diff --git a/nimble/tests/tempest/service/__init__.py b/nimble/tests/tempest/service/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nimble/tests/tempest/service/client.py b/nimble/tests/tempest/service/client.py new file mode 100644 index 00000000..ad29be5f --- /dev/null +++ b/nimble/tests/tempest/service/client.py @@ -0,0 +1,89 @@ +# 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 tempest import config +from tempest.lib.common import rest_client +from tempest import manager + +CONF = config.CONF + + +class BaremetalComputeClient(rest_client.RestClient): + version = '1' + # TODO(liusheng) since the endpoints of Nimble includes '/v1', + # here we shouldn't add this, may remove the 'v1' in endpoint urls + # uri_prefix = "v1" + uri_prefix = "" + + def deserialize(self, body): + return json.loads(body.replace("\n", "")) + + def serialize(self, body): + return json.dumps(body) + + def list_instance_types(self): + uri = '%s/types' % self.uri_prefix + resp, body = self.get(uri) + self.expected_success(200, resp.status) + body = self.deserialize(body)['types'] + return rest_client.ResponseBodyList(resp, body) + + def show_instance_type(self, type_id): + uri = '%s/types/%s' % (self.uri_prefix, type_id) + resp, body = self.get(uri) + self.expected_success(200, resp.status) + body = self.deserialize(body) + return rest_client.ResponseBody(resp, body) + + def delete_instance_type(self, type_id): + uri = "%s/types/%s" % (self.uri_prefix, type_id) + resp, body = self.delete(uri) + self.expected_success(204, resp.status) + if body: + body = self.deserialize(body) + return rest_client.ResponseBody(resp, body) + + def create_instance_type(self, **kwargs): + uri = "%s/types" % self.uri_prefix + body = self.serialize(kwargs) + resp, body = self.post(uri, body) + self.expected_success(201, resp.status) + body = self.deserialize(body) + return rest_client.ResponseBody(resp, body) + + +class Manager(manager.Manager): + default_params = { + 'disable_ssl_certificate_validation': + CONF.identity.disable_ssl_certificate_validation, + 'ca_certs': CONF.identity.ca_certificates_file, + 'trace_requests': CONF.debug.trace_requests + } + + alarming_params = { + 'service': CONF.baremetal_compute_plugin.catalog_type, + 'region': CONF.identity.region, + 'endpoint_type': CONF.baremetal_compute_plugin.endpoint_type, + } + alarming_params.update(default_params) + + def __init__(self, credentials=None, service=None): + super(Manager, self).__init__(credentials) + self.set_baremetal_compute_client() + + def set_baremetal_compute_client(self): + self.baremetal_compute_client = BaremetalComputeClient( + self.auth_provider, **self.alarming_params) diff --git a/setup.cfg b/setup.cfg index b0b58a2f..6ca54dbd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,6 +45,9 @@ console_scripts = nimble.database.migration_backend = sqlalchemy = nimble.db.sqlalchemy.migration +tempest.test_plugins = + nimble_tests = nimble.tests.tempest.plugin:NimbleTempestPlugin + [build_sphinx] source-dir = doc/source build-dir = doc/build diff --git a/test-requirements.txt b/test-requirements.txt index 44e65206..61b364ea 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -18,3 +18,4 @@ sphinxcontrib-pecanwsme>=0.8 # Apache-2.0 sphinxcontrib-seqdiag # BSD reno>=1.8.0 # Apache-2.0 os-api-ref>=1.0.0 # Apache-2.0 +tempest>=12.1.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini index 783dcaa3..697e84f9 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,7 @@ usedevelop = True install_command = {[testenv:common-constraints]install_command} setenv = VIRTUAL_ENV={envdir} + OS_TEST_PATH=nimble/tests/unit deps = -r{toxinidir}/test-requirements.txt commands = python setup.py test --slowest --testr-args='{posargs}'