Add Monasca Tempest Tests

To run the tests see monasca_tempest_tests/README.md.

Change-Id: I7d1df1b88b63ccc2f1a66deaf439c032b1175d99
This commit is contained in:
Roland Hochmuth 2015-09-26 00:10:43 -06:00 committed by Kaiyan Sheng
parent f4d1ce149d
commit dc4a8868ae
24 changed files with 2788 additions and 4 deletions

View File

@ -2,7 +2,7 @@
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover monasca_api $LISTOPT $IDOPTION
${PYTHON:-python} -m subunit.run discover -t . ./monasca_api/tests $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -0,0 +1,102 @@
# Introduction
The Monasca Tempest Tests use the [OpenStack Tempest Plugin Interface](http://docs.openstack.org/developer/tempest/plugin.html). This README describes how to configure and run them using a variety of methods.
Currently monasca-vagrant is used to run tests. This document will be updated when switch the environment to DevStack.
# Configuring to run the Monasca Tempest Tests
1. Clone the OpenStack Tempest repo, and cd to it.
```
git clone https://github.com/openstack/tempest.git
cd tempest
```
2. Create a virtualenv for running the Tempest tests and activate it. For example in the Tempest root dir
```
virtualenv .venv
source .venv/bin/activate
```
3. Install the Tempest requirements in the virtualenv.
```
pip install -r requirements.txt -r test-requirements.txt
pip install nose
```
4. Create ```etc/tempest.conf``` and ```etc/logging.conf``` in the Tempest root dir. I believe the file ```etc/tempest.conf.sample``` can be copied to ```etc/tempest.conf```. Similarly for ```logging.conf```. Add the following sections to ```tempest.conf``` for testing using the monasca-vagrant environment.
```
[identity]
username = mini-mon
password = password
tenant_name = mini-mon
domain_name = default
admin_username = admin
admin_password = admin
admin_domain_name = default
admin_tenant_name = admin
alt_username = mini-mon
alt_password = password
alt_tenant_name = mini-mon
use_ssl = False
auth_version = v3
uri = http://192.168.10.5:5000/v2.0/
uri_v3 = http://192.168.10.5:35357/v3/
[auth]
allow_tenant_isolation = true
tempest_roles = monasca-user
```
5. Clone the monasca-api repo.
6. Install the monasca-api in your venv, which will also register
the Monasca Tempest Plugin as, monasca_tests.
```
python setup.py install
```
See the [OpenStack Tempest Plugin Interface](http://docs.openstack.org/developer/tempest/plugin.html), for more details on Tempest Plugins and the plugin registration process.
# Running the Monasca Tempest Tests
The Monasca Tempest Tests can be run using a variety of methods including:
1. [Testr](https://wiki.openstack.org/wiki/Testr)
2. [Os-testr](http://docs.openstack.org/developer/os-testr/)
3. [PyCharm]([Os-testr](https://www.jetbrains.com/pycharm/)
## Run the tests from the CLI using testr
[Testr](https://wiki.openstack.org/wiki/Testr) is a test runner that can be used to run the Tempest tests.
1. In the Tempest root dir, create a list of the Monasca Tempest Tests in a file.
```
testr list-tests monasca_tempest_tests > monasca_tempest_tests
```
2. Run the tests using testr
```
testr run --load-list=monasca_tempest_tests
```
You can also use testr to create a list of specific tests for your needs.
## Run the tests from the CLI using os-testr (no file necessary)
[Os-testr](http://docs.openstack.org/developer/os-testr/) is a test wrapper that can be used to run the Monasca Tempest tests.
In the Tempest root dir:
```
ostestr --regex monasca_tempest_tests
```
## Running/Debugging the Monasca Tempest Tests in PyCharm
Assuming that you have already created a PyCharm project for the ```monasca-api``` do the following:
1. In PyCharm, Edit Configurations and add a new Python tests configuration by selecting Python tests->Nosetests.
2. Name the test. For example TestVersions.
3. Set the path to the script with the tests to run. For example, ~/repos/monasca-api/monasca_tempest_tests/api/test_versions.py
4. Set the name of the Class to test. For example TestVersions.
5. Set the working directory to your local root Tempest repo. For example, ~/repos/tempest.
6. Select the Python interpreter for your project to be the same as the one virtualenv created above. For example, ~/repos/tempest/.venv
7. Run the tests. You should also be able to debug them.
8. Step and repeat for other tests.
# References
This section provides a few additional references that might be useful:
* [Tempest - The OpenStack Integration Test Suite](http://docs.openstack.org/developer/tempest/overview.html#quickstart)
* [Tempest Configuration Guide](https://github.com/openstack/tempest/blob/master/doc/source/configuration.rst#id1)
* [OpenStack Tempest Plugin Interface](http://docs.openstack.org/developer/tempest/plugin.html)
In addition to the above references, another source of information is the following OpenStack projects:
* [Manila Tempest Tests](https://github.com/openstack/manila/tree/master/manila_tempest_tests)
* [Congress Tempest Tests](https://github.com/openstack/congress/tree/master/congress_tempest_tests).
In particular, the Manila Tempest Tests were used as a reference implementation to develop the Monasca Tempest Tests. There is also a wiki [HOWTO use tempest with manila](https://wiki.openstack.org/wiki/Manila/docs/HOWTO_use_tempest_with_manila) that might be useful for Monasca too.
# Issues
* Update documentation for testing using Devstack when available.
* Consider changing from monasca_tempest_tests to monasca_api_tempest_tests.

View File

View File

@ -0,0 +1,23 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 clients
from monasca_tempest_tests.services import monasca_client
class Manager(clients.Manager):
def __init__(self, credentials=None, service=None):
super(Manager, self).__init__(credentials, service)
self.monasca_client = monasca_client.MonascaClient(self.auth_provider)

View File

@ -0,0 +1,45 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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("monasca",
default=True,
help="Whether or not Monasca is expected to be available"),
]
monitoring_group = cfg.OptGroup(name="monitoring",
title="Monitoring Service Options")
MonitoringGroup = [
cfg.StrOpt("region",
default="",
help="The monitoring region name to use. If empty, the value "
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
cfg.StrOpt("catalog_type",
default="monitoring",
help="Catalog type of the monitoring service."),
cfg.StrOpt('endpoint_type',
default='publicURL',
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for the monitoring service.")
]

View File

@ -0,0 +1,40 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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
from monasca_tempest_tests import config as config_monitoring
class MonascaTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = "monasca_tempest_tests/tests"
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, config_monitoring.service_available_group,
config_monitoring.ServiceAvailableGroup)
config.register_opt_group(conf, config_monitoring.monitoring_group,
config_monitoring.MonitoringGroup)
def get_opt_lists(self):
return [(config_monitoring.monitoring_group.name,
config_monitoring.MonitoringGroup)]

View File

@ -0,0 +1,275 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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
CONF = config.CONF
class MonascaClient(rest_client.RestClient):
def __init__(self, auth_provider):
super(MonascaClient, self).__init__(
auth_provider,
CONF.monitoring.catalog_type,
CONF.monitoring.region or CONF.identity.region,
endpoint_type=CONF.monitoring.endpoint_type)
def get_version(self):
resp, response_body = self.get('')
return resp, response_body
def create_metrics(self, metrics):
uri = 'metrics'
request_body = json.dumps(metrics)
resp, response_body = self.post(uri, request_body)
return resp, response_body
def list_metrics(self, query_params=None):
uri = 'metrics'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def list_metrics_names(self, query_params=None):
uri = 'metrics/names'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def list_measurements(self, query_params=None):
uri = 'metrics/measurements'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def list_statistics(self, query_params=None):
uri = 'metrics/statistics'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def create_notifications(self, notification):
uri = 'notification-methods'
request_body = json.dumps(notification)
resp, response_body = self.post(uri, request_body)
return resp, json.loads(response_body)
def create_notification_method(self,
name=None,
type=None,
address=None):
uri = 'notification-methods'
request_body = {}
if name is not None:
request_body['name'] = name
if type is not None:
request_body['type'] = type
if address is not None:
request_body['address'] = address
resp, response_body = self.post(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def delete_notification_method(self, id):
uri = 'notification-methods/' + id
resp, response_body = self.delete(uri)
return resp, response_body
def get_notification_method(self, id):
uri = 'notification-methods/' + id
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def list_notification_methods(self, query_params=None):
uri = 'notification-methods'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def update_notification_method(self,
id,
name=None,
type=None,
address=None):
uri = 'notification-methods/' + id
request_body = {}
if name is not None:
request_body['name'] = name
if type is not None:
request_body['type'] = type
if address is not None:
request_body['address'] = address
resp, response_body = self.put(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def create_alarm_definitions(self, alarm_definitions):
uri = 'alarm-definitions'
request_body = json.dumps(alarm_definitions)
resp, response_body = self.post(uri, request_body)
return resp, json.loads(response_body)
def list_alarm_definitions(self, query_params=None):
uri = 'alarm-definitions'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def get_alarm_definition(self, id):
uri = 'alarm-definitions/' + id
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def delete_alarm_definition(self, id):
uri = 'alarm-definitions/' + id
resp, response_body = self.delete(uri)
return resp, response_body
def update_alarm_definition(self, id, name, expression, description=None,
actions_enabled=None, match_by=None,
severity=None, alarm_actions=None,
ok_actions=None, undetermined_actions=None,
**kwargs):
uri = 'alarm-definitions/' + id
request_body = {}
request_body['name'] = name
request_body['expression'] = expression
if description is not None:
request_body['description'] = description
if actions_enabled is not None:
request_body['actions_enabled'] = actions_enabled
if match_by is not None:
request_body['match_by'] = match_by
if severity is not None:
request_body['severity'] = severity
if alarm_actions is not None:
request_body['alarm_actions'] = alarm_actions
if ok_actions is not None:
request_body['ok_actions'] = ok_actions
if undetermined_actions is not None:
request_body['undetermined_actions'] = undetermined_actions
for key, value in kwargs.iteritems():
request_body[key] = value
resp, response_body = self.patch(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def patch_alarm_definition(self,
id,
name=None,
description=None,
expression=None,
actions_enabled=None,
match_by=None,
severity=None,
alarm_actions=None,
ok_actions=None,
undetermined_actions=None,
**kwargs):
uri = 'alarm-definitions/' + id
request_body = {}
if name is not None:
request_body['name'] = name
if description is not None:
request_body['description'] = description
if expression is not None:
request_body['expression'] = expression
if actions_enabled is not None:
request_body['actions_enabled'] = actions_enabled
if match_by is not None:
request_body['match_by'] = match_by
if severity is not None:
request_body['severity'] = severity
if alarm_actions is not None:
request_body['alarm_actions'] = alarm_actions
if ok_actions is not None:
request_body['ok_actions'] = ok_actions
if undetermined_actions is not None:
request_body['undetermined_actions'] = undetermined_actions
for key, value in kwargs.iteritems():
request_body[key] = value
resp, response_body = self.patch(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def list_alarms(self, query_params=None):
uri = 'alarms'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def get_alarm(self, id):
uri = 'alarms/' + id
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def delete_alarm(self, id):
uri = 'alarms/' + id
resp, response_body = self.delete(uri)
return resp, response_body
def update_alarm(self, id, state, lifecycle_state, link, **kwargs):
uri = 'alarms/' + id
request_body = {}
request_body['state'] = state
request_body['lifecycle_state'] = lifecycle_state
request_body['link'] = link
for key, value in kwargs.iteritems():
request_body[key] = value
resp, response_body = self.patch(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def patch_alarm(self, id, state=None, lifecycle_state=None, link=None,
**kwargs):
uri = 'alarms/' + id
request_body = {}
if state is not None:
request_body['state'] = state
if lifecycle_state is not None:
request_body['lifecycle_state'] = lifecycle_state
if link is not None:
request_body['link'] = link
for key, value in kwargs.iteritems():
request_body[key] = value
resp, response_body = self.patch(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def list_alarms_state_history(self, query_params=None):
uri = 'alarms/state-history'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)
def list_alarm_state_history(self, id, query_params=None):
uri = 'alarms/' + id + '/state-history'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
return resp, json.loads(response_body)

View File

View File

@ -0,0 +1,52 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 tempest_lib import exceptions
from monasca_tempest_tests import clients
CONF = config.CONF
class BaseMonascaTest(tempest.test.BaseTestCase):
"""Base test case class for all Monasca API tests."""
@classmethod
def skip_checks(cls):
super(BaseMonascaTest, cls).skip_checks()
@classmethod
def resource_setup(cls):
super(BaseMonascaTest, cls).resource_setup()
cls.os = clients.Manager()
cls.monasca_client = cls.os.monasca_client
@staticmethod
def cleanup_resources(method, list_of_ids):
for resource_id in list_of_ids:
try:
method(resource_id)
except exceptions.NotFound:
pass
@classmethod
def resource_cleanup(cls):
super(BaseMonascaTest, cls).resource_cleanup()
resp, response_body = cls.monasca_client.list_alarm_definitions()
elements = response_body['elements']
for definition in elements:
id = definition['id']
resp, response_body = cls.monasca_client. \
delete_alarm_definition(id)

View File

@ -0,0 +1,37 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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.
MAX_METRIC_NAME_LENGTH = 255
MAX_DIMENSION_KEY_LENGTH = 255
MAX_DIMENSION_VALUE_LENGTH = 255
INVALID_CHARS = "<>={}(),\"\;&"
MAX_ALARM_DEFINITION_NAME_LENGTH = 255
MAX_ALARM_DEFINITION_DESCRIPTION_LENGTH = 255
MAX_ALARM_DEFINITION_ACTIONS_LENGTH = 50
MAX_NOTIFICATION_METHOD_NAME_LENGTH = 250
MAX_NOTIFICATION_METHOD_TYPE_LENGTH = 100
MAX_NOTIFICATION_METHOD_ADDRESS_LENGTH = 100
INVALID_CHARS_NOTIFICATION = "<>={}(),\"\;&"
MAX_LIST_MEASUREMENTS_NAME_LENGTH = 255
MAX_LIST_STATISTICS_NAME_LENGTH = 255
MAX_ALARM_LIFECYCLE_STATE_LENGTH = 50
MAX_ALARM_METRIC_NAME_LENGTH = 255
MAX_ALARM_METRIC_DIMENSIONS_KEY_LENGTH = 255
MAX_ALARM_METRIC_DIMENSIONS_VALUE_LENGTH = 255
MAX_ALARM_LINK_LENGTH = 512

View File

@ -0,0 +1,77 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 time
from tempest.common.utils import data_utils
def create_metric(name='name-1',
dimensions={
'key-1': 'value-1',
'key-2': 'value-2'
},
timestamp=time.time() * 1000,
value=0.0):
metric = {}
if name is not None:
metric['name'] = name
if dimensions is not None:
metric['dimensions'] = dimensions
if timestamp is not None:
metric['timestamp'] = timestamp
if value is not None:
metric['value'] = value
return metric
def create_notification(name=data_utils.rand_name('notification-'),
type='EMAIL',
address='john.doe@domain.com'):
notification = {}
if name is not None:
notification['name'] = name
if type is not None:
notification['type'] = type
if address is not None:
notification['address'] = address
return notification
def create_alarm_definition(name=None,
description=None,
expression=None,
match_by=None,
severity=None,
alarm_actions=None,
ok_actions=None,
undetermined_actions=None):
alarm_definition = {}
if name is not None:
alarm_definition['name'] = name
if description is not None:
alarm_definition['description'] = description
if expression is not None:
alarm_definition['expression'] = expression
if match_by is not None:
alarm_definition['match_by'] = match_by
if severity is not None:
alarm_definition['severity'] = severity
if alarm_actions is not None:
alarm_definition['alarm_actions'] = alarm_actions
if ok_actions is not None:
alarm_definition['ok_actions'] = ok_actions
if undetermined_actions is not None:
alarm_definition['undetermined_actions'] = undetermined_actions
return alarm_definition

View File

@ -0,0 +1,483 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import helpers
from tempest.common.utils import data_utils
from tempest import test
from tempest_lib import exceptions
NUM_ALARM_DEFINITIONS = 2
class TestAlarmDefinitions(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestAlarmDefinitions, cls).resource_setup()
cls.rule = {'expression': 'mem_total_mb > 0'}
for i in range(NUM_ALARM_DEFINITIONS):
alarm_definition = helpers.create_alarm_definition(
name='alarm-definition-' + str(i),
description='alarm definition description',
expression='avg(cpu_utilization{service=compute}) >= 1000')
cls.monasca_client.create_alarm_definitions(alarm_definition)
@classmethod
def create_alarm_definition(cls):
# Create an alarm definition
name = data_utils.rand_name('alarm_definition')
expression = "max(cpu.system_perc) > 0"
alarm_definition = helpers.create_alarm_definition(
name=name,
description="description",
expression=expression)
return alarm_definition
# Create
@test.attr(type="gate")
def test_create_alarm_definition(self):
# Create an alarm definition
name = data_utils.rand_name('alarm_definition')
expression = "max(cpu.system_perc) > 0"
alarm_definition = helpers.create_alarm_definition(
name=name, description="description", expression=expression)
resp, response_body = self.monasca_client.create_alarm_definitions(
alarm_definition)
self.assertEqual(201, resp.status)
self.assertEqual(name, response_body['name'])
alarm_def_id = response_body['id']
self.assertEqual(expression, response_body['expression'])
# Delete alarm and verify if deleted
resp, response_body = self.monasca_client.delete_alarm_definition(
alarm_def_id)
self.assertEqual(204, resp.status)
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
alarm_def_id)
@test.attr(type="gate")
def test_create_alarm_definition_with_notification(self):
notification_name = data_utils.rand_name('notification-')
notification_type = 'EMAIL'
u_address = 'root@localhost'
resp, response_body = self.monasca_client.create_notification_method(
notification_name, type=notification_type, address=u_address)
self.assertEqual(201, resp.status)
self.assertEqual(notification_name, response_body['name'])
notification_id = response_body['id']
# Create an alarm definition
alarm_def_name = data_utils.rand_name('monitoring_alarm_definition')
expression = "mem_total_mb > 0"
alarm_definition = helpers.create_alarm_definition(
name=alarm_def_name,
expression=expression,
alarm_actions=notification_id,
ok_actions=notification_id,
undetermined_actions=notification_id,
severity="LOW")
resp, body = self.monasca_client.create_alarm_definitions(
alarm_definition)
self.assertEqual(201, resp.status)
self.assertEqual(alarm_def_name, body['name'])
alarm_def_id = body['id']
self.assertEqual(expression, body['expression'])
self.assertEqual(notification_id, body['ok_actions'][0])
self.assertEqual(notification_id, body['alarm_actions'][0])
self.assertEqual(notification_id, body['undetermined_actions'][0])
# Delete alarm definition and verify if deleted
resp, body = self.monasca_client.delete_alarm_definition(
alarm_def_id)
self.assertEqual(204, resp.status)
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
alarm_def_id)
# Delete notification
resp, body = self.monasca_client.delete_notification_method(
notification_id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
def test_create_alarm_definition_with_multiple_notifications(self):
notification_name1 = data_utils.rand_name('notification-')
notification_type1 = 'EMAIL'
address1 = 'root@localhost'
notification_name2 = data_utils.rand_name('notification-')
notification_type2 = 'PAGERDUTY'
address2 = 'http://localhost.com'
resp, body = self.monasca_client.create_notification_method(
notification_name1, type=notification_type1, address=address1)
self.assertEqual(201, resp.status)
self.assertEqual(notification_name1, body['name'])
notification_id1 = body['id']
resp, body = self.monasca_client.create_notification_method(
notification_name2, type=notification_type2, address=address2)
self.assertEqual(201, resp.status)
self.assertEqual(notification_name2, body['name'])
notification_id2 = body['id']
# Create an alarm definition
alarm_def_name = data_utils.rand_name('monitoring_alarm_definition')
alarm_definition = helpers.create_alarm_definition(
name=alarm_def_name,
expression="mem_total_mb > 0",
alarm_actions=[notification_id1, notification_id2],
ok_actions=[notification_id1, notification_id2],
severity="LOW")
resp, body = self.monasca_client.create_alarm_definitions(
alarm_definition)
self.assertEqual(201, resp.status)
self.assertEqual(alarm_def_name, body['name'])
alarm_def_id = body['id']
self.assertEqual("mem_total_mb > 0", body['expression'])
# Delete alarm definition and validate if deleted
resp, body = self.monasca_client.delete_alarm_definition(
alarm_def_id)
self.assertEqual(204, resp.status)
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
alarm_def_id)
# Delete notification 1
resp, body = self.monasca_client.delete_notification_method(
notification_id1)
self.assertEqual(204, resp.status)
# Delete notification 2
resp, body = self.monasca_client.delete_notification_method(
notification_id2)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
def test_create_alarm_definition_with_url_in_expression(self):
notification_name = data_utils.rand_name('notification-')
notification_type = 'EMAIL'
u_address = 'root@localhost'
resp, body = self.monasca_client.create_notification_method(
notification_name, type=notification_type, address=u_address)
self.assertEqual(201, resp.status)
self.assertEqual(notification_name, body['name'])
notification_id = body['id']
# Create an alarm definition
alarm_def_name = data_utils.rand_name('monitoring_alarm_definition')
alarm_definition = helpers.create_alarm_definition(
name=alarm_def_name,
expression="avg(mem_total_mb{url=https://www.google.com}) gt 0",
alarm_actions=notification_id,
ok_actions=notification_id,
severity="LOW")
resp, body = self.monasca_client.create_alarm_definitions(
alarm_definition)
self.assertEqual(201, resp.status)
self.assertEqual(alarm_def_name, body['name'])
alarm_def_id = body['id']
self.assertEqual("avg(mem_total_mb{url=https://www.google.com}) gt 0",
body['expression'])
# Delete alarm and verify if deleted
resp, body = self.monasca_client.delete_alarm_definition(
alarm_def_id)
self.assertEqual(204, resp.status)
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
alarm_def_id)
# Delete notification
resp, body = self.monasca_client.delete_notification_method(
notification_id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_create_alarm_definition_with_special_chars_in_expression(self):
notification_name = data_utils.rand_name('notification-')
notification_type = 'EMAIL'
u_address = 'root@localhost'
resp, body = self.monasca_client.create_notification_method(
notification_name, type=notification_type, address=u_address)
self.assertEqual(201, resp.status)
self.assertEqual(notification_name, body['name'])
notification_id = body['id']
# Create an alarm definition
alarm_def_name = data_utils.rand_name('monitoring_alarm')
alarm_definition = helpers.create_alarm_definition(
name=alarm_def_name,
expression="avg(mem_total_mb{dev=\usr\local\bin}) "
"gt 0",
alarm_actions=notification_id,
ok_actions=notification_id,
severity="LOW")
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_alarm_definitions,
alarm_definition)
# List
@test.attr(type="gate")
def test_list_alarm_definitions(self):
resp, response_body = self.monasca_client.list_alarm_definitions()
self.assertEqual(200, resp.status)
# Test list alarm definition response body
self.assertTrue(isinstance(response_body, dict))
self.assertTrue(set(['links', 'elements']) ==
set(response_body))
elements = response_body['elements']
links = response_body['links']
self.assertTrue(isinstance(links, list))
link = links[0]
self.assertTrue(set(['rel', 'href']) ==
set(link))
self.assertEqual(link['rel'], u'self')
self.assertEqual(len(elements), NUM_ALARM_DEFINITIONS)
for definition in elements:
self.assertTrue(set(['id',
'links',
'name',
'description',
'expression',
'match_by',
'severity',
'actions_enabled',
'ok_actions',
'alarm_actions',
'undetermined_actions']) ==
set(definition))
@test.attr(type="gate")
def test_list_alarm_definitions_with_name(self):
query_parms = '?name=name-1'
resp, response_body = self.monasca_client.list_alarm_definitions(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_alarm_definitions_with_dimensions(self):
query_parms = '?dimensions=key1:value1'
resp, response_body = self.monasca_client.list_alarm_definitions(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_alarm_definitions_with_offset_limit(self):
query_parms = '?offset=1&limit=2'
resp, response_body = self.monasca_client.list_alarm_definitions(
query_parms)
self.assertEqual(200, resp.status)
# Get
@test.attr(type="gate")
def test_get_alarm_definition(self):
alarm_definition = self.create_alarm_definition()
resp, response_body = self.monasca_client.create_alarm_definitions(
alarm_definition)
alarm_def_id = response_body['id']
resp, response_body = self.monasca_client.get_alarm_definition(
alarm_def_id)
self.assertEqual(200, resp.status)
# Test Get Alarm Definition Response Body
self.assertTrue(isinstance(response_body, dict))
self.assertTrue(set(['id', 'links', 'name', 'description',
'expression', 'match_by', 'severity',
'actions_enabled', 'alarm_actions',
'ok_actions', 'undetermined_actions'
]) ==
set(response_body))
links = response_body['links']
self.assertTrue(isinstance(links, list))
link = links[0]
self.assertTrue(set(['rel', 'href']) ==
set(link))
self.assertEqual(link['rel'], u'self')
# Delete alarm and verify if deleted
resp, response_body = self.monasca_client.delete_alarm_definition(
alarm_def_id)
self.assertEqual(204, resp.status)
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
alarm_def_id)
# Update
@test.attr(type="gate")
def test_update_alarm_definition(self):
alarm_definition = self.create_alarm_definition()
resp, response_body = self.monasca_client.create_alarm_definitions(
alarm_definition)
id = response_body['id']
# Update alarm definition
updated_name = data_utils.rand_name('updated_name')
updated_description = 'updated description'
updated_expression = response_body['expression']
resp, response_body = self.monasca_client.update_alarm_definition(
id=id,
name=updated_name,
expression=updated_expression,
description=updated_description,
actions_enabled='true'
)
self.assertEqual(200, resp.status)
# Validate fields updated
self.assertEqual(updated_name, response_body['name'])
self.assertEqual(updated_expression, response_body['expression'])
self.assertEqual(updated_description, response_body['description'])
# Get and validate details of alarm definition after update
resp, response_body = self.monasca_client.get_alarm_definition(id)
self.assertEqual(200, resp.status)
self.assertEqual(updated_name, response_body['name'])
self.assertEqual(updated_description, response_body['description'])
self.assertEqual(updated_expression, response_body['expression'])
# Test Updated alarm definition Response Body
self.assertTrue(isinstance(response_body, dict))
self.assertTrue(set(['id', 'links', 'name', 'description',
'expression', 'match_by', 'severity',
'actions_enabled', 'alarm_actions',
'ok_actions', 'undetermined_actions'
]) ==
set(response_body))
links = response_body['links']
self.assertTrue(isinstance(links, list))
link = links[0]
self.assertTrue(set(['rel', 'href']) ==
set(link))
self.assertEqual(link['rel'], u'self')
# Delete alarm definition
resp, response_body = self.monasca_client.delete_alarm_definition(
id)
self.assertEqual(204, resp.status)
# Validate alarm ID is not found
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition, id)
@test.attr(type="gate")
def test_update_notification_in_alarm_definition(self):
notification_name = data_utils.rand_name('notification-')
notification_type = 'EMAIL'
u_address = 'root@localhost'
resp, body = self.monasca_client.create_notification_method(
notification_name, type=notification_type, address=u_address)
self.assertEqual(201, resp.status)
self.assertEqual(notification_name, body['name'])
notification_id = body['id']
# Create an alarm definition
alarm_definition = self.create_alarm_definition()
resp, response_body = self.monasca_client.create_alarm_definitions(
alarm_definition)
self.assertEqual(201, resp.status)
alarm_def_id = response_body['id']
expression = response_body['expression']
# Update alarm definition
alarm_def_name = data_utils.rand_name('monitoring_alarm_update')
resp, body = self.monasca_client.update_alarm_definition(
alarm_def_id,
name=alarm_def_name,
expression=expression,
actions_enabled='true',
alarm_actions=notification_id,
ok_actions=notification_id
)
self.assertEqual(200, resp.status)
self.assertEqual(alarm_def_name, body['name'])
self.assertEqual(expression, body['expression'])
self.assertEqual(notification_id, body['alarm_actions'][0])
self.assertEqual(notification_id, body['ok_actions'][0])
# Get and verify details of an alarm after update
resp, body = self.monasca_client.get_alarm_definition(alarm_def_id)
self.assertEqual(200, resp.status)
self.assertEqual(alarm_def_name, body['name'])
self.assertEqual(expression, body['expression'])
# Delete alarm and verify if deleted
resp, _ = self.monasca_client.delete_alarm_definition(alarm_def_id)
self.assertEqual(204, resp.status)
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
alarm_def_id)
# Delete notification
resp, body = self.monasca_client.delete_notification_method(
notification_id)
self.assertEqual(204, resp.status)
# Patch
@test.attr(type="gate")
def test_patch_alarm_definition(self):
alarm_definition = self.create_alarm_definition()
resp, response_body = self.monasca_client.create_alarm_definitions(
alarm_definition)
id = response_body['id']
# Patch alarm definition
patched_name = data_utils.rand_name('patched_name')
resp, response_body = self.monasca_client.patch_alarm_definition(
id=id,
name=patched_name
)
self.assertEqual(200, resp.status)
# Validate fields updated
self.assertEqual(patched_name, response_body['name'])
# Delete alarm definition
resp, response_body = self.monasca_client.delete_alarm_definition(
id)
self.assertEqual(204, resp.status)
# Validate alarm ID is not found
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
id)
# Delete
@test.attr(type="gate")
def test_create_and_delete_alarm_definition(self):
alarm_definition = self.create_alarm_definition()
resp, response_body = self.monasca_client.create_alarm_definitions(
alarm_definition)
alarm_def_id = response_body['id']
# Delete alarm and verify if deleted
resp, response_body = self.monasca_client.delete_alarm_definition(
alarm_def_id)
self.assertEqual(204, resp.status)
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_alarm_definition,
alarm_def_id)

View File

@ -0,0 +1,281 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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.
# TODO(RMH): Update documentation. Get alarms returns alarm_definition, not
# TODO(RMH): alarm_definition_id in response body
import time
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import helpers
from tempest.common.utils import data_utils
from tempest import test
from tempest_lib import exceptions
class TestAlarms(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestAlarms, cls).resource_setup()
@classmethod
def resource_cleanup(cls):
super(TestAlarms, cls).resource_cleanup()
@classmethod
def create_alarms_for_test_alarms(cls):
# create an alarm definition
expression = "avg(name-1) > 0"
name = data_utils.rand_name('name-1')
alarm_definition = helpers.create_alarm_definition(
name=name, expression=expression)
resp, response_body = cls.monasca_client.create_alarm_definitions(
alarm_definition)
# create some metrics
for i in xrange(30):
metric = helpers.create_metric()
resp, response_body = cls.monasca_client.create_metrics(metric)
time.sleep(1)
resp, response_body = cls.monasca_client.list_alarms()
elements = response_body['elements']
if len(elements) > 0:
break
@test.attr(type="gate")
def test_list_alarms(self):
self.create_alarms_for_test_alarms()
resp, response_body = self.monasca_client.list_alarms()
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) ==
set(response_body))
elements = response_body['elements']
element = elements[0]
self.assertTrue(set(['id',
'links',
'alarm_definition',
'metrics',
'state',
'lifecycle_state',
'link',
'state_updated_timestamp',
'updated_timestamp',
'created_timestamp']) ==
set(element))
for metric in element['metrics']:
target_metric = helpers.create_metric()
self.assertEqual(target_metric['name'], metric['name'])
self.assertEqual(target_metric['dimensions'], metric['dimensions'])
@test.attr(type="gate")
def test_list_alarms_by_alarm_definition_id(self):
resp, response_body = self.monasca_client.list_alarms()
elements = response_body['elements']
element = elements[0]
alarm_definition_id = element['alarm_definition']['id']
query_parms = '?alarm_definition_id=' + str(alarm_definition_id)
resp, response_body = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
element_1 = response_body['elements'][0]
self.assertEqual(element_1, element)
@test.attr(type="gate")
def test_list_alarms_by_metric_name(self):
resp, response_body = self.monasca_client.list_alarms()
elements = response_body['elements']
element = elements[0]
metric_name = element['metrics'][0]['name']
query_parms = '?metric_name=' + str(metric_name)
resp, response_body = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
element_1 = response_body['elements'][0]
self.assertEqual(element_1, element)
@test.attr(type="gate")
def test_list_alarms_by_metric_dimensions(self):
query_parms = '?metric_dimensions=key-2:value-2,key-1:value-1'
resp, response_body_1 = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_alarms_by_state(self):
resp, response_body = self.monasca_client.list_alarms()
len0 = len(response_body['elements'])
query_parms = '?state=UNDETERMINED'
resp, response_body1 = self.monasca_client.list_alarms(query_parms)
len1 = len(response_body1['elements'])
self.assertEqual(200, resp.status)
query_parms = '?state=OK'
resp, response_body2 = self.monasca_client.list_alarms(query_parms)
len2 = len(response_body2['elements'])
self.assertEqual(200, resp.status)
query_parms = '?state=ALARM'
resp, response_body3 = self.monasca_client.list_alarms(query_parms)
len3 = len(response_body3['elements'])
self.assertEqual(200, resp.status)
self.assertEqual(len0, len1 + len2 + len3)
@test.attr(type="gate")
def test_list_alarms_by_lifecycle_state(self):
query_parms = '?lifecycle_state=None'
resp, response_body = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_alarms_by_link(self):
query_parms = '?link=None'
resp, response_body = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_alarms_by_state_updated_start_time(self):
resp, response_body = self.monasca_client.list_alarms()
elements = response_body['elements']
element = elements[0]
state_updated_start_time = element['state_updated_timestamp']
query_parms = '?state_updated_timestamp=' + \
str(state_updated_start_time)
resp, response_body = self.monasca_client.list_alarms(query_parms)
self.assertEqual(200, resp.status)
element_1 = response_body['elements'][0]
self.assertEqual(element, element_1)
@test.attr(type="gate")
def test_list_alarms_by_offset_limit(self):
resp, response_body = self.monasca_client.list_alarms()
elements = response_body['elements']
first_element = elements[0]
next_element = elements[1]
id = first_element['id']
query_parms = '?offset=' + str(id) + '&limit=1'
resp, response_body1 = self.monasca_client.list_alarms(query_parms)
elements = response_body1['elements']
self.assertEqual(1, len(elements))
self.assertEqual(elements[0]['id'], next_element['id'])
self.assertEqual(elements[0], next_element)
@test.attr(type="gate")
def test_get_alarm(self):
self.create_alarms_for_test_alarms()
resp, response_body = self.monasca_client.list_alarms()
self.assertEqual(200, resp.status)
elements = response_body['elements']
element = elements[0]
id = element['id']
resp, response_body = self.monasca_client.get_alarm(id)
self.assertEqual(200, resp.status)
self.assertTrue(set(['id',
'links',
'alarm_definition',
'metrics',
'state',
'lifecycle_state',
'link',
'state_updated_timestamp',
'updated_timestamp',
'created_timestamp']) ==
set(response_body))
for metric in element['metrics']:
target_metric = helpers.create_metric()
self.assertEqual(target_metric['name'], metric['name'])
self.assertEqual(target_metric['dimensions'], metric['dimensions'])
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_get_alarm_with_invalid_id(self):
id = data_utils.rand_name()
self.assertRaises(exceptions.NotFound, self.monasca_client.get_alarm,
id)
@test.attr(type="gate")
def test_update_alarm(self):
self.create_alarms_for_test_alarms()
resp, response_body = self.monasca_client.list_alarms()
self.assertEqual(200, resp.status)
elements = response_body['elements']
element = elements[0]
id = element['id']
updated_state = "ALARM"
updated_lifecycle_state = "OPEN"
updated_link = "http://somesite.com"
resp, response_body = self.monasca_client.update_alarm(
id=id, state=updated_state,
lifecycle_state=updated_lifecycle_state, link=updated_link)
self.assertEqual(200, resp.status)
self.assertTrue(set(['id',
'links',
'alarm_definition',
'metrics',
'state',
'lifecycle_state',
'link',
'state_updated_timestamp',
'updated_timestamp',
'created_timestamp']) ==
set(response_body))
# Validate fields updated
self.assertEqual(updated_state, response_body['state'])
self.assertEqual(updated_lifecycle_state, response_body[
'lifecycle_state'])
self.assertEqual(updated_link, response_body[
'link'])
@test.attr(type="gate")
def test_patch_alarm(self):
self.create_alarms_for_test_alarms()
resp, response_body = self.monasca_client.list_alarms()
self.assertEqual(200, resp.status)
elements = response_body['elements']
element = elements[0]
id = element['id']
updated_state = "UNDETERMINED"
resp, response_body = self.monasca_client.patch_alarm(
id=id, state=updated_state)
self.assertEqual(200, resp.status)
self.assertTrue(set(['id',
'links',
'alarm_definition',
'metrics',
'state',
'lifecycle_state',
'link',
'state_updated_timestamp',
'updated_timestamp',
'created_timestamp']) ==
set(response_body))
# Validate the field patched
self.assertEqual(updated_state, response_body['state'])
@test.attr(type="gate")
def test_delete_alarm(self):
self.create_alarms_for_test_alarms()
resp, response_body = self.monasca_client.list_alarms()
self.assertEqual(200, resp.status)
elements = response_body['elements']
element = elements[0]
id = element['id']
resp, response_body = self.monasca_client.delete_alarm(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_delete_alarm_with_invalid_id(self):
id = data_utils.rand_name()
self.assertRaises(exceptions.NotFound,
self.monasca_client.delete_alarm, id)

View File

@ -0,0 +1,212 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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.
# TODO(RMH): Update documentation. Get alarms returns alarm_definition, not
# TODO(RMH): alarm_definition_id in response body
import time
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import helpers
from oslo_utils import timeutils
from tempest.common.utils import data_utils
from tempest import test
class TestAlarmsStateHistory(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestAlarmsStateHistory, cls).resource_setup()
start_timestamp = int(time.time() * 1000)
end_timestamp = int(time.time() * 1000) + 1000
# create an alarm definition
expression = "avg(name-1) > 0"
name = data_utils.rand_name('alarm_definition')
alarm_definition = helpers.create_alarm_definition(
name=name,
expression=expression)
resp, response_body = cls.monasca_client.create_alarm_definitions(
alarm_definition)
# create another alarm definition
name1 = data_utils.rand_name('alarm_definition1')
expression1 = "max(cpu.system_perc) > 0"
alarm_definition1 = helpers.create_alarm_definition(
name=name1,
expression=expression1)
resp, response_body1 = cls.monasca_client.create_alarm_definitions(
alarm_definition1)
# create another alarm definition
name2 = data_utils.rand_name('alarm_definition2')
expression1 = "avg(mysql.performance.slow_queries) > 10.0"
alarm_definition2 = helpers.create_alarm_definition(
name=name2,
expression=expression1)
resp, response_body2 = cls.monasca_client.create_alarm_definitions(
alarm_definition2)
# create some metrics
for i in xrange(180):
metric = helpers.create_metric()
resp, body = cls.monasca_client.create_metrics(metric)
cls._start_timestamp = start_timestamp + i
cls._end_timestamp = end_timestamp + i
time.sleep(1)
resp, response_body = cls.monasca_client.\
list_alarms_state_history()
elements = response_body['elements']
if len(elements) > 4:
break
if len(elements) < 3:
cls.assertEqual(1, False)
@test.attr(type="gate")
def test_list_alarms_state_history(self):
resp, response_body = self.monasca_client.list_alarms_state_history()
self.assertEqual(200, resp.status)
# Test response body
self.assertTrue(set(['links', 'elements']) == set(response_body))
elements = response_body['elements']
element = elements[0]
self.assertTrue(set(['id', 'alarm_id', 'metrics', 'old_state',
'new_state', 'reason', 'reason_data', 'timestamp',
'sub_alarms']) == set(element))
@test.attr(type="gate")
def test_list_alarms_state_history_with_dimensions(self):
resp, response_body = self.monasca_client.list_alarms_state_history()
element = response_body['elements'][0]
dimension = element['metrics'][0]['dimensions']
dimension_items = dimension.items()
dimension_item = dimension_items[0]
dimension_item_0 = dimension_item[0]
dimension_item_1 = dimension_item[1]
name = element['metrics'][0]['name']
query_parms = '?dimensions=' + str(dimension_item_0) + ':' + str(
dimension_item_1)
resp, response_body = self.monasca_client.list_alarms_state_history(
query_parms)
name_new = response_body['elements'][0]['metrics'][0]['name']
self.assertEqual(200, resp.status)
self.assertEqual(name, name_new)
@test.attr(type="gate")
def test_list_alarms_state_history_with_start_time(self):
current_time = int(time.time())
current_time = timeutils.iso8601_from_timestamp(current_time)
query_parms = '?start_time=' + str(current_time)
resp, response_body = self.monasca_client.list_alarms_state_history(
query_parms)
elements = response_body['elements']
self.assertEqual(0, len(elements))
resp, response_body = self.monasca_client.list_alarms_state_history()
elements = response_body['elements']
timestamp = elements[1]['timestamp']
query_parms = '?start_time=' + str(timestamp)
resp, response_body = self.monasca_client.list_alarms_state_history(
query_parms)
elements = response_body['elements']
self.assertEqual(2, len(elements))
@test.attr(type="gate")
def test_list_alarms_state_history_with_end_time(self):
resp, response_body = self.monasca_client.list_alarms_state_history()
elements = response_body['elements']
timestamp = elements[2]['timestamp']
query_parms = '?end_time=' + str(timestamp)
resp, response_body = self.monasca_client.list_alarms_state_history(
query_parms)
elements = response_body['elements']
self.assertEqual(1, len(elements))
@test.attr(type="gate")
def test_list_alarms_state_history_with_offset_limit(self):
resp, response_body = self.monasca_client.list_alarms_state_history()
elements = response_body['elements']
first_element = elements[0]
last_element = elements[2]
first_element_id = first_element['id']
last_element_id = last_element['id']
for limit in xrange(1, 4):
query_parms = '?limit=' + str(limit) + '&offset=' + str(
last_element_id)
resp, response_body = self.monasca_client.\
list_alarms_state_history(query_parms)
elements = response_body['elements']
element_new = elements[0]
self.assertEqual(200, resp.status)
self.assertEqual(element_new, first_element)
self.assertEqual(limit, len(elements))
id_new = element_new['id']
self.assertEqual(id_new, first_element_id)
@test.attr(type="gate")
def test_list_alarm_state_history(self):
# Get the alarm state history for a specific alarm by ID
resp, response_body = self.monasca_client.list_alarms_state_history()
self.assertEqual(200, resp.status)
elements = response_body['elements']
element = elements[0]
alarm_id = element['alarm_id']
resp, response_body = self.monasca_client.list_alarm_state_history(
alarm_id)
self.assertEqual(200, resp.status)
# Test Response Body
self.assertTrue(set(['links', 'elements']) ==
set(response_body))
elements = response_body['elements']
links = response_body['links']
self.assertTrue(isinstance(links, list))
link = links[0]
self.assertTrue(set(['rel', 'href']) ==
set(link))
self.assertEqual(link['rel'], u'self')
definition = elements[0]
self.assertTrue(set(['id', 'alarm_id', 'metrics', 'new_state',
'old_state', 'reason', 'reason_data',
'sub_alarms', 'timestamp']) ==
set(definition))
@test.attr(type="gate")
def test_list_alarm_state_history_with_offset_limit(self):
# Get the alarm state history for a specific alarm by ID
resp, response_body = self.monasca_client.list_alarms_state_history()
self.assertEqual(200, resp.status)
elements = response_body['elements']
element = elements[0]
alarm_id = element['alarm_id']
query_parms = '?limit=1'
resp, response_body = self.monasca_client.list_alarm_state_history(
alarm_id, query_parms)
elements = response_body['elements']
self.assertEqual(200, resp.status)
self.assertEqual(1, len(elements))
id = element['id']
query_parms = '?limit=1&offset=' + str(id)
resp, response_body = self.monasca_client.list_alarm_state_history(
alarm_id, query_parms)
elements_new = response_body['elements']
self.assertEqual(200, resp.status)
self.assertEqual(1, len(elements_new))
self.assertEqual(element, elements_new[0])

View File

@ -0,0 +1,221 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 time
from oslo_utils import timeutils
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import constants
from monasca_tempest_tests.tests.api import helpers
from tempest.common.utils import data_utils
from tempest import test
from tempest_lib import exceptions
NUM_MEASUREMENTS = 100
WAIT_TIME = 30
class TestMeasurements(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestMeasurements, cls).resource_setup()
start_timestamp = int(time.time() * 1000)
end_timestamp = int(time.time() * 1000) + NUM_MEASUREMENTS * 1000
metrics = []
for i in xrange(NUM_MEASUREMENTS):
metric = helpers.create_metric(
name="name-1",
timestamp=start_timestamp + i)
metrics.append(metric)
resp, response_body = cls.monasca_client.create_metrics(metrics)
cls._start_timestamp = start_timestamp
cls._end_timestamp = end_timestamp
cls._metrics = metrics
@test.attr(type="gate")
def test_list_measurements(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=true&start_time=' + str(
start_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
elements = response_body['elements']
element = elements[0]
self.assertTrue(set(['id', 'name', 'dimensions', 'columns',
'measurements']) == set(element))
self.assertTrue(type(element['name']) is unicode)
self.assertTrue(type(element['dimensions']) is dict)
self.assertTrue(type(element['columns']) is list)
self.assertTrue(type(element['measurements']) is list)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_measurements_with_no_start_time(self):
query_parms = '?name=name-1'
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_measurements, query_parms)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_measurements_with_no_name(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?start_time=' + str(start_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_measurements, query_parms)
@test.attr(type="gate")
def test_list_measurements_with_dimensions(self):
key1 = data_utils.rand_name('key1')
value1 = data_utils.rand_name('value1')
start_timestamp = int(time.time() * 1000)
name = data_utils.rand_name()
metric = [
helpers.create_metric(name=name, timestamp=start_timestamp,
dimensions={key1: value1}, value=123)
]
resp, response_body = self.monasca_client.create_metrics(metric)
time.sleep(WAIT_TIME)
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?name=' + name + '&start_time=' + str(
start_time) + '&dimensions=' + key1 + ':' + value1
resp, response_body = self.monasca_client.list_measurements(
query_parms)
value_new = response_body['elements'][0]['measurements'][0][1]
self.assertEqual(200, resp.status)
self.assertEqual(123, value_new)
@test.attr(type="gate")
def test_list_measurements_with_endtime(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
end_time = timeutils.iso8601_from_timestamp(
self._end_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=true&true&start_time=' + str(
start_time) + '&end_time' + str(end_time)
resp, body = self.monasca_client.list_measurements(query_parms)
self.assertEqual(200, resp.status)
len_measurements = len(body['elements'][0]['measurements'])
self.assertEqual(len_measurements, NUM_MEASUREMENTS)
@test.attr(type="gate")
def test_list_measurements_with_offset_limit(self):
start_timestamp = int(time.time() * 1000)
name = data_utils.rand_name()
metric = [
helpers.create_metric(name=name, timestamp=start_timestamp + 0,
dimensions={'key1': 'value-1',
'key2': 'value-1'}),
helpers.create_metric(name=name, timestamp=start_timestamp + 1,
dimensions={'key1': 'value-2',
'key2': 'value-2'}),
helpers.create_metric(name=name, timestamp=start_timestamp + 2,
dimensions={'key1': 'value-3',
'key2': 'value-3'}),
helpers.create_metric(name=name, timestamp=start_timestamp + 3,
dimensions={'key1': 'value-4',
'key2': 'value-4'})
]
resp, response_body = self.monasca_client.create_metrics(metric)
time.sleep(WAIT_TIME)
query_parms = '?name=' + name
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
start_time = timeutils.iso8601_from_timestamp(
start_timestamp / 1000)
query_parms = '?name=' + name + '&merge_metrics=true&start_time=' + \
str(start_time)
resp, body = self.monasca_client.list_measurements(query_parms)
self.assertEqual(200, resp.status)
elements = body['elements'][0]['measurements']
first_element = elements[0]
last_element = elements[3]
query_parms = '?name=' + name + '&merge_metrics=true&start_time=' + \
str(start_time) + '&limit=4'
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements'][0]['measurements']
self.assertEqual(4, len(elements))
self.assertEqual(first_element, elements[0])
for limit in xrange(1, 5):
next_element = elements[limit - 1]
while True:
query_parms = '?name=' + name + \
'&merge_metrics=true&start_time=' + \
str(start_time) + '&offset=' + \
str(next_element[0]) + '&limit=' + \
str(limit)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
new_elements = response_body['elements'][0]['measurements']
if len(new_elements) > limit - 1:
self.assertEqual(limit, len(new_elements))
next_element = new_elements[limit - 1]
elif len(new_elements) > 0 and len(new_elements) <= limit - 1:
self.assertEqual(last_element, new_elements[0])
break
else:
self.assertEqual(last_element, next_element)
break
@test.attr(type="gate")
def test_list_measurements_with_merge_metrics(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=true&start_time=' + str(
start_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_measurements_with_name_exceeds_max_length(self):
long_name = "x" * (constants.MAX_LIST_MEASUREMENTS_NAME_LENGTH + 1)
start_time = timeutils.iso8601_from_timestamp(self._start_timestamp
/ 1000)
query_parms = '?name=' + str(long_name) \
+ '&merge_metrics=true&start_time=' + str(start_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_measurements, query_parms)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_measurements_with_no_merge_metrics(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=false&start_time=' + str(
start_time)
self.assertRaises(exceptions.Conflict,
self.monasca_client.list_measurements, query_parms)

View File

@ -0,0 +1,236 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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.
# TODO(RMH): Check if ' should be added in the list of INVALID_CHARS.
# TODO(RMH): test_create_metric_no_value, should return 422 if value not sent
import time
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import constants
from monasca_tempest_tests.tests.api import helpers
from tempest.common.utils import data_utils
from tempest import test
from tempest_lib import exceptions
WAIT_TIME = 30
class TestMetrics(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestMetrics, cls).resource_setup()
@test.attr(type='gate')
def test_create_metric(self):
metric = helpers.create_metric()
resp, body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
@test.attr(type='gate')
def test_create_metrics(self):
metrics = [
helpers.create_metric(),
helpers.create_metric()
]
resp, body = self.monasca_client.create_metrics(metrics)
self.assertEqual(204, resp.status)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_with_no_name(self):
metric = helpers.create_metric(name=None)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
def test_create_metric_with_no_dimensions(self):
metric = helpers.create_metric(dimensions=None)
resp, body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_with_no_timestamp(self):
metric = helpers.create_metric(timestamp=None)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_no_value(self):
timestamp = time.time() * 1000
metric = helpers.create_metric(timestamp=timestamp,
value=None)
return
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_with_name_exceeds_max_length(self):
long_name = "x" * (constants.MAX_METRIC_NAME_LENGTH + 1)
metric = helpers.create_metric(long_name)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_with_invalid_chars_in_name(self):
for invalid_char in constants.INVALID_CHARS:
metric = helpers.create_metric(invalid_char)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_with_invalid_chars_in_dimensions(self):
for invalid_char in constants.INVALID_CHARS:
metric = helpers.create_metric('name-1', {'key-1': invalid_char})
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
for invalid_char in constants.INVALID_CHARS:
metric = helpers.create_metric('name-1', {invalid_char: 'value-1'})
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_dimension_key_exceeds_max_length(self):
long_key = "x" * (constants.MAX_DIMENSION_KEY_LENGTH + 1)
metric = helpers.create_metric('name-1', {long_key: 'value-1'})
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
@test.attr(type=['negative'])
def test_create_metric_dimension_value_exceeds_max_length(self):
long_value = "x" * (constants.MAX_DIMENSION_VALUE_LENGTH + 1)
metric = helpers.create_metric('name-1', {'key-1': long_value})
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@test.attr(type='gate')
def test_list_metrics(self):
resp, response_body = self.monasca_client.list_metrics()
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
elements = response_body['elements']
element = elements[0]
self.assertTrue(set(['id', 'name', 'dimensions']) == set(element))
self.assertTrue(type(element['id']) is unicode)
self.assertTrue(type(element['name']) is unicode)
self.assertTrue(type(element['dimensions']) is dict)
@test.attr(type='gate')
def test_list_metrics_with_name(self):
name_org = data_utils.rand_name('name')
key = data_utils.rand_name('key')
metric = helpers.create_metric(name=name_org,
dimensions={key: 'value-1'})
resp, body = self.monasca_client.create_metrics(metric)
time.sleep(WAIT_TIME)
query_parms = '?dimensions=' + str(key) + ':value-1'
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
dimensions = elements[0]
name = dimensions['name']
self.assertEqual(name_org, str(name))
@test.attr(type='gate')
def test_list_metrics_with_dimensions(self):
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value_org = data_utils.rand_name('value')
metric = helpers.create_metric(name=name,
dimensions={key: value_org})
resp, body = self.monasca_client.create_metrics(metric)
time.sleep(WAIT_TIME)
query_parms = '?name=' + name
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
dimensions = elements[0]
dimension = dimensions['dimensions']
value = dimension[unicode(key)]
self.assertEqual(value_org, str(value))
@test.attr(type='gate')
def test_list_metrics_with_offset_limit(self):
name = data_utils.rand_name()
key1 = data_utils.rand_name()
key2 = data_utils.rand_name()
metrics = [
helpers.create_metric(name=name, dimensions={
key1: 'value-1', key2: 'value-1'}),
helpers.create_metric(name=name, dimensions={
key1: 'value-2', key2: 'value-2'}),
helpers.create_metric(name=name, dimensions={
key1: 'value-3', key2: 'value-3'}),
helpers.create_metric(name=name, dimensions={
key1: 'value-4', key2: 'value-4'})
]
resp, body = self.monasca_client.create_metrics(metrics)
time.sleep(WAIT_TIME)
query_parms = '?name=' + name
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
first_element = elements[0]
last_element = elements[3]
query_parms = '?name=' + name + '&limit=4'
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(4, len(elements))
self.assertEqual(first_element, elements[0])
for limit in xrange(1, 5):
next_element = elements[limit - 1]
while True:
query_parms = '?name=' + name + '&offset=' +\
str(next_element['id']) + '&limit=' + str(limit)
resp, response_body = self.monasca_client.list_metrics(
query_parms)
self.assertEqual(200, resp.status)
new_elements = response_body['elements']
if len(new_elements) > limit - 1:
self.assertEqual(limit, len(new_elements))
next_element = new_elements[limit - 1]
elif len(new_elements) > 0 and len(new_elements) <= limit - 1:
self.assertEqual(last_element, new_elements[0])
break
else:
self.assertEqual(last_element, next_element)
break

View File

@ -0,0 +1,47 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 monasca_tempest_tests.tests.api import base
from tempest import test
class TestMetricsNames(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestMetricsNames, cls).resource_setup()
@test.attr(type='gate')
def test_list_metrics_names(self):
resp, response_body = self.monasca_client.list_metrics_names()
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
elements = response_body['elements']
element = elements[0]
self.assertTrue(set(['id', 'name']) == set(element))
@test.attr(type='gate')
def test_list_metrics_names_with_dimensions(self):
query_parms = '?dimensions=key1:value1'
resp, response_body = self.monasca_client.list_metrics_names(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type='gate')
def test_list_metrics_names_with_limit_offset(self):
# Can not test list_metrics_names_with_limit_offset for now because
# list_metrics_names returns a list of metric names with no
# duplicates. But the limit and offset are using the original list
# with duplicates as reference.
return

View File

@ -0,0 +1,297 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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.
# TODO(RMH): Validate whether a 200 or 201 should be returned and resolve.
# TODO(RMH): Documentation says 200, but a 201 is being returned.
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import constants
from monasca_tempest_tests.tests.api import helpers
from tempest.common.utils import data_utils
from tempest import test
from tempest_lib import exceptions
DEFAULT_EMAIL_ADDRESS = 'john.doe@domain.com'
class TestNotificationMethods(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestNotificationMethods, cls).resource_setup()
@test.attr(type="gate")
def test_create_notification_method(self):
notification = helpers.create_notification()
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
id = response_body['id']
resp, response_body = self.monasca_client.\
delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_create_notification_method_with_no_name(self):
notification = helpers.create_notification(name=None)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_notifications,
notification)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_create_notification_method_with_no_type(self):
notification = helpers.create_notification(type=None)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_notifications,
notification)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_create_notification_method_with_no_address(self):
notification = helpers.create_notification(address=None)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_notifications,
notification)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_create_notification_method_with_name_exceeds_max_length(self):
long_name = "x" * (constants.MAX_NOTIFICATION_METHOD_NAME_LENGTH + 1)
notification = helpers.create_notification(name=long_name)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_notifications,
notification)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_create_notification_method_with_address_exceeds_max_length(self):
long_address = "x" * (
constants.MAX_NOTIFICATION_METHOD_ADDRESS_LENGTH + 1)
notification = helpers.create_notification(address=long_address)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_notifications,
notification)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_create_notification_method_with_invalid_type(self):
notification = helpers.create_notification(type='random')
self.assertRaises(exceptions.BadRequest,
self.monasca_client.create_notifications,
notification)
@test.attr(type="gate")
def test_list_notification_methods(self):
resp, body = self.monasca_client.list_notification_methods()
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_notification_methods_with_offset_limit(self):
query_parms = '?offset=1&limit=2'
resp, body = self.monasca_client.list_notification_methods(query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_notification_methods_response_body(self):
# TODO(RMH): Validate response body
resp, response_body = self.monasca_client.list_notification_methods()
self.assertTrue(set(['links', 'elements']) == set(response_body))
elements = response_body['elements']
element = elements[0]
self.assertTrue(set(['id', 'links', 'name', 'type', 'address']) ==
set(element))
# check if 'id' is an int. NOPE its unicode
self.assertTrue(type(element['id']) is unicode)
# check if 'links' is link
self.assertTrue(type(element['links']) is list)
# check if 'name' is a string. NOPE its unicode
self.assertTrue(type(element['name']) is unicode)
# check if 'type' is an unicode
self.assertTrue(type(element['type']) is unicode)
# check if 'address' is an unicode
self.assertTrue(type(element['address']) is unicode)
@test.attr(type="gate")
def test_get_notification_method(self):
notification = helpers.create_notification()
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
id = response_body['id']
resp, response_body = self.monasca_client.get_notification_method(id)
self.assertEqual(200, resp.status)
resp, response_body = self.monasca_client.\
delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_get_notification_method_with_invalid_id(self):
notification = helpers.create_notification()
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
id = data_utils.rand_name()
self.assertRaises(exceptions.NotFound,
self.monasca_client.get_notification_method,
id)
resp, response_body = self.monasca_client.\
delete_notification_method(response_body['id'])
self.assertEqual(204, resp.status)
@test.attr(type="gate")
def test_update_notification_method_name(self):
name = data_utils.rand_name('notification-')
notification = helpers.create_notification(name=name)
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
self.assertEqual(name, response_body['name'])
id = response_body['id']
new_name = name + 'update'
resp, response_body = self.monasca_client.\
update_notification_method(id, new_name,
type=response_body['type'],
address=response_body['address'])
self.assertEqual(200, resp.status)
self.assertEqual(new_name, response_body['name'])
resp, response_body = self.monasca_client.\
delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
def test_update_notification_method_type(self):
type = 'EMAIL'
notification = helpers.create_notification(type=type)
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
self.assertEqual(type, response_body['type'])
id = response_body['id']
new_type = 'PAGERDUTY'
resp, response_body = \
self.monasca_client.\
update_notification_method(id, name=response_body['name'],
type=new_type,
address=response_body['address'])
self.assertEqual(200, resp.status)
self.assertEqual(new_type, response_body['type'])
resp, response_body = self.monasca_client.\
delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
def test_update_notification_method_address(self):
address = DEFAULT_EMAIL_ADDRESS
notification = helpers.create_notification(address=address)
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
self.assertEqual(address, response_body['address'])
id = response_body['id']
new_address = 'jane.doe@domain.com'
resp, response_body = self.monasca_client.\
update_notification_method(id,
name=response_body['name'],
type=response_body['type'],
address=new_address)
self.assertEqual(200, resp.status)
self.assertEqual(new_address, response_body['address'])
resp, response_body = \
self.monasca_client.delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_update_notification_method_name_exceeds_max_length(self):
name = data_utils.rand_name('notification-')
notification = helpers.create_notification(name=name)
resp, response_body = self.monasca_client.create_notifications(
notification)
id = response_body['id']
self.assertEqual(201, resp.status)
new_name_long = "x" * (constants.MAX_NOTIFICATION_METHOD_NAME_LENGTH
+ 1)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.update_notification_method, id,
name=new_name_long, type=response_body['type'],
address=response_body['address'])
resp, response_body = \
self.monasca_client.delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_update_notification_method_invalid_type(self):
name = data_utils.rand_name('notification-')
notification = helpers.create_notification(name=name)
resp, response_body = self.monasca_client.create_notifications(
notification)
id = response_body['id']
self.assertEqual(201, resp.status)
self.assertRaises(exceptions.BadRequest,
self.monasca_client.update_notification_method, id,
name=response_body['name'], type='random',
address=response_body['address'])
resp, response_body = \
self.monasca_client.delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_update_notification_method_address_exceeds_max_length(self):
name = data_utils.rand_name('notification-')
notification = helpers.create_notification(name=name)
resp, response_body = self.monasca_client.create_notifications(
notification)
id = response_body['id']
self.assertEqual(201, resp.status)
new_address_long = "x" * (
constants.MAX_NOTIFICATION_METHOD_ADDRESS_LENGTH + 1)
self.assertRaises(exceptions.BadRequest,
self.monasca_client.update_notification_method, id,
name=response_body['name'], type=new_address_long,
address=response_body['address'])
resp, response_body = \
self.monasca_client.delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
def test_delete_notification_method(self):
notification = helpers.create_notification()
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
id = response_body['id']
resp, response_body = self.monasca_client.\
delete_notification_method(id)
self.assertEqual(204, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_delete_notification_method_with_invalid_id(self):
name = data_utils.rand_name('notification-')
notification = helpers.create_notification(name=name)
resp, response_body = self.monasca_client.create_notifications(
notification)
self.assertEqual(201, resp.status)
id = data_utils.rand_name()
self.assertRaises(exceptions.NotFound,
self.monasca_client.delete_notification_method,
id)
resp, response_body = self.monasca_client.\
delete_notification_method(response_body['id'])
self.assertEqual(204, resp.status)

View File

@ -0,0 +1,301 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 time
from oslo_utils import timeutils
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import constants
from monasca_tempest_tests.tests.api import helpers
from tempest.common.utils import data_utils
from tempest import test
from tempest_lib import exceptions
NUM_MEASUREMENTS = 100
WAIT_TIME = 30
class TestStatistics(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestStatistics, cls).resource_setup()
start_timestamp = int(time.time() * 1000)
end_timestamp = int(time.time() * 1000) + NUM_MEASUREMENTS * 1000
metrics = []
for i in xrange(NUM_MEASUREMENTS):
metric = helpers.create_metric(
name="name-1",
timestamp=start_timestamp + i)
metrics.append(metric)
resp, response_body = cls.monasca_client.create_metrics(metric)
cls._start_timestamp = start_timestamp
cls._end_timestamp = end_timestamp
cls._metrics = metrics
@classmethod
def resource_cleanup(cls):
super(TestStatistics, cls).resource_cleanup()
@test.attr(type="gate")
def test_list_statistics(self):
start_time = timeutils.iso8601_from_timestamp(self._start_timestamp /
1000)
query_parms = '?name=name-1&merge_metrics=true&statistics=avg' \
'&start_time=' + str(start_time)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
elements = response_body['elements']
element = elements[0]
self.assertTrue(set(['id', 'name', 'dimensions', 'columns',
'statistics']) == set(element))
# check if 'id' is unicode type
self.assertTrue(type(element['id']) is unicode)
# check if 'name' is a string. NOPE its unicode
self.assertTrue(type(element['name']) is unicode)
self.assertTrue(type(element['dimensions']) is dict)
self.assertTrue(type(element['columns']) is list)
self.assertTrue(type(element['statistics']) is list)
statistic = element['statistics']
column = element['columns']
self.assertTrue(type(statistic) is list)
self.assertTrue(type(column) is list)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_statistics_with_no_name(self):
start_time = timeutils.iso8601_from_timestamp(self._start_timestamp /
1000)
query_parms = '?merge_metrics=true&statistics=avg&start_time=' + \
str(start_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_statistics_with_no_statistics(self):
start_time = timeutils.iso8601_from_timestamp(self._start_timestamp /
1000)
query_parms = '?name=name-1&start_time=' + str(start_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_statistics_with_no_start_time(self):
query_parms = '?name=name-1&statistics=avg'
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_statistics_with_invalid_statistics(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?name=name-1&statistics=abc&start_time=' + str(
start_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@test.attr(type="gate")
def test_list_statistics_with_dimensions(self):
start_time = timeutils.iso8601_from_timestamp(self._start_timestamp
/ 1000)
query_parms = '?name=name-1&merge_metrics=true&statistics=avg&' \
'start_time=' + str(start_time) + \
'&dimensions=key1:value1'
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_statistics_with_end_time(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
end_time = timeutils.iso8601_from_timestamp(
self._end_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=true&statistics=avg&' \
'start_time=' + str(start_time) + '&end_time=' + \
str(end_time)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_statistics_with_period(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=true&statistics=avg&' \
'start_time=' + str(start_time) + '&period=300'
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_statistics_with_offset_limit(self):
start_timestamp = int(time.time() * 1000)
name = data_utils.rand_name()
metric = [
helpers.create_metric(name=name, timestamp=start_timestamp + 0,
dimensions={'key1': 'value-1',
'key2': 'value-1'},
value=1),
helpers.create_metric(name=name, timestamp=start_timestamp + 500,
dimensions={'key1': 'value-2',
'key2': 'value-2'},
value=2),
helpers.create_metric(name=name, timestamp=start_timestamp + 1000,
dimensions={'key1': 'value-3',
'key2': 'value-3'},
value=3),
helpers.create_metric(name=name, timestamp=start_timestamp + 1500,
dimensions={'key1': 'value-4',
'key2': 'value-4'},
value=4),
helpers.create_metric(name=name, timestamp=start_timestamp + 2000,
dimensions={'key1': 'value-2',
'key2': 'value-2'},
value=5),
helpers.create_metric(name=name, timestamp=start_timestamp + 2500,
dimensions={'key1': 'value-3',
'key2': 'value-3'},
value=6),
helpers.create_metric(name=name, timestamp=start_timestamp + 3000,
dimensions={'key1': 'value-4',
'key2': 'value-4'},
value=7),
helpers.create_metric(name=name, timestamp=start_timestamp + 3500,
dimensions={'key1': 'value-4',
'key2': 'value-4'},
value=8)
]
resp, response_body = self.monasca_client.create_metrics(metric)
time.sleep(WAIT_TIME)
query_parms = '?name=' + name
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
start_time = timeutils.iso8601_from_timestamp(
start_timestamp / 1000)
end_timestamp = start_timestamp + 4000
end_time = timeutils.iso8601_from_timestamp(end_timestamp / 1000)
query_parms = '?name=' + name + '&merge_metrics=true&statistics=avg,' \
'max,min,sum,count&start_time=' + str(start_time) + \
'&end_time=' + str(end_time) + '&period=1'
resp, body = self.monasca_client.list_statistics(query_parms)
self.assertEqual(200, resp.status)
elements = body['elements'][0]['statistics']
first_element = elements[0]
last_element = elements[3]
query_parms = '?name=' + name + '&merge_metrics=true&statistics=avg,' \
'max,min,sum,count&start_time=' + str(start_time) + \
'&end_time=' + str(end_time) + '&period=1' + '&limit=4'
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements'][0]['statistics']
self.assertEqual(4, len(elements))
self.assertEqual(first_element, elements[0])
for limit in xrange(1, 5):
next_element = elements[limit - 1]
offset_timestamp = start_timestamp
while True:
offset_timestamp += 1000 * limit
offset = timeutils.iso8601_from_timestamp(offset_timestamp /
1000)
query_parms = '?name=' + name + '&merge_metrics=true' + \
'&statistics=avg,max,min,sum,' \
'count&start_time=' + str(start_time) + \
'&end_time=' + str(end_time) + '&period=1' + \
'&limit=' + str(limit) + '&offset=' + str(offset)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
new_elements = response_body['elements'][0]['statistics']
if len(new_elements) > limit - 1:
self.assertEqual(limit, len(new_elements))
next_element = new_elements[limit - 1]
elif len(new_elements) > 0 and len(new_elements) <= limit - 1:
self.assertEqual(last_element, new_elements[0])
break
else:
self.assertEqual(last_element, next_element)
break
@test.attr(type="gate")
def test_list_statistics_with_merge_metrics(self):
start_time = timeutils.iso8601_from_timestamp(
self._start_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=true&statistics=avg&' \
'merge_metrics=true&start_time=' + str(start_time)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_statistics_with_no_merge_metrics(self):
start_time = timeutils.\
iso8601_from_timestamp(self._start_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=false&' \
'statistics=avg,min,max&start_time=' + str(start_time)
self.assertRaises(exceptions.Conflict,
self.monasca_client.list_statistics, query_parms)
@test.attr(type="gate")
@test.attr(type=['negative'])
def test_list_statistics_with_name_exceeds_max_length(self):
long_name = "x" * (constants.MAX_LIST_STATISTICS_NAME_LENGTH + 1)
start_time = timeutils.iso8601_from_timestamp(self._start_timestamp
/ 1000)
query_parms = '?merge_metrics=true&name=' + str(long_name) + \
'&start_time=' + str(start_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@test.attr(type="gate")
def test_list_statistics_with_more_than_one_statistics(self):
start_time = timeutils.\
iso8601_from_timestamp(self._start_timestamp / 1000)
query_parms = '?name=name-1&merge_metrics=true&' \
'statistics=avg,min,max&start_time=' + str(start_time)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
@test.attr(type="gate")
def test_list_statistics_response_body_statistic_result_type(self):
start_time = timeutils.iso8601_from_timestamp(self._start_timestamp
/ 1000)
query_parms = '?name=name-1&merge_metrics=true&statistics=avg&' \
'start_time=' + str(start_time)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
element = response_body['elements'][0]
statistic = element['statistics']
statistic_result_type = type(statistic[0][1])
self.assertEqual(statistic_result_type, float)

View File

@ -0,0 +1,51 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
#
# 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 datetime
from oslo_serialization import jsonutils as json
from monasca_tempest_tests.tests.api import base
from tempest import test
class TestVersions(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestVersions, cls).resource_setup()
@test.attr(type='gate')
def test_get_version(self):
resp, response_body = self.monasca_client.get_version()
self.assertEqual(resp.status, 200)
response_body = json.loads(response_body)
self.assertTrue(isinstance(response_body, dict))
version = response_body
self.assertTrue(set(['id', 'links', 'status', 'updated']) ==
set(version))
self.assertEqual(version['id'], u'v2.0')
self.assertEqual(version['status'], u'CURRENT')
date_object = datetime.datetime.strptime(version['updated'],
"%Y-%m-%dT%H:%M:%S.%fZ")
self.assertTrue(isinstance(date_object, datetime.datetime))
links = response_body['links']
self.assertTrue(isinstance(links, list))
link = links[0]
self.assertTrue(set(['rel', 'href']) ==
set(link))
self.assertEqual(link['rel'], u'self')
self.assertTrue(link['href'].endswith('/v2.0'))
return

View File

@ -20,9 +20,10 @@ classifier =
[files]
packages =
monasca_api
monasca_tempest_tests
data_files =
/etc/monasca =
etc/monasca =
etc/api-config.conf
etc/api-config.ini
@ -30,5 +31,8 @@ data_files =
console_scripts =
monasca-api = monasca_api.api.server:launch
tempest.test_plugins =
monasca_tests = monasca_tempest_tests.plugin:MonascaTempestPlugin
[pbr]
warnerrors = True
warnerrors = True

View File

@ -9,7 +9,7 @@ usedevelop = True
install_command = pip install -U {opts} {packages}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = nosetests
commands = python setup.py testr --testr-args='{posargs}'
[testenv:cover]
setenv = NOSE_WITH_COVERAGE=1