tempest: migrate api and scnario tests from tempest

tempest: use ceilometer client manager instead of tempest one

This patch replaces client manager used in base test class from tempest
one to ceilometer dedicated manager which only has clients necessary to
specific ceilometer test cases.

The conflicts in config parameter are solved by adding '_plugin' in
paramter names as suffix.

This patch also includes the following changes in tempest.

  - Ie99bbbe7655138c4c3ecae69ae0b361198a9651d
  - I340d96c27f0e906df5b8a109494920e9cd3b21d1
  - I14e16a1a7d9813b324ee40545c07f0e88fb637b7

Closes-Bug: 1549424
Depends-On: Ifc29617743b76b01eb6cd30a375cf47b56e4f635
Implements: blueprint tempest-plugin
Change-Id: Ifbe3152c486ddba79bb851c0ec3097213975f95c
This commit is contained in:
Ryota MIBU 2015-12-10 15:54:38 +09:00
parent 7b3712eb50
commit 6238c3be39
8 changed files with 458 additions and 131 deletions

View File

@ -13,27 +13,43 @@
import time
from oslo_utils import timeutils
from tempest_lib import exceptions as lib_exc
from tempest.common import compute
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
from tempest.lib import exceptions as lib_exc
import tempest.test
from ceilometer.tests.tempest.service import client
CONF = config.CONF
class ClientManager(client.Manager):
load_clients = [
'servers_client',
'compute_networks_client',
'compute_floating_ips_client',
'flavors_client',
'image_client',
'image_client_v2',
'telemetry_client',
]
class BaseTelemetryTest(tempest.test.BaseTestCase):
"""Base test case class for all Telemetry API tests."""
credentials = ['primary']
client_manager = ClientManager
@classmethod
def skip_checks(cls):
super(BaseTelemetryTest, cls).skip_checks()
if not CONF.service_available.ceilometer:
if not CONF.service_available.ceilometer_plugin:
raise cls.skipException("Ceilometer support is required")
@classmethod
@ -44,11 +60,11 @@ class BaseTelemetryTest(tempest.test.BaseTestCase):
@classmethod
def setup_clients(cls):
super(BaseTelemetryTest, cls).setup_clients()
cls.telemetry_client = cls.os.telemetry_client
cls.servers_client = cls.os.servers_client
cls.flavors_client = cls.os.flavors_client
cls.image_client = cls.os.image_client
cls.image_client_v2 = cls.os.image_client_v2
cls.telemetry_client = cls.os_primary.telemetry_client
cls.servers_client = cls.os_primary.servers_client
cls.flavors_client = cls.os_primary.flavors_client
cls.image_client = cls.os_primary.image_client
cls.image_client_v2 = cls.os_primary.image_client_v2
@classmethod
def resource_setup(cls):
@ -67,7 +83,7 @@ class BaseTelemetryTest(tempest.test.BaseTestCase):
def create_server(cls):
tenant_network = cls.get_tenant_network()
body, server = compute.create_test_server(
cls.os,
cls.os_primary,
tenant_network=tenant_network,
name=data_utils.rand_name('ceilometer-instance'),
wait_until='ACTIVE')
@ -75,10 +91,11 @@ class BaseTelemetryTest(tempest.test.BaseTestCase):
return body
@classmethod
def create_image(cls, client):
body = client.create_image(
data_utils.rand_name('image'), container_format='bare',
disk_format='raw', visibility='private')
def create_image(cls, client, **kwargs):
body = client.create_image(name=data_utils.rand_name('image'),
container_format='bare',
disk_format='raw',
**kwargs)
# TODO(jswarren) Move ['image'] up to initial body value assignment
# once both v1 and v2 glance clients include the full response
# object.

View File

