Fix devgate

* add senlin-tempest-plugin as required project for zuul
* change senlin-dsvm-tempest-* to run against senlin-tempest-plugin
* remove entry points tempest plugin
* change entry point for openstack_test to point to senlin-tempest-plugin
* add missing methods in neutron test driver
* fix check of force option for cluster delete and node delete
* add zaqar-tempest-plugin in devstack for gate test
* fix bug with attached_volume property
* removed tempest
* updated readme

Depends-On: I4eb9a9dbc0a1bdd5e0864c147974cf8e371789c2

Change-Id: I39761f5d1dd7fa4c38cf76929e996aafa65297ca
This commit is contained in:
Duc Truong 2018-01-12 07:19:51 +00:00 committed by tengqm
parent 63a360c0ad
commit fa1ac4caf2
152 changed files with 170 additions and 10181 deletions

View File

@ -36,6 +36,7 @@
- openstack/neutron-lbaas
- openstack/python-zaqarclient
- openstack/senlin
- openstack/senlin-tempest-plugin
- openstack/tempest
- openstack/zaqar
- openstack/zaqar-ui
@ -43,6 +44,7 @@
- ^.*\.rst$
- ^api-ref/.*$
- ^doc/.*$
- ^senlin/tests/unit/.*$
- ^releasenotes/.*$
- job:
@ -57,6 +59,7 @@
- openstack/neutron-lbaas
- openstack/python-zaqarclient
- openstack/senlin
- openstack/senlin-tempest-plugin
- openstack/tempest
- openstack/zaqar
- openstack/zaqar-ui
@ -64,6 +67,7 @@
- ^.*\.rst$
- ^api-ref/.*$
- ^doc/.*$
- ^senlin/tests/unit/.*$
- ^releasenotes/.*$
- job:
@ -78,13 +82,16 @@
- openstack/neutron-lbaas
- openstack/python-zaqarclient
- openstack/senlin
- openstack/senlin-tempest-plugin
- openstack/tempest
- openstack/zaqar
- openstack/zaqar-ui
- openstack/zaqar-tempest-plugin
irrelevant-files:
- ^.*\.rst$
- ^api-ref/.*$
- ^doc/.*$
- ^senlin/tests/unit/.*$
- ^releasenotes/.*$
- job:
@ -99,6 +106,7 @@
- openstack/neutron-lbaas
- openstack/python-zaqarclient
- openstack/senlin
- openstack/senlin-tempest-plugin
- openstack/tempest
- openstack/zaqar
- openstack/zaqar-ui
@ -106,6 +114,7 @@
- ^.*\.rst$
- ^api-ref/.*$
- ^doc/.*$
- ^senlin/tests/unit/.*$
- ^releasenotes/.*$
- job:
@ -120,6 +129,7 @@
- openstack/neutron-lbaas
- openstack/python-zaqarclient
- openstack/senlin
- openstack/senlin-tempest-plugin
- openstack/tempest
- openstack/zaqar
- openstack/zaqar-ui
@ -127,6 +137,7 @@
- ^.*\.rst$
- ^api-ref/.*$
- ^doc/.*$
- ^senlin/tests/unit/.*$
- ^releasenotes/.*$
- job:
@ -141,13 +152,16 @@
- openstack/neutron-lbaas
- openstack/python-zaqarclient
- openstack/senlin
- openstack/senlin-tempest-plugin
- openstack/tempest
- openstack/zaqar
- openstack/zaqar-ui
- openstack/zaqar-tempest-plugin
irrelevant-files:
- ^.*\.rst$
- ^api-ref/.*$
- ^doc/.*$
- ^senlin/tests/unit/.*$
- ^releasenotes/.*$
- job:

View File

@ -50,20 +50,25 @@ Launchpad Projects
- Server: https://launchpad.net/senlin
- Client: https://launchpad.net/python-senlinclient
- Dashboard: https://launchpad.net/senlin-dashboard
- Tempest Plugin: https://launchpad.net/senlin-tempest-plugin
Code Repository
---------------
- Server: https://git.openstack.org/cgit/openstack/senlin
- Client: https://git.openstack.org/cgit/openstack/python-senlinclient
- Dashboard: https://git.openstack.org/cgit/openstack/senlin-dashboard
- Tempest Plugin: https://git.openstack.org/cgit/openstack/senlin-tempest-plugin
Blueprints
----------
- Blueprints: https://blueprints.launchpad.net/senlin
- Blueprints: https://blueprints.launchpad.net/senlinA
Bug Tracking
------------
- Bugs: https://bugs.launchpad.net/senlin
- Server Bugs: https://bugs.launchpad.net/senlin
- Client Bugs: https://bugs.launchpad.net/python-senlinclient
- Dashboard Bugs: https://bugs.launchpad.net/senlin-dashboard
- Tempest Plugin Bugs: https://bugs.launchpad.net/senlin-tempest-plugin
Weekly Meetings
---------------

View File

@ -42,7 +42,8 @@
export DEVSTACK_GATE_USE_PYTHON3=False
fi
export DEVSTACK_GATE_TEMPEST_REGEX="senlin.tests.tempest.api"
export SENLIN_TEST_TYPE="api"
export DEVSTACK_GATE_TEMPEST_REGEX="senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}"
services=rabbit,mysql,dstat,key,tempest
services+=,g-api,g-reg
@ -57,7 +58,7 @@
export PROJECTS="openstack/senlin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG="enable_plugin senlin https://git.openstack.org/openstack/senlin"
if [ "api" == "api" ]||[ "api" == "functional" ]; then
if [ "${SENLIN_TEST_TYPE}" == "api" ]||[ "${SENLIN_TEST_TYPE}" == "functional" ]; then
export SENLIN_BACKEND="openstack_test"
else
export SENLIN_BACKEND="openstack"
@ -76,6 +77,10 @@
export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar"
fi
# use senlin-tempest-plugin
export PROJECTS="openstack/senlin-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/senlin-tempest-plugin'"
export OVERRIDE_ENABLED_SERVICES=$services
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
@ -90,7 +95,7 @@
function post_test_hook {
cd /opt/stack/new/senlin/senlin/tests/tempest/
./post_test_hook.sh
./post_test_hook.sh senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}
}
export -f post_test_hook

View File

@ -43,7 +43,8 @@
export DEVSTACK_GATE_USE_PYTHON3=False
fi
export DEVSTACK_GATE_TEMPEST_REGEX="senlin.tests.tempest.functional"
export SENLIN_TEST_TYPE="functional"
export DEVSTACK_GATE_TEMPEST_REGEX="senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}"
services=rabbit,mysql,dstat,key,tempest
services+=,g-api,g-reg
@ -58,7 +59,7 @@
export PROJECTS="openstack/senlin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG="enable_plugin senlin https://git.openstack.org/openstack/senlin"
if [ "functional" == "api" ]||[ "functional" == "functional" ]; then
if [ "${SENLIN_TEST_TYPE}" == "api" ]||[ "${SENLIN_TEST_TYPE}" == "functional" ]; then
export SENLIN_BACKEND="openstack_test"
else
export SENLIN_BACKEND="openstack"
@ -77,6 +78,10 @@
export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar"
fi
# use senlin-tempest-plugin
export PROJECTS="openstack/senlin-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/senlin-tempest-plugin'"
export OVERRIDE_ENABLED_SERVICES=$services
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
@ -91,7 +96,7 @@
function post_test_hook {
cd /opt/stack/new/senlin/senlin/tests/tempest/
./post_test_hook.sh
./post_test_hook.sh senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}
}
export -f post_test_hook

View File

@ -43,7 +43,8 @@
export DEVSTACK_GATE_USE_PYTHON3=False
fi
export DEVSTACK_GATE_TEMPEST_REGEX="senlin.tests.tempest.integration"
export SENLIN_TEST_TYPE="integration"
export DEVSTACK_GATE_TEMPEST_REGEX="senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}"
services=rabbit,mysql,dstat,key,tempest
services+=,g-api,g-reg
@ -58,7 +59,7 @@
export PROJECTS="openstack/senlin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG="enable_plugin senlin https://git.openstack.org/openstack/senlin"
if [ "integration" == "api" ]||[ "integration" == "functional" ]; then
if [ "${SENLIN_TEST_TYPE}" == "api" ]||[ "${SENLIN_TEST_TYPE}" == "functional" ]; then
export SENLIN_BACKEND="openstack_test"
else
export SENLIN_BACKEND="openstack"
@ -75,8 +76,14 @@
export PROJECTS="openstack/python-zaqarclient $PROJECTS"
export PROJECTS="openstack/zaqar-ui $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar"
export PROJECTS="openstack/zaqar-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/zaqar-tempest-plugin'"
fi
# use senlin-tempest-plugin
export PROJECTS="openstack/senlin-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/senlin-tempest-plugin'"
export OVERRIDE_ENABLED_SERVICES=$services
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
@ -91,7 +98,7 @@
function post_test_hook {
cd /opt/stack/new/senlin/senlin/tests/tempest/
./post_test_hook.sh
./post_test_hook.sh senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}
}
export -f post_test_hook

View File

@ -31,10 +31,10 @@
export PYTHONUNBUFFERED=True
export DEVSTACK_GATE_NEUTRON=1
export DEVSTACK_GATE_TEMPEST=1
export KEEP_LOCALRC=1
export DEVSTACK_GATE_TEMPEST_NOTESTS=1
export DEVSTACK_GATE_EXERCISES=0
export DEVSTACK_GATE_INSTALL_TESTONLY=1
export KEEP_LOCALRC=1
if [ "py35" == "py35" ]; then
export DEVSTACK_GATE_USE_PYTHON3=True
@ -42,7 +42,8 @@
export DEVSTACK_GATE_USE_PYTHON3=False
fi
export DEVSTACK_GATE_TEMPEST_REGEX="senlin.tests.tempest.api"
export SENLIN_TEST_TYPE="api"
export DEVSTACK_GATE_TEMPEST_REGEX="senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}"
services=rabbit,mysql,dstat,key,tempest
services+=,g-api,g-reg
@ -57,7 +58,7 @@
export PROJECTS="openstack/senlin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG="enable_plugin senlin https://git.openstack.org/openstack/senlin"
if [ "api" == "api" ]||[ "api" == "functional" ]; then
if [ "${SENLIN_TEST_TYPE}" == "api" ]||[ "${SENLIN_TEST_TYPE}" == "functional" ]; then
export SENLIN_BACKEND="openstack_test"
else
export SENLIN_BACKEND="openstack"
@ -76,6 +77,10 @@
export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar"
fi
# use senlin-tempest-plugin
export PROJECTS="openstack/senlin-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/senlin-tempest-plugin'"
export OVERRIDE_ENABLED_SERVICES=$services
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
@ -90,7 +95,7 @@
function post_test_hook {
cd /opt/stack/new/senlin/senlin/tests/tempest/
./post_test_hook.sh
./post_test_hook.sh senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}
}
export -f post_test_hook

View File

@ -43,7 +43,8 @@
export DEVSTACK_GATE_USE_PYTHON3=False
fi
export DEVSTACK_GATE_TEMPEST_REGEX="senlin.tests.tempest.functional"
export SENLIN_TEST_TYPE="functional"
export DEVSTACK_GATE_TEMPEST_REGEX="senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}"
services=rabbit,mysql,dstat,key,tempest
services+=,g-api,g-reg
@ -58,7 +59,7 @@
export PROJECTS="openstack/senlin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG="enable_plugin senlin https://git.openstack.org/openstack/senlin"
if [ "functional" == "api" ]||[ "functional" == "functional" ]; then
if [ "${SENLIN_TEST_TYPE}" == "api" ]||[ "${SENLIN_TEST_TYPE}" == "functional" ]; then
export SENLIN_BACKEND="openstack_test"
else
export SENLIN_BACKEND="openstack"
@ -77,6 +78,10 @@
export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar"
fi
# use senlin-tempest-plugin
export PROJECTS="openstack/senlin-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/senlin-tempest-plugin'"
export OVERRIDE_ENABLED_SERVICES=$services
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
@ -91,7 +96,7 @@
function post_test_hook {
cd /opt/stack/new/senlin/senlin/tests/tempest/
./post_test_hook.sh
./post_test_hook.sh senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}
}
export -f post_test_hook

View File

@ -43,7 +43,8 @@
export DEVSTACK_GATE_USE_PYTHON3=False
fi
export DEVSTACK_GATE_TEMPEST_REGEX="senlin.tests.tempest.integration"
export SENLIN_TEST_TYPE="integration"
export DEVSTACK_GATE_TEMPEST_REGEX="senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}"
services=rabbit,mysql,dstat,key,tempest
services+=,g-api,g-reg
@ -58,7 +59,7 @@
export PROJECTS="openstack/senlin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG="enable_plugin senlin https://git.openstack.org/openstack/senlin"
if [ "integration" == "api" ]||[ "integration" == "functional" ]; then
if [ "${SENLIN_TEST_TYPE}" == "api" ]||[ "${SENLIN_TEST_TYPE}" == "functional" ]; then
export SENLIN_BACKEND="openstack_test"
else
export SENLIN_BACKEND="openstack"
@ -75,8 +76,14 @@
export PROJECTS="openstack/python-zaqarclient $PROJECTS"
export PROJECTS="openstack/zaqar-ui $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar"
export PROJECTS="openstack/zaqar-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/zaqar-tempest-plugin'"
fi
# use senlin-tempest-plugin
export PROJECTS="openstack/senlin-tempest-plugin $PROJECTS"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"TEMPEST_PLUGINS+=' /opt/stack/new/senlin-tempest-plugin'"
export OVERRIDE_ENABLED_SERVICES=$services
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
@ -91,7 +98,7 @@
function post_test_hook {
cd /opt/stack/new/senlin/senlin/tests/tempest/
./post_test_hook.sh
./post_test_hook.sh senlin_tempest_plugin.tests.${SENLIN_TEST_TYPE}
}
export -f post_test_hook

View File

@ -302,15 +302,16 @@ class ClusterController(wsgi.Controller):
@util.policy_enforce
def delete(self, req, cluster_id, body=None):
if body:
if req.params.get('force') is not None:
force = util.parse_bool_param(consts.CLUSTER_DELETE_FORCE,
req.params.get('force'))
elif body:
force = body.get('force')
if force is None:
force = False
else:
force = False
if force is not None:
force = util.parse_bool_param(consts.CLUSTER_DELETE_FORCE,
force)
params = {'identity': cluster_id, 'force': force}
obj = util.parse_request('ClusterDeleteRequest', req, params)
res = self.rpc_client.call(req.context, 'cluster_delete', obj)

View File

@ -126,8 +126,7 @@ class NodeController(wsgi.Controller):
force = False
if force is not None:
force = util.parse_bool_param(consts.NODE_DELETE_FORCE,
force)
force = util.parse_bool_param(consts.NODE_DELETE_FORCE, force)
params = {'identity': node_id, 'force': force}

View File

