diff --git a/zun_tempest_plugin/tests/tempest/api/clients.py b/zun_tempest_plugin/tests/tempest/api/clients.py index f7965a0..e7166e2 100644 --- a/zun_tempest_plugin/tests/tempest/api/clients.py +++ b/zun_tempest_plugin/tests/tempest/api/clients.py @@ -17,6 +17,7 @@ from tempest.lib.services.compute import keypairs_client from tempest import manager from zun.tests.tempest.api.models import container_model +from zun.tests.tempest.api.models import service_model CONF = config.CONF @@ -72,6 +73,13 @@ class ZunClient(rest_client.RestClient): """ return "{0}/{1}".format(cls.containers_uri(), container_id) + @classmethod + def services_uri(cls, filters=None): + url = "/services/" + if filters: + url = cls.add_filters(url, filters) + return url + def post_container(self, model, **kwargs): """Makes POST /container request @@ -92,3 +100,8 @@ class ZunClient(rest_client.RestClient): def delete_container(self, container_id, **kwargs): self.delete(self.container_uri(container_id), **kwargs) + + def list_services(self, filters=None, **kwargs): + resp, body = self.get(self.services_uri(filters), **kwargs) + return self.deserialize(resp, body, + service_model.ServiceCollection) diff --git a/zun_tempest_plugin/tests/tempest/api/common/datagen.py b/zun_tempest_plugin/tests/tempest/api/common/datagen.py index efa9701..6844fc7 100644 --- a/zun_tempest_plugin/tests/tempest/api/common/datagen.py +++ b/zun_tempest_plugin/tests/tempest/api/common/datagen.py @@ -47,7 +47,7 @@ def gen_url(scheme="http", domain="example.com", port=80): return "%s://%s:%s" % (scheme, domain, port) -def contaienr_data(**kwargs): +def container_data(**kwargs): data = { 'name': data_utils.rand_name('container'), 'image': 'cirros:latest', diff --git a/zun_tempest_plugin/tests/tempest/api/models/service_model.py b/zun_tempest_plugin/tests/tempest/api/models/service_model.py new file mode 100644 index 0000000..13ae608 --- /dev/null +++ b/zun_tempest_plugin/tests/tempest/api/models/service_model.py @@ -0,0 +1,30 @@ +# 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 zun.tests.tempest.api.common import base_model + + +class ServiceData(base_model.BaseModel): + """Data that encapsulates service attributes""" + pass + + +class ServiceEntity(base_model.EntityModel): + """Entity Model that represents a single instance of ServiceData""" + ENTITY_NAME = 'service' + MODEL_TYPE = ServiceData + + +class ServiceCollection(base_model.CollectionModel): + """Collection Model that represents a list of ServiceData objects""" + COLLECTION_NAME = 'servicelists' + MODEL_TYPE = ServiceData diff --git a/zun_tempest_plugin/tests/tempest/api/test_containers.py b/zun_tempest_plugin/tests/tempest/api/test_containers.py index 5702d62..2088473 100644 --- a/zun_tempest_plugin/tests/tempest/api/test_containers.py +++ b/zun_tempest_plugin/tests/tempest/api/test_containers.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import time + from tempest.lib import decorators from zun.tests.tempest.api import clients @@ -43,12 +45,32 @@ class TestContainer(base.BaseZunTest): def _create_container(self, **kwargs): - model = datagen.contaienr_data(**kwargs) + model = datagen.container_data(**kwargs) return self.container_client.post_container(model) - def _delete_container(self, container_id): + def _delete_container(self, container_id, **kwargs): - self.container_client.delete_container(container_id) + self.container_client.delete_container(container_id, **kwargs) + + def _wait_on_creation(self, container_id, timeout=60): + def _check_status(): + resp, model = self.container_client.get_container(container_id) + status = model.status + if status == 'Creating': + return False + else: + return True + time.sleep(1) + start_time = time.time() + end_time = time.time() + timeout + while time.time() < end_time: + result = _check_status() + if result: + return result + time.sleep(1) + raise Exception(("Timed out after %s seconds. Started " + + "on %s and ended on %s") % (timeout, start_time, + end_time)) @decorators.idempotent_id('a04f61f2-15ae-4200-83b7-1f311b101f35') def test_container_create_list_delete(self): @@ -59,11 +81,11 @@ class TestContainer(base.BaseZunTest): resp, model = self.container_client.list_containers() self.assertEqual(200, resp.status) self.assertGreater(len(model.containers), 0) + # NOTE(mkrai): Check and wait for container creation to get over + self._wait_on_creation(container.uuid) - # Fixme(eliqiao): Currently, zun don't allow delete a container in - # Creating status, API will raise 409, this should be wrong. - # self._delete_container(container.uuid) + self._delete_container(container.uuid, headers={'force': True}) - # resp, model = self.container_client.list_containers() - # self.assertEqual(200, resp.status) - # self.assertEqual(len(model.containers), 0) + resp, model = self.container_client.list_containers() + self.assertEqual(200, resp.status) + self.assertEqual(len(model.containers), 0) diff --git a/zun_tempest_plugin/tests/tempest/api/test_services.py b/zun_tempest_plugin/tests/tempest/api/test_services.py new file mode 100644 index 0000000..0896d91 --- /dev/null +++ b/zun_tempest_plugin/tests/tempest/api/test_services.py @@ -0,0 +1,52 @@ +# 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 zun.tests.tempest.api import clients +from zun.tests.tempest import base + + +class TestService(base.BaseZunTest): + + @classmethod + def get_client_manager(cls, credential_type=None, roles=None, + force_new=None): + + manager = super(TestService, cls).get_client_manager( + credential_type=credential_type, + roles=roles, + force_new=force_new + ) + return clients.Manager(manager.credentials) + + @classmethod + def setup_clients(cls): + + super(TestService, cls).setup_clients() + cls.container_client = cls.os.container_client + + @classmethod + def resource_setup(cls): + + super(TestService, cls).resource_setup() + + @decorators.idempotent_id('a04f61f2-15ae-4200-83b7-1f311b101f36') + def test_service_list(self): + resp, model = self.container_client.list_services() + self.assertEqual(200, resp.status) + self.assertEqual(len(model.services), 1) + zun_comp = model.services[0] + self.assertEqual(zun_comp['id'], 1) + self.assertEqual('up', zun_comp['state']) + self.assertEqual('zun-compute', zun_comp['binary']) + self.assertGreater(zun_comp['report_count'], 0)