@ -0,0 +1,87 @@
# 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.
# Change-Id: I14e16a1a7d9813b324ee40545c07f0e88fb637b7
import testtools
from ceilometer.tests.tempest.api import base
from tempest import config
from tempest.lib import decorators
from tempest import test
CONF = config.CONF
class TelemetryNotificationAPITest(base.BaseTelemetryTest):
@test.idempotent_id('d7f8c1c8-d470-4731-8604-315d3956caae')
@test.services('compute')
def test_check_nova_notification(self):
body = self.create_server()
query = ('resource', 'eq', body['id'])
for metric in self.nova_notifications:
self.await_samples(metric, query)
@test.attr(type="smoke")
@test.idempotent_id('04b10bfe-a5dc-47af-b22f-0460426bf499')
@test.services("image")
@testtools.skipIf(not CONF.image_feature_enabled.api_v1,
"Glance api v1 is disabled")
def test_check_glance_v1_notifications(self):
body = self.create_image(self.image_client, is_public=False)
self.image_client.update_image(body['id'], data='data')
query = 'resource', 'eq', body['id']
self.image_client.delete_image(body['id'])
for metric in self.glance_notifications:
self.await_samples(metric, query)
@test.attr(type="smoke")
@test.idempotent_id('c240457d-d943-439b-8aea-85e26d64fe8f')
@test.services("image")
@testtools.skipIf(not CONF.image_feature_enabled.api_v2,
"Glance api v2 is disabled")
def test_check_glance_v2_notifications(self):
body = self.create_image(self.image_client_v2, visibility='private')
self.image_client_v2.store_image_file(body['id'], "file")
self.image_client_v2.show_image_file(body['id'])
query = 'resource', 'eq', body['id']
for metric in self.glance_v2_notifications:
self.await_samples(metric, query)
class TelemetryNotificationAdminAPITest(base.BaseTelemetryAdminTest):
@test.idempotent_id('29604198-8b45-4fc0-8af8-1cae4f94ebea')
@test.services('compute')
@decorators.skip_because(bug='1480490')
def test_check_nova_notification_event_and_meter(self):
body = self.create_server()
if CONF.telemetry_plugin.event_enabled:
query = ('instance_id', 'eq', body['id'])
self.await_events(query)
query = ('resource', 'eq', body['id'])
for metric in self.nova_notifications:
self.await_samples(metric, query)

View File

@ -1,116 +0,0 @@
# 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.common import service_client
from tempest import config
from tempest import manager
CONF = config.CONF
class TelemetryClient(service_client.ServiceClient):
version = '2'
uri_prefix = "v2"
def deserialize(self, body):
return json.loads(body.replace("\n", ""))
def serialize(self, body):
return json.dumps(body)
def add_sample(self, sample_list, meter_name, meter_unit, volume,
sample_type, resource_id, **kwargs):
sample = {"counter_name": meter_name, "counter_unit": meter_unit,
"counter_volume": volume, "counter_type": sample_type,
"resource_id": resource_id}
for key in kwargs:
sample[key] = kwargs[key]
sample_list.append(self.serialize(sample))
return sample_list
def create_sample(self, meter_name, sample_list):
uri = "%s/meters/%s" % (self.uri_prefix, meter_name)
body = self.serialize(sample_list)
resp, body = self.post(uri, body)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return service_client.ResponseBody(resp, body)
def _helper_list(self, uri, query=None, period=None):
uri_dict = {}
if query:
uri_dict = {'q.field': query[0],
'q.op': query[1],
'q.value': query[2]}
if period:
uri_dict['period'] = period
if uri_dict:
uri += "?%s" % urllib.urlencode(uri_dict)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return service_client.ResponseBodyList(resp, body)
def list_resources(self, query=None):
uri = '%s/resources' % self.uri_prefix
return self._helper_list(uri, query)
def list_meters(self, query=None):
uri = '%s/meters' % self.uri_prefix
return self._helper_list(uri, query)
def list_statistics(self, meter, period=None, query=None):
uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
return self._helper_list(uri, query, period)
def list_samples(self, meter_id, query=None):
uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
return self._helper_list(uri, query)
def list_events(self, query=None):
uri = '%s/events' % self.uri_prefix
return self._helper_list(uri, query)
def show_resource(self, resource_id):
uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return service_client.ResponseBody(resp, body)
class Manager(manager.Manager):
def __init__(self, credentials=None, service=None):
super(Manager, self).__init__(credentials, service)
self._set_telemetry_client()
def _set_telemetry_client(self):
if CONF.service_available.ceilometer:
self.telemetry_client = TelemetryClient(
self.auth_provider,
CONF.telemetry.catalog_type,
CONF.identity.region,
endpoint_type=CONF.telemetry.endpoint_type,
disable_ssl_certificate_validation=(
CONF.identity.disable_ssl_certificate_validation),
ca_certs=CONF.identity.ca_certificates_file,
trace_requests=CONF.debug.trace_requests)

View File

