Remove bundled intree monasca-api tempest plugin

* https://review.openstack.org/#/c/526844/ move the intree
  bundled tempest plugin to a new repo monasca-tempest-plugin.
  Let's use it and remove the bundled tempest plugin from repo.

* Moved post_host script to main root directory
* Removed dummy gate_hook.sh script
* Fixed the jobs for the same

Story: 2001400
Task: 6085

Depends-On: I2ce2bd8238d44a451faeba9ddbfe27d900e9adef
Change-Id: I79cea368271bbef33914dba7b95f5546a1b8d3c1
This commit is contained in:
Chandan Kumar 2017-12-17 12:25:24 +05:30
parent dbb0fcb67c
commit 80b4f18e1e
33 changed files with 8 additions and 7488 deletions

View File

@ -17,6 +17,7 @@
- openstack/monasca-ui
- openstack/python-monascaclient
- openstack/tempest
- openstack/monasca-tempest-plugin
- job:
name: monasca-tempest-python-mysql

View File

@ -91,12 +91,4 @@ sudo chown -R $USER:stack $TEMPEST_DIR
load_devstack_utilities
setup_monasca_api
set_tempest_conf
(cd $TEMPEST_DIR; testr init)
(cd $TEMPEST_DIR; testr list-tests monasca_tempest_tests > monasca_tempest_tests)
(cd $TEMPEST_DIR; cat monasca_tempest_tests)
(cd $TEMPEST_DIR; cat monasca_tempest_tests | grep gate > monasca_tempest_tests_gate)
(cd $TEMPEST_DIR; testr run --subunit --load-list=monasca_tempest_tests_gate | subunit-trace --fails)
set_tempest_conf

View File