@ -34,7 +34,6 @@ DateTimeField = fields.DateTimeField
DictOfStringsField = fields.DictOfStringsField
ListOfStringsField = fields.ListOfStringsField
ListOfEnumField = fields.ListOfEnumField
ObjectField = fields.ObjectField
class Boolean(fields.FieldType):
@ -78,6 +77,18 @@ class NonNegativeInteger(fields.FieldType):
}
# Senlin has a stricter field checking for object fields.
class Object(fields.Object):
def get_schema(self):
schema = super(Object, self).get_schema()
# we are not checking whether self._obj_name is registered, an
# exception will be raised anyway if it is not registered.
data_key = 'senlin_object.data'
schema['properties'][data_key]['additionalProperties'] = False
return schema
class UUID(fields.FieldType):
_PATTERN = (r'^[a-fA-F0-9]{8}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]{4}-?[a-fA-F0-9]'
@ -393,6 +404,16 @@ class BooleanField(fields.AutoTypedField):
AUTO_TYPE = Boolean()
# An override to the oslo.versionedobjects version so that we are using
# our own Object definition.
class ObjectField(fields.AutoTypedField):
def __init__(self, objtype, subclasses=False, **kwargs):
self.AUTO_TYPE = Object(objtype, subclasses)
self.objname = objtype
super(ObjectField, self).__init__(**kwargs)
class JsonField(fields.AutoTypedField):
AUTO_TYPE = Json()

View File

@ -1279,7 +1279,8 @@ class ServerProfile(base.Profile):
else:
image_id = server_data['image']
attached_volumes = []
if len(server_data['attached_volumes']) > 0:
if ('attached_volumes' in server_data and
len(server_data['attached_volumes']) > 0):
for volume in server_data['attached_volumes']:
attached_volumes.append(volume['id'])
details = {

View File

@ -19,6 +19,7 @@ from senlin.tests.drivers.openstack import lbaas
from senlin.tests.drivers.openstack import mistral_v2
from senlin.tests.drivers.openstack import neutron_v2
from senlin.tests.drivers.openstack import nova_v2
from senlin.tests.drivers.openstack import octavia_v2
compute = nova_v2.NovaClient
@ -26,6 +27,7 @@ identity = keystone_v3.KeystoneClient
loadbalancing = lbaas.LoadBalancerDriver
message = zaqar_v2.ZaqarClient
network = neutron_v2.NeutronClient
octavia = octavia_v2.OctaviaClient
orchestration = heat_v1.HeatClient
telemetry = ceilometer_v2.CeilometerClient
workflow = mistral_v2.MistralClient

View File

@ -32,6 +32,33 @@ class NeutronClient(base.DriverBase):
"port_security_enabled": True,
"id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
}
self.fake_port = {
"ip_address": "10.0.1.10",
"fixed_ips": [
"172.17.1.129"
],
"network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
"status": "ACTIVE",
"subnet_id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b",
"id": "60f65938-3ebb-451d-a3a3-a0918d345469",
"security_group_ids": [
"45aa2abc-47f0-4008-8d67-606b41cabb7a"
]
}
self.fake_subnet = {
"network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
"subnet_pool_id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b",
"id": "60f65938-3ebb-451d-a3a3-a0918d345469"
}
def network_get(self, value, ignore_missing=False):
return sdk.FakeResourceObject(self.fake_network)
def port_create(self, **attr):
return sdk.FakeResourceObject(self.fake_port)
def port_delete(self, port, ignore_missing=True):
return None
def subnet_get(self, name_or_id, ignore_missing=False):
return sdk.FakeResourceObject(self.fake_subnet)

View File

@ -0,0 +1,26 @@
# 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 senlin.drivers import base
class OctaviaClient(base.DriverBase):
def __init__(self, params):
self.lb_result = {
"loadbalancer": "a36c20d0-18e9-42ce-88fd-82a35977ee8c",
"vip_address": "192.168.1.100",
"listener": "35cb8516-1173-4035-8dae-0dae3453f37f",
"pool": "4c0a0a5f-cf8f-44b7-b912-957daa8ce5e5",
"healthmonitor": "0a9ac99d-0a09-4b18-8499-a0796850279a"
}
self.member_id = "9a7aff27-fd41-4ec1-ba4c-3eb92c629313"

View File

@ -1,21 +1,5 @@
====================
Tempest Integration
====================
=====
MOVED
=====
This directory contains Tempest tests to cover senlin project.
To list all senlin tempest cases, go to tempest directory, then run::
$ testr list-tests senlin
To run only these tests in tempest, go to tempest directory, then run::
$ ./run_tempest.sh -N -- senlin
To run a single test case, go to tempest directory, then run with test case name, e.g.::
$ ./run_tempest.sh -N -- senlin.tests.tempest.api.test_cluster_basic.TestClusterBasic.test_cluster_create_delete
If you can't find run_tempest.sh script in tempest directory, that means the script has been removed in a certain version.
Then you can use "nosetests -v" to replace "./run_tempest.sh -N" in above command.
More information about running tempest test can be found here: https://docs.openstack.org/tempest/latest/
The senlin tempest plugin has moved to http://git.openstack.org/cgit/openstack/senlin-tempest-plugin

View File

@ -1,44 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestActionList(base.BaseSenlinAPITest):
def setUp(self):
super(TestActionList, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, cluster_id)
@decorators.idempotent_id('2e47639b-7f58-4fb4-a147-a8c6bf184e97')
def test_action_list(self):
res = self.client.list_objs('actions')
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
actions = res['body']
for action in actions:
for key in ['action', 'cause', 'created_at', 'data',
'depended_by', 'depends_on', 'end_time', 'id',
'inputs', 'interval', 'name', 'outputs', 'owner',
'start_time', 'status', 'status_reason', 'target',
'timeout', 'updated_at']:
self.assertIn(key, action)

View File

@ -1,86 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestActionListNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('2f857bee-99a8-4881-bde9-5909e3ff121a')
def test_action_list_invalid_params(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'actions', {'bogus': 'foo'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid parameter bogus", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6b93221e-ca14-443b-be54-4423a636672a')
def test_action_list_limit_not_int(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'actions', {'limit': 'not-int'})
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for limit must be an integer: 'not-int'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d13e3011-32b5-4f9d-bb57-3532c4c46228')
def test_action_list_global_project_false(self):
ex = self.assertRaises(exceptions.Forbidden,
self.client.list_objs,
'actions', {'global_project': 'True'})
message = ex.resp_body['error']['message']
self.assertEqual("You are not authorized to complete this operation.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d7804b5e-6efd-4084-adec-531d0a8399dc')
def test_action_list_global_project_not_bool(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'actions', {'global_project': 'not-bool'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid value 'not-bool' specified for "
"'global_project'", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6ca48051-6030-4333-9483-074e03da5ba0')
def test_action_list_invalid_sort(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'actions', {'sort': 'bad-sort'})
message = ex.resp_body['error']['message']
self.assertEqual("Unsupported sort key 'bad-sort' for 'sort'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('588517ed-bfcf-4d92-9d7c-5ed11fc2c2ee')
def test_action_list_invalid_marker(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'actions', {'marker': 'bad-marker'})
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for marker is not a valid UUID: 'bad-marker'.",
str(message))

View File

@ -1,57 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestActionShow(base.BaseSenlinAPITest):
def setUp(self):
super(TestActionShow, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
params = {
'cluster': {
'profile_id': profile_id,
'desired_capacity': 0,
'min_size': 0,
'max_size': -1,
'timeout': None,
'metadata': {},
'name': 'test-cluster-action-show'
}
}
res = self.client.create_obj('clusters', params)
self.action_id = res['location'].split('/actions/')[1]
self.addCleanup(utils.delete_a_cluster, self, res['body']['id'])
self.client.wait_for_status('actions', self.action_id, 'SUCCEEDED')
@decorators.idempotent_id('c6376f60-8f52-4384-8b6d-57df264f2e23')
def test_action_show(self):
res = self.client.get_obj('actions', self.action_id)
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
action = res['body']
for key in ['action', 'cause', 'created_at', 'data',
'depended_by', 'depends_on', 'end_time', 'id',
'inputs', 'interval', 'name', 'outputs', 'owner',
'start_time', 'status', 'status_reason', 'target',
'timeout', 'updated_at']:
self.assertIn(key, action)

View File

@ -1,31 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestActionShowNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('26cb0f3a-4e6c-49f6-8475-7cb472933bff')
def test_action_show_not_found(self):
ex = self.assertRaises(
exceptions.NotFound, self.client.get_obj,
'actions', '26cb0f3a-4e6c-49f6-8475-7cb472933bff')
message = ex.resp_body['error']['message']
self.assertEqual(
"The action '26cb0f3a-4e6c-49f6-8475-7cb472933bff' could "
"not be found.", str(message))

View File

@ -1,31 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
class TestAPIVersionShow(base.BaseSenlinAPITest):
@decorators.idempotent_id('4a270caa-9917-4acd-98ef-6636f9618037')
def test_API_version_show(self):
resp, body = self.client.request('GET', '/v1/')
res = self.client.get_resp(resp, body)
# Verify resp of API version show
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
version = res['body']
for key in ['id', 'links', 'media-types', 'status', 'updated']:
self.assertIn(key, version)
self.assertEqual('1.0', version['id'])

View File

@ -1,26 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestAPIVersionShowNegative(base.BaseSenlinAPITest):
@decorators.idempotent_id('a3b02638-2459-41ab-a70b-a6f1a269914e')
def test_API_version_show_invalid_version(self):
resp, body = self.client.request('GET', '/v1/')
self.assertRaises(exceptions.NotFound,
self.client.request,
'GET', '/vx')

View File

@ -1,35 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
class TestAPIVersions(base.BaseSenlinAPITest):
@decorators.idempotent_id('c7378a80-9a82-4148-937d-25e046c6316f')
def test_API_versions_list(self):
resp, body = self.client.request('GET', '/')
res = self.client.get_resp(resp, body)
# Verify resp of API versions list
self.assertEqual(300, res['status'])
self.assertIsNotNone(res['body'])
versions = res['body']
for version in versions:
for key in ['id', 'links', 'max_version', 'media-types',
'min_version', 'status', 'updated']:
self.assertIn(key, version)
# Only version 1.0 API is now supported
self.assertEqual(1, len(versions))
self.assertEqual('1.0', versions[0]['id'])

View File

@ -1,55 +0,0 @@
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from tempest import config
from senlin.tests.tempest import base
from senlin.tests.tempest.common import clustering_client
from senlin.tests.tempest.common import compute_client
from senlin.tests.tempest.common import network_client
CONF = config.CONF
class BaseSenlinAPITest(base.BaseSenlinTest):
@classmethod
def setup_credentials(cls):
# Set no network resources for test accounts
cls.set_network_resources()
super(BaseSenlinAPITest, cls).setup_credentials()
@classmethod
def setup_clients(cls):
super(BaseSenlinAPITest, cls).setup_clients()
cls.client = clustering_client.ClusteringAPIClient(
cls.os_primary.auth_provider,
CONF.clustering.catalog_type,
CONF.identity.region,
**cls.default_params_with_timeout_values
)
cls.compute_client = compute_client.V21ComputeClient(
cls.os_primary.auth_provider,
CONF.compute.catalog_type,
CONF.identity.region,
**cls.default_params_with_timeout_values
)
cls.network_client = network_client.NetworkClient(
cls.os_primary.auth_provider,
CONF.network.catalog_type,
CONF.identity.region,
**cls.default_params_with_timeout_values
)

View File

@ -1,29 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
class TestBuildInfo(base.BaseSenlinAPITest):
@decorators.idempotent_id('bf7a8bdf-d896-49ff-a7a8-7c8fdbfc3667')
def test_build_info_get(self):
uri = '{0}/build-info'.format(self.client.version)
resp, info = self.client.get(uri)
# Verify resp of get build-info API
self.assertEqual(200, int(resp['status']))
self.assertIsNotNone(info)
for key in ['api', 'engine']:
self.assertIn(key, info)

View File

@ -1,49 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterPolicyList(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyList, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
utils.cluster_attach_policy(self, self.cluster_id, self.policy_id)
self.addCleanup(utils.cluster_detach_policy, self, self.cluster_id,
self.policy_id)
@decorators.idempotent_id('ebaeedcb-7198-4997-9b9c-a8f1eccfc2a6')
def test_cluster_policy_list(self):
res = self.client.list_cluster_policies(self.cluster_id)
# Verify resp of cluster policy list API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
policies = res['body']
self.assertEqual(1, len(policies))
for key in ['cluster_id', 'cluster_name', 'enabled', 'id',
'policy_id', 'policy_name', 'policy_type']:
self.assertIn(key, policies[0])
self.assertEqual(self.policy_id, policies[0]['policy_id'])

View File

@ -1,66 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestClusterPolicyListNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7f23de64-60c4-456e-9e24-db86ac89480c')
def test_cluster_policy_list_invalid_params(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_cluster_policies,
'7f23de64-60c4-456e-9e24-db86ac89480c',
{'bogus': 'foo'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid parameter bogus", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0259cbac-0fb3-480b-8f23-1ec59616f3af')
def test_cluster_policy_list_cluster_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.list_cluster_policies,
'0259cbac-0fb3-480b-8f23-1ec59616f3af')
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '0259cbac-0fb3-480b-8f23-1ec59616f3af' "
"could not be found.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('958c6fd2-a647-4b5a-8133-8b4232267b40')
def test_cluster_policy_list_invalid_sort(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_cluster_policies,
'958c6fd2-a647-4b5a-8133-8b4232267b40',
{'sort': 'bad-sort'})
message = ex.resp_body['error']['message']
self.assertEqual("Unsupported sort key 'bad-sort' for 'sort'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0e59c1c7-7477-45ee-8f12-7e5b87373bf7')
def test_cluster_policy_list_enabled_not_bool(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_cluster_policies,
'0e59c1c7-7477-45ee-8f12-7e5b87373bf7',
{'enabled': 'bad-enabled'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid value 'bad-enabled' specified for 'enabled'",
str(message))

View File

@ -1,48 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterPolicyShow(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyShow, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
utils.cluster_attach_policy(self, self.cluster_id, self.policy_id)
self.addCleanup(utils.cluster_detach_policy, self, self.cluster_id,
self.policy_id)
@decorators.idempotent_id('fdf4dbf9-fcc6-4eb0-96c1-d8e8caa90f6d')
def test_cluster_policy_show(self):
res = self.client.get_cluster_policy(self.cluster_id, self.policy_id)
# Verify resp of cluster policy show API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
policy = res['body']
for key in ['cluster_id', 'cluster_name', 'id', 'policy_id',
'policy_name', 'policy_type', 'enabled']:
self.assertIn(key, policy)
self.assertEqual(self.policy_id, policy['policy_id'])

View File

@ -1,117 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterPolicyShowNegativeClusterNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('965d7324-e3f7-4d77-8e7f-44c862b851f7')
def test_cluster_policy_show_cluster_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.get_cluster_policy,
'965d7324-e3f7-4d77-8e7f-44c862b851f7',
'POLICY_ID')
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '965d7324-e3f7-4d77-8e7f-44c862b851f7' "
"could not be found.", str(message))
class TestClusterPolicyShowNegativePolicyNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyShowNegativePolicyNotFound, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('e3e24058-ed07-42b6-b47c-a972c6047509')
def test_cluster_policy_show_policy_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.get_cluster_policy,
self.cluster_id,
'fake_policy')
message = ex.resp_body['error']['message']
self.assertEqual("The policy 'fake_policy' could not be found.",
str(message))
class TestClusterPolicyShowNegativeNoPolicyBinding(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyShowNegativeNoPolicyBinding, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9c9e01fc-dfb9-4a27-9a06-f4d6de2b2d1c')
def test_cluster_policy_show_no_policy_binding(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.get_cluster_policy,
self.cluster_id, self.policy_id)
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy '%s' is not found attached to the specified cluster "
"'%s'." % (self.policy_id, self.cluster_id), str(message))
class TestClusterPolicyShowNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyShowNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id1 = utils.create_a_policy(self, name='test-policy')
self.addCleanup(utils.delete_a_policy, self, self.policy_id1)
self.policy_id2 = utils.create_a_policy(self, name='test-policy')
self.addCleanup(utils.delete_a_policy, self, self.policy_id2)
utils.cluster_attach_policy(self, self.cluster_id, self.policy_id1)
self.addCleanup(utils.cluster_detach_policy, self, self.cluster_id,
self.policy_id1)
utils.cluster_attach_policy(self, self.cluster_id, self.policy_id2)
self.addCleanup(utils.cluster_detach_policy, self, self.cluster_id,
self.policy_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3faaaf65-0606-4853-a660-2bb04f10485b')
def test_cluster_policy_show_multiple_choice(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.get_cluster_policy,
self.cluster_id, 'test-policy')
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria "
"'test-policy'. Please be more specific.", str(message))

View File

@ -1,64 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestClusterActionNegativeCommon(base.BaseSenlinAPITest):
@decorators.idempotent_id('9c972d49-81bd-4448-9afc-b93053aa835d')
def test_cluster_action_no_action_specified(self):
# No action is specified
params = {}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("No action specified", str(message))
@decorators.idempotent_id('997d2e19-7914-4883-9b6a-86e907898d3b')
def test_cluster_action_multiple_action_specified(self):
# Multiple actions are specified
params = {
'resize': {},
'check': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Multiple actions specified", str(message))
@decorators.idempotent_id('43e142ac-9579-40d9-845a-b8190691b91a')
def test_cluster_action_unrecognized_action(self):
# Unrecognized action is specified
params = {
'bogus': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Unrecognized action 'bogus' specified",
str(message))

View File

@ -1,270 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
from senlin.tests.tempest.common import utils
class TestClusterActionAddNodes(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionAddNodes, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.node_id = utils.create_a_node(self, self.profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('db0faadf-9cd2-457f-b434-4891b77938ab')
def test_cluster_action_add_nodes(self):
params = {
"add_nodes": {
"nodes": [
self.node_id
]
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterAddNodesNegativeInvalidNodesParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('912bb24d-73e1-4801-a6de-bdd453cbbdbf')
def test_cluster_add_nodes_missing_nodes_params(self):
params = {
'add_nodes': {
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Value for 'nodes' must have at least 1 item(s).",
str(message))
@decorators.idempotent_id('6cb029f7-9b72-4f10-a28b-3ed5bd3ed7b0')
def test_cluster_add_nodes_params_not_list(self):
params = {
'add_nodes': {
'nodes': 'node_id'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Items for 'nodes' must be unique", str(message))
@decorators.idempotent_id('b8ae9b5f-967f-48a6-8e31-c77f86ba06aa')
def test_cluster_add_nodes_params_empty_list(self):
params = {
'add_nodes': {
'nodes': []
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Value for 'nodes' must have at least 1 item(s).",
str(message))
@decorators.idempotent_id('a97f1712-46ba-43c1-abd6-12c209c9d640')
def test_cluster_add_mult_node_with_same_name(self):
params = {
'add_nodes': {
'nodes': ['id1', 'id1']
}
}
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Items for 'nodes' must be unique",
str(message))
class TestClusterAddNodesNegativeNodeNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterAddNodesNegativeNodeNotFound, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('5ddf7e5a-3f67-4f1e-af1e-c5a7da319dc0')
def test_cluster_add_nodes_node_not_found(self):
params = {
'add_nodes': {
'nodes': ['5ddf7e5a-3f67-4f1e-af1e-c5a7da319dc0']
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Nodes not found: [u'5ddf7e5a-3f67-4f1e-af1e-c5a7da319dc0'].",
str(message))
class TestClusterAddNodesNegativeNodeNotOrphan(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterAddNodesNegativeNodeNotOrphan, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.cluster_id2 = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id2)
self.node_id = utils.create_a_node(self, self.profile_id,
cluster_id=self.cluster_id2)
@decorators.idempotent_id('08e1271c-025e-4670-a20e-4a96fa179dca')
def test_cluster_add_nodes_node_not_orphan(self):
params = {
'add_nodes': {
'nodes': [self.node_id]
}
}
# Verify conflict exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Nodes ['%s'] already owned by some cluster." % self.node_id,
str(message))
class TestClusterAddNodesNegativeProfileTypeUnmatch(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterAddNodesNegativeProfileTypeUnmatch, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.profile_id2 = utils.create_a_profile(
self, spec=constants.spec_heat_stack)
self.addCleanup(utils.delete_a_profile, self, self.profile_id2)
self.node_id = utils.create_a_node(self, self.profile_id2)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('7a27c697-6d29-46f0-8b2a-3a7282c15b33')
def test_cluster_add_nodes_profile_type_unmatch(self):
params = {
'add_nodes': {
'nodes': [
self.node_id
]
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Profile type of nodes ['%s'] does not match that of the "
"cluster." % self.node_id, str(message))
class TestClusterAddNodesNegativeSizeCheckFailed(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterAddNodesNegativeSizeCheckFailed, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id,
desired_capacity=1,
max_size=1)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.node_id = utils.create_a_node(self, self.profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('3b485352-53e3-481d-b471-9a042c76d758')
def test_cluster_add_nodes_cluster_size_check_failed(self):
params = {
'add_nodes': {
'nodes': [
self.node_id
]
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The target capacity (2) is greater than the cluster's "
"max_size (1).", str(message))
class TestClusterAddNodesNegativeClusterNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('22f10d36-c29a-4cde-a975-af262a5775a1')
def test_cluster_add_nodes_cluster_not_found(self):
params = {
'add_nodes': {
'nodes': ['node_id']
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'db0faadf-9cd2-457f-b434-4891b77938ab', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'db0faadf-9cd2-457f-b434-4891b77938ab' "
"could not be found.", str(message))

View File

@ -1,79 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionCheck(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionCheck, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id,
desired_capacity=1)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('0d2063a8-b3d3-489d-b949-e2c61a0997ee')
def test_cluster_action_check(self):
params = {
"check": {}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterCheckNegativeInvalidParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('9a305b4f-2f05-4aa9-95ae-e08fd24b0593')
def test_cluster_check_params_not_dict(self):
params = {
'check': ['k1', 'v1']
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The data provided is not a map", str(message))
class TestClusterCheckNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('bbbe3feb-8482-4ae4-9c29-b4732efce931')
def test_cluster_check_cluster_not_found(self):
params = {
'check': {'k1': 'v1'}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'bbbe3feb-8482-4ae4-9c29-b4732efce931', params)
message = ex.resp_body['error']['message']
self.assertEqual("The cluster 'bbbe3feb-8482-4ae4-9c29-b4732efce931' "
"could not be found.", str(message))

View File

@ -1,96 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterCollect(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterCollect, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.node1 = utils.create_a_node(self, profile_id, name='N01',
cluster_id=self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.node1)
self.node2 = utils.create_a_node(self, profile_id, name='N02',
cluster_id=self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.node2)
@utils.api_microversion('1.2')
@decorators.idempotent_id('00c389f8-3e83-4171-bd72-2202f1f3954d')
def test_cluster_collect(self):
# Collect on a basic path
res = self.client.cluster_collect(self.cluster_id, path='name')
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn({u'id': self.node1, u'value': u'N01'}, res['body'])
self.assertIn({u'id': self.node2, u'value': u'N02'}, res['body'])
@utils.api_microversion('1.2')
@decorators.idempotent_id('1ec4ca67-20db-43eb-95af-1301aa2b1948')
def test_cluster_collect_details(self):
# Collect on a basic path
res = self.client.cluster_collect(self.cluster_id,
path='details.status')
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn({u'id': self.node1, u'value': u'ACTIVE'}, res['body'])
self.assertIn({u'id': self.node2, u'value': u'ACTIVE'}, res['body'])
class TestClusterCollectNegative(base.BaseSenlinAPITest):
@utils.api_microversion('1.1')
@decorators.idempotent_id('88fff27d-27eb-4a4d-906b-b3a9761072ba')
def test_cluster_collect_failed_api_version(self):
# Collect on a basic path
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_collect,
'FAKE_CLUSTER', path='name')
message = ex.resp_body['error']['message']
self.assertEqual("API version '1.1' is not supported on this method.",
str(message))
@utils.api_microversion('1.2')
@decorators.idempotent_id('a3d59666-93be-47ee-a484-c248ed2f49fe')
def test_cluster_collect_failed_path(self):
# Collect on a basic path
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_collect,
'FAKE_CLUSTER', path='None')
message = ex.resp_body['error']['message']
self.assertEqual("Required path attribute is missing.",
str(message))
@utils.api_microversion('1.2')
@decorators.idempotent_id('a3d59666-93be-47ee-a484-c248ed2f49fe')
def test_cluster_collect_cluster_not_found(self):
# Collect on a basic path
ex = self.assertRaises(exceptions.NotFound,
self.client.cluster_collect,
'a3d59666-93be-47ee-a484-c248ed2f49fe',
path='name')
message = ex.resp_body['error']['message']
self.assertEqual("The cluster 'a3d59666-93be-47ee-a484-c248ed2f49fe' "
"could not be found.", str(message))

View File

@ -1,70 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterCreate(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterCreate, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
@decorators.idempotent_id('61cbe340-937a-40d5-9d2f-067f2c7cafcc')
def test_cluster_create_all_attrs_defined(self):
# Create cluster
name = 'test-cluster'
desired_capacity = 2
min_size = 1
max_size = 3
metadata = {'k1': 'v1'}
timeout = 120
params = {
'cluster': {
'profile_id': self.profile_id,
'desired_capacity': desired_capacity,
'min_size': min_size,
'max_size': max_size,
'timeout': timeout,
'metadata': {'k1': 'v1'},
'name': name
}
}
res = self.client.create_obj('clusters', params)
# Verify resp of cluster create API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
cluster = res['body']
for key in ['created_at', 'data', 'domain', 'id', 'init_at', 'nodes',
'policies', 'profile_id', 'profile_name', 'project',
'status', 'status_reason', 'updated_at', 'user']:
self.assertIn(key, cluster)
self.assertIn(name, cluster['name'])
self.assertEqual(desired_capacity, cluster['desired_capacity'])
self.assertEqual(min_size, cluster['min_size'])
self.assertEqual(max_size, cluster['max_size'])
self.assertEqual(metadata, cluster['metadata'])
self.assertEqual(timeout, cluster['timeout'])
# Wait cluster to be active before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
self.addCleanup(utils.delete_a_cluster, self, cluster['id'])

View File

@ -1,111 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterCreateNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterCreateNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
@decorators.attr(type=['negative'])
@decorators.idempotent_id('498a06eb-8c5f-4d9e-852f-87ac295f1a96')
def test_cluster_create_cluster_data_not_specified(self):
# cluster key is missing in request data
params = {
'bad': {
'profile_id': self.profile_id,
'name': 'test-cluster'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'clusters', params)
message = ex.resp_body['error']['message']
self.assertEqual("Request body missing 'cluster' key.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3aced30b-ccb2-4e40-90c2-7b6aa205e3d6')
def test_cluster_create_profile_invalid(self):
# Invalid profile_id is provided
params = {
'cluster': {
'profile_id': '3aced30b-ccb2-4e40-90c2-7b6aa205e3d6',
'name': 'test-cluster'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'clusters', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified profile '3aced30b-ccb2-4e40-90c2-7b6aa205e3d6' "
"could not be found.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('61b190bb-ef5a-47b3-acbe-6467fbb44439')
def test_cluster_create_miss_profile(self):
# Invalid profile_id is provided
params = {
'cluster': {
'name': 'test-cluster'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'clusters', params)
message = ex.resp_body['error']['message']
self.assertEqual("'profile_id' is a required property",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7eaf60c3-f33d-403b-a4ee-0276ae90928c')
def test_cluster_create_size_constraint_illegal(self):
# Invalid size limitation is defined: min_size > max_size
desired_capacity = 2
min_size = 5
max_size = 3
params = {
'cluster': {
'profile_id': self.profile_id,
'desired_capacity': desired_capacity,
'min_size': min_size,
'max_size': max_size,
'name': 'test-cluster'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'clusters', params)
message = ex.resp_body['error']['message']
self.assertEqual("The target capacity (2) is less than the "
"specified min_size (5).", str(message))

View File

@ -1,265 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionDelNodes(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionDelNodes, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.node_id = utils.create_a_node(self, profile_id,
cluster_id=self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('ab4e0738-98f9-4521-a4a9-81ed151b4c71')
def test_cluster_action_del_nodes(self):
params = {
"del_nodes": {
"nodes": [
self.node_id
]
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterDelNodesNegativeInvalidNodesParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('89af1e6f-17b4-4c6f-ae5f-91a2da784c05')
def test_cluster_del_nodes_missing_nodes_params(self):
params = {
'del_nodes': {
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Value for 'nodes' must have at least 1 item(s).",
str(message))
@decorators.idempotent_id('c15c387c-3c3c-4005-8818-8fc0cdbfe679')
def test_cluster_del_nodes_params_not_list(self):
params = {
'del_nodes': {
'nodes': 'node_id'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Items for 'nodes' must be unique",
str(message))
@decorators.idempotent_id('662c548d-a89a-40e3-a238-72b2193e5dc2')
def test_cluster_del_nodes_params_empty_list(self):
params = {
'del_nodes': {
'nodes': []
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Value for 'nodes' must have at least 1 item(s).",
str(message))
@decorators.idempotent_id('26479afe-b8bf-4389-85b2-cccf6b83d2b7')
def test_cluster_del_nodes_destroy_not_bool(self):
params = {
'del_nodes': {
'nodes': ['fake_id'],
'destroy_after_deletion': 'not_bool'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Unrecognized value 'not_bool', acceptable values are: '0', '1', "
"'f', 'false', 'n', 'no', 'off', 'on', 't', 'true', 'y', 'yes'",
str(message))
class TestClusterDelNodesNegativeNodeNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDelNodesNegativeNodeNotFound, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('e896948b-44c0-4dfa-9466-407391504833')
def test_cluster_del_nodes_node_not_found(self):
params = {
'del_nodes': {
'nodes': ['e896948b-44c0-4dfa-9466-407391504833']
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Nodes not found: [u'e896948b-44c0-4dfa-9466-407391504833'].",
str(message))
class TestClusterDelNodesNegativeOrphanNode(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDelNodesNegativeOrphanNode, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.node_id = utils.create_a_node(self, self.profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('d7e77bd2-2a80-4995-b2e8-e4e9c58b3de5')
def test_cluster_del_nodes_orphan_node(self):
params = {
'del_nodes': {
'nodes': [self.node_id]
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("Nodes not members of specified cluster: "
"['%s']." % self.node_id, str(message))
class TestClusterDelNodesNegativeNodeOfOtherCluster(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDelNodesNegativeNodeOfOtherCluster, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.cluster_id2 = utils.create_a_cluster(self, self.profile_id)
self.node_id = utils.create_a_node(self, self.profile_id,
cluster_id=self.cluster_id2)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id2)
@decorators.idempotent_id('e83135af-1d42-4a80-a039-7e78cbc7e3f4')
def test_cluster_del_nodes_node_of_other_cluster(self):
params = {
'del_nodes': {
'nodes': [self.node_id]
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("Nodes not members of specified cluster: "
"['%s']." % self.node_id, str(message))
class TestClusterDelNodesNegativeSizeCheckFailed(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDelNodesNegativeSizeCheckFailed, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id,
desired_capacity=1,
min_size=1)
self.cluster = utils.get_a_cluster(self, self.cluster_id)
self.node_id = self.cluster['nodes'][0]
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('b83bdeac-8d23-46ec-9c50-8c47140982a4')
def test_cluster_del_nodes_cluster_size_check_failed(self):
params = {
'del_nodes': {
'nodes': [
self.node_id
]
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("The target capacity (0) is less than the cluster's "
"min_size (1).", str(message))
class TestClusterDelNodesNegativeClusterNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('dc8f106a-10b7-47a3-8494-c86035207351')
def test_cluster_del_nodes_cluster_not_found(self):
params = {
'del_nodes': {
'nodes': ['node_id']
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'dc8f106a-10b7-47a3-8494-c86035207351', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'dc8f106a-10b7-47a3-8494-c86035207351' could not "
"be found.", str(message))

View File

@ -1,39 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterDelete(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDelete, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
# cluster will be deleted by test case
self.cluster_id = utils.create_a_cluster(self, profile_id)
@decorators.idempotent_id('33d7426e-0138-42c9-9ab4-ba796a7d1fdc')
def test_cluster_delete_in_active_status(self):
res = self.client.delete_obj('clusters', self.cluster_id)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIsNone(res['body'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')

View File

@ -1,124 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterDeleteNegativePolicyConflict(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDeleteNegativePolicyConflict, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, policy_id)
utils.cluster_attach_policy(self, self.cluster_id, policy_id)
self.addCleanup(utils.cluster_detach_policy, self, self.cluster_id,
policy_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0de81427-2b2f-4821-9462-c893d35fb212')
def test_cluster_delete_policy_conflict(self):
# Verify conflict exception(409) is raised.
ex = self.assertRaises(exceptions.Conflict,
self.client.delete_obj,
'clusters', self.cluster_id)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '%s' cannot be deleted: there is still "
"policy(s) attached to it." % self.cluster_id,
str(message))
class TestClusterDeleteNegativeReceiverConflict(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDeleteNegativeReceiverConflict, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.receiver_id = utils.create_a_receiver(
self, self.cluster_id, 'CLUSTER_SCALE_OUT', 'webhook',
'fake', params={'count': '1'})
self.addCleanup(utils.delete_a_receiver, self, self.receiver_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0de81427-2b2f-4821-9462-c893d35fb212')
def test_cluster_delete_receiver_conflict(self):
# Verify conflict exception(409) is raised.
ex = self.assertRaises(exceptions.Conflict,
self.client.delete_obj,
'clusters', self.cluster_id)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '%s' cannot be deleted: there is still "
"receiver(s) associated with it." % self.cluster_id,
str(message))
class TestClusterDeleteNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('8a583b8e-eeaa-4920-a6f5-2880b070624f')
def test_cluster_delete_not_found(self):
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.delete_obj,
'clusters',
'8a583b8e-eeaa-4920-a6f5-2880b070624f')
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '8a583b8e-eeaa-4920-a6f5-2880b070624f' could "
"not be found.", str(message))
class TestClusterDeleteNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterDeleteNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id1 = utils.create_a_cluster(self, profile_id,
name='c-01')
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id1)
self.cluster_id2 = utils.create_a_cluster(self, profile_id,
name='c-01')
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3d8b73db-e2d2-42c2-952c-936048d36f21')
def test_cluster_delete_multiple_choice(self):
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.delete_obj,
'clusters', 'c-01')
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria 'c-01'. "
"Please be more specific.", str(message))

View File

@ -1,48 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterList(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterList, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('943cdc02-81bd-4200-a08d-bc1932d932f7')
def test_cluster_list(self):
res = self.client.list_objs('clusters')
# Verify resp of cluster list API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
clusters = res['body']
cluster_ids = []
for cluster in clusters:
for key in ['created_at', 'data', 'desired_capacity', 'domain',
'id', 'init_at', 'max_size', 'metadata', 'min_size',
'name', 'nodes', 'policies', 'profile_id',
'profile_name', 'project', 'status', 'status_reason',
'timeout', 'updated_at', 'user']:
self.assertIn(key, cluster)
cluster_ids.append(cluster['id'])
self.assertIn(self.cluster_id, cluster_ids)

View File

@ -1,96 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestClusterListNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b18c2b98-0dcf-489f-8245-080db10298d8')
def test_cluster_list_invalid_params(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'clusters', {'bogus': 'foo'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid parameter 'bogus'", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f6687ce2-288c-42fa-8132-e0faec813129')
def test_cluster_list_limit_not_int(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'clusters', {'limit': 'not-int'})
message = ex.resp_body['error']['message']
self.assertEqual("The value for limit must be an integer: 'not-int'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('32a9f3ad-0284-4fe7-b6e8-d98915637c7f')
def test_cluster_list_global_project_false(self):
ex = self.assertRaises(exceptions.Forbidden,
self.client.list_objs,
'clusters', {'global_project': 'True'})
message = ex.resp_body['error']['message']
self.assertEqual("You are not authorized to complete this operation.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('2944d7dd-72d5-4dd0-9f3e-6f5c6ead8b30')
def test_cluster_list_global_project_not_bool(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'clusters', {'global_project': 'not-bool'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid value 'not-bool' specified for "
"'global_project'", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('dc4194f1-6487-47c4-8ad7-da6ca0e88ca2')
def test_cluster_list_invalid_sort(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'clusters', {'sort': 'bad-sort'})
message = ex.resp_body['error']['message']
self.assertEqual("Unsupported sort key 'bad-sort' for 'sort'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('91489f49-686d-470d-9b74-c5e8f46eaae5')
def test_cluster_list_invalid_marker(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'clusters', {'marker': 'bad-marker'})
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for marker is not a valid UUID: 'bad-marker'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d13ff32f-aa8a-4704-824a-54d52a160874')
def test_cluster_list_unsupported_status(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'clusters', {'status': ['bad-status']})
message = ex.resp_body['error']['message']
self.assertEqual("Field value ['bad-status'] is invalid",
str(message))

View File

@ -1,153 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionPolicyAttach(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionPolicyAttach, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
self.addCleanup(utils.cluster_detach_policy, self, self.cluster_id,
self.policy_id)
@decorators.idempotent_id('214c48f8-cca9-4512-a904-2985743a1155')
def test_cluster_action_policy_attach(self):
params = {
"policy_attach": {
"enabled": True,
"policy_id": self.policy_id
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterPolicyAttachNegativeInvalidParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('76dcdc8d-7680-4e27-bccd-26ad9d697528')
def test_cluster_policy_attach_params_not_dict(self):
params = {
'policy_attach': 'POLICY_ID'
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The data provided is not a map",
str(message))
@decorators.idempotent_id('34f6ceec-bde2-4013-87fe-db704ada5987')
def test_cluster_policy_attach_missing_policy_id_param(self):
params = {
'policy_attach': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("'policy_id' is a required property",
str(message))
@decorators.idempotent_id('5f5c42be-8ef4-4150-93cf-1e6b2515a293')
def test_cluster_policy_attach_invalid_enabled_param(self):
params = {
'policy_attach': {
'policy_id': 'POLICY_ID',
'enabled': 'not-bool'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Unrecognized value 'not-bool', acceptable values are: '0', '1', "
"'f', 'false', 'n', 'no', 'off', 'on', 't', 'true', 'y', 'yes'",
str(message))
class TestClusterPolicyAttachNegativePolicyNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyAttachNegativePolicyNotFound, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('7ee49643-a5a0-4567-b9d0-0210b05a6138')
def test_cluster_policy_attach_policy_not_found(self):
params = {
'policy_attach': {
'poilicy_id': '7ee49643-a5a0-4567-b9d0-0210b05a6138'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Additional properties are not allowed (u'poilicy_id' "
"was unexpected)", str(message))
class TestClusterPolicyAttachNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('29e66d49-9ffa-47c9-bbe3-e0cf9c3370ee')
def test_cluster_policy_attach_cluster_not_found(self):
params = {
'policy_attach': {
'policy_id': 'POLICY_ID'
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'29e66d49-9ffa-47c9-bbe3-e0cf9c3370ee',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '29e66d49-9ffa-47c9-bbe3-e0cf9c3370ee' could "
"not be found.", str(message))

View File

@ -1,161 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionPolicyDetach(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionPolicyDetach, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
utils.cluster_attach_policy(self, self.cluster_id, self.policy_id)
@decorators.idempotent_id('8643245e-ee32-41bb-a736-e33c9e77202a')
def test_cluster_action_policy_detach(self):
params = {
"policy_detach": {
"policy_id": self.policy_id
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterPolicyDetachNegativeInvalidParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('832c3c2d-0434-4d8d-bbe4-6552528d8647')
def test_cluster_policy_detach_param_not_dict(self):
params = {
'policy_detach': 'fake_policy'
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The data provided is not a map",
str(message))
@decorators.idempotent_id('815a1c5a-f27b-4620-8711-bbef46507447')
def test_cluster_policy_detach_missing_profile_id_param(self):
params = {
'policy_detach': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("'policy_id' is a required property",
str(message))
class TestClusterPolicyDetachNegativePolicyNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyDetachNegativePolicyNotFound, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('d8edc8bd-530c-4495-94ea-52d844633335')
def test_cluster_policy_detach_policy_not_found(self):
params = {
'policy_detach': {
'policy_id': '7ee49643-a5a0-4567-b9d0-0210b05a6138'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified policy '7ee49643-a5a0-4567-b9d0-0210b05a6138' "
"could not be found.", str(message))
class TestClusterPolicyDetachNegativeUnattached(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyDetachNegativeUnattached, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
@decorators.idempotent_id('f302142c-3536-4524-8ce2-da86306731cb')
def test_cluster_policy_detach_policy_unattached(self):
params = {
'policy_detach': {
'policy_id': self.policy_id
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy '%s' is not attached to the specified cluster "
"'%s'." % (self.policy_id, self.cluster_id), str(message))
class TestClusterPolicyDetachNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('11ff0486-a022-4b28-9def-9b2d78d47fab')
def test_cluster_policy_detach_cluster_not_found(self):
params = {
'policy_detach': {
'policy_id': 'POLICY_ID'
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'11ff0486-a022-4b28-9def-9b2d78d47fab',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '11ff0486-a022-4b28-9def-9b2d78d47fab' could "
"not be found.", str(message))

View File

@ -1,185 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionPolicyUpdate(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionPolicyUpdate, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
utils.cluster_attach_policy(self, self.cluster_id, self.policy_id)
self.addCleanup(utils.cluster_detach_policy, self, self.cluster_id,
self.policy_id)
@decorators.idempotent_id('0b9efe3e-0abf-4230-a278-b282578df111')
def test_cluster_action_policy_update(self):
params = {
"policy_update": {
"enabled": False,
"policy_id": self.policy_id
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterPolicyUpdateNegativeInvalidParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('653d8ea9-9c7e-48f2-b568-6167bb7f8666')
def test_cluster_policy_update_params_not_dict(self):
params = {
'policy_update': 'POLICY_ID'
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The data provided is not a map",
str(message))
@decorators.idempotent_id('b47dff55-3ff0-4303-b86e-c4ab5f9a0878')
def test_cluster_policy_update_missing_profile_id_param(self):
params = {
'policy_update': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("'policy_id' is a required property",
str(message))
@decorators.idempotent_id('4adb03f4-35e6-40eb-b867-d75315ca8a89')
def test_cluster_policy_update_invalid_enabled_param(self):
params = {
'policy_update': {
'policy_id': 'POLICY_ID',
'enabled': 'not-bool'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Unrecognized value 'not-bool', acceptable values are: '0', '1', "
"'f', 'false', 'n', 'no', 'off', 'on', 't', 'true', 'y', 'yes'",
str(message))
class TestClusterPolicyUpdateNegativePolicyNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyUpdateNegativePolicyNotFound, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('7528bfa5-2106-459a-9ece-f201498b3ace')
def test_cluster_policy_update_policy_not_found(self):
params = {
'policy_update': {
'policy_id': '7528bfa5-2106-459a-9ece-f201498b3ace'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified policy '7528bfa5-2106-459a-9ece-f201498b3ace' "
"could not be found.", str(message))
class TestClusterPolicyUpdateNegativeUnattached(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterPolicyUpdateNegativeUnattached, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
@decorators.idempotent_id('81931b14-0a4c-43e5-a5eb-fdfd5386627e')
def test_cluster_policy_update_policy_unattached(self):
params = {
'policy_update': {
'policy_id': self.policy_id
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy '%s' is not attached to the specified cluster "
"'%s'." % (self.policy_id, self.cluster_id), str(message))
class TestClusterPolicyUpdateNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('c7605959-3bc9-41e2-9685-7e11fa03b9e6')
def test_cluster_policy_update_cluster_not_found(self):
params = {
'policy_update': {
'policy_id': 'POLICY_ID',
'enabled': False
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'c7605959-3bc9-41e2-9685-7e11fa03b9e6',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'c7605959-3bc9-41e2-9685-7e11fa03b9e6' could "
"not be found.", str(message))

View File

@ -1,85 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionRecover(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionRecover, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id,
desired_capacity=1)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('9020bc7e-db2a-47d0-9f78-7e6a3d231fad')
def test_cluster_action_recover(self):
params = {
"recover": {
"operation": "rebuild"
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterRecoverNegativeInvalidParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('1f93e909-b271-4e46-acd8-8cb621b27546')
def test_cluster_recover_params_not_dict(self):
params = {
'recover': ['k1', 'v1']
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The data provided is not a map",
str(message))
class TestClusterRecoverNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('e6e522f4-34d4-42f7-b7f1-45004e06f3d9')
def test_cluster_recover_cluster_not_found(self):
params = {
'recover': {'k1': 'v1'}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'e6e522f4-34d4-42f7-b7f1-45004e06f3d9',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'e6e522f4-34d4-42f7-b7f1-45004e06f3d9' "
"could not be found.", str(message))

View File

@ -1,337 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
from senlin.tests.tempest.common import utils
class TestClusterActionReplaceNodes(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionReplaceNodes, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.origin_node = utils.create_a_node(
self, profile_id, cluster_id=self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.origin_node)
self.replace_node = utils.create_a_node(self, profile_id)
@utils.api_microversion('1.3')
@decorators.idempotent_id('a17c2bff-eab7-4d02-a49f-9388eb53aa14')
def test_cluster_action_replace(self):
params = {
"replace_nodes": {
'nodes': {
self.origin_node: self.replace_node
}
}
}
# Trigger cluster action
res = self.client.cluster_replace_nodes('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('action', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterReplaceNodesNegativeInvalidParams(base.BaseSenlinAPITest):
@utils.api_microversion('1.3')
@decorators.idempotent_id('fbfb0819-6a15-4926-a21f-44fda6960bed')
def test_cluster_replace_nodes_params_not_map(self):
params = {
'replace_nodes': {
'nodes': []
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The data provided is not a map",
str(message))
@utils.api_microversion('1.3')
@decorators.idempotent_id('600baf2f-e74f-467d-9883-3dcf1c357b57')
def test_cluster_replace_nodes_params_empty_map(self):
params = {
'replace_nodes': {
'nodes': {}
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The data provided is not a map",
str(message))
@utils.api_microversion('1.3')
@decorators.idempotent_id('3e227f8f-7da3-4dc1-b647-68ed8fbdd111')
def test_cluster_replace_nodes_missing_new_node(self):
params = {
'replace_nodes': {
'nodes': {
'old_node': None
}
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Field `nodes[old_node]' cannot be None",
str(message))
@utils.api_microversion('1.3')
@decorators.idempotent_id('82ebbd5a-47fc-4d32-be3c-7bf3262dd574')
def test_cluster_replace_nodes_duplicated_node(self):
params = {
'replace_nodes': {
'nodes': {
'old_node1': 'new_node',
'old_node2': 'new_node'
}
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Map contains duplicated values",
str(message))
class TestClusterReplaceNodesNegativeOldNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterReplaceNodesNegativeOldNotFound, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.new_node = utils.create_a_node(self, self.profile_id)
self.addCleanup(utils.delete_a_node, self, self.new_node)
@utils.api_microversion('1.3')
@decorators.idempotent_id('911d6e85-220f-4208-9a0b-b91e83c5e787')
def test_cluster_replace_nodes_old_node_not_found(self):
params = {
'replace_nodes': {
'nodes': {
'old_node': self.new_node
}
}
}
# Verify not found badrequest is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("Original nodes not found: [u'old_node'].",
str(message))
class TestClusterReplaceNodesNegativeNewNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterReplaceNodesNegativeNewNotFound, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.old_node = utils.create_a_node(self, self.profile_id,
cluster_id=self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.old_node)
@utils.api_microversion('1.3')
@decorators.idempotent_id('1282c521-c479-42f3-b375-8d6d62b1d5dc')
def test_cluster_replace_nodes_old_node_not_found(self):
params = {
'replace_nodes': {
'nodes': {
self.old_node: 'new_node'
}
}
}
# Verify badrequest exception is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("Replacement nodes not found: [u'new_node'].",
str(message))
class TestClusterReplaceNodesNegativeNewNotOrphan(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterReplaceNodesNegativeNewNotOrphan, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.old_node = utils.create_a_node(self, self.profile_id,
cluster_id=self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.old_node)
self.cluster_id2 = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id2)
self.new_node = utils.create_a_node(self, self.profile_id,
self.cluster_id2)
self.addCleanup(utils.delete_a_node, self, self.new_node)
@utils.api_microversion('1.3')
@decorators.idempotent_id('e001ba28-f7ad-4af5-a281-5652ca040c65')
def test_cluster_replace_nodes_new_node_not_orphan(self):
params = {
'replace_nodes': {
'nodes': {
self.old_node: self.new_node
}
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Nodes [u'%s'] already member of a cluster." % self.new_node,
str(message))
class TestClusterReplaceNodeNegativeProfileUnmatch(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterReplaceNodeNegativeProfileUnmatch, self).setUp()
self.profile_id = utils.create_a_profile(
self, spec=constants.spec_nova_server)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.old_node = utils.create_a_node(self, self.profile_id,
self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.old_node)
self.profile_id2 = utils.create_a_profile(
self, spec=constants.spec_heat_stack)
self.addCleanup(utils.delete_a_profile, self, self.profile_id2)
self.new_node = utils.create_a_node(self, self.profile_id2)
self.addCleanup(utils.delete_a_node, self, self.new_node)
@utils.api_microversion('1.3')
@decorators.idempotent_id('d1cb2068-b23c-4023-ad25-271f8e5b1bfa')
def test_cluster_replace_nodes_profile_type_unmatch(self):
params = {
'replace_nodes': {
'nodes': {
self.old_node: self.new_node
}
}
}
# Verify badrequest exception is raised
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Profile type of nodes [u'%s'] do not match that of the "
"cluster." % self.new_node, str(message))
class TestClusterReplaceNodeNegativeOldOrphan(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterReplaceNodeNegativeOldOrphan, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.old_node = utils.create_a_node(self, self.profile_id)
self.addCleanup(utils.delete_a_node, self, self.old_node)
self.new_node = utils.create_a_node(self, self.profile_id)
self.addCleanup(utils.delete_a_node, self, self.new_node)
@utils.api_microversion('1.3')
@decorators.idempotent_id('ca0afe22-e758-477c-8ca5-cd1b686747dc')
def test_cluster_replace_nodes_old_node_orphan(self):
params = {
'replace_nodes': {
'nodes': {
self.old_node: self.new_node
}
}
}
# Versify badrequest exeception is raised
ex = self.assertRaises(exceptions.BadRequest,
self.client.cluster_replace_nodes, 'clusters',
self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified nodes [u'%s'] to be replaced are not members "
"of the cluster %s." % (self.old_node, self.cluster_id),
str(message))
class TestClusterReplaceNodeNegativeClusterNotFound(base.BaseSenlinAPITest):
@utils.api_microversion('1.3')
@decorators.idempotent_id('086c0657-f7a1-4722-a585-ac281725bcfc')
def test_cluster_replace_nodes_cluster_not_found(self):
params = {
'replace_nodes': {
'nodes': {
'old_node': 'new_node'
}
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.cluster_replace_nodes, 'clusters',
'db0faadf-9cd2-457f-b434-4891b77938ab',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'db0faadf-9cd2-457f-b434-4891b77938ab' could "
"not be found.", str(message))

View File

@ -1,352 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionResize(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionResize, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('f5f75882-df3d-481f-bd05-019e4d08af65')
def test_cluster_action_resize(self):
params = {
"resize": {
"adjustment_type": "CHANGE_IN_CAPACITY",
"max_size": 20,
"min_step": 1,
"min_size": 5,
"number": 20,
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterResizeNegativeInvalidResizeParams(base.BaseSenlinAPITest):
@decorators.idempotent_id('57bc61a2-df38-4bf5-a26a-d23d2cc67ca3')
def test_cluster_resize_invalid_adj_type(self):
params = {
"resize": {
"adjustment_type": "bogus",
"max_size": 20,
"min_size": 5,
"number": 5
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Value 'bogus' is not acceptable for field "
"'adjustment_type'.", str(message))
@decorators.idempotent_id('cef85ed4-9dd3-4f9f-91fe-4372d9aa8956')
def test_cluster_resize_missing_adj_type(self):
params = {
"resize": {
"max_size": 20,
"min_size": 5,
"number": 5
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Missing adjustment_type value for size adjustment.",
str(message))
@decorators.idempotent_id('e42dd7e1-aa36-4e46-8b5b-2571d00574c9')
def test_cluster_resize_missing_adj_number(self):
params = {
"resize": {
"adjustment_type": "CHANGE_IN_CAPACITY",
"max_size": 20,
"min_size": 5
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Missing number value for size adjustment.",
str(message))
@decorators.idempotent_id('7e669b3e-8fbd-4820-a281-7cc4b29c6020')
def test_cluster_resize_invalid_adj_number(self):
params = {
"resize": {
"adjustment_type": "EXACT_CAPACITY",
"max_size": 20,
"min_size": 5,
"number": -1
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The 'number' must be positive integer for adjustment "
"type 'EXACT_CAPACITY'.", str(message))
@decorators.idempotent_id('5a069782-d6d8-4389-a68c-beb32375a39e')
def test_cluster_resize_min_size_over_max_size(self):
params = {
"resize": {
"adjustment_type": "CHANGE_IN_CAPACITY",
"max_size": 10,
"min_size": 20,
"number": 5
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'cluster_id', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified min_size (20) is greater than the "
"specified max_size (10).", str(message))
class TestClusterResizeNegativeClusterNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('087ef694-55d2-4616-a58b-1073cacb2bcd')
def test_cluster_resize_cluster_not_found(self):
params = {
"resize": {
"adjustment_type": "CHANGE_IN_CAPACITY",
"max_size": 20,
"min_size": 5,
"number": 5
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'087ef694-55d2-4616-a58b-1073cacb2bcd',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '087ef694-55d2-4616-a58b-1073cacb2bcd' could "
"not be found.", str(message))
class TestClusterResizeNegativeSizeCheckFailed(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterResizeNegativeSizeCheckFailed, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id,
min_size=2, max_size=5,
desired_capacity=3)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('92e7d3c8-2d38-4766-86c3-41dc14bf89a1')
def test_cluster_resize_break_upper_limit(self):
# New desired_capacity will be greater than max_size
params = {
"resize": {
"adjustment_type": "CHANGE_IN_CAPACITY",
"number": 3,
"strict": True
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The target capacity (6) is greater than the cluster's "
"max_size (5).", str(message))
@decorators.idempotent_id('9dcac577-d768-44d1-b119-02d27202ef08')
def test_cluster_resize_break_lower_limit(self):
# New desired_capacity will be less than min_size
params = {
"resize": {
"adjustment_type": "CHANGE_IN_CAPACITY",
"number": -2,
"strict": True
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The target capacity (1) is less than the cluster's "
"min_size (2).", str(message))
@decorators.idempotent_id('d7a96d95-2944-4749-be34-cfe39a5dbcb4')
def test_cluster_resize_max_size_under_current_desired_capacity(self):
# New max_size is less than current desired_capacity of cluster
params = {
"resize": {
"max_size": 2,
"strict": True
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified max_size (2) is less than the current "
"desired_capacity (3) of the cluster.", str(message))
@decorators.idempotent_id('3b35938f-a73a-4096-bf13-af3709aed47f')
def test_cluster_resize_max_size_under_current_min_size(self):
# New max_size is less than current min_size of cluster
# with strict set to False
params = {
"resize": {
"max_size": 1,
"strict": False
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified max_size (1) is less than the current "
"min_size (2) of the cluster.", str(message))
# New max_size is less than current min_size of cluster
# with strict set to True
params = {
"resize": {
"max_size": 1,
"strict": True
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified max_size (1) is less than the current min_size "
"(2) of the cluster.", str(message))
@decorators.idempotent_id('1d7595a4-a7a8-42a4-9f90-7501a4bbb7e5')
def test_cluster_resize_min_size_over_current_desired_capacity(self):
# New min_size is greater than current desired_capacity of cluster
params = {
"resize": {
"min_size": 4,
"strict": True
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified min_size (4) is greater than the current "
"desired_capacity (3) of the cluster.", str(message))
@decorators.idempotent_id('606e5d3f-0857-4bfe-b52d-2ea1ad0cec16')
def test_cluster_resize_min_size_over_current_max_size(self):
# New min_size is greater than current max_size of cluster
# with strict set to False
params = {
"resize": {
"min_size": 6,
"strict": False
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified min_size (6) is greater than the current "
"max_size (5) of the cluster.", str(message))
# New min_size is greater than current max_size of cluster
# with strict set to True
params = {
"resize": {
"min_size": 6,
"strict": True
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified min_size (6) is greater than the current "
"max_size (5) of the cluster.", str(message))

View File

@ -1,118 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionScaleIn(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionScaleIn, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id,
desired_capacity=1)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('a579cd01-8096-4bee-9978-d095025f605c')
def test_cluster_action_scale_in(self):
params = {
"scale_in": {
"count": "1"
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterScaleInInvalidRequest(base.BaseSenlinAPITest):
@decorators.idempotent_id('d826dc0f-ef1c-47ee-b31f-3042aaa8ec54')
def test_cluster_scale_in_invalid_count(self):
params = {
"scale_in": {
"count": "bad-count"
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'fake', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for count must be an integer: 'bad-count'.",
str(message))
class TestClusterScaleInNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterScaleInNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id,
min_size=0, max_size=5,
desired_capacity=1)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('337a8a8f-a368-4d4f-949a-8b116dbb6a75')
def test_cluster_scale_in_invalid_count(self):
params = {
"scale_in": {
"count": -1
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("Value must be >= 0 for field 'count'.",
str(message))
class TestClusterScaleInNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('0124c7de-66d0-4a84-9c8f-80bc4d246b79')
def test_cluster_scale_in_cluster_not_found(self):
params = {
"scale_in": {
"count": 1
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'0124c7de-66d0-4a84-9c8f-80bc4d246b79',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster '0124c7de-66d0-4a84-9c8f-80bc4d246b79' could "
"not be found.", str(message))

View File

@ -1,117 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterActionScaleOut(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterActionScaleOut, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('f15ff8cc-4be3-4c93-9979-6be428e83cd7')
def test_cluster_action_scale_out(self):
params = {
"scale_out": {
"count": "1"
}
}
# Trigger cluster action
res = self.client.trigger_action('clusters', self.cluster_id,
params=params)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestClusterScaleOutNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterScaleOutNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id,
min_size=0, max_size=5,
desired_capacity=1)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('2bbf6e0c-a8cc-4b29-8060-83652ffd6cd2')
def test_cluster_scale_out_invalid_count(self):
params = {
"scale_out": {
"count": -1
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("Value must be >= 0 for field 'count'.",
str(message))
class TestClusterScaleOutInvalidRequest(base.BaseSenlinAPITest):
@decorators.idempotent_id('7aa3fd0c-c092-4a54-8dae-3814492101b0')
def test_cluster_scale_out_invalid_count(self):
params = {
"scale_out": {
"count": "bad-count"
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'clusters', 'fake', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for count must be an integer: 'bad-count'.",
str(message))
class TestClusterScaleOutNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('b7038d95-204c-455f-a866-94dc535dd840')
def test_cluster_scale_out_cluster_not_found(self):
params = {
"scale_out": {
"count": 1
}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'clusters',
'b7038d95-204c-455f-a866-94dc535dd840',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'b7038d95-204c-455f-a866-94dc535dd840' could "
"not be found.", str(message))

View File

@ -1,43 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterShow(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterShow, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('45f56c9a-4589-48dd-9256-9b368727dd6c')
def test_cluster_show(self):
res = self.client.get_obj('clusters', self.cluster_id)
# Verify resp of cluster get API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
cluster = res['body']
for key in ['created_at', 'data', 'desired_capacity', 'domain',
'id', 'init_at', 'max_size', 'metadata', 'min_size',
'name', 'nodes', 'policies', 'profile_id', 'profile_name',
'project', 'status', 'status_reason', 'timeout',
'updated_at', 'user']:
self.assertIn(key, cluster)

View File

@ -1,58 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterShowNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterShowNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id1 = utils.create_a_cluster(self, profile_id,
name='c-01')
self.cluster_id2 = utils.create_a_cluster(self, profile_id,
name='c-01')
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id1)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3365dca5-8895-4dc3-befe-fd15b17c824c')
def test_cluster_show_multiple_choice(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.get_obj,
'clusters', 'c-01')
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria "
"'c-01'. Please be more specific.", str(message))
class TestClusterShowNegativeNotFound(base.BaseSenlinAPITest):
@decorators.idempotent_id('4706516e-002d-42b2-9805-69058178cd9c')
def test_cluster_show_cluster_not_found(self):
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.get_obj,
'clusters', 'c-01')
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'c-01' could "
"not be found.", str(message))

View File

@ -1,55 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestClusterUpdate(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterUpdate, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('ba8514b2-b3c4-47a4-9176-7fe9bb2781ae')
def test_cluster_update_basic_properties(self):
# Update basic properties of cluster
params = {
'cluster': {
'timeout': 240,
'metadata': {'k2': 'v2'},
'name': 'cluster_new_name'
}
}
res = self.client.update_obj('clusters', self.cluster_id, params)
# Verify resp of cluster update API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
cluster = res['body']
for key in ['created_at', 'data', 'domain', 'id', 'init_at',
'metadata', 'name', 'nodes', 'policies', 'profile_id',
'profile_name', 'project', 'status', 'status_reason',
'timeout', 'updated_at', 'user']:
self.assertIn(key, cluster)
# Wait for cluster update to be done before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')

View File

@ -1,205 +0,0 @@
# 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 copy
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
from senlin.tests.tempest.common import utils
class TestClusterUpdateNegativeInvalidParam(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7bddd411-b890-4a36-a523-3e49b87cb645')
def test_cluster_update_cluster_invalid_param(self):
params = {
'cluster': {
'bad': 'invalid'
}
}
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj, 'clusters',
'f7a97fce-f495-44a8-b41a-7408139adacf',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Additional properties are not allowed (u'bad' was "
"unexpected)", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('80cd0acd-772f-482f-8c6d-90843d986eb1')
def test_cluster_update_cluster_empty_param(self):
params = {}
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj, 'clusters',
'80cd0acd-772f-482f-8c6d-90843d986eb1',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Malformed request data, missing 'cluster' key in "
"request body.", str(message))
class TestClusterUpdateNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f7a97fce-f495-44a8-b41a-7408139adacf')
def test_cluster_update_cluster_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.update_obj, 'clusters',
'f7a97fce-f495-44a8-b41a-7408139adacf',
{'cluster': {'name': 'new-name'}})
message = ex.resp_body['error']['message']
self.assertEqual(
"The cluster 'f7a97fce-f495-44a8-b41a-7408139adacf' could "
"not be found.", str(message))
class TestClusterUpdateNegativeProfileNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterUpdateNegativeProfileNotFound, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a cluster
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('fb68921d-1fe8-4c14-be9a-51fa43d4f705')
def test_cluster_update_profile_not_found(self):
# Provided profile can not be found
params = {
'cluster': {
'profile_id': 'fb68921d-1fe8-4c14-be9a-51fa43d4f705',
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified profile 'fb68921d-1fe8-4c14-be9a-51fa43d4f705' "
"could not be found.", str(message))
class TestClusterUpdateNegativeProfileMultichoices(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterUpdateNegativeProfileMultichoices, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a cluster
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
# Create two new profiles of the same type with the same name
new_spec = copy.deepcopy(constants.spec_nova_server)
new_spec['properties']['flavor'] = 'new_flavor'
new_profile_id1 = utils.create_a_profile(self, new_spec, name='p-nova')
new_profile_id2 = utils.create_a_profile(self, new_spec, name='p-nova')
self.addCleanup(utils.delete_a_profile, self, new_profile_id1)
self.addCleanup(utils.delete_a_profile, self, new_profile_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6a3eb86c-4b5c-4cfc-891c-7b0be17715f2')
def test_cluster_update_profile_multichoices(self):
# Multiple profiles are found for given name
params = {
'cluster': {
'profile_id': 'p-nova',
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria 'p-nova'. "
"Please be more specific.", str(message))
class TestClusterUpdateNegativeProfileTypeUnmatch(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterUpdateNegativeProfileTypeUnmatch, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a cluster
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
# Create a new profile of different type
self.new_profile_id = utils.create_a_profile(
self, spec=constants.spec_heat_stack)
self.addCleanup(utils.delete_a_profile, self, self.new_profile_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c28e1bc0-fadb-4394-b2d0-67ad8b87ac04')
def test_cluster_update_profile_type_unmatch(self):
# New profile type is different from original cone
params = {
'cluster': {
'profile_id': self.new_profile_id,
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Cannot update a cluster to a different profile type, "
"operation aborted.", str(message))
class TestClusterUpdateNegativeNoPropertyUpdated(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterUpdateNegativeNoPropertyUpdated, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a cluster
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0fbd8fd9-7789-47da-b806-d91631a28556')
def test_cluster_update_no_property_updated(self):
# No any property is updated
params = {
'cluster': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'clusters', self.cluster_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("No property needs an update.", str(message))

View File

@ -1,124 +0,0 @@
# 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 copy
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
from senlin.tests.tempest.common import utils
class TestClusterUpdateProfile(base.BaseSenlinAPITest):
def setUp(self):
super(TestClusterUpdateProfile, self).setUp()
self.old_profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.old_profile_id)
# create a new profile
new_spec = copy.deepcopy(constants.spec_nova_server)
new_spec['properties']['flavor'] = 'new_flavor'
new_spec['properties']['image'] = 'new_image'
self.new_profile_id = utils.create_a_profile(self, new_spec)
self.addCleanup(utils.delete_a_profile, self, self.new_profile_id)
self.cluster_id = utils.create_a_cluster(self, self.old_profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
self.node1_id = utils.create_a_node(
self, self.old_profile_id, name='N01', cluster_id=self.cluster_id)
self.addCleanup(utils.delete_a_node, self, self.node1_id)
@decorators.idempotent_id('abff7891-21af-4c37-a8df-5bc7379ce349')
def test_cluster_update_profile(self):
# Update cluster with new profile
params = {
'cluster': {
'profile_id': self.new_profile_id
}
}
res = self.client.update_obj('clusters', self.cluster_id, params)
# Verify resp of cluster update API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
cluster = res['body']
for key in ['created_at', 'data', 'domain', 'id', 'init_at',
'metadata', 'name', 'nodes', 'policies', 'profile_id',
'profile_name', 'project', 'status', 'status_reason',
'timeout', 'updated_at', 'user']:
self.assertIn(key, cluster)
# Wait for cluster update to be done before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
@utils.api_microversion('1.6')
@decorators.idempotent_id('686cd38a-16eb-4364-b495-367fc7c8bb26')
def test_cluster_update_profile_profile_only(self):
# Update cluster with new profile
params = {
'cluster': {
'profile_id': self.new_profile_id,
'profile_only': True
}
}
res = self.client.update_obj('clusters', self.cluster_id, params)
# Verify resp of cluster update API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
# Wait for cluster update to be done before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
# verify cluster profile id changed
res = self.client.get_obj('clusters', self.cluster_id)
self.assertEqual(self.new_profile_id, res['body']['profile_id'])
# verify node profile id not changed.
res = self.client.get_obj('nodes', self.node1_id)
self.assertEqual(self.old_profile_id, res['body']['profile_id'])
@utils.api_microversion('1.5')
@decorators.idempotent_id('8a67876f-e9ea-4cbe-807a-73eefe482536')
def test_cluster_update_profile_profile_only_backward(self):
# Update cluster with new profile
params = {
'cluster': {
'profile_id': self.new_profile_id,
'profile_only': True
}
}
res = self.client.update_obj('clusters', self.cluster_id, params)
# Verify resp of cluster update API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
# Wait for cluster update to be done before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
# verify cluster profile id changed
res = self.client.get_obj('clusters', self.cluster_id)
self.assertEqual(self.new_profile_id, res['body']['profile_id'])
# verify node profile id not changed.
res = self.client.get_obj('nodes', self.node1_id)
self.assertEqual(self.new_profile_id, res['body']['profile_id'])

View File

@ -1,41 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestEventList(base.BaseSenlinAPITest):
def setup(self):
super(TestEventList, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, cluster_id)
@decorators.idempotent_id('498a7e22-7ada-415b-a7cf-927b0ad3d9f6')
def test_event_list(self):
res = self.client.list_objs('events')
# Verify resp of event list API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
events = res['body']
for event in events:
for key in ['action', 'cluster_id', 'id', 'level', 'oid',
'oname', 'otype', 'project', 'status',
'status_reason', 'timestamp', 'user']:
self.assertIn(key, event)

View File

@ -1,108 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestEventListNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ddbc0735-869c-4da4-ae1d-ec67984cca46')
def test_event_list_invalid_params(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'events', {'bogus': 'foo'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid parameter bogus", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('fc3a5097-d332-42e5-8fb8-682cb248d9ad')
def test_event_list_limit_not_int(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'events', {'limit': 'not-int'})
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for limit must be an integer: 'not-int'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('da0871d7-9eb4-4349-b1db-0287d444ff58')
def test_event_list_global_project_false(self):
ex = self.assertRaises(exceptions.Forbidden,
self.client.list_objs,
'events', {'global_project': 'True'})
message = ex.resp_body['error']['message']
self.assertEqual("You are not authorized to complete this operation.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('bccbbec0-08e5-4594-8fa4-c874d4359033')
def test_event_list_global_project_not_bool(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'events', {'global_project': 'not-bool'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid value 'not-bool' specified for "
"'global_project'", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('84d2d883-9402-4735-8be6-b726b0e0edbd')
def test_event_list_invalid_sort(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'events', {'sort': 'bad-sort'})
message = ex.resp_body['error']['message']
self.assertEqual("Unsupported sort key 'bad-sort' for 'sort'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c53500fc-0504-4f0f-b540-1f39e524db53')
def test_event_list_invalid_marker(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'events', {'marker': 'bad-marker'})
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for marker is not a valid UUID: 'bad-marker'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('72e0fd48-2dc7-47ce-abad-299e508fabd4')
def test_event_list_unsupported_level(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'events', {'level': ['bad-level']})
message = ex.resp_body['error']['message']
self.assertEqual("Field value ['bad-level'] is invalid",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('72e0fd48-2dc7-47ce-abad-299e508fabd4')
def test_event_list_unsupported_action(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'events', {'action': ['bad-action']})
message = ex.resp_body['error']['message']
self.assertEqual("Field value ['bad-action'] is invalid",
str(message))

View File

@ -1,43 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestEventShow(base.BaseSenlinAPITest):
def setUp(self):
super(TestEventShow, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('b23490a7-0ae2-44be-a1f9-9f2d82dfe6aa')
def test_event_show(self):
# Get cluster events
events = self.client.list_objs('events',
{'oid': self.cluster_id})['body']
res = self.client.get_obj('events', events[0]['id'])
# Verify resp of event list API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
event = res['body']
for key in ['action', 'cluster_id', 'id', 'level', 'oid',
'oname', 'otype', 'project', 'status',
'status_reason', 'timestamp', 'user']:
self.assertIn(key, event)

View File

@ -1,31 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestEventShowNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('318ae275-ed68-48f5-9151-523085107112')
def test_event_show_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.get_obj, 'events',
'318ae275-ed68-48f5-9151-523085107112')
message = ex.resp_body['error']['message']
self.assertEqual(
"The event '318ae275-ed68-48f5-9151-523085107112' could "
"not be found.", str(message))

View File

@ -1,66 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestNodeActionNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.idempotent_id('9ab462e2-ea3a-49f8-bd78-5a056ae80a48')
def test_no_action_specified(self):
# No action is specified
params = {}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'nodes', 'node_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("No action specified.",
str(message))
@decorators.idempotent_id('9e696e4f-1ec8-45d7-8461-81d275aae81d')
def test_multiple_action_specified(self):
# Multiple actions are specified
params = {
'check': {},
'recover': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'nodes', 'node_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Multiple actions specified.",
str(message))
@decorators.idempotent_id('4bd97c71-fbfc-421d-95ff-b3f4a212cc38')
def test_unrecognized_action(self):
# Unrecoginized action is specified
params = {
'bogus': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'nodes', 'node_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("Unrecognized action 'bogus' specified",
str(message))

View File

@ -1,80 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeCheck(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeCheck, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('ae124bfe-9fcf-4e87-91b7-319102efbdcc')
def test_check(self):
params = {
'check': {
}
}
# Trigger node action
res = self.client.trigger_action('nodes', self.node_id, params=params)
# Verfiy resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestNodeCheckNegative(base.BaseSenlinAPITest):
@decorators.idempotent_id('723ea351-1bcb-4d45-bfe7-35c656d29761')
def test_param_is_not_map(self):
# Check action parameter is not a map
params = {
'check': []
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'nodes', 'node_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The params provided is not a map.",
str(message))
@decorators.idempotent_id('90c46123-f992-4833-859a-46f6d2ccd8e9')
def test_node_not_found(self):
params = {
'check': {}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action, 'nodes',
'90c46123-f992-4833-859a-46f6d2ccd8e9',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The node '90c46123-f992-4833-859a-46f6d2ccd8e9' could "
"not be found.", str(message))

View File

@ -1,61 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeCreate(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeCreate, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.idempotent_id('14d06753-7f0a-4ad2-84be-37fce7114a8f')
def test_node_create_all_attrs_defined(self):
params = {
'node': {
'profile_id': self.profile_id,
'cluster_id': self.cluster_id,
'metadata': {'k1': 'v1'},
'role': 'member',
'name': 'test-node'
}
}
res = self.client.create_obj('nodes', params)
# Verify resp of node create API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
node = res['body']
self.addCleanup(utils.delete_a_node, self, node['id'])
for key in ['cluster_id', 'created_at', 'data', 'domain', 'id',
'index', 'init_at', 'metadata', 'name', 'physical_id',
'profile_id', 'profile_name', 'project', 'role',
'status', 'status_reason', 'updated_at', 'user']:
self.assertIn(key, node)
self.assertIn('test-node', node['name'])
self.assertEqual(self.profile_id, node['profile_id'])
self.assertEqual(self.cluster_id, node['cluster_id'])
self.assertEqual({'k1': 'v1'}, node['metadata'])
self.assertEqual('member', node['role'])
self.assertEqual('test-node', node['name'])
# Wait node to be active before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')

View File

@ -1,170 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
from senlin.tests.tempest.common import utils
class TestNodeCreateNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeCreateNegativeBadRequest, self).setUp()
self.profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, self.profile_id)
self.profile_id2 = utils.create_a_profile(
self, spec=constants.spec_heat_stack)
self.addCleanup(utils.delete_a_profile, self, self.profile_id2)
self.cluster_id = utils.create_a_cluster(self, self.profile_id)
self.addCleanup(utils.delete_a_cluster, self, self.cluster_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('cbe7827a-60ca-42c0-99d2-38167cb4f46d')
def test_node_create_profile_invalid(self):
# Invalid profile_id is provided
params = {
'node': {
'profile_id': 'cbe7827a-60ca-42c0-99d2-38167cb4f46d',
'cluster_id': self.cluster_id,
'metadata': {'k1': 'v1'},
'role': 'member',
'name': 'test-node'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'nodes', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified profile 'cbe7827a-60ca-42c0-99d2-38167cb4f46d' "
"could not be found.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('960cd427-2487-4c83-b679-1b5e1f9dd985')
def test_node_create_cluster_invalid(self):
# Invalid cluster_id is provided
params = {
'node': {
'profile_id': self.profile_id,
'cluster_id': '960cd427-2487-4c83-b679-1b5e1f9dd985',
'metadata': {'k1': 'v1'},
'role': 'member',
'name': 'test-node'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'nodes', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified cluster '960cd427-2487-4c83-b679-1b5e1f9dd985' "
"could not be found.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('8ddf45a5-f45f-4cc8-813d-2bff75498576')
def test_node_create_profile_type_unmatch(self):
# Node profile type is different from cluster profile type
params = {
'node': {
'profile_id': self.profile_id2,
'cluster_id': self.cluster_id,
'metadata': {'k1': 'v1'},
'role': 'member',
'name': 'test-node'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'nodes', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Node and cluster have different profile type, "
"operation aborted.", str(message))
class TestNodeCreateNegativeInvalidRequest(base.BaseSenlinAPITest):
@decorators.idempotent_id('b109aa66-2a54-493e-8a07-1ea6f20e17ce')
def test_node_create_empty_param(self):
params = {}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'nodes', params)
message = ex.resp_body['error']['message']
self.assertEqual("Request body missing 'node' key.",
str(message))
@decorators.idempotent_id('080946ef-a9e0-46b4-add7-da70d05391d6')
def test_node_create_unsupported_param(self):
params = {
'node': {
'profile_id': 'fake_profile',
'name': 'fake_name',
'boo': 'foo'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'nodes', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Additional properties are not allowed (u'boo' "
"was unexpected)", str(message))
@decorators.idempotent_id('0ac2a77e-082c-47d2-8156-92e7fb43689c')
def test_node_create_miss_name(self):
params = {
'node': {
'profile_id': 'fake_profile',
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'nodes', params)
message = ex.resp_body['error']['message']
self.assertEqual("'name' is a required property",
str(message))
@decorators.idempotent_id('39eb68ed-7808-4a73-85b1-83faca124546')
def test_node_create_miss_profile(self):
params = {
'node': {
'name': 'fake',
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'nodes', params)
message = ex.resp_body['error']['message']
self.assertEqual("'profile_id' is a required property",
str(message))

View File

@ -1,39 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeDelete(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeDelete, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id)
@decorators.idempotent_id('29b18f65-2e0e-4a61-b00a-e5803365525b')
def test_node_delete(self):
# Delete test node
res = self.client.delete_obj('nodes', self.node_id)
# Verify resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIsNone(res['body'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')

View File

@ -1,59 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeDeleteNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('86bd7425-cddd-457e-a467-78e290aceab9')
def test_node_delete_not_found(self):
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.delete_obj, 'nodes',
'86bd7425-cddd-457e-a467-78e290aceab9')
message = ex.resp_body['error']['message']
self.assertEqual(
"The node '86bd7425-cddd-457e-a467-78e290aceab9' could "
"not be found.", str(message))
class TestNodeDeleteNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeDeleteNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id1 = utils.create_a_node(self, profile_id, name='n-01')
self.addCleanup(utils.delete_a_node, self, self.node_id1)
self.node_id2 = utils.create_a_node(self, profile_id, name='n-01')
self.addCleanup(utils.delete_a_node, self, self.node_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('669203c5-6abd-4e0e-bc66-0bdd588c7b63')
def test_node_delete_multiple_choice(self):
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.delete_obj,
'nodes', 'n-01')
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria 'n-01'. "
"Please be more specific.", str(message))

View File

@ -1,48 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeList(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeList, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('cd086dcb-7509-4125-adfc-6beb63b10d0a')
def test_node_list(self):
res = self.client.list_objs('nodes')
# Verify resp of node list API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
nodes = res['body']
node_ids = []
for node in nodes:
for key in ['cluster_id', 'created_at', 'data', 'domain',
'id', 'index', 'init_at', 'metadata', 'name',
'physical_id', 'profile_id', 'profile_name',
'project', 'role', 'status', 'status_reason',
'updated_at', 'user']:
self.assertIn(key, node)
node_ids.append(node['id'])
self.assertIn(self.node_id, node_ids)

View File

@ -1,118 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestNodeListNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d27172ca-00ad-465d-b854-4fac7f1edc13')
def test_node_list_invalid_params(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'bogus': 'foo'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid parameter bogus", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('bb668501-b48e-4355-8bf0-eb9b2e2a89fd')
def test_node_list_cluster_not_found(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'cluster_id': 'fake'})
message = ex.resp_body['error']['message']
self.assertEqual("Cannot find the given cluster: fake.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('2e6677ad-8f0d-410e-bd30-baea7882c6fd')
def test_node_list_limit_negative(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'limit': '-5'})
message = ex.resp_body['error']['message']
self.assertEqual("Value must be >= 0 for field 'limit'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('57e4fd0c-35ae-4270-a9a2-01e9f89fdaf3')
def test_node_list_limit_not_int(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'limit': 'not-int'})
message = ex.resp_body['error']['message']
self.assertEqual("The value for limit must be an integer: 'not-int'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('733b1812-0ce6-4b21-ab07-3e4dfda10273')
def test_node_list_global_project_false(self):
ex = self.assertRaises(exceptions.Forbidden,
self.client.list_objs,
'nodes', {'global_project': 'True'})
message = ex.resp_body['error']['message']
self.assertEqual("You are not authorized to complete this operation.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('a9936950-0127-475f-bee6-700a553a7465')
def test_node_list_global_project_not_bool(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'global_project': 'not-bool'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid value 'not-bool' specified for "
"'global_project'", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('688270f0-9f08-43fe-8ff3-4598aa637493')
def test_node_list_invalid_sort(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'sort': 'bad-sort'})
message = ex.resp_body['error']['message']
self.assertEqual("Unsupported sort key 'bad-sort' for 'sort'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0ae75360-4445-4c20-8d26-55a86770ad21')
def test_node_list_invalid_marker(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'marker': 'bad-marker'})
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for marker is not a valid UUID: 'bad-marker'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d8d7dd1e-afd8-4921-83b2-c4ce73b1cb22')
def test_node_list_unsupported_status(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'nodes', {'status': ['bad-status']})
message = ex.resp_body['error']['message']
self.assertEqual("Field value ['bad-status'] is invalid",
str(message))

View File

@ -1,141 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeOperation(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeOperation, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@utils.api_microversion('1.4')
@decorators.idempotent_id('a824fe2c-b8cc-455d-9ec1-73ff9606f9cc')
def test_reboot(self):
params = {
'reboot': {
'type': 'SOFT'
}
}
# Trigger node action
res = self.client.trigger_operation('nodes', self.node_id, params)
# Verfiy resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestNodeOperationNegative(base.BaseSenlinAPITest):
@utils.api_microversion('1.3')
@decorators.idempotent_id('4b3fc5dd-507a-4414-859c-44c87a2879fc')
def test_bad_microversion(self):
params = {'reboot': {}}
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_operation,
'nodes', 'FAKE_ID', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"API version '1.3' is not supported on this method.",
str(message))
@utils.api_microversion('1.4')
@decorators.idempotent_id('2b53a240-7ec6-4d92-bc2d-aaba2e63ee21')
def test_no_operation(self):
params = {}
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_operation,
'nodes', 'FAKE_ID', params)
message = ex.resp_body['error']['message']
self.assertEqual("No operation specified.",
str(message))
@utils.api_microversion('1.4')
@decorators.idempotent_id('b1c3a00b-e00c-4829-ba4a-475f8d34d1d9')
def test_multiple_ops(self):
params = {'foo': {}, 'bar': {}}
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_operation,
'nodes', 'FAKE_ID', params)
message = ex.resp_body['error']['message']
self.assertEqual("Multiple operations specified.",
str(message))
class TestNodeOperationNegativeEngineFailure(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeOperationNegativeEngineFailure, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@utils.api_microversion('1.4')
@decorators.idempotent_id('bbfbd693-4c46-4670-a9d3-5658a43eb0d5')
def test_node_not_found(self):
params = {'dance': {}}
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_operation, 'nodes',
'bbfbd693-4c46-4670-a9d3-5658a43eb0d5',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The node 'bbfbd693-4c46-4670-a9d3-5658a43eb0d5' could "
"not be found.", str(message))
@utils.api_microversion('1.4')
@decorators.idempotent_id('5c0a23c0-9efe-4d04-9208-0f11da690e79')
def test_operation_not_supported(self):
params = {'dance': {}}
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_operation,
'nodes', self.node_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The requested operation 'dance' is not supported by "
"the profile type 'os.nova.server-1.0'.", str(message))
@utils.api_microversion('1.4')
@decorators.idempotent_id('b00f1ef8-9ae6-4ed3-8622-566e7d0d3a75')
def test_operation_bad_params(self):
params = {'reboot': {'type': 'Unknown'}}
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_operation,
'nodes', self.node_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"'Unknown' must be one of the allowed values: SOFT, HARD.",
str(message))

View File

@ -1,81 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeRecover(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeRecover, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('217af65a-4029-40ce-a833-74faeac8c1f5')
def test_node_action_recover(self):
params = {
"recover": {
"operation": "REBUILD"
}
}
# Trigger node action
res = self.client.trigger_action('nodes', self.node_id, params=params)
# Verfiy resp code, body and location in headers
self.assertEqual(202, res['status'])
self.assertIn('actions', res['location'])
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')
class TestNodeRecoverNegative(base.BaseSenlinAPITest):
@decorators.idempotent_id('60790d8a-fd9e-47d8-b9e2-c06aa7701c33')
def test_param_is_not_map(self):
# Recover action parameter is not a map
params = {
'recover': []
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.trigger_action,
'nodes', 'node_id', params)
message = ex.resp_body['error']['message']
self.assertEqual("The params provided is not a map.",
str(message))
@decorators.idempotent_id('694e59ce-551e-4e77-a684-e77781583e12')
def test_node_not_found(self):
params = {
'recover': {}
}
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.trigger_action,
'nodes', '694e59ce-551e-4e77-a684-e77781583e12',
params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The node '694e59ce-551e-4e77-a684-e77781583e12' could "
"not be found.", str(message))

View File

@ -1,43 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeShow(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeShow, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('302372e8-efa2-4348-88dd-8a1829e5e26c')
def test_node_show(self):
res = self.client.get_obj('nodes', self.node_id)
# Verify resp of node get API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
node = res['body']
for key in ['cluster_id', 'created_at', 'data', 'domain',
'id', 'index', 'init_at', 'metadata', 'name',
'physical_id', 'profile_id', 'profile_name',
'project', 'role', 'status', 'status_reason',
'updated_at', 'user']:
self.assertIn(key, node)

View File

@ -1,56 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeShowNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f7a2ed7e-bf92-452b-bc76-37a8bbde2169')
def test_node_show_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.get_obj, 'nodes',
'f7a2ed7e-bf92-452b-bc76-37a8bbde2169')
message = ex.resp_body['error']['message']
self.assertEqual(
"The node 'f7a2ed7e-bf92-452b-bc76-37a8bbde2169' could "
"not be found.", str(message))
class TestNodeShowNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeShowNegativeBadRequest, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id1 = utils.create_a_node(self, profile_id, name='n-01')
self.node_id2 = utils.create_a_node(self, profile_id, name='n-01')
self.addCleanup(utils.delete_a_node, self, self.node_id1)
self.addCleanup(utils.delete_a_node, self, self.node_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('49db9d49-76f1-47a7-9bd2-5e67311c453c')
def test_node_show_multiple_choice(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.get_obj,
'nodes', 'n-01')
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria 'n-01'. "
"Please be more specific.", str(message))

View File

@ -1,56 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestNodeUpdate(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeUpdate, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.node_id = utils.create_a_node(self, profile_id, name='node1',
metadata={'k1': 'v1'},
role='member')
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('bd8a39bf-eee0-4056-aec0-0d8f8706efea')
def test_node_update_basic_properties(self):
# Update basic properties of node
params = {
'node': {
'name': 'node_new_name',
'role': 'admin',
'metadata': {'k2': 'v2'}
}
}
res = self.client.update_obj('nodes', self.node_id, params)
# Verify resp of node update API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
node = res['body']
for key in ['cluster_id', 'created_at', 'data', 'domain', 'id',
'index', 'init_at', 'metadata', 'name', 'physical_id',
'profile_id', 'profile_name', 'project', 'role', 'status',
'status_reason', 'updated_at', 'user']:
self.assertIn(key, node)
# Wait for node update to be done before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')

View File

@ -1,171 +0,0 @@
# 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 copy
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
from senlin.tests.tempest.common import utils
class TestNodeUpdateNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('608addc9-cbbe-45cd-a00a-495cae7db400')
def test_node_update_node_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.update_obj, 'nodes',
'608addc9-cbbe-45cd-a00a-495cae7db400',
{'node': {'name': 'new-name'}})
message = ex.resp_body['error']['message']
self.assertEqual(
"The node '608addc9-cbbe-45cd-a00a-495cae7db400' could "
"not be found.", str(message))
class TestNodeUpdateNegativeProfileNotFound(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeUpdateNegativeProfileNotFound, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a node
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3243dd63-1008-4181-849a-0058af975800')
def test_node_update_profile_not_found(self):
# Provided profile can not be found
params = {
'node': {
'profile_id': '3243dd63-1008-4181-849a-0058af975800',
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'nodes', self.node_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The specified profile '3243dd63-1008-4181-849a-0058af975800' "
"could not be found.", str(message))
class TestNodeUpdateNegativeProfileMultichoices(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeUpdateNegativeProfileMultichoices, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a node
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
# Create two new profiles of the same type with the same name
new_spec = copy.deepcopy(constants.spec_nova_server)
new_spec['properties']['flavor'] = 'new_flavor'
new_profile_id1 = utils.create_a_profile(self, new_spec, name='p-nova')
new_profile_id2 = utils.create_a_profile(self, new_spec, name='p-nova')
self.addCleanup(utils.delete_a_profile, self, new_profile_id1)
self.addCleanup(utils.delete_a_profile, self, new_profile_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0d73eff6-1916-43e1-9518-31820fcfe01f')
def test_node_update_profile_multichoices(self):
# Multiple profiles are found for given name
params = {
'node': {
'profile_id': 'p-nova',
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'nodes', self.node_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria 'p-nova'. "
"Please be more specific.", str(message))
class TestNodeUpdateNegativeProfileTypeUnmatch(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeUpdateNegativeProfileTypeUnmatch, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a node
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
# Create a new profile of different type
self.new_profile_id = utils.create_a_profile(
self, spec=constants.spec_heat_stack)
self.addCleanup(utils.delete_a_profile, self, self.new_profile_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ec5821d8-142e-4fff-a998-81428ecc239c')
def test_node_update_profile_type_unmatch(self):
# New profile type is different from original cone
params = {
'node': {
'profile_id': self.new_profile_id,
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'nodes', self.node_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Cannot update a node to a different profile type, "
"operation aborted.", str(message))
class TestNodeUpdateNegativeNoPropertyUpdated(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeUpdateNegativeNoPropertyUpdated, self).setUp()
# Create a profile
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
self.profile_id = profile_id
# Create a node
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ed6f385d-780b-4562-928d-3e00f27550d2')
def test_node_update_no_property_updated(self):
# Provided profile can not be found
params = {
'node': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'nodes', self.node_id, params)
message = ex.resp_body['error']['message']
self.assertEqual("No property needs an update.",
str(message))

View File

@ -1,60 +0,0 @@
# 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 copy
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
from senlin.tests.tempest.common import utils
class TestNodeUpdateProfile(base.BaseSenlinAPITest):
def setUp(self):
super(TestNodeUpdateProfile, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
new_spec = copy.deepcopy(constants.spec_nova_server)
new_spec['properties']['flavor'] = 'new_flavor'
new_spec['properties']['image'] = 'new_image'
self.new_profile_id = utils.create_a_profile(self, new_spec)
self.addCleanup(utils.delete_a_profile, self, self.new_profile_id)
self.node_id = utils.create_a_node(self, profile_id)
self.addCleanup(utils.delete_a_node, self, self.node_id)
@decorators.idempotent_id('de9465f2-95b4-41ce-81f5-b092967cb2b8')
def test_node_update_profile(self):
# Update node with new profile
params = {
'node': {
'profile_id': self.new_profile_id
}
}
res = self.client.update_obj('nodes', self.node_id, params)
# Verify resp of node update API
self.assertEqual(202, res['status'])
self.assertIsNotNone(res['body'])
self.assertIn('actions', res['location'])
node = res['body']
for key in ['cluster_id', 'created_at', 'data', 'domain', 'id',
'index', 'init_at', 'metadata', 'name', 'physical_id',
'profile_id', 'profile_name', 'project', 'role', 'status',
'status_reason', 'updated_at', 'user']:
self.assertIn(key, node)
# Wait for node update to be done before moving on
action_id = res['location'].split('/actions/')[1]
self.client.wait_for_status('actions', action_id, 'SUCCEEDED')

View File

@ -1,47 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
class TestPolicyCreate(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyCreate, self).setUp()
self.policy_id = None
@decorators.idempotent_id('f50648d9-f38c-479a-a82b-3c6909733496')
def test_policy_create(self):
params = {
'policy': {
'name': 'test-scaling-policy',
'spec': constants.spec_scaling_policy,
}
}
res = self.client.create_obj('policies', params)
# Verify resp of receiver create API
self.assertEqual(201, res['status'])
self.assertIsNotNone(res['body'])
policy = res['body']
self.addCleanup(self.client.delete_obj, 'policies', policy['id'])
for key in ['created_at', 'data', 'domain', 'id', 'name', 'project',
'spec', 'type', 'updated_at', 'user']:
self.assertIn(key, policy)
self.assertEqual('test-scaling-policy', policy['name'])
self.assertEqual('senlin.policy.scaling-1.0', policy['type'])
self.assertEqual(constants.spec_scaling_policy, policy['spec'])

View File

@ -1,112 +0,0 @@
# 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 copy
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
class TestPolicyCreateNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3fea4aa9-6dee-4202-8611-cf2d008a4d42')
def test_policy_create_policy_data_not_specified(self):
params = {
'policy': {
'name': 'test-policy'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual("'spec' is a required property", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4a4d6c83-f0fa-4c9e-914b-d89478903d95')
def test_policy_create_name_not_specified(self):
params = {
'policy': {
'spec': constants.spec_scaling_policy
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual("'name' is a required property", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b898de6c-996a-4bc3-bdef-6490e62fb3b0')
def test_policy_create_invalid_param(self):
params = {
'policy': {
'boo': 'foo'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.create_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Additional properties are not allowed (u'boo' was "
"unexpected)", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1c0ed145-bca6-4e53-b222-44fc6978eb1f')
def test_policy_create_policy_type_incorrect(self):
spec = copy.deepcopy(constants.spec_scaling_policy)
spec['type'] = 'senlin.policy.bogus'
params = {
'policy': {
'name': 'test-policy',
'spec': spec
}
}
# Verify badrequest exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.create_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy_type 'senlin.policy.bogus-1.0' could "
"not be found.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f55dc7eb-9863-49c2-b001-368d2057c53c')
def test_policy_create_spec_validation_failed(self):
spec = copy.deepcopy(constants.spec_scaling_policy)
spec['properties']['bogus'] = 'foo'
params = {
'policy': {
'name': 'test-policy',
'spec': spec
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.ServerFault,
self.client.create_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual("Unrecognizable spec item 'bogus'",
str(message))

View File

@ -1,31 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyDelete(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyDelete, self).setUp()
self.policy_id = utils.create_a_policy(self)
@decorators.idempotent_id('b707e4e3-3d42-4a9f-9a09-3e330959b498')
def test_policy_delete(self):
# Verify resp of policy delete API
res = self.client.delete_obj('policies', self.policy_id)
self.assertEqual(204, res['status'])
self.assertIsNone(res['body'])
self.assertEqual('0', res['content-length'])

View File

@ -1,87 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyDeleteNegativeConflict(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyDeleteNegativeConflict, self).setUp()
profile_id = utils.create_a_profile(self)
self.addCleanup(utils.delete_a_profile, self, profile_id)
cluster_id = utils.create_a_cluster(self, profile_id)
self.addCleanup(utils.delete_a_cluster, self, cluster_id)
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
utils.cluster_attach_policy(self, cluster_id, self.policy_id)
self.addCleanup(utils.cluster_detach_policy, self, cluster_id,
self.policy_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b8b8fca8-962f-4cad-bfca-76683df7b617')
def test_policy_delete_conflict(self):
# Verify conflict exception(409) is raised.
ex = self.assertRaises(exceptions.Conflict,
self.client.delete_obj,
'policies', self.policy_id)
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy '%s' cannot be deleted: still attached to some "
"clusters." % self.policy_id, str(message))
class TestPolicyDeleteNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5591416f-4646-46c2-83b4-231e72aa4bfe')
def test_policy_delete_not_found(self):
# Verify notfound exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.delete_obj, 'policies',
'5591416f-4646-46c2-83b4-231e72aa4bfe')
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy '5591416f-4646-46c2-83b4-231e72aa4bfe' "
"could not be found.", str(message))
class TestPolicyDeleteNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyDeleteNegativeBadRequest, self).setUp()
self.policy_id1 = utils.create_a_policy(self, name='p-01')
self.addCleanup(utils.delete_a_policy, self, self.policy_id1)
self.policy_id2 = utils.create_a_policy(self, name='p-01')
self.addCleanup(utils.delete_a_policy, self, self.policy_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d6f35043-2db5-49ff-8bc4-ba14a652f748')
def test_policy_delete_multiple_choice(self):
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.delete_obj,
'policies', 'p-01')
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria 'p-01'. "
"Please be more specific.", str(message))

View File

@ -1,41 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyList(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyList, self).setUp()
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
@decorators.idempotent_id('67ce5d15-c1fd-402f-bcd8-2974dbd93da8')
def test_policy_list(self):
res = self.client.list_objs('policies')
# Verify resp of policy list API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
policies = res['body']
ids = []
for policy in policies:
for key in ['created_at', 'data', 'domain', 'id', 'name',
'project', 'spec', 'type', 'updated_at', 'user']:
self.assertIn(key, policy)
ids.append(policy['id'])
self.assertIn(self.policy_id, ids)

View File

@ -1,85 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestPolicyListNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b936b936-f891-4389-bbeb-f81b7dc3c688')
def test_policy_list_invalid_params(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'policies', {'bogus': 'foo'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid parameter bogus", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('04ce3766-acf9-4549-91c8-e6ffdf7bafbd')
def test_policy_list_limit_not_int(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'policies', {'limit': 'not-int'})
message = ex.resp_body['error']['message']
self.assertEqual("The value for limit must be an integer: 'not-int'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('cfd50d13-5ed8-48d9-b03f-95480ba06fad')
def test_policy_list_global_project_false(self):
ex = self.assertRaises(exceptions.Forbidden,
self.client.list_objs,
'policies', {'global_project': 'True'})
message = ex.resp_body['error']['message']
self.assertEqual("You are not authorized to complete this operation.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ab477cf8-6c37-4762-bd85-d55b46444d8f')
def test_policy_list_global_project_not_bool(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'policies', {'global_project': 'not-bool'})
message = ex.resp_body['error']['message']
self.assertEqual("Invalid value 'not-bool' specified for "
"'global_project'", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f5bd7807-2b3e-43b2-8ed6-7bdb5e9af46b')
def test_policy_list_invalid_sort(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'policies', {'sort': 'bad-sort'})
message = ex.resp_body['error']['message']
self.assertEqual("Unsupported sort key 'bad-sort' for 'sort'.",
str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('077f39f0-bb2a-4de8-9568-2ed49e99b720')
def test_policy_list_invalid_marker(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.list_objs,
'policies', {'marker': 'bad-marker'})
message = ex.resp_body['error']['message']
self.assertEqual(
"The value for marker is not a valid UUID: 'bad-marker'.",
str(message))

View File

@ -1,37 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyShow(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyShow, self).setUp()
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
@decorators.idempotent_id('7ab18be1-e554-452d-91ac-9b5e5c87430b')
def test_policy_show(self):
res = self.client.get_obj('policies', self.policy_id)
# Verify resp of policy show API
self.assertEqual(200, res['status'])
self.assertIsNone(res['location'])
self.assertIsNotNone(res['body'])
policy = res['body']
for key in ['created_at', 'data', 'domain', 'id', 'name', 'project',
'spec', 'type', 'updated_at', 'user']:
self.assertIn(key, policy)

View File

@ -1,54 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyShowNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f1615466-7fca-4670-8c9a-66cb4bb24e54')
def test_policy_show_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.get_obj, 'policies',
'f1615466-7fca-4670-8c9a-66cb4bb24e54')
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy 'f1615466-7fca-4670-8c9a-66cb4bb24e54' "
"could not be found.", str(message))
class TestPolicyShowNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyShowNegativeBadRequest, self).setUp()
self.policy_id1 = utils.create_a_policy(self, name='p-01')
self.policy_id2 = utils.create_a_policy(self, name='p-01')
self.addCleanup(utils.delete_a_policy, self, self.policy_id1)
self.addCleanup(utils.delete_a_policy, self, self.policy_id2)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c2eadbae-29b7-4d12-a407-259f387286f5')
def test_policy_show_multiple_choice(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.get_obj,
'policies', 'p-01')
message = ex.resp_body['error']['message']
self.assertEqual(
"Multiple results found matching the query criteria 'p-01'. "
"Please be more specific.", str(message))

View File

@ -1,42 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyUpdate(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyUpdate, self).setUp()
self.policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, self.policy_id)
@decorators.idempotent_id('dbe9c6a6-882c-41cf-b862-7f648804db24')
def test_policy_update(self):
params = {
'policy': {
'name': 'updated-policy-name'
}
}
res = self.client.update_obj('policies', self.policy_id, params)
# Verify resp of policy update API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
policy = res['body']
for key in ['created_at', 'data', 'domain', 'id', 'name', 'project',
'spec', 'type', 'updated_at', 'user']:
self.assertIn(key, policy)
self.assertEqual('updated-policy-name', policy['name'])

View File

@ -1,107 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyUpdateNegativeNotFound(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5df90d82-9889-4c6f-824c-30272bcfa767')
def test_policy_update_policy_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.update_obj, 'policies',
'5df90d82-9889-4c6f-824c-30272bcfa767',
{'policy': {'name': 'new-name'}})
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy '5df90d82-9889-4c6f-824c-30272bcfa767' "
"could not be found.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('29414add-9cba-4b72-a7bb-36718671dcab')
def test_policy_update_policy_invalid_param(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj, 'policies',
'5df90d82-9889-4c6f-824c-30272bcfa767',
{'policy': {'boo': 'foo'}})
message = ex.resp_body['error']['message']
self.assertEqual(
"Additional properties are not allowed (u'boo' was "
"unexpected)", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('bf26ed1e-1d26-4472-b4c8-0bcca1c0a838')
def test_policy_update_policy_empty_param(self):
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj, 'policies',
'5df90d82-9889-4c6f-824c-30272bcfa767',
{})
message = ex.resp_body['error']['message']
self.assertEqual(
"Malformed request data, missing 'policy' key in "
"request body.", str(message))
class TestPolicyUpdateNegativeBadRequest(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyUpdateNegativeBadRequest, self).setUp()
# Create a policy
policy_id = utils.create_a_policy(self)
self.addCleanup(utils.delete_a_policy, self, policy_id)
self.policy_id = policy_id
@decorators.attr(type=['negative'])
@decorators.idempotent_id('31242de5-55ac-4589-87a1-a9940e4beca2')
def test_policy_update_no_property_updated(self):
# No property is updated.
params = {
'policy': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'policies', self.policy_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"'name' is a required property", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d2ca7de6-0069-48c9-b3de-ee975a2428dc')
def test_policy_update_spec_not_updatable(self):
# Try to update spec of policy.
# Note: name is the only property that can be updated
# after policy is created.
params = {
'policy': {
'name': 'new-name',
'spec': {'k1': 'v1'}
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.update_obj,
'policies', self.policy_id, params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Additional properties are not allowed (u'spec' was "
"unexpected)", str(message))

View File

@ -1,44 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
class TestPolicyValidate(base.BaseSenlinAPITest):
def setUp(self):
super(TestPolicyValidate, self).setUp()
self.policy_id = None
@decorators.idempotent_id('a3f5ad0d-4f3d-4b40-b473-1cfc562cfcee')
def test_policy_validate(self):
params = {
'policy': {
'spec': constants.spec_scaling_policy,
}
}
res = self.client.validate_obj('policies', params)
# Verify resp of policy validate API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
policy = res['body']
for key in ['created_at', 'data', 'domain', 'id', 'name', 'project',
'spec', 'type', 'updated_at', 'user']:
self.assertIn(key, policy)
self.assertEqual('validated_policy', policy['name'])
self.assertEqual('senlin.policy.scaling-1.0', policy['type'])
self.assertEqual(constants.spec_scaling_policy, policy['spec'])

View File

@ -1,106 +0,0 @@
# 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 copy
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import constants
class TestPolicyValidateNegativeBadRequest(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4b55bb3e-12d6-4728-9b53-9db5094ac8b5')
def test_policy_validate_with_empty_body(self):
params = {}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.validate_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Request body missing 'policy' key.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4c9f26cc-f4f3-4303-9f29-f30fae400843')
def test_policy_validate_invalid_param(self):
params = {
'policy': {
'name': 'fake'
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.validate_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Additional properties are not allowed (u'name' "
"was unexpected)", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('a1c35d93-2d19-4a72-919f-cfd70f5cbf06')
def test_policy_validate_no_spec(self):
params = {
'policy': {}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.BadRequest,
self.client.validate_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"'spec' is a required property", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6073da36-ee3e-4925-bce1-6c9a158e710d')
def test_policy_validate_policy_type_incorrect(self):
spec = copy.deepcopy(constants.spec_scaling_policy)
spec['type'] = 'senlin.policy.bogus'
params = {
'policy': {
'spec': spec
}
}
# Verify badrequest exception(404) is raised.
ex = self.assertRaises(exceptions.NotFound,
self.client.validate_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy_type 'senlin.policy.bogus-1.0' could "
"not be found.", str(message))
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1e1833ea-4a67-4ac1-b6e2-f9afff51c945')
def test_policy_validate_spec_validation_failed(self):
spec = copy.deepcopy(constants.spec_scaling_policy)
spec['properties']['bogus'] = 'foo'
params = {
'policy': {
'spec': spec
}
}
# Verify badrequest exception(400) is raised.
ex = self.assertRaises(exceptions.ServerFault,
self.client.validate_obj,
'policies', params)
message = ex.resp_body['error']['message']
self.assertEqual(
"Unrecognizable spec item 'bogus'", str(message))

View File

@ -1,55 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyTypeList(base.BaseSenlinAPITest):
@utils.api_microversion('1.4')
@decorators.idempotent_id('72cc0347-3eab-4cf6-b1ee-531b11f20550')
def test_policy_type_list(self):
res = self.client.list_objs('policy-types')
# Verify resp of policy type list API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
policy_types = res['body']
for policy_type in policy_types:
self.assertIn('name', policy_type)
@utils.api_microversion('1.5')
@decorators.idempotent_id('1900b22a-012d-41f0-85a2-8aa6b65ec2ca')
def test_policy_type_list_v1_5(self):
res = self.client.list_objs('policy-types')
# Verify resp of policy type list API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
policy_types = res['body']
expected_names = [
'senlin.policy.affinity',
'senlin.policy.batch',
'senlin.policy.deletion',
'senlin.policy.health',
'senlin.policy.loadbalance',
'senlin.policy.region_placement',
'senlin.policy.scaling',
'senlin.policy.zone_placement',
]
for t in policy_types:
self.assertIn(t['name'], expected_names)
self.assertIsNotNone(t['support_status'])
self.assertIsNotNone(t['version'])

View File

@ -1,46 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestPolicyTypeShow(base.BaseSenlinAPITest):
@utils.api_microversion('1.4')
@decorators.idempotent_id('57791ed7-7f57-4369-ba6e-7e039169ebdc')
def test_policy_type_show(self):
res = self.client.get_obj('policy-types', 'senlin.policy.deletion-1.0')
# Verify resp of policy type show API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
policy_type = res['body']
for key in ['name', 'schema']:
self.assertIn(key, policy_type)
self.assertEqual('senlin.policy.deletion-1.0', policy_type['name'])
@utils.api_microversion('1.5')
@decorators.idempotent_id('1900b22a-012d-41f0-85a2-8aa6b65ec2ca')
def test_policy_type_show_v1_5(self):
res = self.client.get_obj('policy-types', 'senlin.policy.deletion-1.0')
# Verify resp of policy type show API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
policy_type = res['body']
for key in ['name', 'schema', 'support_status']:
self.assertIn(key, policy_type)
self.assertEqual('senlin.policy.deletion-1.0', policy_type['name'])
self.assertIsNotNone(policy_type['support_status'])

View File

@ -1,32 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from tempest.lib import exceptions
from senlin.tests.tempest.api import base
class TestPolicyTypeShowNegative(base.BaseSenlinAPITest):
@decorators.attr(type=['negative'])
@decorators.idempotent_id('13d70be3-5998-412b-ab75-da72a2f84c75')
def test_policy_type_show_not_found(self):
ex = self.assertRaises(exceptions.NotFound,
self.client.get_obj,
'policy-types',
'13d70be3-5998-412b-ab75-da72a2f84c75')
message = ex.resp_body['error']['message']
self.assertEqual(
"The policy_type '13d70be3-5998-412b-ab75-da72a2f84c75' "
"could not be found.", str(message))

View File

@ -1,55 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from senlin.tests.tempest.api import base
from senlin.tests.tempest.common import utils
class TestProfileTypeList(base.BaseSenlinAPITest):
@utils.api_microversion('1.4')
@decorators.idempotent_id('fa0cf9e3-5b75-4d4d-9a0f-1748772b65d3')
def test_profile_type_list(self):
res = self.client.list_objs('profile-types')
# Verify resp of profile type list API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
profile_types = res['body']
expected_profile_types = [
{'name': 'os.nova.server-1.0'},
{'name': 'os.heat.stack-1.0'},
{'name': 'container.dockerinc.docker-1.0'}
]
for profile_type in expected_profile_types:
self.assertIn(profile_type, profile_types)
@utils.api_microversion('1.5')
@decorators.idempotent_id('778d41df-0ce0-421f-98e5-2efdcec6d995')
def test_profile_type_list_v1_5(self):
res = self.client.list_objs('profile-types')
# Verify resp of profile type list API
self.assertEqual(200, res['status'])
self.assertIsNotNone(res['body'])
profile_types = res['body']
expected_names = [
'os.nova.server',
'os.heat.stack',
'container.dockerinc.docker'
]
for t in profile_types:
self.assertIn(t['name'], expected_names)
self.assertIsNotNone(t['support_status'])
self.assertIsNotNone(t['version'])

Some files were not shown because too many files have changed in this diff Show More