@ -20,12 +20,12 @@ service_available_group = cfg.OptGroup(name="service_available",
title="Available OpenStack Services")
ServiceAvailableGroup = [
cfg.BoolOpt('ceilometer',
cfg.BoolOpt('ceilometer_plugin',
default=True,
help="Whether or not Ceilometer is expected to be available"),
]
telemetry_group = cfg.OptGroup(name='telemetry',
telemetry_group = cfg.OptGroup(name='telemetry_plugin',
title='Telemetry Service Options')
TelemetryGroup = [
@ -37,4 +37,7 @@ TelemetryGroup = [
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for the telemetry service."),
cfg.BoolOpt('event_enabled',
default=True,
help="Runs Ceilometer event-related tests"),
]

View File

@ -0,0 +1,146 @@
# Copyright 2014 Red Hat
#
# 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_log import log as logging
from tempest.common.utils import data_utils
from tempest import config
from tempest import test
from ceilometer.tests.tempest.service import client
CONF = config.CONF
LOG = logging.getLogger(__name__)
# Loop for up to 120 seconds waiting on notifications
# NOTE(chdent): The choice of 120 seconds is fairly
# arbitrary: Long enough to give the notifications the
# chance to travel across a highly latent bus but not
# so long as to allow excessive latency to never be visible.
# TODO(chdent): Ideally this value would come from configuration.
NOTIFICATIONS_WAIT = 120
NOTIFICATIONS_SLEEP = 1
class ClientManager(client.Manager):
load_clients = [
'telemetry_client',
'container_client',
'object_client',
]
class TestObjectStorageTelemetry(test.BaseTestCase):
"""Test that swift uses the ceilometer middleware.
* create container.
* upload a file to the created container.
* retrieve the file from the created container.
* wait for notifications from ceilometer.
"""
credentials = ['primary']
client_manager = ClientManager
@classmethod
def skip_checks(cls):
super(TestObjectStorageTelemetry, cls).skip_checks()
if not CONF.service_available.swift:
skip_msg = ("%s skipped as swift is not available" %
cls.__name__)
raise cls.skipException(skip_msg)
if not CONF.service_available.ceilometer_plugin:
skip_msg = ("%s skipped as ceilometer is not available" %
cls.__name__)
raise cls.skipException(skip_msg)
@classmethod
def setup_credentials(cls):
cls.set_network_resources()
super(TestObjectStorageTelemetry, cls).setup_credentials()
@classmethod
def setup_clients(cls):
super(TestObjectStorageTelemetry, cls).setup_clients()
cls.telemetry_client = cls.os_primary.telemetry_client
cls.container_client = cls.os_primary.container_client
cls.object_client = cls.os_primary.object_client
def _confirm_notifications(self, container_name, obj_name):
# NOTE: Loop seeking for appropriate notifications about the containers
# and objects sent to swift.
def _check_samples():
# NOTE: Return True only if we have notifications about some
# containers and some objects and the notifications are about
# the expected containers and objects.
# Otherwise returning False will case _check_samples to be
# called again.
results = self.telemetry_client.list_samples(
'storage.objects.incoming.bytes')
LOG.debug('got samples %s', results)
# Extract container info from samples.
containers, objects = [], []
for sample in results:
meta = sample['resource_metadata']
if meta.get('container') and meta['container'] != 'None':
containers.append(meta['container'])
elif (meta.get('target.metadata:container') and
meta['target.metadata:container'] != 'None'):
containers.append(meta['target.metadata:container'])
if meta.get('object') and meta['object'] != 'None':
objects.append(meta['object'])
elif (meta.get('target.metadata:object') and
meta['target.metadata:object'] != 'None'):
objects.append(meta['target.metadata:object'])
return (container_name in containers and obj_name in objects)
self.assertTrue(test.call_until_true(_check_samples,
NOTIFICATIONS_WAIT,
NOTIFICATIONS_SLEEP),
'Correct notifications were not received after '
'%s seconds.' % NOTIFICATIONS_WAIT)
def create_container(self):
name = data_utils.rand_name('swift-scenario-container')
self.container_client.create_container(name)
# look for the container to assure it is created
self.container_client.list_container_contents(name)
LOG.debug('Container %s created' % (name))
self.addCleanup(self.container_client.delete_container,
name)
return name
def upload_object_to_container(self, container_name):
obj_name = data_utils.rand_name('swift-scenario-object')
obj_data = data_utils.arbitrary_string()
self.object_client.create_object(container_name, obj_name, obj_data)
self.addCleanup(self.object_client.delete_object,
container_name,
obj_name)
return obj_name
@test.idempotent_id('6d6b88e5-3e38-41bc-b34a-79f713a6cb85')
@test.services('object_storage', 'telemetry')
def test_swift_middleware_notifies(self):
container_name = self.create_container()
obj_name = self.upload_object_to_container(container_name)
self._confirm_notifications(container_name, obj_name)

View File

@ -0,0 +1,190 @@
# 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 import config
from tempest.lib.common import rest_client
from tempest.lib.services.compute.flavors_client import FlavorsClient
from tempest.lib.services.compute.floating_ips_client import FloatingIPsClient
from tempest.lib.services.compute.networks_client import NetworksClient
from tempest.lib.services.compute.servers_client import ServersClient
from tempest import manager
from tempest.services.image.v1.json.images_client import ImagesClient
from tempest.services.image.v2.json.images_client import ImagesClientV2
from tempest.services.object_storage.container_client import ContainerClient
from tempest.services.object_storage.object_client import ObjectClient
CONF = config.CONF
class TelemetryClient(rest_client.RestClient):
version = '2'
uri_prefix = "v2"
def deserialize(self, body):
return json.loads(body.replace("\n", ""))
def serialize(self, body):
return json.dumps(body)
def create_sample(self, meter_name, sample_list):
uri = "%s/meters/%s" % (self.uri_prefix, meter_name)
body = self.serialize(sample_list)
resp, body = self.post(uri, body)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
def _helper_list(self, uri, query=None, period=None):
uri_dict = {}
if query:
uri_dict = {'q.field': query[0],
'q.op': query[1],
'q.value': query[2]}
if period:
uri_dict['period'] = period
if uri_dict:
uri += "?%s" % urllib.urlencode(uri_dict)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return rest_client.ResponseBodyList(resp, body)
def list_resources(self, query=None):
uri = '%s/resources' % self.uri_prefix
return self._helper_list(uri, query)
def list_meters(self, query=None):
uri = '%s/meters' % self.uri_prefix
return self._helper_list(uri, query)
def list_statistics(self, meter, period=None, query=None):
uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
return self._helper_list(uri, query, period)
def list_samples(self, meter_id, query=None):
uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
return self._helper_list(uri, query)
def list_events(self, query=None):
uri = '%s/events' % self.uri_prefix
return self._helper_list(uri, query)
def show_resource(self, resource_id):
uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
class Manager(manager.Manager):
load_clients = [
'servers_client',
'compute_networks_client',
'compute_floating_ips_client',
'flavors_client',
'image_client',
'image_client_v2',
'telemetry_client',
'container_client',
'object_client',
]
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
}
compute_params = {
'service': CONF.compute.catalog_type,
'region': CONF.compute.region or CONF.identity.region,
'endpoint_type': CONF.compute.endpoint_type,
'build_interval': CONF.compute.build_interval,
'build_timeout': CONF.compute.build_timeout,
}
compute_params.update(default_params)
image_params = {
'catalog_type': CONF.image.catalog_type,
'region': CONF.image.region or CONF.identity.region,
'endpoint_type': CONF.image.endpoint_type,
'build_interval': CONF.image.build_interval,
'build_timeout': CONF.image.build_timeout,
}
image_params.update(default_params)
telemetry_params = {
'service': CONF.telemetry_plugin.catalog_type,
'region': CONF.identity.region,
'endpoint_type': CONF.telemetry_plugin.endpoint_type,
}
telemetry_params.update(default_params)
object_storage_params = {
'service': CONF.object_storage.catalog_type,
'region': CONF.object_storage.region or CONF.identity.region,
'endpoint_type': CONF.object_storage.endpoint_type
}
object_storage_params.update(default_params)
def __init__(self, credentials=None, service=None):
super(Manager, self).__init__(credentials)
for client in self.load_clients:
getattr(self, 'set_%s' % client)()
def set_servers_client(self):
self.servers_client = ServersClient(self.auth_provider,
**self.compute_params)
def set_compute_networks_client(self):
self.compute_networks_client = NetworksClient(self.auth_provider,
**self.compute_params)
def set_compute_floating_ips_client(self):
self.compute_floating_ips_client = FloatingIPsClient(
self.auth_provider,
**self.compute_params)
def set_flavors_client(self):
self.flavors_client = FlavorsClient(self.auth_provider,
**self.compute_params)
def set_image_client(self):
self.image_client = ImagesClient(self.auth_provider,
**self.image_params)
def set_image_client_v2(self):
self.image_client_v2 = ImagesClientV2(self.auth_provider,
**self.image_params)
def set_telemetry_client(self):
self.telemetry_client = TelemetryClient(self.auth_provider,
**self.telemetry_params)
def set_container_client(self):
self.container_client = ContainerClient(self.auth_provider,
**self.object_storage_params)
def set_object_client(self):
self.object_client = ObjectClient(self.auth_provider,
**self.object_storage_params)