@ -1,186 +0,0 @@
# Introduction
The Monasca Tempest Tests use the [OpenStack Tempest Plugin Interface](https://docs.openstack.org/tempest/latest/plugin.html). This README describes how to configure and run them using a variety of methods.
Currently the devstack environment is needed to run the tests. Instructions on setting up a devstack environment can be found here: https://github.com/openstack/monasca-api/devstack/README.md.
# Configuring to run the Monasca Tempest Tests
1. Clone the OpenStack Tempest repo, and cd to it.
```
git clone https://git.openstack.org/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
```
4. Create ```etc/tempest.conf``` in the Tempest root dir by running the following command:
```
oslo-config-generator --config-file tempest/cmd/config-generator.tempest.conf --output-file etc/tempest.conf
```
Add the following sections to ```tempest.conf``` for testing using the devstack environment.
```
[identity]
auth_version = v3
uri = http://127.0.0.1/identity_admin/v2.0/
uri_v3 = http://127.0.0.1/identity_admin/v3/
user_lockout_failure_attempts = 2
user_locakout_duration = 5
user_unique_last_password_count = 2
admin_domain_scope = True
[auth]
use_dynamic_credentials = True
admin_project_name = admin
admin_username = admin
admin_password = secretadmin
admin_domain_name = Default
```
Edit the variable values in the identity section to match your particular environment.
5. Create ```etc/logging.conf``` in the Tempest root dir by making a copying ```logging.conf.sample```.
6. Clone the monasca-api repo in a directory somewhere outside of the Tempest root dir.
7. Install the monasca-api in your venv, which will also register
the Monasca Tempest Plugin as, monasca_tests.
cd into the monasca-api root directory. Making sure that the tempest virtual env is still active,
run the following command.
```
python setup.py install
```
See the [OpenStack Tempest Plugin Interface](https://docs.openstack.org/tempest/latest/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](https://docs.openstack.org/os-testr/latest/)
3. [PyCharm](https://www.jetbrains.com/pycharm/)
4. Tempest Scripts in Devstack
## 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. Initializing testr is necessary to set up the .testrepository directory before using it for the first time. In the Tempest root dir:
```
testr init
```
2. Create a list of the Monasca Tempest Tests in a file:
```
testr list-tests monasca_tempest_tests > monasca_tempest_tests
```
3. 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 using Tempest Run command
``tempest run`` is a domain-specific command to be used as the primary
entry point for running Tempest tests.
1. In the Tempest root dir:
```
tempest run -r monasca_tempest_tests
```
## Run the tests from the CLI using os-testr (no file necessary)
[Os-testr](https://docs.openstack.org/os-testr/latest/) is a test wrapper that can be used to run the Monasca Tempest tests.
1. In the Tempest root dir:
```
ostestr --serial --regex monasca_tempest_tests
```
```--serial``` option is necessary here. Monasca tempest tests can't be run in parallel (default option in ostestr) because some tests depend on the same data and will randomly fail.
## Running/Debugging the Monasca Tempest Tests in PyCharm
You need to install `nose` for running tests from PyCharm:
```
pip install nose
```
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.
## Run the tests from the CLI using tempest scripts in devstack
1. Create a virtualenv in devstack for running the tempest tests and activate it:
```
cd /opt/stack/tempest
virtualenv .venv
source .venv/bin/activate
```
2. Install the tempest requirements in the virtualenv:
```
pip install -r requirements.txt -r test-requirements.txt
```
3. If you want to test changes in monasca-api code on your local machine, change directory to monasca-api and install the latest monasca-api code:
```
cd /vagrant_home/<monasca-api directory>
python setup.py install
```
Or if you want to use the current monasca api in devstack:
```
cd /opt/stack/monasca-api
python setup.py install
```
4. Run tempest tests:
```
cd /opt/stack/tempest
testr init
ostestr --serial --regex monasca_tempest_tests
```
# References
This section provides a few additional references that might be useful:
* [Tempest - The OpenStack Integration Test Suite](https://docs.openstack.org/tempest/latest/overview.html#quickstart)
* [Tempest Configuration Guide](https://github.com/openstack/tempest/blob/master/doc/source/configuration.rst#id1)
* [OpenStack Tempest Plugin Interface](https://docs.openstack.org/tempest/latest/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

@ -1,23 +0,0 @@
# (C) Copyright 2015,2017 Hewlett Packard Enterprise Development 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):
super(Manager, self).__init__(credentials)
self.monasca_client = monasca_client.MonascaClient(self.auth_provider)

View File

@ -1,41 +0,0 @@
# (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_option = 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

@ -1,40 +0,0 @@
# (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.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):
conf.register_opt(config_monitoring.service_option,
group='service_available')
conf.register_group(config_monitoring.monitoring_group)
conf.register_opts(config_monitoring.MonitoringGroup,
group='monitoring')
def get_opt_lists(self):
return [(config_monitoring.monitoring_group.name,
config_monitoring.MonitoringGroup),
('service_available', [config_monitoring.service_option])]

View File

@ -1,346 +0,0 @@
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development 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, tenant_id=None):
uri = 'metrics'
if tenant_id:
uri = uri + '?tenant_id=%s' % tenant_id
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_dimension_names(self, query_params=None):
uri = 'metrics/dimensions/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_dimension_values(self, query_params=None):
uri = 'metrics/dimensions/names/values'
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,
period=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
if period is not None:
request_body['period'] = period
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, type, address, period=None):
uri = 'notification-methods/' + id
request_body = {}
request_body['name'] = name
request_body['type'] = type
request_body['address'] = address
if period is not None:
request_body['period'] = period
resp, response_body = self.put(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def patch_notification_method(self, id,
name=None, type=None,
address=None, period=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
if period is not None:
request_body['period'] = period
resp, response_body = self.patch(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def list_notification_method_types(self, query_params=None):
uri = 'notification-methods/types'
if query_params is not None:
uri = uri + query_params
resp, response_body = self.get(uri)
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,
actions_enabled, match_by,
severity, alarm_actions,
ok_actions, undetermined_actions,
**kwargs):
uri = 'alarm-definitions/' + id
request_body = {}
request_body['name'] = name
request_body['expression'] = expression
request_body['description'] = description
request_body['actions_enabled'] = actions_enabled
request_body['match_by'] = match_by
request_body['severity'] = severity
request_body['alarm_actions'] = alarm_actions
request_body['ok_actions'] = ok_actions
request_body['undetermined_actions'] = undetermined_actions
for key, value in kwargs.items():
request_body[key] = value
resp, response_body = self.put(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.items():
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.items():
request_body[key] = value
resp, response_body = self.put(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.items():
request_body[key] = value
resp, response_body = self.patch(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def count_alarms(self, query_params=None):
uri = 'alarms/count'
if query_params is not None:
uri += query_params
resp, response_body = self.get(uri)
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)
# For Negative Tests
def update_alarm_definition_with_no_ok_actions(self, id, name,
expression, description,
actions_enabled, match_by,
severity, alarm_actions,
undetermined_actions,
**kwargs):
uri = 'alarm-definitions/' + id
request_body = {}
request_body['name'] = name
request_body['expression'] = expression
request_body['description'] = description
request_body['actions_enabled'] = actions_enabled
request_body['match_by'] = match_by
request_body['severity'] = severity
request_body['alarm_actions'] = alarm_actions
request_body['undetermined_actions'] = undetermined_actions
for key, value in kwargs.items():
request_body[key] = value
resp, response_body = self.put(uri, json.dumps(request_body))
return resp, json.loads(response_body)
def update_notification_method_with_no_address(self, id, name, type,
period=None):
uri = 'notification-methods/' + id
request_body = {}
request_body['name'] = name
request_body['type'] = type
if period is not None:
request_body['period'] = period
resp, response_body = self.put(uri, json.dumps(request_body))
return resp, json.loads(response_body)

View File

@ -1,97 +0,0 @@
# (C) Copyright 2015-2017 Hewlett Packard Enterprise Development 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 six.moves.urllib.parse as urlparse
from tempest.common import credentials_factory
from tempest import config
from tempest.lib import exceptions
import tempest.test
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()
auth_version = CONF.identity.auth_version
cls.cred_provider = credentials_factory.get_credentials_provider(
cls.__name__,
force_tenant_isolation=True,
identity_version=auth_version)
credentials = cls.cred_provider.get_creds_by_roles(
['monasca-user', 'monasca-read-only-user', 'admin']).credentials
cls.os = clients.Manager(credentials=credentials)
cls.monasca_client = cls.os.monasca_client
cls.projects_client = cls.os.projects_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()
if resp.status == 200:
if 'elements' in response_body:
elements = response_body['elements']
for element in elements:
id = element['id']
cls.monasca_client.delete_alarm_definition(id)
resp, response_body = cls.monasca_client.list_notification_methods()
if resp.status == 200:
if 'elements' in response_body:
elements = response_body['elements']
for element in elements:
id = element['id']
cls.monasca_client.delete_notification_method(id)
resp, response_body = cls.monasca_client.list_alarms()
if resp.status == 200:
if 'elements' in response_body:
elements = response_body['elements']
for element in elements:
id = element['id']
cls.monasca_client.delete_alarm(id)
cls.cred_provider.clear_creds()
def _get_offset(self, response_body):
next_link = None
self_link = None
for link in response_body['links']:
if link['rel'] == 'next':
next_link = link['href']
if link['rel'] == 'self':
self_link = link['href']
if not next_link:
query_parms = urlparse.parse_qs(urlparse.urlparse(self_link).query)
self.fail("No next link returned with query parameters: {}".format(query_parms))
query_params = urlparse.parse_qs(urlparse.urlparse(next_link).query)
if 'offset' not in query_params:
self.fail("No offset in next link: {}".format(next_link))
return query_params['offset'][0]

View File

@ -1,47 +0,0 @@
# (C) Copyright 2015-2016 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_RETRIES = 60
RETRY_WAIT_SECS = 1
ONE_MINUTE_TIME_OUT = 60
ALARM_DEFINITION_CREATION_WAIT = 1
MAX_METRIC_NAME_LENGTH = 255
MAX_DIMENSION_KEY_LENGTH = 255
MAX_DIMENSION_VALUE_LENGTH = 255
INVALID_DIMENSION_CHARS = "<>={},\"\;&"
INVALID_NAME_CHARS = INVALID_DIMENSION_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 = 512
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
MAX_VALUE_META_NAME_LENGTH = 255
MAX_VALUE_META_TOTAL_LENGTH = 2048

View File

@ -1,179 +0,0 @@
# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
# (C) Copyright SUSE LLC
#
# 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
import time
import six.moves.urllib.parse as urlparse
from tempest.lib.common.utils import data_utils
NUM_ALARM_DEFINITIONS = 2
NUM_MEASUREMENTS = 100
def create_metric(name='name-1',
dimensions={
'key-1': 'value-1',
'key-2': 'value-2'
},
timestamp=None,
value=0.0,
value_meta={
'key-1': 'value-1',
'key-2': 'value-2'
},
):
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
else:
metric['timestamp'] = int(time.time() * 1000)
if value is not None:
metric['value'] = value
if value_meta is not None:
metric['value_meta'] = value_meta
return metric
def create_notification(name=data_utils.rand_name('notification-'),
type='EMAIL',
address='john.doe@domain.com',
period=0):
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
if period is not None:
notification['period'] = period
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
def delete_alarm_definitions(monasca_client):
# Delete alarm definitions
resp, response_body = monasca_client.list_alarm_definitions()
elements = response_body['elements']
if elements:
for element in elements:
alarm_def_id = element['id']
monasca_client.delete_alarm_definition(alarm_def_id)
def timestamp_to_iso(timestamp):
time_utc = datetime.datetime.utcfromtimestamp(timestamp / 1000.0)
time_iso_base = time_utc.strftime("%Y-%m-%dT%H:%M:%S")
time_iso_base += 'Z'
return time_iso_base
def timestamp_to_iso_millis(timestamp):
time_utc = datetime.datetime.utcfromtimestamp(timestamp / 1000.0)
time_iso_base = time_utc.strftime("%Y-%m-%dT%H:%M:%S")
time_iso_microsecond = time_utc.strftime(".%f")
time_iso_millisecond = time_iso_base + time_iso_microsecond[0:4] + 'Z'
return time_iso_millisecond
def get_query_param(uri, query_param_name):
query_param_val = None
parsed_uri = urlparse.urlparse(uri)
for query_param in parsed_uri.query.split('&'):
parsed_query_name, parsed_query_val = query_param.split('=', 1)
if query_param_name == parsed_query_name:
query_param_val = parsed_query_val
return query_param_val
def get_expected_elements_inner_offset_limit(all_elements, offset, limit, inner_key):
expected_elements = []
total_statistics = 0
if offset is None:
offset_id = None
offset_time = ""
passed_offset = True
else:
offset_tuple = offset.split('_')
offset_id = offset_tuple[0] if len(offset_tuple) > 1 else u'0'
offset_time = offset_tuple[1] if len(offset_tuple) > 1 else offset_tuple[0]
passed_offset = False
for element in all_elements:
element_id = element['id']
if (not passed_offset) and element_id != offset_id:
continue
next_element = None
for value in element[inner_key]:
if passed_offset or (element_id == offset_id and value[0] > offset_time):
if not passed_offset:
passed_offset = True
if not next_element:
next_element = element.copy()
next_element[inner_key] = [value]
else:
next_element[inner_key].append(value)
total_statistics += 1
if total_statistics >= limit:
break
if next_element:
expected_elements.append(next_element)
if total_statistics >= limit:
break
if element_id == offset_id:
passed_offset = True
# if index is used in the element id, reset to start at zero
if expected_elements and expected_elements[0]['id'].isdigit():
for i in range(len(expected_elements)):
expected_elements[i]['id'] = str(i)
return expected_elements

File diff suppressed because it is too large Load Diff

View File

@ -1,141 +0,0 @@
# (C) Copyright 2016-2017 Hewlett Packard Enterprise Development 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 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.lib.common.utils import data_utils
from tempest.lib import decorators
MIN_HISTORY = 2
class TestAlarmStateHistoryMultipleTransitions(base.BaseMonascaTest):
# For testing list alarm state history with the same alarm ID, two alarm
# transitions are needed. One transit from ALARM state to UNDETERMINED
# state and the other one from UNDETERMINED state to ALARM state.
@classmethod
def resource_setup(cls):
super(TestAlarmStateHistoryMultipleTransitions, cls).resource_setup()
alarm_definition = helpers.create_alarm_definition(
name=data_utils.rand_name('alarm_state_history'),
expression="min(name-1) < 1.0")
cls.monasca_client.create_alarm_definitions(alarm_definition)
for timer in range(constants.MAX_RETRIES):
# create some metrics to prime the system and create
# MIN_HISTORY alarms
metric = helpers.create_metric(
name="name-1", dimensions={'key1': 'value1'}, value=0.0)
cls.monasca_client.create_metrics(metric)
# sleep 1 second between metrics to make sure timestamps
# are different in the second field. Influxdb has a bug
# where it does not sort properly by milliseconds. .014
# is sorted as greater than .138
time.sleep(1.0)
resp, response_body = cls.monasca_client.\
list_alarms_state_history()
elements = response_body['elements']
if len(elements) >= 1:
break
time.sleep(constants.RETRY_WAIT_SECS)
time.sleep(constants.MAX_RETRIES)
for timer in range(constants.MAX_RETRIES * 2):
metric = helpers.create_metric(
name="name-1", dimensions={'key2': 'value2'}, value=2.0)
cls.monasca_client.create_metrics(metric)
# sleep 0.05 second between metrics to make sure timestamps
# are different
time.sleep(0.05)
resp, response_body = \
cls.monasca_client.list_alarms_state_history()
elements = response_body['elements']
if len(elements) >= 2:
return
else:
num_transitions = len(elements)
time.sleep(constants.RETRY_WAIT_SECS)
assert False, "Required {} alarm state transitions, but found {}".\
format(MIN_HISTORY, num_transitions)
@classmethod
def resource_cleanup(cls):
super(TestAlarmStateHistoryMultipleTransitions, cls).\
resource_cleanup()
@decorators.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']
if 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.assertIsInstance(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))
else:
error_msg = "Failed test_list_alarm_state_history: at least one " \
"alarm state history is needed."
self.fail(error_msg)
@decorators.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']
if len(elements) >= MIN_HISTORY:
element = elements[0]
second_element = elements[1]
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))
query_parms = '?offset=' + str(element['timestamp'])
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(second_element, elements_new[0])
else:
error_msg = "Failed test_list_alarm_state_history_with_offset" \
"_limit: two alarms state history are needed."
self.fail(error_msg)

View File

@ -1,180 +0,0 @@
# (C) Copyright 2016-2017 Hewlett Packard Enterprise Development 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 monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import helpers
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
WAIT_SECS = 10
class TestAlarmTransitions(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestAlarmTransitions, cls).resource_setup()
@classmethod
def resource_cleanup(cls):
super(TestAlarmTransitions, cls).resource_cleanup()
def _wait_for_alarm_creation(self, definition_id):
for x in range(WAIT_SECS):
time.sleep(1)
resp, resp_body = self.monasca_client.list_alarms(
query_params="?alarm_definition_id=" + definition_id)
self.assertEqual(200, resp.status)
if len(resp_body['elements']) != 0:
break
self.assertEqual(1, len(resp_body['elements']))
alarm_id = resp_body['elements'][0]['id']
initial_state = resp_body['elements'][0]['state']
return alarm_id, initial_state
def _wait_for_alarm_transition(self, alarm_id, expected_state):
for x in range(WAIT_SECS):
time.sleep(1)
resp, resp_body = self.monasca_client.get_alarm(alarm_id)
self.assertEqual(200, resp.status)
if resp_body['state'] == expected_state:
break
self.assertEqual(expected_state, resp_body['state'])
def _send_measurement(self, metric_def, value):
metric = helpers.create_metric(name=metric_def['name'],
dimensions=metric_def['dimensions'],
value=value)
resp, resp_body = self.monasca_client.create_metrics([metric])
self.assertEqual(204, resp.status)
@decorators.attr(type="gate")
def test_alarm_max_function(self):
metric_def = {
'name': data_utils.rand_name("max_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("max_match")
}
}
expression = "max(" + metric_def['name'] + ") > 14"
definition = helpers.create_alarm_definition(name="Test Max Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = (self.monasca_client
.create_alarm_definitions(definition))
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("UNDETERMINED", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
@decorators.attr(type="gate")
def test_alarm_max_with_deterministic(self):
metric_def = {
'name': data_utils.rand_name("max_deterministic_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("max_match")
}
}
expression = "max(" + metric_def['name'] + ",deterministic) > 14"
definition = helpers.create_alarm_definition(name="Test Max Deterministic Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("OK", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
@decorators.attr(type="gate")
def test_alarm_last_function(self):
metric_def = {
'name': data_utils.rand_name("last_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("last_match")
}
}
expression = "last(" + metric_def['name'] + ") > 14"
definition = helpers.create_alarm_definition(name="Test Last Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("OK", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
self._send_measurement(metric_def, 3)
self._wait_for_alarm_transition(alarm_id, "OK")
@decorators.attr(type="gate")
def test_alarm_last_with_deterministic(self):
metric_def = {
'name': data_utils.rand_name("last_deterministic_test"),
'dimensions': {
'dim_to_match': data_utils.rand_name("last_match")
}
}
expression = "last(" + metric_def['name'] + ",deterministic) > 14"
definition = helpers.create_alarm_definition(name="Test Last Deterministic Function",
description="",
expression=expression,
match_by=["dim_to_match"])
resp, resp_body = self.monasca_client.create_alarm_definitions(definition)
self.assertEqual(201, resp.status)
definition_id = resp_body['id']
time.sleep(1)
self._send_measurement(metric_def, 1)
alarm_id, initial_state = self._wait_for_alarm_creation(definition_id)
self.assertEqual("OK", initial_state)
self._send_measurement(metric_def, 20)
self._wait_for_alarm_transition(alarm_id, "ALARM")
self._send_measurement(metric_def, 3)
self._wait_for_alarm_transition(alarm_id, "OK")

File diff suppressed because it is too large Load Diff

View File

@ -1,355 +0,0 @@
# (C) Copyright 2016-2017 Hewlett Packard Enterprise Development 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
import urllib
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import helpers
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
GROUP_BY_ALLOWED_PARAMS = {'alarm_definition_id', 'name', 'state', 'severity',
'link', 'lifecycle_state', 'metric_name',
'dimension_name', 'dimension_value'}
class TestAlarmsCount(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestAlarmsCount, cls).resource_setup()
num_hosts = 20
alarm_definitions = []
expected_alarm_counts = []
metrics_to_send = []
# OK, LOW
expression = "max(test_metric_01) > 10"
name = data_utils.rand_name('test-counts-01')
alarm_definitions.append(helpers.create_alarm_definition(
name=name,
expression=expression,
severity='LOW',
match_by=['hostname', 'unique']))
for i in range(100):
metrics_to_send.append(helpers.create_metric(
name='test_metric_01',
dimensions={'hostname': 'test_' + str(i % num_hosts),
'unique': str(i)},
value=1
))
expected_alarm_counts.append(100)
# ALARM, MEDIUM
expression = "max(test_metric_02) > 10"
name = data_utils.rand_name('test-counts-02')
alarm_definitions.append(helpers.create_alarm_definition(
name=name,
expression=expression,
severity='MEDIUM',
match_by=['hostname', 'unique']))
for i in range(75):
metrics_to_send.append(helpers.create_metric(
name='test_metric_02',
dimensions={'hostname': 'test_' + str(i % num_hosts),
'unique': str(i)},
value=11
))
# append again to move from undetermined to alarm
metrics_to_send.append(helpers.create_metric(
name='test_metric_02',
dimensions={'hostname': 'test_' + str(i % num_hosts),
'unique': str(i)},
value=11
))
expected_alarm_counts.append(75)
# OK, HIGH, shared dimension
expression = "max(test_metric_03) > 100"
name = data_utils.rand_name('test_counts-03')
alarm_definitions.append(helpers.create_alarm_definition(
name=name,
expression=expression,
severity='HIGH',
match_by=['hostname', 'unique']))
for i in range(50):
metrics_to_send.append(helpers.create_metric(
name='test_metric_03',
dimensions={'hostname': 'test_' + str(i % num_hosts),
'unique': str(i),
'height': '55'},
value=i
))
expected_alarm_counts.append(50)
# UNDERTERMINED, CRITICAL
expression = "max(test_metric_undet) > 100"
name = data_utils.rand_name('test-counts-04')
alarm_definitions.append(helpers.create_alarm_definition(
name=name,
expression=expression,
severity='CRITICAL',
match_by=['hostname', 'unique']))
for i in range(25):
metrics_to_send.append(helpers.create_metric(
name='test_metric_undet',
dimensions={'hostname': 'test_' + str(i % num_hosts),
'unique': str(i)},
value=1
))
expected_alarm_counts.append(25)
# create alarm definitions
cls.alarm_definition_ids = []
for definition in alarm_definitions:
resp, response_body = cls.monasca_client.create_alarm_definitions(
definition)
if resp.status == 201:
cls.alarm_definition_ids.append(response_body['id'])
else:
msg = "Failed to create alarm_definition during setup: {} {}".format(resp.status, response_body)
assert False, msg
# create alarms
for metric in metrics_to_send:
metric['timestamp'] = int(time.time() * 1000)
cls.monasca_client.create_metrics(metric)
# ensure metric timestamps are unique
time.sleep(0.01)
# check that alarms exist
time_out = time.time() + 70
while time.time() < time_out:
setup_complete = True
alarm_count = 0
for i in range(len(cls.alarm_definition_ids)):
resp, response_body = cls.monasca_client.list_alarms(
'?alarm_definition_id=' + cls.alarm_definition_ids[i])
if resp.status != 200:
msg = "Error listing alarms: {} {}".format(resp.status, response_body)
assert False, msg
if len(response_body['elements']) < expected_alarm_counts[i]:
setup_complete = False
alarm_count += len(response_body['elements'])
break
if setup_complete:
# allow alarm transitions to occur
# time.sleep(15)
return
msg = "Failed to create all specified alarms during setup, alarm_count was {}".format(alarm_count)
assert False, msg
@classmethod
def resource_cleanup(cls):
super(TestAlarmsCount, cls).resource_cleanup()
def _verify_counts_format(self, response_body, group_by=None, expected_length=None):
expected_keys = ['links', 'counts', 'columns']
for key in expected_keys:
self.assertIn(key, response_body)
self.assertIsInstance(response_body[key], list)
expected_columns = ['count']
if isinstance(group_by, list):
expected_columns.extend(group_by)
self.assertEqual(expected_columns, response_body['columns'])
if expected_length is not None:
self.assertEqual(expected_length, len(response_body['counts']))
else:
expected_length = len(response_body['counts'])
for i in range(expected_length):
self.assertEqual(len(expected_columns), len(response_body['counts'][i]))
# test with no params
@decorators.attr(type='gate')
def test_count(self):
resp, response_body = self.monasca_client.count_alarms()
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body)
self.assertEqual(250, response_body['counts'][0][0])
# test with each group_by parameter singularly
@decorators.attr(type='gate')
def test_group_by_singular(self):
resp, response_body = self.monasca_client.list_alarms("?state=ALARM")
self.assertEqual(200, resp.status)
alarm_state_count = len(response_body['elements'])
resp, response_body = self.monasca_client.list_alarms("?state=undetermined")
self.assertEqual(200, resp.status)
undet_state_count = len(response_body['elements'])
resp, response_body = self.monasca_client.count_alarms("?group_by=state")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body, group_by=['state'])
self.assertEqual('ALARM', response_body['counts'][0][1])
self.assertEqual(alarm_state_count, response_body['counts'][0][0])
self.assertEqual('UNDETERMINED', response_body['counts'][-1][1])
self.assertEqual(undet_state_count, response_body['counts'][-1][0])
resp, response_body = self.monasca_client.count_alarms("?group_by=name")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body, group_by=['name'], expected_length=4)
# test with group by a parameter that is not allowed
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_group_by_not_allowed(self):
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.count_alarms, "?group_by=not_allowed")
# test with a few group_by fields
@decorators.attr(type='gate')
def test_group_by_multiple(self):
resp, response_body = self.monasca_client.list_alarms()
alarm_low_count = 0
for alarm in response_body['elements']:
if alarm['state'] is 'ALARM' and alarm['severity'] is 'LOW':
alarm_low_count += 1
# Using urlencode mimics the CLI behavior. Without the urlencode, falcon
# treats group_by as a list, with the urlencode it treats group_by as
# a string. The API needs to handle both.
# test_with_all_group_by_params tests multiple group_by without
# urlencode
query_params = urllib.urlencode([('group_by', 'state,severity')])
resp, response_body = self.monasca_client.count_alarms("?" + query_params)
self._verify_counts_format(response_body, group_by=['state', 'severity'])
def run_count_test(self, query_string):
resp, response_body = self.monasca_client.list_alarms(query_string)
self.assertEqual(200, resp.status)
expected_count = len(response_body['elements'])
# Make sure something was found
self.assertTrue(expected_count > 0)
resp, response_body = self.monasca_client.count_alarms(query_string)
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body, expected_length=1)
self.assertEqual(expected_count, response_body['counts'][0][0])
# test filter by severity
@decorators.attr(type='gate')
def test_filter_severity(self):
self.run_count_test("?severity=LOW")
# test filter by state
@decorators.attr(type='gate')
def test_filter_state(self):
self.run_count_test("?state=ALARM")
# test filter by metric name
@decorators.attr(type='gate')
def test_filter_metric_name(self):
self.run_count_test("?metric_name=test_metric_01")
# test with multiple metric dimensions
@decorators.attr(type='gate')
def test_filter_multiple_dimensions(self):
self.run_count_test("?metric_dimensions=hostname:test_1,unique:1")
# test with filter and group_by parameters
@decorators.attr(type='gate')
def test_filter_and_group_by_params(self):
resp, response_body = self.monasca_client.list_alarms("?state=ALARM")
self.assertEqual(200, resp.status)
expected_count = 0
for element in response_body['elements']:
if element['alarm_definition']['severity'] == 'MEDIUM':
expected_count += 1
resp, response_body = self.monasca_client.count_alarms("?state=ALARM&group_by=severity")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body, group_by=['severity'])
self.assertEqual(expected_count, response_body['counts'][0][0])
@decorators.attr(type='gate')
def test_with_all_group_by_params(self):
resp, response_body = self.monasca_client.list_alarms()
self.assertEqual(200, resp.status)
expected_num_count = len(response_body['elements'])
query_params = "?group_by=" + ','.join(GROUP_BY_ALLOWED_PARAMS)
resp, response_body = self.monasca_client.count_alarms(query_params)
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body, group_by=list(GROUP_BY_ALLOWED_PARAMS))
# Expect duplicates
msg = "Not enough distinct counts. Expected at least {}, found {}".format(expected_num_count,
len(response_body['counts']))
assert expected_num_count <= len(response_body['counts']), msg
@decorators.attr(type='gate')
def test_limit(self):
resp, response_body = self.monasca_client.count_alarms(
"?group_by=metric_name,dimension_name,dimension_value")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body,
group_by=['metric_name', 'dimension_name', 'dimension_value'])
assert len(response_body['counts']) > 1, "Too few counts to test limit, found 1"
resp, response_body = self.monasca_client.count_alarms(
"?group_by=metric_name,dimension_name,dimension_value&limit=1")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body,
group_by=['metric_name', 'dimension_name', 'dimension_value'],
expected_length=1)
@decorators.attr(type='gate')
def test_offset(self):
resp, response_body = self.monasca_client.count_alarms(
"?group_by=metric_name,dimension_name,dimension_value")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body,
group_by=['metric_name', 'dimension_name', 'dimension_value'])
expected_counts = len(response_body['counts']) - 1
resp, response_body = self.monasca_client.count_alarms(
"?group_by=metric_name,dimension_name,dimension_value&offset=1")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body,
group_by=['metric_name', 'dimension_name', 'dimension_value'],
expected_length=expected_counts)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_invalid_offset(self):
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.count_alarms, "?group_by=metric_name&offset=not_an_int")
@decorators.attr(type='gate')
def test_limit_and_offset(self):
resp, response_body = self.monasca_client.count_alarms(
"?group_by=metric_name,dimension_name,dimension_value")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body,
group_by=['metric_name', 'dimension_name', 'dimension_value'])
expected_first_result = response_body['counts'][1]
resp, response_body = self.monasca_client.count_alarms(
"?group_by=metric_name,dimension_name,dimension_value&offset=1&limit=5")
self.assertEqual(200, resp.status)
self._verify_counts_format(response_body,
group_by=['metric_name', 'dimension_name', 'dimension_value'],
expected_length=5)
self.assertEqual(expected_first_result, response_body['counts'][0])

View File

@ -1,237 +0,0 @@
# (C) Copyright 2015-2017 Hewlett Packard Enterprise Development 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 monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import constants
from monasca_tempest_tests.tests.api import helpers
from oslo_utils import timeutils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
NUM_ALARM_DEFINITIONS = 3
MIN_HISTORY = 3
class TestAlarmsStateHistoryOneTransition(base.BaseMonascaTest):
# Alarms state histories with one transition but different alarm
# definitions are needed for this test class.
@classmethod
def resource_setup(cls):
super(TestAlarmsStateHistoryOneTransition, cls).resource_setup()
for i in range(MIN_HISTORY):
alarm_definition = helpers.create_alarm_definition(
name=data_utils.rand_name('alarm_state_history' + str(i + 1)),
expression="min(name-" + str(i + 1) + ") < " + str(i + 1))
cls.monasca_client.create_alarm_definitions(alarm_definition)
num_transitions = 0
for timer in range(constants.MAX_RETRIES):
for i in range(MIN_HISTORY):
# Create some metrics to prime the system and waiting for the
# alarms to be created and then for them to change state.
# MIN_HISTORY number of Alarms State History are needed.
metric = helpers.create_metric(name="name-" + str(i + 1))
cls.monasca_client.create_metrics(metric)
# Ensure alarms transition at different times
time.sleep(0.1)
resp, response_body = cls.monasca_client.\
list_alarms_state_history()
elements = response_body['elements']
if len(elements) >= MIN_HISTORY:
return
else:
num_transitions = len(elements)
time.sleep(constants.RETRY_WAIT_SECS)
assert False, "Required {} alarm state transitions, but found {}".\
format(MIN_HISTORY, num_transitions)
@classmethod
def resource_cleanup(cls):
super(TestAlarmsStateHistoryOneTransition, cls).resource_cleanup()
@decorators.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']
number_of_alarms = len(elements)
if number_of_alarms < 1:
error_msg = "Failed test_list_alarms_state_history: need " \
"at least one alarms state history to test."
self.fail(error_msg)
else:
element = elements[0]
self.assertTrue(set(['id', 'alarm_id', 'metrics', 'old_state',
'new_state', 'reason', 'reason_data',
'timestamp', 'sub_alarms'])
== set(element))
@decorators.attr(type="gate")
def test_list_alarms_state_history_with_dimensions(self):
resp, response_body = self.monasca_client.list_alarms_state_history()
elements = response_body['elements']
if elements:
element = 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)
else:
error_msg = "Failed test_list_alarms_state_history_with_" \
"dimensions: need at least one alarms state history " \
"to test."
self.fail(error_msg)
@decorators.attr(type="gate")
def test_list_alarms_state_history_with_start_time(self):
# 1, get all histories
resp, all_response_body = self.monasca_client.\
list_alarms_state_history()
all_elements = all_response_body['elements']
if len(all_elements) < 3:
error_msg = "Failed test_list_alarms_state_history_with_" \
"start_time: need 3 or more alarms state history " \
"to test."
self.fail(error_msg)
# 2, query second(timestamp) <= x
min_element, second_element, max_element = \
self._get_elements_with_min_max_timestamp(all_elements)
start_time = second_element['timestamp']
query_params = '?start_time=' + str(start_time)
resp, selected_response_body = self.monasca_client.\
list_alarms_state_history(query_params)
selected_elements = selected_response_body['elements']
# 3. compare #1 and #2
expected_elements = all_elements
expected_elements.remove(min_element)
self.assertEqual(expected_elements, selected_elements)
@decorators.attr(type="gate")
def test_list_alarms_state_history_with_end_time(self):
# 1, get all histories
resp, all_response_body = self.monasca_client.\
list_alarms_state_history()
all_elements = all_response_body['elements']
if len(all_elements) < 3:
error_msg = "Failed test_list_alarms_state_history_with_" \
"end_time: need 3 or more alarms state history " \
"to test."
self.fail(error_msg)
# 2, query x <= second(timestamp)
min_element, second_element, max_element = \
self._get_elements_with_min_max_timestamp(all_elements)
end_time = second_element['timestamp']
query_params = '?end_time=' + str(end_time)
resp, selected_response_body = self.monasca_client.\
list_alarms_state_history(query_params)
selected_elements = selected_response_body['elements']
# 3. compare #1 and #2
expected_elements = all_elements
expected_elements.remove(max_element)
self.assertEqual(expected_elements, selected_elements)
@decorators.attr(type="gate")
def test_list_alarms_state_history_with_start_end_time(self):
# 1, get all histories
resp, all_response_body = self.monasca_client.\
list_alarms_state_history()
all_elements = all_response_body['elements']
if len(all_elements) < 3:
error_msg = "Failed test_list_alarms_state_history_with_" \
"start_end_time: need 3 or more alarms state history" \
"to test."
self.fail(error_msg)
# 2, query min(timestamp) <= x <= max(timestamp)
min_element, second_element, max_element = \
self._get_elements_with_min_max_timestamp(all_elements)
start_time = min_element['timestamp']
end_time = max_element['timestamp']
query_params = '?start_time=' + str(start_time) + '&end_time=' + \
str(end_time)
resp, selected_response_body = self.monasca_client.\
list_alarms_state_history(query_params)
selected_elements = selected_response_body['elements']
# 3. compare #1 and #2
self.assertEqual(all_elements, selected_elements)
@decorators.attr(type="gate")
def test_list_alarms_state_history_with_offset_limit(self):
resp, response_body = self.monasca_client.list_alarms_state_history()
elements_set1 = response_body['elements']
number_of_alarms = len(elements_set1)
if number_of_alarms >= MIN_HISTORY:
query_parms = '?limit=' + str(number_of_alarms)
resp, response_body = self.monasca_client.\
list_alarms_state_history(query_parms)
self.assertEqual(200, resp.status)
elements_set2 = response_body['elements']
self.assertEqual(number_of_alarms, len(elements_set2))
for index in range(MIN_HISTORY - 1):
self.assertEqual(elements_set1[index], elements_set2[index])
for index in range(MIN_HISTORY - 1):
alarm_history = elements_set2[index]
max_limit = len(elements_set2) - index
for limit in range(1, max_limit):
first_index = index + 1
last_index = first_index + limit
expected_elements = elements_set2[first_index:last_index]
query_parms = '?offset=' + str(alarm_history['timestamp'])\
+ '&limit=' + str(limit)
resp, response_body = self.\
monasca_client.list_alarms_state_history(query_parms)
self.assertEqual(200, resp.status)
new_elements = response_body['elements']
self.assertEqual(limit, len(new_elements))
for i in range(len(expected_elements)):
self.assertEqual(expected_elements[i], new_elements[i])
else:
error_msg = ("Failed test_list_alarms_state_history_with_offset "
"limit: need three alarms state history to test. "
"Current number of alarms = {}").format(
number_of_alarms)
self.fail(error_msg)
def _get_elements_with_min_max_timestamp(self, elements):
sorted_elements = sorted(elements, key=lambda element: timeutils.
parse_isotime(element['timestamp']))
min_element = sorted_elements[0]
second_element = sorted_elements[1]
max_element = sorted_elements[-1]
return min_element, second_element, max_element

View File

@ -1,249 +0,0 @@
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
# (C) Copyright 2017 SUSE LLC
#
# 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 urllib import urlencode
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import constants
from monasca_tempest_tests.tests.api import helpers
class TestDimensions(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestDimensions, cls).resource_setup()
metric_name1 = data_utils.rand_name()
name1 = "name_1"
name2 = "name_2"
value1 = "value_1"
value2 = "value_2"
timestamp = int(round(time.time() * 1000))
time_iso = helpers.timestamp_to_iso(timestamp)
metric1 = helpers.create_metric(name=metric_name1,
dimensions={name1: value1,
name2: value2
})
cls.monasca_client.create_metrics(metric1)
metric1 = helpers.create_metric(name=metric_name1,
dimensions={name1: value2})
cls.monasca_client.create_metrics(metric1)
metric_name2 = data_utils.rand_name()
name3 = "name_3"
value3 = "value_3"
metric2 = helpers.create_metric(name=metric_name2,
dimensions={name3: value3})
cls.monasca_client.create_metrics(metric2)
metric_name3 = data_utils.rand_name()
metric3 = helpers.create_metric(name=metric_name3,
dimensions={name1: value3})
cls.monasca_client.create_metrics(metric3)
cls._test_metric1 = metric1
cls._test_metric2 = metric2
cls._test_metric_names = {metric_name1, metric_name2, metric_name3}
cls._dim_names_metric1 = [name1, name2]
cls._dim_names_metric2 = [name3]
cls._dim_names = cls._dim_names_metric1 + cls._dim_names_metric2
cls._dim_values_for_metric1 = [value1, value2]
cls._dim_values = [value1, value2, value3]
param = '?start_time=' + time_iso
returned_name_set = set()
for i in range(constants.MAX_RETRIES):
resp, response_body = cls.monasca_client.list_metrics(
param)
elements = response_body['elements']
metric_name1_count = 0
for element in elements:
returned_name_set.add(str(element['name']))
if (str(element['name']) == metric_name1):
metric_name1_count += 1
# Java version of influxdb never returns both metric1 in the list but Python does.
if cls._test_metric_names.issubset(returned_name_set) \
and (metric_name1_count == 2 or i == constants.MAX_RETRIES - 1):
return
time.sleep(constants.RETRY_WAIT_SECS)
assert False, 'Unable to initialize metrics'
@classmethod
def resource_cleanup(cls):
super(TestDimensions, cls).resource_cleanup()
@decorators.attr(type='gate')
def test_list_dimension_values_without_metric_name(self):
param = '?dimension_name=' + self._dim_names[0]
resp, response_body = self.monasca_client.list_dimension_values(param)
self.assertEqual(200, resp.status)
self.assertTrue({'links', 'elements'} == set(response_body))
response_values_length = len(response_body['elements'])
values = [str(response_body['elements'][i]['dimension_value'])
for i in range(response_values_length)]
self.assertEqual(values, self._dim_values)
@decorators.attr(type='gate')
def test_list_dimension_values_with_metric_name(self):
parms = '?metric_name=' + self._test_metric1['name']
parms += '&dimension_name=' + self._dim_names[0]
resp, response_body = self.monasca_client.list_dimension_values(parms)
self.assertEqual(200, resp.status)
self.assertTrue({'links', 'elements'} == set(response_body))
response_values_length = len(response_body['elements'])
values = [str(response_body['elements'][i]['dimension_value'])
for i in range(response_values_length)]
self.assertEqual(values, self._dim_values_for_metric1)
@decorators.attr(type='gate')
def test_list_dimension_values_limit_and_offset(self):
param = '?dimension_name=' + self._dim_names[0]
resp, response_body = self.monasca_client.list_dimension_values(param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
num_dim_values = len(elements)
for limit in range(1, num_dim_values):
start_index = 0
params = [('limit', limit)]
offset = None
while True:
num_expected_elements = limit
if (num_expected_elements + start_index) > num_dim_values:
num_expected_elements = num_dim_values - start_index
these_params = list(params)
# If not the first call, use the offset returned by the last
# call
if offset:
these_params.extend([('offset', str(offset))])
query_parms = '?dimension_name=' + self._dim_names[0] + '&' + \
urlencode(these_params)
resp, response_body = \
self.monasca_client.list_dimension_values(query_parms)
self.assertEqual(200, resp.status)
if not response_body['elements']:
self.fail("No metrics returned")
response_values_length = len(response_body['elements'])
if response_values_length == 0:
self.fail("No dimension names returned")
new_elements = [str(response_body['elements'][i]
['dimension_value']) for i in
range(response_values_length)]
self.assertEqual(num_expected_elements, len(new_elements))
expected_elements = elements[start_index:start_index + limit]
expected_dimension_values = \
[expected_elements[i]['dimension_value'] for i in range(
len(expected_elements))]
self.assertEqual(expected_dimension_values, new_elements)
start_index += num_expected_elements
if start_index >= num_dim_values:
break
# Get the next set
offset = self._get_offset(response_body)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_list_dimension_values_no_dimension_name(self):
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_dimension_values)
@decorators.attr(type='gate')
def test_list_dimension_names(self):
resp, response_body = self.monasca_client.list_dimension_names()
self.assertEqual(200, resp.status)
self.assertTrue({'links', 'elements'} == set(response_body))
response_names_length = len(response_body['elements'])
names = [str(response_body['elements'][i]['dimension_name']) for i
in range(response_names_length)]
self.assertEqual(names, self._dim_names)
@decorators.attr(type='gate')
def test_list_dimension_names_with_metric_name(self):
self._test_list_dimension_names_with_metric_name(
self._test_metric1['name'], self._dim_names_metric1)
self._test_list_dimension_names_with_metric_name(
self._test_metric2['name'], self._dim_names_metric2)
@decorators.attr(type='gate')
def test_list_dimension_names_limit_and_offset(self):
resp, response_body = self.monasca_client.list_dimension_names()
self.assertEqual(200, resp.status)
elements = response_body['elements']
num_dim_names = len(elements)
for limit in range(1, num_dim_names):
start_index = 0
params = [('limit', limit)]
offset = None
while True:
num_expected_elements = limit
if (num_expected_elements + start_index) > num_dim_names:
num_expected_elements = num_dim_names - start_index
these_params = list(params)
# If not the first call, use the offset returned by the last
# call
if offset:
these_params.extend([('offset', str(offset))])
query_parms = '?' + urlencode(these_params)
resp, response_body = self.monasca_client.list_dimension_names(
query_parms)
self.assertEqual(200, resp.status)
if not response_body['elements']:
self.fail("No metrics returned")
response_names_length = len(response_body['elements'])
if response_names_length == 0:
self.fail("No dimension names returned")
new_elements = [str(response_body['elements'][i]
['dimension_name']) for i in
range(response_names_length)]
self.assertEqual(num_expected_elements, len(new_elements))
expected_elements = elements[start_index:start_index + limit]
expected_dimension_names = \
[expected_elements[i]['dimension_name'] for i in range(
len(expected_elements))]
self.assertEqual(expected_dimension_names, new_elements)
start_index += num_expected_elements
if start_index >= num_dim_names:
break
# Get the next set
offset = self._get_offset(response_body)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_list_dimension_names_with_wrong_metric_name(self):
self._test_list_dimension_names_with_metric_name(
'wrong_metric_name', [])
def _test_list_dimension_names_with_metric_name(self, metric_name,
dimension_names):
param = '?metric_name=' + metric_name
resp, response_body = self.monasca_client.list_dimension_names(param)
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
response_names_length = len(response_body['elements'])
names = [str(response_body['elements'][i]['dimension_name']) for i
in range(response_names_length)]
self.assertEqual(names, dimension_names)

View File

@ -1,409 +0,0 @@
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development 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 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.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
NUM_MEASUREMENTS = 50
ONE_SECOND = 1000
class TestMeasurements(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestMeasurements, cls).resource_setup()
start_timestamp = int(time.time() * 1000)
start_time = str(helpers.timestamp_to_iso(start_timestamp))
metrics = []
name1 = data_utils.rand_name()
name2 = data_utils.rand_name()
cls._names_list = [name1, name2]
key = data_utils.rand_name('key')
value = data_utils.rand_name('value')
cls._key = key
cls._value = value
cls._start_timestamp = start_timestamp
for i in range(NUM_MEASUREMENTS):
metric = helpers.create_metric(
name=name1,
timestamp=start_timestamp + (i * 10),
value=i)
metrics.append(metric)
cls.monasca_client.create_metrics(metrics)
# Create metric2 for test_list_measurements_with_dimensions
metric2 = helpers.create_metric(
name=name1, timestamp=start_timestamp + ONE_SECOND * 2,
dimensions={key: value}, value=NUM_MEASUREMENTS)
cls.monasca_client.create_metrics(metric2)
# Create metric3 for test_list_measurements_with_offset_limit
metric3 = [
helpers.create_metric(
name=name2, timestamp=start_timestamp + ONE_SECOND * 3,
dimensions={'key1': 'value1', 'key2': 'value5', 'key3': 'value7'}),
helpers.create_metric(
name=name2, timestamp=start_timestamp + ONE_SECOND * 3 + 10,
dimensions={'key1': 'value2', 'key2': 'value5', 'key3': 'value7'}),
helpers.create_metric(
name=name2, timestamp=start_timestamp + ONE_SECOND * 3 + 20,
dimensions={'key1': 'value3', 'key2': 'value6', 'key3': 'value7'}),
helpers.create_metric(
name=name2, timestamp=start_timestamp + ONE_SECOND * 3 + 30,
dimensions={'key1': 'value4', 'key2': 'value6', 'key3': 'value8'})
]
cls.monasca_client.create_metrics(metric3)
# Create metric3 for test_list_measurements_with_no_merge_metrics
metric4 = helpers.create_metric(
name=name1, timestamp=start_timestamp + ONE_SECOND * 4,
dimensions={'key-1': 'value-1'},
value=NUM_MEASUREMENTS + 1)
cls.monasca_client.create_metrics(metric4)
end_time = str(helpers.timestamp_to_iso(
start_timestamp + NUM_MEASUREMENTS + ONE_SECOND * 5))
queries = []
queries.append('?name={}&start_time={}&end_time={}&merge_metrics=true'.
format(name1, start_time, end_time))
queries.append('?name={}&start_time={}&end_time={}&merge_metrics=true'.
format(name2, start_time, end_time))
for timer in range(constants.MAX_RETRIES):
responses = map(cls.monasca_client.list_measurements, queries)
resp_first = responses[0][0]
response_body_first = responses[0][1]
resp_second = responses[1][0]
response_body_second = responses[1][1]
if resp_first.status == 200 and resp_second.status == 200 \
and len(response_body_first['elements']) == 1 \
and len(response_body_second['elements']) == 1:
len_meas_first = len(
response_body_first['elements'][0]['measurements'])
len_meas_second = len(
response_body_second['elements'][0]['measurements'])
if len_meas_first == NUM_MEASUREMENTS + 2 \
and len_meas_second == 4:
break
else:
time.sleep(constants.RETRY_WAIT_SECS)
else:
time.sleep(constants.RETRY_WAIT_SECS)
cls._start_time = start_time
cls._end_time = end_time
@decorators.attr(type="gate")
def test_list_measurements(self):
query_parms = '?name=' + str(self._names_list[0]) + \
'&merge_metrics=true' + \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._end_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self._verify_list_measurements(resp, response_body)
elements = response_body['elements']
self._verify_list_measurements_elements(
elements=elements, test_key=None, test_value=None)
measurements = elements[0]['measurements']
self._verify_list_measurements_meas_len(
measurements, test_len=NUM_MEASUREMENTS + 2)
i = 0
for measurement in measurements:
self._verify_list_measurements_measurement(measurement, i)
i += 1
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_measurements_with_no_start_time(self):
query_parms = '?name=' + str(self._names_list[0])
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_measurements, query_parms)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_measurements_with_no_name(self):
query_parms = '?start_time=' + str(self._start_time) + '&end_time=' + \
str(self._end_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_measurements, query_parms)
@decorators.attr(type="gate")
def test_list_measurements_with_dimensions(self):
query_parms = '?name=' + self._names_list[0] + '&start_time=' + \
str(self._start_time) + '&end_time=' + \
str(self._end_time) + '&dimensions=' + self._key + ':' \
+ self._value
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self._verify_list_measurements(resp, response_body)
elements = response_body['elements']
self._verify_list_measurements_elements(
elements=elements, test_key=None, test_value=None)
measurements = elements[0]['measurements']
self._verify_list_measurements_meas_len(measurements, 1)
measurement = measurements[0]
self._verify_list_measurements_measurement(
measurement=measurement, test_value=NUM_MEASUREMENTS)
@decorators.attr(type="gate")
def test_list_measurements_with_endtime(self):
time_iso = helpers.timestamp_to_iso(
self._start_timestamp + ONE_SECOND * 2)
query_parms = '?name=' + str(self._names_list[0]) + \
'&merge_metrics=true' \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(time_iso)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self._verify_list_measurements(resp, response_body)
elements = response_body['elements']
self._verify_list_measurements_elements(elements=elements,
test_key=None, test_value=None)
measurements = elements[0]['measurements']
self._verify_list_measurements_meas_len(measurements=measurements,
test_len=NUM_MEASUREMENTS)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_measurements_with_endtime_equals_starttime(self):
query_parms = '?name=' + str(self._names_list[0]) + \
'&merge_metrics=true' \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._start_time)
self.assertRaises(exceptions.BadRequest,
self.monasca_client.list_measurements, query_parms)
@decorators.attr(type="gate")
def test_list_measurements_with_offset_limit(self):
query_parms = '?name=' + str(self._names_list[1]) + \
'&merge_metrics=true&start_time=' + self._start_time + \
'&end_time=' + self._end_time
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self._verify_list_measurements(resp, response_body)
elements = response_body['elements']
self._verify_list_measurements_elements(elements=elements,
test_key=None, test_value=None)
measurements = elements[0]['measurements']
self._verify_list_measurements_meas_len(measurements=measurements,
test_len=4)
for measurement_index in range(1, len(measurements) - 3):
max_limit = len(measurements) - measurement_index
# Get first offset from api
query_parms = '?name=' + str(self._names_list[1]) + \
'&merge_metrics=true&start_time=' + measurements[measurement_index - 1][0] + \
'&end_time=' + self._end_time + \
'&limit=1'
resp, response_body = self.monasca_client.list_measurements(query_parms)
for link in response_body['links']:
if link['rel'] == 'next':
next_link = link['href']
if not next_link:
self.fail("No next link returned with query parameters: {}".formet(query_parms))
offset = helpers.get_query_param(next_link, "offset")
first_index = measurement_index + 1
for limit in range(1, max_limit):
last_index = measurement_index + limit + 1
expected_measurements = measurements[first_index:last_index]
query_parms = '?name=' + str(self._names_list[1]) + \
'&merge_metrics=true&start_time=' + \
self._start_time + '&end_time=' + \
self._end_time + '&limit=' + str(limit) + \
'&offset=' + str(offset)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self._verify_list_measurements(resp, response_body)
new_measurements = response_body['elements'][0]['measurements']
self.assertEqual(limit, len(new_measurements))
for i in range(len(expected_measurements)):
self.assertEqual(expected_measurements[i],
new_measurements[i])
@decorators.attr(type="gate")
def test_list_measurements_with_merge_metrics(self):
query_parms = '?name=' + str(self._names_list[0]) + \
'&merge_metrics=true' + \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._end_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
@decorators.attr(type="gate")
def test_list_measurements_with_group_by_one(self):
query_parms = '?name=' + str(self._names_list[1]) + \
'&group_by=key2' + \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._end_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(len(elements), 2)
self._verify_list_measurements_elements(elements, None, None)
for measurements in elements:
self.assertEqual(1, len(measurements['dimensions'].keys()))
self.assertEqual([u'key2'], measurements['dimensions'].keys())
@decorators.attr(type="gate")
def test_list_measurements_with_group_by_multiple(self):
query_parms = '?name=' + str(self._names_list[1]) + \
'&group_by=key2,key3' + \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._end_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(len(elements), 3)
self._verify_list_measurements_elements(elements, None, None)
for measurements in elements:
self.assertEqual(2, len(measurements['dimensions'].keys()))
self.assertEqual({u'key2', u'key3'}, set(measurements['dimensions'].keys()))
@decorators.attr(type="gate")
def test_list_measurements_with_group_by_all(self):
query_parms = '?name=' + str(self._names_list[1]) + \
'&group_by=*' + \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._end_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(len(elements), 4)
self._verify_list_measurements_elements(elements, None, None)
@decorators.attr(type="gate")
def test_list_measurements_with_group_by_and_merge(self):
query_parms = '?name=' + str(self._names_list[1]) + \
'&group_by=*' + \
'&merge_metrics=true' + \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._end_time)
resp, response_body = self.monasca_client.list_measurements(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(len(elements), 4)
self._verify_list_measurements_elements(elements, None, None)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_measurements_with_name_exceeds_max_length(self):
long_name = "x" * (constants.MAX_LIST_MEASUREMENTS_NAME_LENGTH + 1)
query_parms = '?name=' + str(long_name) + '&merge_metrics=true' + \
'&start_time=' + str(self._start_time) + \
'&end_time=' + str(self._end_time)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_measurements, query_parms)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_measurements_with_no_merge_metrics(self):
query_parms = '?name=' + str(self._names_list[0]) + \
'&start_time=' + str(self._start_time) + '&end_time=' \
+ str(self._end_time)
self.assertRaises(exceptions.Conflict,
self.monasca_client.list_measurements, query_parms)
@decorators.attr(type="gate")
def test_list_measurements_with_duplicate_query_param_merges_positive(
self):
queries = []
queries.append('?name={}&merge_metrics=true&start_time={}&end_time={'
'}&merge_metrics=true'.
format(self._names_list[0], self._start_time,
self._end_time))
queries.append('?name={}&merge_metrics=true&start_time={}&end_time={'
'}&merge_metrics=false'.
format(self._names_list[0], self._start_time,
self._end_time))
responses = map(self.monasca_client.list_measurements, queries)
for i in range(2):
self._verify_list_measurements(responses[i][0], responses[i][1])
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_measurements_with_duplicate_query_param_merges_negative(
self):
queries = []
queries.append('?name={}&merge_metrics=false&start_time={}&end_time={'
'}&merge_metrics=true'.
format(self._names_list[0], self._start_time,
self._end_time))
queries.append('?name={}&merge_metrics=false&start_time={}&end_time={'
'}&merge_metrics=false'.
format(self._names_list[0], self._start_time,
self._end_time))
for i in range(2):
self.assertRaises(exceptions.Conflict,
self.monasca_client.list_measurements,
queries[i])
def _verify_list_measurements_measurement(self, measurement, test_value):
self.assertEqual(test_value, float(measurement[1]))
def _verify_list_measurements(self, resp, response_body):
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
def _verify_list_measurements_elements(self, elements, test_key,
test_value):
if not elements:
error_msg = "Failed: at least one element is needed. " \
"Number of element = 0."
self.fail(error_msg)
for element in elements:
# element = elements[0]
self.assertEqual(set(element),
set(['columns', 'dimensions', 'id',
'measurements', 'name']))
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)
self.assertEqual(set(element['columns']),
set(['timestamp', 'value', 'value_meta']))
self.assertTrue(str(element['id']) is not None)
if test_key is not None and test_value is not None:
self.assertEqual(str(element['dimensions'][test_key]),
test_value)
def _verify_list_measurements_meas_len(self, measurements, test_len):
if measurements:
len_measurements = len(measurements)
self.assertEqual(len_measurements, test_len)
else:
error_msg = "Failed: one specific measurement is needed. " \
"Number of measurements = 0"
self.fail(error_msg)

View File

@ -1,711 +0,0 @@
# -*- coding: utf-8 -*-
# (C) Copyright 2014-2016 Hewlett Packard Enterprise Development 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 six.moves import urllib_parse as urlparse
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import constants
from monasca_tempest_tests.tests.api import helpers
class TestMetrics(base.BaseMonascaTest):
@decorators.attr(type='gate')
def test_create_metric(self):
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value = data_utils.rand_name('value')
timestamp = int(round(time.time() * 1000))
time_iso = helpers.timestamp_to_iso(timestamp)
end_timestamp = int(round((time.time() + 3600 * 24) * 1000))
end_time_iso = helpers.timestamp_to_iso(end_timestamp)
value_meta_key = data_utils.rand_name('value_meta_key')
value_meta_value = data_utils.rand_name('value_meta_value')
metric = helpers.create_metric(name=name,
dimensions={key: value},
timestamp=timestamp,
value=1.23,
value_meta={
value_meta_key: value_meta_value
})
resp, response_body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
query_param = '?name=' + name + '&start_time=' + time_iso + \
'&end_time=' + end_time_iso
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.\
list_measurements(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if str(element['name']) == name:
self._verify_list_measurements_element(element, key, value)
measurement = element['measurements'][0]
self._verify_list_measurements_measurement(
measurement, metric, value_meta_key, value_meta_value)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_create_metric: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.attr(type='gate')
def test_create_metric_with_multibyte_character(self):
name = data_utils.rand_name('').decode('utf8')
key = data_utils.rand_name('').decode('utf8')
value = data_utils.rand_name('').decode('utf8')
timestamp = int(round(time.time() * 1000))
time_iso = helpers.timestamp_to_iso(timestamp)
end_timestamp = int(round((time.time() + 3600 * 24) * 1000))
end_time_iso = helpers.timestamp_to_iso(end_timestamp)
value_meta_key = data_utils.rand_name('value_meta_').decode('utf8')
value_meta_value = data_utils.rand_name('value_meta_').decode('utf8')
metric = helpers.create_metric(name=name,
dimensions={key: value},
timestamp=timestamp,
value=1.23,
value_meta={
value_meta_key: value_meta_value
})
resp, response_body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
query_param = '?name=' + urlparse.quote(name.encode('utf8')) + \
'&start_time=' + time_iso + '&end_time=' + end_time_iso
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.\
list_measurements(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if element['name'] == name:
self._verify_list_measurements_element(element, key, value)
measurement = element['measurements'][0]
self._verify_list_measurements_measurement(
measurement, metric, value_meta_key, value_meta_value)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_create_metric: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.attr(type='gate')
def test_create_metrics(self):
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value = data_utils.rand_name('value')
timestamp = int(round(time.time() * 1000))
time_iso = helpers.timestamp_to_iso(timestamp)
end_timestamp = int(round(timestamp + 3600 * 24 * 1000))
end_time_iso = helpers.timestamp_to_iso(end_timestamp)
value_meta_key1 = data_utils.rand_name('meta_key')
value_meta_value1 = data_utils.rand_name('meta_value')
value_meta_key2 = data_utils.rand_name('value_meta_key')
value_meta_value2 = data_utils.rand_name('value_meta_value')
metrics = [
helpers.create_metric(name=name,
dimensions={key: value},
timestamp=timestamp,
value=1.23,
value_meta={
value_meta_key1: value_meta_value1
}),
helpers.create_metric(name=name,
dimensions={key: value},
timestamp=timestamp + 6000,
value=4.56,
value_meta={
value_meta_key2: value_meta_value2
})
]
resp, response_body = self.monasca_client.create_metrics(metrics)
self.assertEqual(204, resp.status)
query_param = '?name=' + name + '&start_time=' + str(time_iso) + \
'&end_time=' + str(end_time_iso)
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.\
list_measurements(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if str(element['name']) == name \
and len(element['measurements']) == 2:
self._verify_list_measurements_element(element, key, value)
first_measurement = element['measurements'][0]
second_measurement = element['measurements'][1]
self._verify_list_measurements_measurement(
first_measurement, metrics[0], value_meta_key1,
value_meta_value1)
self._verify_list_measurements_measurement(
second_measurement, metrics[1], value_meta_key2,
value_meta_value2)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_create_metrics: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.attr(type='gate')
@decorators.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)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_empty_name(self):
metric = helpers.create_metric(name='')
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_empty_value_in_dimensions(self):
name = data_utils.rand_name('name')
metric = helpers.create_metric(name=name,
dimensions={'key': ''})
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_empty_key_in_dimensions(self):
name = data_utils.rand_name('name')
metric = helpers.create_metric(name=name,
dimensions={'': 'value'})
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
def test_create_metric_with_no_dimensions(self):
name = data_utils.rand_name('name')
timestamp = int(round(time.time() * 1000))
time_iso = helpers.timestamp_to_iso(timestamp)
end_timestamp = int(round(timestamp + 3600 * 24 * 1000))
end_time_iso = helpers.timestamp_to_iso(end_timestamp)
value_meta_key = data_utils.rand_name('value_meta_key')
value_meta_value = data_utils.rand_name('value_meta_value')
metric = helpers.create_metric(name=name,
dimensions=None,
timestamp=timestamp,
value=1.23,
value_meta={
value_meta_key: value_meta_value})
resp, response_body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
query_param = '?name=' + str(name) + '&start_time=' + str(time_iso) \
+ '&end_time=' + str(end_time_iso)
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.\
list_measurements(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if str(element['name']) == name:
self._verify_list_measurements_element(
element, test_key=None, test_value=None)
if len(element['measurements']) > 0:
measurement = element['measurements'][0]
self._verify_list_measurements_measurement(
measurement, metric, value_meta_key,
value_meta_value)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_create_metric_with_no_dimensions: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.attr(type='gate')
def test_create_metric_with_colon_in_dimension_value(self):
name = data_utils.rand_name('name')
key = 'url'
value = 'http://localhost:8070/v2.0'
timestamp = int(round(time.time() * 1000))
time_iso = helpers.timestamp_to_iso(timestamp)
end_timestamp = int(round((time.time() + 3600 * 24) * 1000))
end_time_iso = helpers.timestamp_to_iso(end_timestamp)
metric = helpers.create_metric(name=name,
dimensions={key: value})
resp, response_body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
query_param = '?name=' + name + '&start_time=' + time_iso + \
'&end_time=' + end_time_iso + \
'&dimensions=' + key + ':' + value
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client. \
list_measurements(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if str(element['name']) == name:
self._verify_list_measurements_element(element, key, value)
measurement = element['measurements'][0]
self._verify_list_measurements_measurement(
measurement, metric, None, None)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_create_metric: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_no_timestamp(self):
metric = helpers.create_metric()
metric['timestamp'] = None
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_no_value(self):
timestamp = int(round(time.time() * 1000))
metric = helpers.create_metric(timestamp=timestamp,
value=None)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
@decorators.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)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_invalid_chars_in_name(self):
for invalid_char in constants.INVALID_NAME_CHARS:
metric = helpers.create_metric(invalid_char)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_invalid_chars_in_dimensions(self):
for invalid_char in constants.INVALID_DIMENSION_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_DIMENSION_CHARS:
metric = helpers.create_metric('name-1', {invalid_char: 'value-1'})
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
@decorators.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)
@decorators.attr(type='gate')
@decorators.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)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_value_meta_name_exceeds_max_length(self):
long_value_meta_name = "x" * (constants.MAX_VALUE_META_NAME_LENGTH + 1)
value_meta_dict = {long_value_meta_name: "value_meta_value"}
metric = helpers.create_metric(name='name', value_meta=value_meta_dict)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_with_value_meta_exceeds_max_length(self):
value_meta_name = "x"
long_value_meta_value = "y" * constants.MAX_VALUE_META_TOTAL_LENGTH
value_meta_dict = {value_meta_name: long_value_meta_value}
metric = helpers.create_metric(name='name', value_meta=value_meta_dict)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.create_metrics,
metric)
@decorators.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._verify_list_metrics_element(element, test_key=None,
test_value=None, test_name=None)
self.assertTrue(set(['id', 'name', 'dimensions']) == set(element))
@decorators.attr(type='gate')
def test_list_metrics_with_dimensions(self):
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value = data_utils.rand_name('value')
metric = helpers.create_metric(name=name, dimensions={key: value})
resp, response_body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
query_param = '?dimensions=' + key + ':' + value
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.list_metrics(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if str(element['dimensions'][key]) == value:
self._verify_list_metrics_element(element, test_name=name)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_list_metrics_with_dimensions: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.attr(type='gate')
def test_list_metrics_dimension_query_multi_value_with_diff_names(self):
metrics, name, key_service, values = \
self._create_metrics_with_different_dimensions(same_name=False)
metric_dimensions = self._get_metric_dimensions(
key_service, values, same_metric_name=False)
query_param = '?dimensions=' + key_service + ':' + values[0] + '|' +\
values[1]
self._verify_dimensions(query_param, metric_dimensions)
@decorators.attr(type='gate')
def test_list_metrics_dimension_query_no_value_with_diff_names(self):
metrics, name, key_service, values = \
self._create_metrics_with_different_dimensions(same_name=False)
metric_dimensions = self._get_metric_dimensions(
key_service, values, same_metric_name=False)
query_param = '?dimensions=' + key_service
self._verify_dimensions(query_param, metric_dimensions)
@decorators.attr(type='gate')
def test_list_metrics_dimension_query_multi_value_with_same_name(self):
# Skip the test for now due to InfluxDB Inconsistency
return
metrics, name, key_service, values = \
self._create_metrics_with_different_dimensions(same_name=True)
metric_dimensions = self._get_metric_dimensions(
key_service, values, same_metric_name=True)
query_param = '?name=' + name + '&dimensions=' + key_service + ':' +\
values[0] + '|' + values[1]
self._verify_dimensions(query_param, metric_dimensions)
@decorators.attr(type='gate')
def test_list_metrics_dimension_query_no_value_with_same_name(self):
# Skip the test for now due to InfluxDB Inconsistency
return
metrics, name, key_service, values = \
self._create_metrics_with_different_dimensions(same_name=True)
metric_dimensions = self._get_metric_dimensions(
key_service, values, same_metric_name=True)
query_param = '?name=' + name + '&dimensions=' + key_service
self._verify_dimensions(query_param, metric_dimensions)
@decorators.attr(type='gate')
def test_list_metrics_with_name(self):
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value = data_utils.rand_name('value')
metric = helpers.create_metric(name=name,
dimensions={key: value})
resp, response_body = self.monasca_client.create_metrics(metric)
self.assertEqual(204, resp.status)
query_param = '?name=' + str(name)
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.list_metrics(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if str(element['name']) == name:
self._verify_list_metrics_element(element, test_key=key,
test_value=value)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_list_metrics_with_name: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.attr(type='gate')
def test_list_metrics_with_project(self):
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value = data_utils.rand_name('value')
project = self.projects_client.create_project(
name=data_utils.rand_name('test_project'))['project']
# Delete the project at the end of the test
self.addCleanup(self.projects_client.delete_project, project['id'])
metric = helpers.create_metric(name=name,
dimensions={key: value})
resp, response_body = self.monasca_client.create_metrics(
metric, tenant_id=project['id'])
self.assertEqual(204, resp.status)
query_param = '?tenant_id=' + str(project['id'])
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.list_metrics(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
for element in elements:
if str(element['name']) == name:
self._verify_list_metrics_element(element, test_key=key,
test_value=value)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Failed test_list_metrics_with_tenant: " \
"timeout on waiting for metrics: at least " \
"one metric is needed. Current number of " \
"metrics = 0"
self.fail(error_msg)
@decorators.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'})
]
self.monasca_client.create_metrics(metrics)
query_param = '?name=' + name
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.list_metrics(query_param)
elements = response_body['elements']
if elements and len(elements) == 4:
break
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = ("Failed test_list_metrics_with_offset_limit: "
"timeout on waiting for metrics: 4 metrics "
"are needed. Current number of elements = "
"{}").format(len(elements))
self.fail(error_msg)
first_element = elements[0]
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 metric_index in range(len(elements) - 1):
metric = elements[metric_index]
max_limit = 3 - metric_index
for limit in range(1, max_limit):
first_index = metric_index + 1
last_index = first_index + limit
expected_elements = elements[first_index:last_index]
query_parms = '?name=' + name + '&offset=' + \
str(metric['id']) + '&limit=' + \
str(limit)
resp, response_body = self.\
monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
new_elements = response_body['elements']
self.assertEqual(limit, len(new_elements))
for i in range(len(expected_elements)):
self.assertEqual(expected_elements[i], new_elements[i])
def _verify_list_measurements_element(self, element, test_key, test_value):
self.assertEqual(set(element),
set(['columns', 'dimensions', 'id', 'measurements',
'name']))
self.assertEqual(set(element['columns']),
set(['timestamp', 'value', 'value_meta']))
self.assertTrue(str(element['id']) is not None)
if test_key is not None and test_value is not None:
self.assertEqual(
element['dimensions'][test_key].encode('utf-8'),
test_value.encode('utf-8')
)
def _verify_list_measurements_measurement(self, measurement,
test_metric, test_vm_key,
test_vm_value):
# Timestamps stored in influx sometimes are 1 millisecond different to
# the value stored by the persister. Check if the timestamps are
# equal in one millisecond range to pass the test.
time_iso_millis = helpers.timestamp_to_iso_millis(
test_metric['timestamp'] + 0)
time_iso_millis_plus = helpers.timestamp_to_iso_millis(
test_metric['timestamp'] + 1)
time_iso_millis_minus = helpers.timestamp_to_iso_millis(
test_metric['timestamp'] - 1)
if str(measurement[0]) != time_iso_millis and str(measurement[0]) != \
time_iso_millis_plus and str(measurement[0]) != \
time_iso_millis_minus:
error_msg = ("Mismatch Error: None of {}, {}, {} matches {}").\
format(time_iso_millis, time_iso_millis_plus,
time_iso_millis_minus, str(measurement[0]))
self.fail(error_msg)
self.assertEqual(measurement[1], test_metric['value'])
if test_vm_key is not None and test_vm_value is not None:
self.assertEqual(
measurement[2][test_vm_key].encode('utf-8'),
test_vm_value.encode('utf-8')
)
def _verify_list_metrics_element(self, element, test_key=None,
test_value=None, test_name=None):
self.assertTrue(type(element['id']) is unicode)
self.assertTrue(type(element['name']) is unicode)
self.assertTrue(type(element['dimensions']) is dict)
self.assertEqual(set(element), set(['dimensions', 'id', 'name']))
self.assertTrue(str(element['id']) is not None)
if test_key is not None and test_value is not None:
self.assertEqual(str(element['dimensions'][test_key]), test_value)
if test_name is not None:
self.assertEqual(str(element['name']), test_name)
@decorators.attr(type='gate')
def test_list_metrics_with_time_args(self):
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value_org = data_utils.rand_name('value')
now = int(round(time.time() * 1000))
#
# Built start and end time args before and after the measurement.
#
start_iso = helpers.timestamp_to_iso(now - 1000)
end_timestamp = int(round(now + 1000))
end_iso = helpers.timestamp_to_iso(end_timestamp)
metric = helpers.create_metric(name=name,
dimensions={key: value_org},
timestamp=now)
self.monasca_client.create_metrics(metric)
for timer in range(constants.MAX_RETRIES):
query_parms = '?name=' + name + '&start_time=' + start_iso + '&end_time=' + end_iso
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
if elements:
dimensions = elements[0]
dimension = dimensions['dimensions']
value = dimension[unicode(key)]
self.assertEqual(value_org, str(value))
break
else:
time.sleep(constants.RETRY_WAIT_SECS)
if timer == constants.MAX_RETRIES - 1:
skip_msg = "Skipped test_list_metrics_with_time_args: " \
"timeout on waiting for metrics: at least one " \
"metric is needed. Current number of metrics " \
"= 0"
raise self.skipException(skip_msg)
@staticmethod
def _get_metric_dimensions(key_service, values, same_metric_name):
if same_metric_name:
metric_dimensions = [{key_service: values[0], 'key3': ''},
{key_service: values[1], 'key3': ''},
{key_service: '', 'key3': 'value3'}]
else:
metric_dimensions = [{key_service: values[0]},
{key_service: values[1]},
{'key3': 'value3'}]
return metric_dimensions
def _verify_dimensions(self, query_param, metric_dimensions):
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.list_metrics(query_param)
self.assertEqual(200, resp.status)
elements = response_body['elements']
if len(elements) == 2:
dimension_sets = []
for element in elements:
dimension_sets.append(element['dimensions'])
self.assertIn(metric_dimensions[0], dimension_sets)
self.assertIn(metric_dimensions[1], dimension_sets)
self.assertNotIn(metric_dimensions[2], dimension_sets)
return
time.sleep(constants.RETRY_WAIT_SECS)
if i == constants.MAX_RETRIES - 1:
error_msg = "Timeout on waiting for metrics: at least " \
"2 metrics are needed. Current number of " \
"metrics = {}".format(len(elements))
self.fail(error_msg)
def _create_metrics_with_different_dimensions(self, same_name=True):
name1 = data_utils.rand_name('name1')
name2 = name1 if same_name else data_utils.rand_name('name2')
name3 = name1 if same_name else data_utils.rand_name('name3')
key_service = data_utils.rand_name('service')
values = [data_utils.rand_name('value1'),
data_utils.rand_name('value2')]
metrics = [helpers.create_metric(name1, {key_service: values[0]}),
helpers.create_metric(name2, {key_service: values[1]}),
helpers.create_metric(name3, {'key3': 'value3'})]
resp, response_body = self.monasca_client.create_metrics(metrics)
self.assertEqual(204, resp.status)
return metrics, name1, key_service, values

View File

@ -1,162 +0,0 @@
# (C) Copyright 2015-2017 Hewlett Packard Enterprise Development 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 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.lib.common.utils import data_utils
from tempest.lib import decorators
from urllib import urlencode
class TestMetricsNames(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestMetricsNames, cls).resource_setup()
name1 = data_utils.rand_name('name1')
name2 = data_utils.rand_name('name2')
name3 = data_utils.rand_name('name3')
key = data_utils.rand_name()
key1 = data_utils.rand_name()
value = data_utils.rand_name()
value1 = data_utils.rand_name()
timestamp = int(round(time.time() * 1000))
time_iso = helpers.timestamp_to_iso(timestamp)
metric1 = helpers.create_metric(name=name1,
dimensions={key: value})
metric2 = helpers.create_metric(name=name2,
dimensions={key1: value1})
metric3 = helpers.create_metric(name=name3,
dimensions={key: value})
cls._test_metric_names = {name1, name2, name3}
cls._expected_names_list = list(cls._test_metric_names)
cls._expected_names_list.sort()
cls._test_metric_names_with_same_dim = [name1, name3]
cls._test_metrics = [metric1, metric2, metric3]
cls._dimensions_param = key + ':' + value
cls.monasca_client.create_metrics(cls._test_metrics)
query_param = '?start_time=' + time_iso
returned_name_set = set()
for i in range(constants.MAX_RETRIES):
resp, response_body = cls.monasca_client.list_metrics(query_param)
elements = response_body['elements']
for element in elements:
returned_name_set.add(str(element['name']))
if cls._test_metric_names.issubset(returned_name_set):
return
time.sleep(constants.RETRY_WAIT_SECS)
assert False, 'Unable to initialize metrics'
@classmethod
def resource_cleanup(cls):
super(TestMetricsNames, cls).resource_cleanup()
@decorators.attr(type='gate')
def test_list_metrics_names(self):
resp, response_body = self.monasca_client.list_metrics_names()
metric_names = self._verify_response(resp, response_body)
self.assertEqual(metric_names, self._expected_names_list)
@decorators.attr(type='gate')
def test_list_metrics_names_with_dimensions(self):
query_params = '?dimensions=' + self._dimensions_param
resp, response_body = self.monasca_client.list_metrics_names(
query_params)
metric_names = self._verify_response(resp, response_body)
self.assertEqual(metric_names,
self._test_metric_names_with_same_dim)
@decorators.attr(type='gate')
def test_list_metrics_names_with_limit_offset(self):
resp, response_body = self.monasca_client.list_metrics_names()
self.assertEqual(200, resp.status)
elements = response_body['elements']
num_names = len(elements)
for limit in range(1, num_names):
start_index = 0
params = [('limit', limit)]
offset = None
while True:
num_expected_elements = limit
if (num_expected_elements + start_index) > num_names:
num_expected_elements = num_names - start_index
these_params = list(params)
# If not the first call, use the offset returned by the last
# call
if offset:
these_params.extend([('offset', str(offset))])
query_params = '?' + urlencode(these_params)
resp, response_body = \
self.monasca_client.list_metrics_names(query_params)
new_elements = self._verify_response(resp, response_body)
self.assertEqual(num_expected_elements, len(new_elements))
expected_elements = elements[start_index:start_index + limit]
expected_names = \
[expected_elements[i]['name'] for i in range(
len(expected_elements))]
self.assertEqual(expected_names, new_elements)
start_index += num_expected_elements
if start_index >= num_names:
break
# Get the next set
offset = self._get_offset(response_body)
@decorators.attr(type='gate')
def test_list_metrics_names_with_offset_not_in_metrics_names_list(self):
offset1 = 'tempest-abc'
offset2 = 'tempest-name111'
offset3 = 'tempest-name4-random'
query_param1 = '?' + urlencode([('offset', offset1)])
query_param2 = '?' + urlencode([('offset', offset2)])
query_param3 = '?' + urlencode([('offset', offset3)])
resp, response_body = self.monasca_client.list_metrics_names(
query_param1)
metric_names = self._verify_response(resp, response_body)
self.assertEqual(metric_names, self._expected_names_list[:])
resp, response_body = self.monasca_client.list_metrics_names(
query_param2)
metric_names = self._verify_response(resp, response_body)
self.assertEqual(metric_names, self._expected_names_list[1:])
resp, response_body = self.monasca_client.list_metrics_names(
query_param3)
self.assertEqual(response_body['elements'], [])
def _verify_response(self, resp, response_body):
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
response_names_length = len(response_body['elements'])
if response_names_length == 0:
self.fail("No metric names returned")
metric_names = [str(response_body['elements'][i]['name']) for i in
range(response_names_length)]
return metric_names

View File

@ -1,33 +0,0 @@
# (C) Copyright 2016-2017 Hewlett Packard Enterprise Development 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.lib import decorators
class TestNotificationMethodType(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestNotificationMethodType, cls).resource_setup()
@classmethod
def resource_cleanup(cls):
super(TestNotificationMethodType, cls).resource_cleanup()
@decorators.attr(type="gate")
def test_list_notification_method_type(self):
resp, response_body = (self.monasca_client.
list_notification_method_types())
self.assertEqual(200, resp.status)

File diff suppressed because it is too large Load Diff

View File

@ -1,184 +0,0 @@
# (C) Copyright 2016 Hewlett Packard Enterprise Development 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.lib import decorators
from tempest.lib import exceptions
from monasca_tempest_tests import clients
from monasca_tempest_tests.tests.api import base
from monasca_tempest_tests.tests.api import helpers
class TestReadOnlyRole(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestReadOnlyRole, cls).resource_setup()
credentials = cls.cred_provider.get_creds_by_roles(
['monasca-read-only-user']).credentials
cls.os = clients.Manager(credentials=credentials)
cls.monasca_client = cls.os.monasca_client
@classmethod
def resource_cleanup(cls):
super(TestReadOnlyRole, cls).resource_cleanup()
@decorators.attr(type="gate")
def test_list_alarms_success(self):
resp, response_body = self.monasca_client.list_alarms()
#
# Validate the call succeeds with empty result (we didn't
# create any alarms)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue(response_body['links'][0]['href'].endswith('/v2.0/alarms'))
@decorators.attr(type="gate")
def test_list_metrics_success(self):
resp, response_body = self.monasca_client.list_metrics()
#
# Validate the call succeeds with empty result (we didn't
# create any metrics)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue(response_body['links'][0]['href'].endswith('/v2.0/metrics'))
@decorators.attr(type="gate")
def test_list_alarm_definition_success(self):
resp, response_body = self.monasca_client.list_alarm_definitions()
#
# Validate the call succeeds with empty result (we didn't
# create any alarm definitions)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue(response_body['links'][0]['href'].endswith('/v2.0/alarm-definitions'))
@decorators.attr(type="gate")
def test_list_notification_methods_success(self):
resp, response_body = self.monasca_client.list_notification_methods()
#
# Validate the call succeeds with empty result (we didn't
# create any notifications)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue(response_body['links'][0]['href'].endswith('/v2.0/notification-methods'))
@decorators.attr(type="gate")
def test_list_alarm_count_success(self):
resp, response_body = self.monasca_client.count_alarms()
#
# Validate the call succeeds with empty result (we didn't
# create any alarms to count)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, response_body['counts'][0][0])
self.assertTrue(response_body['links'][0]['href'].endswith('/v2.0/alarms/count'))
@decorators.attr(type="gate")
def test_list_alarm_state_history_success(self):
resp, response_body = self.monasca_client.list_alarms_state_history()
#
# Validate the call succeeds with empty result (we didn't
# create any alarms that have history)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue(response_body['links'][0]['href'].endswith('/v2.0/alarms/state-history'))
@decorators.attr(type="gate")
def test_list_dimension_values_success(self):
parms = '?dimension_name=foo'
resp, response_body = self.monasca_client.list_dimension_values(parms)
#
# Validate the call succeeds with empty result (we didn't
# create any metrics/dimensions)
#
url = '/v2.0/metrics/dimensions/names/values?dimension_name=foo'
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue(response_body['links'][0]['href'].endswith(url))
@decorators.attr(type="gate")
def test_list_dimension_names_success(self):
resp, response_body = self.monasca_client.list_dimension_names()
#
# Validate the call succeeds with empty result (we didn't
# create any metrics/dimensions)
#
url = '/v2.0/metrics/dimensions/names'
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue(response_body['links'][0]['href'].endswith(url))
@decorators.attr(type="gate")
def test_list_measurements_success(self):
start_timestamp = int(time.time() * 1000)
start_time = str(helpers.timestamp_to_iso(start_timestamp))
parms = '?name=foo&start_time=' + start_time
resp, response_body = self.monasca_client.list_measurements(parms)
#
# Validate the call succeeds with empty result (we didn't
# create any metrics to get measurements for)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue('/v2.0/metrics/measurements' in response_body['links'][0]['href'])
@decorators.attr(type="gate")
def test_list_statistics_success(self):
start_timestamp = int(time.time() * 1000)
start_time = str(helpers.timestamp_to_iso(start_timestamp))
query_parms = '?name=foo&statistics=avg&start_time=' + start_time
resp, response_body = self.monasca_client.list_statistics(
query_parms)
#
# Validate the call succeeds with empty result (we didn't
# create any metrics to get statistics for)
#
self.assertEqual(200, resp.status)
self.assertEqual(0, len(response_body['elements']))
self.assertTrue('/v2.0/metrics/statistics' in response_body['links'][0]['href'])
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_delete_alarms_fails(self):
self.assertRaises(exceptions.Unauthorized,
self.monasca_client.delete_alarm, "foo")
@decorators.attr(type='gate')
@decorators.attr(type=['negative'])
def test_create_metric_fails(self):
self.assertRaises(exceptions.Unauthorized,
self.monasca_client.create_metrics,
None)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_create_alarm_definition_fails(self):
self.assertRaises(exceptions.Unauthorized,
self.monasca_client.create_alarm_definitions,
None)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_create_notification_fails(self):
notif = helpers.create_notification()
self.assertRaises(exceptions.Unauthorized,
self.monasca_client.create_notifications,
notif)

View File

@ -1,510 +0,0 @@
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
# (C) Copyright 2017-2018 SUSE LLC
#
# 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
import six.moves.urllib.parse as urlparse
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.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from urllib import urlencode
NUM_MEASUREMENTS = 100
MIN_REQUIRED_MEASUREMENTS = 2
WAIT_TIME = 30
class TestStatistics(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestStatistics, cls).resource_setup()
name = data_utils.rand_name('name')
key = data_utils.rand_name('key')
value1 = data_utils.rand_name('value1')
value2 = data_utils.rand_name('value2')
cls._test_name = name
cls._test_key = key
cls._test_value1 = value1
cls._start_timestamp = int(time.time() * 1000)
metrics = [
helpers.create_metric(name=name,
dimensions={key: value1},
timestamp=cls._start_timestamp,
value=1.23),
helpers.create_metric(name=name,
dimensions={key: value2},
timestamp=cls._start_timestamp + 1000,
value=4.56)
]
cls.metric_values = [m['value'] for m in metrics]
cls.monasca_client.create_metrics(metrics)
start_time_iso = helpers.timestamp_to_iso(cls._start_timestamp)
query_param = '?name=' + str(name) + '&start_time=' + \
start_time_iso + '&merge_metrics=true' + '&end_time=' + \
helpers.timestamp_to_iso(cls._start_timestamp + 1000 * 2)
start_time_iso = helpers.timestamp_to_iso(cls._start_timestamp)
cls._start_time_iso = start_time_iso
num_measurements = 0
for i in range(constants.MAX_RETRIES):
resp, response_body = cls.monasca_client.\
list_measurements(query_param)
elements = response_body['elements']
if len(elements) > 0:
num_measurements = len(elements[0]['measurements'])
if num_measurements >= MIN_REQUIRED_MEASUREMENTS:
break
time.sleep(constants.RETRY_WAIT_SECS)
if num_measurements < MIN_REQUIRED_MEASUREMENTS:
assert False, "Required {} measurements, found {}".format(MIN_REQUIRED_MEASUREMENTS, num_measurements)
cls._end_timestamp = cls._start_timestamp + 3000
cls._end_time_iso = helpers.timestamp_to_iso(cls._end_timestamp)
name2 = data_utils.rand_name("group-by")
cls._group_by_metric_name = name2
cls._group_by_end_time_iso = helpers.timestamp_to_iso(cls._start_timestamp + 4000)
group_by_metrics = [
helpers.create_metric(name=name2, dimensions={'key1': 'value1', 'key2': 'value5', 'key3': 'value7'},
timestamp=cls._start_timestamp + 1, value=2),
helpers.create_metric(name=name2, dimensions={'key1': 'value2', 'key2': 'value5', 'key3': 'value7'},
timestamp=cls._start_timestamp + 1001, value=3),
helpers.create_metric(name=name2, dimensions={'key1': 'value3', 'key2': 'value6', 'key3': 'value7'},
timestamp=cls._start_timestamp + 2001, value=5),
helpers.create_metric(name=name2, dimensions={'key1': 'value4', 'key2': 'value6', 'key3': 'value8'},
timestamp=cls._start_timestamp + 3001, value=7),
]
cls.monasca_client.create_metrics(group_by_metrics)
query_param = '?name=' + str(name2) + \
'&start_time=' + start_time_iso + \
'&merge_metrics=true' + \
'&end_time=' + cls._group_by_end_time_iso
num_measurements = 0
for i in range(constants.MAX_RETRIES):
resp, response_body = cls.monasca_client. \
list_measurements(query_param)
elements = response_body['elements']
if len(elements) > 0:
num_measurements = len(elements[0]['measurements'])
if num_measurements >= len(group_by_metrics):
break
time.sleep(constants.RETRY_WAIT_SECS)
if num_measurements < len(group_by_metrics):
assert False, "Required {} measurements, found {}".format(len(group_by_metrics),
response_body)
@classmethod
def resource_cleanup(cls):
super(TestStatistics, cls).resource_cleanup()
@decorators.attr(type="gate")
def test_list_statistics(self):
self._test_list_statistic(with_end_time=True)
@decorators.attr(type="gate")
def test_list_statistics_with_no_end_time(self):
self._test_list_statistic(with_end_time=False)
def _test_list_statistic(self, with_end_time=True):
query_parms = '?name=' + str(self._test_name) + \
'&statistics=' + urlparse.quote('avg,sum,min,max,count') + \
'&start_time=' + str(self._start_time_iso) + \
'&merge_metrics=true' + '&period=100000'
if with_end_time is True:
query_parms += '&end_time=' + str(self._end_time_iso)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
element = response_body['elements'][0]
self._verify_element(element)
column = element['columns']
num_statistics_method = 5
statistics = element['statistics'][0]
self._verify_column_and_statistics(
column, num_statistics_method, statistics, self.metric_values)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_statistics_with_no_name(self):
query_parms = '?merge_metrics=true&statistics=avg&start_time=' + \
str(self._start_time_iso) + '&end_time=' + \
str(self._end_time_iso)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_statistics_with_no_statistics(self):
query_parms = '?name=' + str(self._test_name) + '&start_time=' + str(
self._start_time_iso) + '&end_time=' + str(self._end_time_iso)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_statistics_with_no_start_time(self):
query_parms = '?name=' + str(self._test_name) + '&statistics=avg'
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_statistics_with_invalid_statistics(self):
query_parms = '?name=' + str(self._test_name) + '&statistics=abc' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._end_time_iso)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@decorators.attr(type="gate")
def test_list_statistics_with_dimensions(self):
query_parms = '?name=' + str(self._test_name) + '&statistics=avg' \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._end_time_iso) + \
'&dimensions=' + str(self._test_key) + ':' + \
str(self._test_value1) + '&period=100000'
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
dimensions = response_body['elements'][0]['dimensions']
self.assertEqual(dimensions[self._test_key], self._test_value1)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_statistics_with_end_time_equals_start_time(self):
query_parms = '?name=' + str(self._test_name) + \
'&merge_metrics=true&statistics=avg&' \
'start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._start_time_iso) + \
'&period=100000'
self.assertRaises(exceptions.BadRequest,
self.monasca_client.list_statistics, query_parms)
@decorators.attr(type="gate")
def test_list_statistics_with_period(self):
query_parms = '?name=' + str(self._test_name) + \
'&merge_metrics=true&statistics=avg&' \
'start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._end_time_iso) + \
'&period=1'
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
time_diff = self._end_timestamp - self._start_timestamp
len_statistics = len(response_body['elements'][0]['statistics'])
self.assertEqual(time_diff / 1000, len_statistics)
@decorators.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 + 1,
dimensions={'key1': 'value-1',
'key2': 'value-1'},
value=1),
helpers.create_metric(name=name, timestamp=start_timestamp + 1001,
dimensions={'key1': 'value-2',
'key2': 'value-2'},
value=2),
helpers.create_metric(name=name, timestamp=start_timestamp + 2001,
dimensions={'key1': 'value-3',
'key2': 'value-3'},
value=3),
helpers.create_metric(name=name, timestamp=start_timestamp + 3001,
dimensions={'key1': 'value-4',
'key2': 'value-4'},
value=4)
]
num_metrics = len(metric)
self.monasca_client.create_metrics(metric)
query_parms = '?name=' + name
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.list_metrics(query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
if elements and len(elements) == num_metrics:
break
else:
time.sleep(constants.RETRY_WAIT_SECS)
self._check_timeout(i, constants.MAX_RETRIES, elements, num_metrics)
start_time = helpers.timestamp_to_iso(start_timestamp)
end_timestamp = start_timestamp + 4001
end_time = helpers.timestamp_to_iso(end_timestamp)
query_parms = '?name=' + name + '&merge_metrics=true&statistics=avg' \
+ '&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]
query_parms = '?name=' + name + '&merge_metrics=true&statistics=avg'\
+ '&start_time=' + str(start_time) + '&end_time=' + \
str(end_time) + '&period=1' + '&limit=' + str(num_metrics)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements'][0]['statistics']
self.assertEqual(num_metrics, len(elements))
self.assertEqual(first_element, elements[0])
for limit in range(1, num_metrics):
start_index = 0
params = [('name', name),
('merge_metrics', 'true'),
('statistics', 'avg'),
('start_time', str(start_time)),
('end_time', str(end_time)),
('period', 1),
('limit', limit)]
offset = None
while True:
num_expected_elements = limit
if (num_expected_elements + start_index) > num_metrics:
num_expected_elements = num_metrics - start_index
these_params = list(params)
# If not the first call, use the offset returned by the last call
if offset:
these_params.extend([('offset', str(offset))])
query_parms = '?' + urlencode(these_params)
resp, response_body = self.monasca_client.list_statistics(query_parms)
self.assertEqual(200, resp.status)
if not response_body['elements']:
self.fail("No metrics returned")
if not response_body['elements'][0]['statistics']:
self.fail("No statistics returned")
new_elements = response_body['elements'][0]['statistics']
self.assertEqual(num_expected_elements, len(new_elements))
expected_elements = elements[start_index:start_index + limit]
self.assertEqual(expected_elements, new_elements)
start_index += num_expected_elements
if start_index >= num_metrics:
break
# Get the next set
offset = self._get_offset(response_body)
@decorators.attr(type="gate")
def test_list_statistics_with_group_by_one(self):
query_parms = '?name=' + self._group_by_metric_name + \
'&group_by=key2' + \
'&statistics=max,avg,min' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._group_by_end_time_iso)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(len(elements), 2)
for statistics in elements:
self.assertEqual(1, len(statistics['dimensions'].keys()))
self.assertEqual([u'key2'], statistics['dimensions'].keys())
@decorators.attr(type="gate")
def test_list_statistics_with_group_by_multiple(self):
query_parms = '?name=' + self._group_by_metric_name + \
'&group_by=key2,key3' + \
'&statistics=max,avg,min' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._group_by_end_time_iso)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(len(elements), 3)
for statistics in elements:
self.assertEqual(2, len(statistics['dimensions'].keys()))
self.assertEqual({u'key2', u'key3'}, set(statistics['dimensions'].keys()))
@decorators.attr(type="gate")
def test_list_statistics_with_group_by_all(self):
query_parms = '?name=' + self._group_by_metric_name + \
'&group_by=*' + \
'&statistics=max,avg,min' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._group_by_end_time_iso)
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
elements = response_body['elements']
self.assertEqual(len(elements), 4)
@decorators.attr(type="gate")
def test_list_statistics_with_group_by_offset_limit(self):
query_parms = '?name=' + str(self._group_by_metric_name) + \
'&group_by=key2' + \
'&statistics=avg,max' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._group_by_end_time_iso) + \
'&period=1'
resp, response_body = self.monasca_client.list_statistics(query_parms)
self.assertEqual(200, resp.status)
all_expected_elements = response_body['elements']
for limit in range(1, 4):
offset = None
for i in range(4 - limit):
query_parms = '?name=' + str(self._group_by_metric_name) + \
'&group_by=key2' + \
'&statistics=avg,max' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._group_by_end_time_iso) + \
'&period=1' + \
'&limit=' + str(limit)
if i > 0:
offset = self._get_offset(response_body)
query_parms += "&offset=" + offset
expected_elements = helpers.get_expected_elements_inner_offset_limit(
all_expected_elements,
offset,
limit,
'statistics')
resp, response_body = self.monasca_client.list_statistics(query_parms)
self.assertEqual(200, resp.status)
self.assertEqual(expected_elements, response_body['elements'])
@decorators.attr(type="gate")
def test_list_statistics_with_long_start_time(self):
query_parms = '?name=' + str(self._test_name) + \
'&statistics=' + urlparse.quote('avg,sum,min,max,count') + \
'&start_time=' + "2017-01-01T00:00:00.00Z" + \
'&end_time=' + str(self._end_time_iso) + \
'&merge_metrics=true' + '&period=100000'
resp, response_body = self.monasca_client.list_statistics(
query_parms)
self.assertEqual(200, resp.status)
self.assertTrue(set(['links', 'elements']) == set(response_body))
element = response_body['elements'][0]
self._verify_element(element)
column = element['columns']
num_statistics_method = 5
statistics = element['statistics'][0]
self._verify_column_and_statistics(
column, num_statistics_method, statistics, self.metric_values)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_statistics_with_no_merge_metrics(self):
key = data_utils.rand_name('key')
value = data_utils.rand_name('value')
metric3 = helpers.create_metric(
name=self._test_name,
dimensions={key: value},
timestamp=self._start_timestamp + 2000)
self.monasca_client.create_metrics(metric3)
query_param = '?name=' + str(self._test_name) + '&start_time=' + \
self._start_time_iso + '&end_time=' + helpers.\
timestamp_to_iso(self._start_timestamp + 1000 * 4) + \
'&merge_metrics=True'
for i in range(constants.MAX_RETRIES):
resp, response_body = self.monasca_client.\
list_measurements(query_param)
elements = response_body['elements']
for element in elements:
if str(element['name']) == self._test_name and len(
element['measurements']) == 3:
end_time_iso = helpers.timestamp_to_iso(
self._start_timestamp + 1000 * 4)
query_parms = '?name=' + str(self._test_name) + \
'&statistics=avg' + '&start_time=' + \
str(self._start_time_iso) + '&end_time=' +\
str(end_time_iso) + '&period=100000'
self.assertRaises(exceptions.Conflict,
self.monasca_client.list_statistics,
query_parms)
return
time.sleep(constants.RETRY_WAIT_SECS)
self._check_timeout(i, constants.MAX_RETRIES, elements, 3)
@decorators.attr(type="gate")
@decorators.attr(type=['negative'])
def test_list_statistics_with_name_exceeds_max_length(self):
long_name = "x" * (constants.MAX_LIST_STATISTICS_NAME_LENGTH + 1)
query_parms = '?name=' + str(long_name) + '&merge_metrics=true' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._end_time_iso)
self.assertRaises(exceptions.UnprocessableEntity,
self.monasca_client.list_statistics, query_parms)
@decorators.attr(type="gate")
def test_list_statistics_response_body_statistic_result_type(self):
query_parms = '?name=' + str(self._test_name) + '&period=100000' + \
'&statistics=avg' + '&merge_metrics=true' + \
'&start_time=' + str(self._start_time_iso) + \
'&end_time=' + str(self._end_time_iso)
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)
def _verify_element(self, element):
self.assertTrue(set(['id', 'name', 'dimensions', 'columns',
'statistics']) == set(element))
self.assertTrue(type(element['id']) is unicode)
self.assertTrue(element['id'] is not None)
self.assertTrue(type(element['name']) is unicode)
self.assertTrue(type(element['dimensions']) is dict)
self.assertEqual(len(element['dimensions']), 0)
self.assertTrue(type(element['columns']) is list)
self.assertTrue(type(element['statistics']) is list)
self.assertEqual(element['name'], self._test_name)
def _verify_column_and_statistics(
self, column, num_statistics_method, statistics, values):
self.assertTrue(type(column) is list)
self.assertTrue(type(statistics) is list)
self.assertEqual(len(column), num_statistics_method + 1)
self.assertEqual(column[0], 'timestamp')
for i, method in enumerate(column):
if method == 'avg':
self.assertAlmostEqual(statistics[i], float(sum(values) / len(values)))
elif method == 'max':
self.assertEqual(statistics[i], max(values))
elif method == 'min':
self.assertEqual(statistics[i], min(values))
elif method == 'sum':
self.assertAlmostEqual(statistics[i], sum(values))
elif method == 'count':
self.assertEqual(statistics[i], len(values))
def _check_timeout(self, timer, max_retries, elements,
expect_num_elements):
if timer == max_retries - 1:
error_msg = ("Failed: timeout on waiting for metrics: {} elements "
"are needed. Current number of elements = {}").\
format(expect_num_elements, len(elements))
raise self.fail(error_msg)

View File

@ -1,50 +0,0 @@
# (C) Copyright 2015,2017 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.lib import decorators
class TestVersions(base.BaseMonascaTest):
@classmethod
def resource_setup(cls):
super(TestVersions, cls).resource_setup()
@decorators.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.assertIsInstance(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.assertIsInstance(date_object, datetime.datetime)
links = response_body['links']
self.assertIsInstance(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'))

View File

@ -34,7 +34,7 @@
MONASCA_API_IMPLEMENTATION_LANG="{{ api_lang }}"
MONASCA_PERSISTER_IMPLEMENTATION_LANG="{{ persister_lang }}"
MONASCA_METRICS_DB="{{ tsdb }}"
TEMPEST_PLUGINS+='/opt/stack/new/monasca-tempest-plugin'
EOF
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
@ -50,6 +50,8 @@
export DEVSTACK_GATE_NEUTRON=1
export DEVSTACK_GATE_EXERCISES=0
export DEVSTACK_GATE_TEMPEST=1
export DEVSTACK_GATE_TEMPEST_REGEX="monasca_tempest_tests.tests.api"
if [ "{{ database }}" == "postgresql" ]; then
export DEVSTACK_GATE_POSTGRES=1
@ -67,15 +69,11 @@
export PROJECTS="openstack/python-monascaclient $PROJECTS"
export PROJECTS="openstack/monasca-grafana-datasource $PROJECTS"
export PROJECTS="openstack/monasca-ui $PROJECTS"
function pre_test_hook {
source $BASE/new/monasca-api/monasca_tempest_tests/contrib/gate_hook.sh
}
export -f pre_test_hook
export PROJECTS="openstack/monasca-tempest-plugin $PROJECTS"
function post_test_hook {
# Configure and run tempest on monasca-api installation
source $BASE/new/monasca-api/monasca_tempest_tests/contrib/post_test_hook.sh
source $BASE/new/monasca-api/contrib/post_test_hook.sh
}
export -f post_test_hook

View File

@ -20,7 +20,6 @@ classifier =
[files]
packages =
monasca_api
monasca_tempest_tests
data_files =
/etc/monasca =
@ -31,9 +30,6 @@ data_files =
console_scripts =
monasca-api = monasca_api.api.server:launch
tempest.test_plugins =
monasca_tests = monasca_tempest_tests.plugin:MonascaTempestPlugin
oslo.config.opts =
monasca_api = monasca_api.conf:list_opts

View File

@ -51,7 +51,7 @@ skip_install = True
usedevelop = False
commands =
{[testenv]commands}
flake8 monasca_api monasca_tempest_tests
flake8 monasca_api
[testenv:bandit]
skip_install = True
@ -59,8 +59,6 @@ usedevelop = False
commands =
# B101(assert_ussed) - API uses asserts because of performance reasons
bandit -r monasca_api -n5 -s B101 -x monasca_api/tests
# B101(assert_ussed) - asserts in test layers seems appropriate
bandit -r monasca_tempest_tests -n5 -s B101
[testenv:bashate]
skip_install = True