Merge "Use keystone session with heatclient in integration tests"
diff --git a/.zuul.yaml b/.zuul.yaml
index 46ccf7f..c9aea1b 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -1,11 +1,30 @@
+- job:
+ name: heat-functional-convg-queens
+ parent: heat-functional-convg-mysql-lbaasv2
+ override-checkout: stable/queens
+
+- job:
+ name: heat-functional-orig-queens
+ parent: heat-functional-orig-mysql-lbaasv2
+ override-checkout: stable/queens
+
+- job:
+ name: heat-functional-convg-queens-py35
+ parent: heat-functional-convg-mysql-lbaasv2-py35
+ override-checkout: stable/queens
+
+
+
- project:
- name: openstack/heat-tempest-plugin
check:
jobs:
- heat-functional-orig-mysql-lbaasv2
- heat-functional-convg-mysql-lbaasv2
- heat-functional-convg-mysql-lbaasv2-non-apache
- heat-functional-convg-mysql-lbaasv2-py35
+ - heat-functional-convg-queens
+ - heat-functional-convg-queens-py35
+ - heat-functional-orig-queens
gate:
jobs:
- heat-functional-orig-mysql-lbaasv2
diff --git a/heat_tempest_plugin/common/test.py b/heat_tempest_plugin/common/test.py
index 4fdfb8e..429d4ae 100644
--- a/heat_tempest_plugin/common/test.py
+++ b/heat_tempest_plugin/common/test.py
@@ -34,6 +34,7 @@
LOG = logging.getLogger(__name__)
_LOG_FORMAT = "%(levelname)8s [%(name)s] %(message)s"
+_resource_types = None
def call_until_true(duration, sleep_for, func, *args, **kwargs):
@@ -86,7 +87,47 @@
return skipper(test_method)
-class HeatIntegrationTest(testscenarios.WithScenarios,
+def requires_resource_type(resource_type):
+ '''Decorator for tests requiring a resource type.
+
+ The decorated test will be skipped when the resource type is not available.
+ '''
+ def decorator(test_method):
+ conf = getattr(config.CONF, 'heat_plugin', None)
+ if not conf or conf.auth_url is None:
+ return test_method
+
+ global _resource_types
+ if not _resource_types:
+ manager = clients.ClientManager(conf)
+ obj_rtypes = manager.orchestration_client.resource_types.list()
+ _resource_types = list(t.resource_type for t in obj_rtypes)
+ rtype_available = resource_type and resource_type in _resource_types
+ skipper = testtools.skipUnless(
+ rtype_available,
+ "%s resource type not available, skipping test." % resource_type)
+ return skipper(test_method)
+ return decorator
+
+
+def requires_feature(feature):
+ '''Decorator for tests requring specific feature.
+
+ The decorated test will be skipped when a specific feature is disabled.
+ '''
+ def decorator(test_method):
+ features_group = getattr(config.CONF, 'heat_features_enabled', None)
+ if not features_group:
+ return test_method
+ feature_enabled = config.CONF.heat_features_enabled.get(feature, False)
+ skipper = testtools.skipUnless(feature_enabled,
+ "%s - Feature not enabled." % feature)
+ return skipper(test_method)
+ return decorator
+
+
+class HeatIntegrationTest(testtools.testcase.WithAttributes,
+ testscenarios.WithScenarios,
testtools.TestCase):
def setUp(self):
@@ -712,13 +753,13 @@
time.sleep(build_interval)
def check_autoscale_complete(self, stack_id, expected_num, parent_stack,
- policy):
+ group_name):
res_list = self.client.resources.list(stack_id)
all_res_complete = all(res.resource_status in ('UPDATE_COMPLETE',
'CREATE_COMPLETE')
for res in res_list)
all_res = len(res_list) == expected_num
if all_res and all_res_complete:
- metadata = self.client.resources.metadata(parent_stack, policy)
+ metadata = self.client.resources.metadata(parent_stack, group_name)
return not metadata.get('scaling_in_progress')
return False
diff --git a/heat_tempest_plugin/config.py b/heat_tempest_plugin/config.py
index d658a98..c77bb51 100644
--- a/heat_tempest_plugin/config.py
+++ b/heat_tempest_plugin/config.py
@@ -153,10 +153,23 @@
cfg.StrOpt('heat_config_notify_script',
default=('heat-config-notify'),
help="Path to the script heat-config-notify"),
+ cfg.StrOpt('hidden_stack_tag',
+ default='data-processing-cluster',
+ help="Tag to be considered as hidden for stack tags tests"),
+]
+heat_features_group = cfg.OptGroup(
+ name='heat_features_enabled',
+ title="Enabled Orchestration Service Features")
+
+HeatFeaturesGroup = [
+ cfg.BoolOpt('stack_cancel',
+ default=False,
+ help="If false, skip stack cancel tests")
]
def list_opts():
yield heat_group.name, HeatGroup
+ yield heat_features_group.name, HeatFeaturesGroup
yield service_available_group.name, ServiceAvailableGroup
diff --git a/heat_tempest_plugin/plugin.py b/heat_tempest_plugin/plugin.py
index acf4fc7..6926691 100644
--- a/heat_tempest_plugin/plugin.py
+++ b/heat_tempest_plugin/plugin.py
@@ -34,7 +34,11 @@
heat_config.ServiceAvailableGroup)
config.register_opt_group(conf, heat_config.heat_group,
heat_config.HeatGroup)
+ config.register_opt_group(conf, heat_config.heat_features_group,
+ heat_config.HeatFeaturesGroup)
def get_opt_lists(self):
return [(heat_config.heat_group.name,
- heat_config.HeatGroup)]
+ heat_config.HeatGroup),
+ (heat_config.heat_features_group.name,
+ heat_config.HeatFeaturesGroup)]
diff --git a/heat_tempest_plugin/tests/api/gabbits/environments.yaml b/heat_tempest_plugin/tests/api/gabbits/environments.yaml
index 17ac476..fe1dc04 100644
--- a/heat_tempest_plugin/tests/api/gabbits/environments.yaml
+++ b/heat_tempest_plugin/tests/api/gabbits/environments.yaml
@@ -4,6 +4,7 @@
tests:
- name: environment with parameter
+ desc: 8281d088-0c80-4071-a13d-333b309be6ca
POST: /stacks
request_headers:
content-type: application/json
@@ -34,15 +35,17 @@
location: //stacks/$ENVIRON['PREFIX']-envstack/[a-f0-9-]+/
- name: poll for envstack CREATE_COMPLETE
+ desc: 29899c70-9c94-4e24-8988-df76f7eaaa70
GET: $LOCATION
redirects: True
poll:
- count: 5
+ count: 10
delay: 1.0
response_json_paths:
$.stack.stack_status: CREATE_COMPLETE
- name: get stack output
+ desc: f60dd8df-82d1-4228-8926-54d65ebd12e1
GET: $LAST_URL/outputs/output_value
redirects: True
status: 200
@@ -50,6 +53,7 @@
$.output.output_value: test
- name: delete envstack
+ desc: 0efde180-cc0e-4f2c-bb18-fa345e8d21ad
DELETE: /stacks/$ENVIRON['PREFIX']-envstack
redirects: True
status: 204
diff --git a/heat_tempest_plugin/tests/api/gabbits/resources.yaml b/heat_tempest_plugin/tests/api/gabbits/resources.yaml
index 41da444..c20333b 100644
--- a/heat_tempest_plugin/tests/api/gabbits/resources.yaml
+++ b/heat_tempest_plugin/tests/api/gabbits/resources.yaml
@@ -4,6 +4,7 @@
tests:
- name: create stack with resources
+ desc: 947be7b2-503d-41f5-9843-61be50954f13
POST: /stacks
request_headers:
content-type: application/json
@@ -29,15 +30,17 @@
location: //stacks/$ENVIRON['PREFIX']-rsrcstack/[a-f0-9-]+/
- name: poll for rsrcstack CREATE_COMPLETE
+ desc: e9eac22f-c3e7-450f-a087-08a8655a6e8e
GET: $LOCATION
redirects: True
poll:
- count: 5
+ count: 10
delay: 1.0
response_json_paths:
$.stack.stack_status: CREATE_COMPLETE
- name: list resources
+ desc: ec53f10d-a89a-4243-8706-629a01ea890f
GET: $LAST_URL/resources
request_headers:
content-type: application/json
@@ -47,6 +50,7 @@
$.resources[0].resource_status: CREATE_COMPLETE
- name: list filtered resources
+ desc: da07d3d2-9ccc-4fa1-9b1b-9cb3074fe9b9
GET: $LAST_URL
request_headers:
content-type: application/json
@@ -57,6 +61,7 @@
$.resources: []
- name: show resource
+ desc: 2cbcedc5-0aa7-454e-bf89-a3dd5d379dc1
GET: $LAST_URL/test
request_headers:
content-type: application/json
@@ -65,6 +70,7 @@
$.resource.attributes.output: test
- name: mark resource unhealthy
+ desc: 6031516b-3a8f-4d1b-8990-81a571b5f956
PATCH: $LAST_URL
request_headers:
content-type: application/json
@@ -74,6 +80,7 @@
status: 200
- name: show unhealthy resource
+ desc: 9e784490-2e88-49af-8ee7-c4c6aba2be64
GET: $LAST_URL
status: 200
response_json_paths:
@@ -81,10 +88,12 @@
$.resource.resource_status_reason: 'resource deleted'
- name: signal resource
+ desc: c65a047c-8c7b-4b44-9f5f-bf1069751c5c
POST: $LAST_URL/signal
status: 400
- name: delete stack with resources
+ desc: 0edc4fdc-811d-4d27-a0dd-6ec4db2bda6e
DELETE: /stacks/$ENVIRON['PREFIX']-rsrcstack
redirects: True
status: 204
diff --git a/heat_tempest_plugin/tests/api/gabbits/resourcetypes.yaml b/heat_tempest_plugin/tests/api/gabbits/resourcetypes.yaml
index 0730cc8..a259214 100644
--- a/heat_tempest_plugin/tests/api/gabbits/resourcetypes.yaml
+++ b/heat_tempest_plugin/tests/api/gabbits/resourcetypes.yaml
@@ -4,10 +4,12 @@
tests:
- name: list resource types
+ desc: 5b4db88b-d171-4400-b7a7-a7dc8f597d31
GET: /resource_types
status: 200
- name: show resource type
+ desc: cc05d1ef-17f1-430e-bea1-0f6766f7d0b4
GET: /resource_types/OS::Heat::TestResource
status: 200
response_json_paths:
@@ -15,6 +17,7 @@
$.properties.wait_secs.default: 0
- name: resource type template
+ desc: 5a2164eb-645a-4245-acd7-b222a715fc09
GET: /resource_types/OS::Heat::TestResource/template
query_parameters:
template_type: hot
diff --git a/heat_tempest_plugin/tests/api/gabbits/stacks.yaml b/heat_tempest_plugin/tests/api/gabbits/stacks.yaml
index cb67e71..9d9328e 100644
--- a/heat_tempest_plugin/tests/api/gabbits/stacks.yaml
+++ b/heat_tempest_plugin/tests/api/gabbits/stacks.yaml
@@ -4,12 +4,14 @@
tests:
- name: stack list
+ desc: 39c0245e-6055-41cf-9f0e-15adfe55ded6
GET: /stacks
status: 200
response_headers:
content-type: application/json
- name: create empty stack
+ desc: bde1b827-65fb-47ea-909f-82537e6260d3
POST: /stacks
request_headers:
content-type: application/json
@@ -28,25 +30,29 @@
- name: poll for empty CREATE_COMPLETE
+ desc: f575e5c4-2aed-4381-9f0d-2dfcb0640c4b
GET: $LOCATION
redirects: True
poll:
- count: 5
+ count: 10
delay: 1.0
response_json_paths:
$.stack.stack_status: CREATE_COMPLETE
- name: show empty stack
+ desc: 89b233fe-0d55-4959-9289-0b5dabe4e4c9
GET: $LAST_URL
redirects: True
status: 200
- name: delete empty stack
+ desc: 7eca55fe-8300-43b6-a6b8-fb2d99b51911
DELETE: $LAST_URL
redirects: True
status: 204
- name: create stack
+ desc: 56ac2173-97c5-4347-bd32-529a260cfac3
POST: /stacks
request_headers:
content-type: application/json
@@ -74,20 +80,23 @@
location: //stacks/$ENVIRON['PREFIX']-stack/[a-f0-9-]+/
- name: poll for stack CREATE_COMPLETE
+ desc: 6a0fe2dc-2822-4af3-b606-321ff7ad3de9
GET: $LOCATION
redirects: True
poll:
- count: 5
+ count: 10
delay: 1.0
response_json_paths:
$.stack.stack_status: CREATE_COMPLETE
- name: show stack
+ desc: 9b268607-0335-4667-a613-bccf81e66f8f
GET: $LAST_URL
redirects: True
status: 200
- name: update stack
+ desc: 6bb1ec02-dd19-4b2c-9a6d-866ce666650f
PUT: $LAST_URL
request_headers:
content-type: application/json
@@ -115,15 +124,17 @@
status: 202
- name: poll for stack UPDATE_COMPLETE
+ desc: 3e280fb3-02b6-44fb-84dd-e04921d47733
GET: $LAST_URL
redirects: True
poll:
- count: 5
+ count: 10
delay: 1.0
response_json_paths:
$.stack.stack_status: UPDATE_COMPLETE
- name: patch update stack
+ desc: 927cea42-a35b-4664-b209-ab2cb34e6ef4
PATCH: $LAST_URL
request_headers:
content-type: application/json
@@ -133,16 +144,18 @@
status: 202
- name: poll for stack patch UPDATE_COMPLETE
+ desc: a1cfd3b4-2536-4c54-94f4-12093f2ccf3b
GET: $LAST_URL
redirects: True
poll:
- count: 5
+ count: 10
delay: 1.0
response_json_paths:
$.stack.stack_status: UPDATE_COMPLETE
$.stack.updated_time: /^(?!$HISTORY['poll for stack UPDATE_COMPLETE'].$RESPONSE['$.stack.updated_time'])/
- name: list stack outputs
+ desc: bbd98b50-b75b-44a1-b7e8-0a68fd7c6d33
GET: $LAST_URL/outputs
redirects: True
status: 200
@@ -150,6 +163,7 @@
$.outputs[0].output_key: output_value
- name: get stack output
+ desc: e761f5d7-70f6-4d95-a11b-e5fa0ecb43d2
GET: $LAST_URL/output_value
redirects: True
status: 200
@@ -157,6 +171,7 @@
$.output.output_value: new_patched_value
- name: delete stack
+ desc: bcf4c359-0a64-4652-b465-df3f688a9d4d
DELETE: /stacks/$ENVIRON['PREFIX']-stack
redirects: True
status: 204
diff --git a/heat_tempest_plugin/tests/api/gabbits/templates.yaml b/heat_tempest_plugin/tests/api/gabbits/templates.yaml
index 7b67054..0533f4a 100644
--- a/heat_tempest_plugin/tests/api/gabbits/templates.yaml
+++ b/heat_tempest_plugin/tests/api/gabbits/templates.yaml
@@ -4,12 +4,14 @@
tests:
- name: list template versions
+ desc: cbc28c20-e740-43ef-a01b-b1a39f4a0db3
GET: /template_versions
status: 200
response_json_paths:
$.template_versions[?(@.version='heat_template_version.2017-02-24')].type: hot
- name: list template functions
+ desc: 721ff23c-8527-480f-a090-1c915b4f8430
GET: /template_versions/heat_template_version.2016-10-14/functions
status: 200
response_json_paths:
@@ -17,6 +19,7 @@
A function for including a file inline.
- name: template validate
+ desc: f307139b-03d0-4006-92b7-81c86c949727
POST: /validate
request_headers:
content-type: application/json
diff --git a/heat_tempest_plugin/tests/api/test_heat_api.py b/heat_tempest_plugin/tests/api/test_heat_api.py
index bf86839..804f445 100644
--- a/heat_tempest_plugin/tests/api/test_heat_api.py
+++ b/heat_tempest_plugin/tests/api/test_heat_api.py
@@ -13,15 +13,19 @@
"""A test module to exercise the Heat API with gabbi. """
+import keystoneauth1
import os
+import sys
+import unittest
from gabbi import driver
-from six.moves.urllib import parse as urlparse
+from oslo_log import log as logging
+from tempest import config
from heat_tempest_plugin.common import test
from heat_tempest_plugin.services import clients
-from tempest import config
+LOG = logging.getLogger(__name__)
TESTS_DIR = 'gabbits'
@@ -29,16 +33,67 @@
"""Provide a TestSuite to the discovery process."""
test_dir = os.path.join(os.path.dirname(__file__), TESTS_DIR)
+ endpoint = None
conf = config.CONF.heat_plugin
- if conf.auth_url is None:
- # It's not configured, let's not load tests
- return
- manager = clients.ClientManager(conf)
- endpoint = manager.identity_client.get_endpoint_url(
- 'orchestration', region=conf.region, endpoint_type=conf.endpoint_type)
- host = urlparse.urlparse(endpoint).hostname
- os.environ['OS_TOKEN'] = manager.identity_client.auth_token
- os.environ['PREFIX'] = test.rand_name('api')
+ if conf.auth_url:
+ try:
+ manager = clients.ClientManager(conf)
+ endpoint = manager.identity_client.get_endpoint_url(
+ 'orchestration', region=conf.region,
+ endpoint_type=conf.endpoint_type)
+ os.environ['OS_TOKEN'] = manager.identity_client.auth_token
+ os.environ['PREFIX'] = test.rand_name('api')
- return driver.build_tests(test_dir, loader, host=host,
- url=endpoint, test_loader_name=__name__)
+ # Catch the authentication exceptions that can happen if one of the
+ # following conditions occur:
+ # 1. conf.auth_url IP/port is incorrect or keystone not available
+ # (ConnectFailure)
+ # 2. conf.auth_url is malformed (BadRequest, UnknownConnectionError,
+ # EndpointNotFound, NotFound, or DiscoveryFailure)
+ # 3. conf.username/password is incorrect (Unauthorized)
+ # 4. conf.project_name is missing/incorrect (EmptyCatalog)
+ # These exceptions should not prevent a test list from being returned,
+ # so just issue a warning log and move forward with test listing.
+ except (keystoneauth1.exceptions.http.BadRequest,
+ keystoneauth1.exceptions.http.Unauthorized,
+ keystoneauth1.exceptions.http.NotFound,
+ keystoneauth1.exceptions.catalog.EmptyCatalog,
+ keystoneauth1.exceptions.catalog.EndpointNotFound,
+ keystoneauth1.exceptions.discovery.DiscoveryFailure,
+ keystoneauth1.exceptions.connection.UnknownConnectionError,
+ keystoneauth1.exceptions.connection.ConnectFailure):
+ LOG.warn("Keystone auth exception: %s: %s" % (sys.exc_info()[0],
+ sys.exc_info()[1]))
+ # Clear the auth_url, as there is no point in tempest trying
+ # to authenticate later with mis-configured or unreachable endpoint
+ conf.auth_url = None
+
+ except Exception:
+ LOG.error("Fatal exception: %s: %s" % (sys.exc_info()[0],
+ sys.exc_info()[1]))
+ raise
+
+ def register_test_case_id(test_case):
+ tempest_id = test_case.test_data.get('desc')
+ test_name = test_case.id()
+ if not tempest_id:
+ raise AssertionError(
+ "No Tempest ID registered for API test %s" % test_name)
+
+ def test_id():
+ return test_name + '[id-%s]' % tempest_id
+
+ test_case.id = test_id
+
+ def register_test_suite_ids(test_suite):
+ for test_case in test_suite:
+ if isinstance(test_case, unittest.TestSuite):
+ register_test_suite_ids(test_case)
+ else:
+ register_test_case_id(test_case)
+
+ api_tests = driver.build_tests(test_dir, loader, url=endpoint, host="",
+ test_loader_name=__name__)
+
+ register_test_suite_ids(api_tests)
+ return api_tests
diff --git a/heat_tempest_plugin/tests/functional/templates/lb_member.yaml b/heat_tempest_plugin/tests/functional/templates/lb_member.yaml
new file mode 100644
index 0000000..0afa754
--- /dev/null
+++ b/heat_tempest_plugin/tests/functional/templates/lb_member.yaml
@@ -0,0 +1,61 @@
+heat_template_version: pike
+parameters:
+ image:
+ type: string
+ flavor:
+ type: string
+ network:
+ type: string
+ sec_group:
+ type: string
+ pool:
+ type: string
+ app_port:
+ type: number
+ timeout:
+ type: number
+ default: 120
+ subnet:
+ type: string
+
+resources:
+ server:
+ type: OS::Nova::Server
+ properties:
+ image: {get_param: image}
+ flavor: {get_param: flavor}
+ networks:
+ - network: {get_param: network}
+ security_groups:
+ - {get_param: sec_group}
+ user_data_format: RAW
+ user_data:
+ str_replace:
+ template: |
+ #! /bin/sh -v
+ Body=$(hostname)
+ Response="HTTP/1.1 200 OK\r\nContent-Length: ${#Body}\r\n\r\n$Body"
+ wc_notify --data-binary '{"status": "SUCCESS"}'
+ while true ; do echo -e $Response | nc -llp PORT; done
+ params:
+ PORT: {get_param: app_port}
+ wc_notify: { get_attr: [handle, curl_cli]}
+
+ handle:
+ type: OS::Heat::WaitConditionHandle
+
+ waiter:
+ type: OS::Heat::WaitCondition
+ depends_on: server
+ properties:
+ timeout: {get_param: timeout}
+ handle: {get_resource: handle}
+
+ pool_member:
+ type: OS::Octavia::PoolMember
+ depends_on: waiter
+ properties:
+ address: {get_attr: [server, networks, {get_param: network}, 0]}
+ pool: {get_param: pool}
+ protocol_port: {get_param: app_port}
+ subnet: {get_param: subnet}
diff --git a/heat_tempest_plugin/tests/functional/templates/octavia_lbaas.yaml b/heat_tempest_plugin/tests/functional/templates/octavia_lbaas.yaml
new file mode 100644
index 0000000..d20ae60
--- /dev/null
+++ b/heat_tempest_plugin/tests/functional/templates/octavia_lbaas.yaml
@@ -0,0 +1,86 @@
+heat_template_version: pike
+parameters:
+ app_port:
+ type: number
+ default: 8080
+ flavor:
+ type: string
+ default: m1.nano
+ image:
+ type: string
+ default: cirros-0.3.5-x86_64-disk
+ lb_port:
+ type: number
+ default: 80
+ network:
+ type: string
+ default: heat-net
+ subnet:
+ type: string
+ default: heat-subnet
+ member_count:
+ type: number
+ default: 1
+ lb_algorithm:
+ type: string
+ default: ROUND_ROBIN
+
+resources:
+ sec_group:
+ type: OS::Neutron::SecurityGroup
+ properties:
+ rules:
+ - remote_ip_prefix: 0.0.0.0/0
+ protocol: tcp
+ port_range_min: {get_param: app_port}
+ port_range_max: {get_param: app_port}
+
+ pool_members:
+ type: OS::Heat::ResourceGroup
+ properties:
+ count: {get_param: member_count}
+ resource_def:
+ type: OS::Test::PoolMember
+ properties:
+ image: {get_param: image}
+ flavor: {get_param: flavor}
+ pool: {get_resource: pool}
+ app_port: {get_param: app_port}
+ network: {get_param: network}
+ sec_group: {get_resource: sec_group}
+ subnet: {get_param: subnet}
+
+ monitor:
+ type: OS::Octavia::HealthMonitor
+ properties:
+ delay: 3
+ type: HTTP
+ timeout: 3
+ max_retries: 3
+ pool: {get_resource: pool}
+
+ pool:
+ type: OS::Octavia::Pool
+ properties:
+ lb_algorithm: {get_param: lb_algorithm}
+ protocol: HTTP
+ listener: {get_resource: listener}
+
+ listener:
+ type: OS::Octavia::Listener
+ properties:
+ loadbalancer: {get_resource: loadbalancer}
+ protocol: HTTP
+ protocol_port: {get_param: lb_port}
+
+ loadbalancer:
+ type: OS::Octavia::LoadBalancer
+ properties:
+ vip_subnet: {get_param: subnet}
+outputs:
+ loadbalancer:
+ value: {get_attr: [loadbalancer, show]}
+ pool:
+ value: {get_attr: [pool, show]}
+ listener:
+ value: {get_attr: [listener, show]}
diff --git a/heat_tempest_plugin/tests/functional/test_create_update_neutron_port.py b/heat_tempest_plugin/tests/functional/test_create_update_neutron_port.py
index 72cd47c..eeeabf3 100644
--- a/heat_tempest_plugin/tests/functional/test_create_update_neutron_port.py
+++ b/heat_tempest_plugin/tests/functional/test_create_update_neutron_port.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -62,6 +64,7 @@
port_mac = self._stack_output(stack, 'mac_address')
return port_id[0], port_ip, port_mac
+ @decorators.idempotent_id('8e37933b-345c-4ce5-a523-e67bdf198d73')
def test_update_remove_ip(self):
# create with defined ip_address
stack_identifier = self.stack_create(template=test_template)
@@ -77,6 +80,7 @@
self.assertEqual(_id, new_id)
self.assertEqual(_mac, new_mac)
+ @decorators.idempotent_id('df1bf0fb-115e-42f3-b6cc-e12b5d506c98')
def test_update_with_mac_address(self):
if not self.conf.admin_username or not self.conf.admin_password:
self.skipTest('No admin creds found, skipping')
diff --git a/heat_tempest_plugin/tests/functional/test_create_update_neutron_subnet.py b/heat_tempest_plugin/tests/functional/test_create_update_neutron_subnet.py
index 345a740..9a10ba2 100644
--- a/heat_tempest_plugin/tests/functional/test_create_update_neutron_subnet.py
+++ b/heat_tempest_plugin/tests/functional/test_create_update_neutron_subnet.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -41,6 +43,7 @@
output = self._stack_output(stack, output_key)
return output
+ @decorators.idempotent_id('af43fc6d-58ba-4b5f-bd68-07b29f0a96bc')
def test_update_allocation_pools(self):
stack_identifier = self.stack_create(template=test_template)
alloc_pools = self.get_outputs(stack_identifier, 'alloc_pools')
@@ -57,6 +60,7 @@
self.assertEqual([{'start': '11.11.11.10', 'end': '11.11.11.100'}],
new_alloc_pools)
+ @decorators.idempotent_id('2f1d3b04-2183-4e50-8aa3-fa0fbff5c861')
def test_update_allocation_pools_to_empty(self):
stack_identifier = self.stack_create(template=test_template)
alloc_pools = self.get_outputs(stack_identifier, 'alloc_pools')
@@ -72,6 +76,7 @@
# new_alloc_pools should be []
self.assertEqual([], new_alloc_pools)
+ @decorators.idempotent_id('6ec51150-6f83-4179-9faa-a3aee91ea150')
def test_update_to_no_allocation_pools(self):
stack_identifier = self.stack_create(template=test_template)
alloc_pools = self.get_outputs(stack_identifier, 'alloc_pools')
@@ -87,6 +92,7 @@
# last_alloc_pools should be []
self.assertEqual([], last_alloc_pools)
+ @decorators.idempotent_id('ffb3eaf8-044b-4229-99f9-5fd983ccc9d9')
def test_update_gateway_ip(self):
stack_identifier = self.stack_create(template=test_template)
gw_ip = self.get_outputs(stack_identifier, 'gateway_ip')
@@ -100,6 +106,7 @@
# the gateway_ip should be the new one
self.assertEqual('11.11.11.9', new_gw_ip)
+ @decorators.idempotent_id('e7b37a6b-e883-4c0c-b6a3-9ece1843e902')
def test_update_gateway_ip_to_empty(self):
stack_identifier = self.stack_create(template=test_template)
gw_ip = self.get_outputs(stack_identifier, 'gateway_ip')
@@ -113,6 +120,7 @@
# new gateway_ip should be None
self.assertIsNone(new_gw_ip)
+ @decorators.idempotent_id('373bab03-1f66-4883-b1de-2ecc39efe17e')
def test_update_to_no_gateway_ip(self):
stack_identifier = self.stack_create(template=test_template)
gw_ip = self.get_outputs(stack_identifier, 'gateway_ip')
diff --git a/heat_tempest_plugin/tests/functional/test_create_update_neutron_trunk.py b/heat_tempest_plugin/tests/functional/test_create_update_neutron_trunk.py
index d572405..bdcb58e 100644
--- a/heat_tempest_plugin/tests/functional/test_create_update_neutron_trunk.py
+++ b/heat_tempest_plugin/tests/functional/test_create_update_neutron_trunk.py
@@ -15,6 +15,9 @@
import copy
import yaml
+from tempest.lib import decorators
+
+from heat_tempest_plugin.common import test
from heat_tempest_plugin.tests.functional import functional_base
@@ -70,6 +73,7 @@
'''
+@test.requires_resource_type('OS::Neutron::Trunk')
class UpdateTrunkTest(functional_base.FunctionalTestsBase):
@staticmethod
@@ -94,6 +98,7 @@
sub_ports_set = {frozenset(d.items()) for d in new_sub_ports}
return sub_ports_set
+ @decorators.idempotent_id('5572b0ac-fdb2-4c68-a49e-024771814471')
def test_add_first_sub_port(self):
stack_identifier = self.stack_create(template=test_template)
@@ -117,6 +122,7 @@
self.assertEqual(self._sub_ports_dict_to_set(new_sub_port),
self._sub_ports_dict_to_set(trunk_sub_port))
+ @decorators.idempotent_id('c3f52330-01b7-4649-99fd-43700e6bbda3')
def test_add_a_second_sub_port(self):
parsed_template = yaml.safe_load(test_template)
sub_ports = [{'port': {'get_resource': 'sub_port_one'},
@@ -153,6 +159,7 @@
self.assertEqual(self._sub_ports_dict_to_set(expected_sub_ports),
self._sub_ports_dict_to_set(trunk_sub_ports))
+ @decorators.idempotent_id('cb59363e-5517-42f9-8b93-9ad700e2ef4c')
def test_remove_sub_port_from_trunk(self):
sub_ports = [{'port': {'get_resource': 'sub_port_one'},
'segmentation_type': 'vlan',
@@ -189,6 +196,7 @@
self.assertEqual(self._sub_ports_dict_to_set(expected_sub_ports),
self._sub_ports_dict_to_set(trunk_sub_ports))
+ @decorators.idempotent_id('7f0836c7-1d35-4d11-bcdc-e0e19ca68b68')
def test_remove_last_sub_port_from_trunk(self):
sub_ports = [{'port': {'get_resource': 'sub_port_one'},
'segmentation_type': 'vlan',
@@ -224,6 +232,7 @@
'The returned sub ports (%s) in trunk_details is '
'not empty!' % trunk_sub_ports)
+ @decorators.idempotent_id('e9296d6f-009c-4530-9aaf-84a0f8281bcb')
def test_update_existing_sub_port_on_trunk(self):
sub_ports = [{'port': {'get_resource': 'sub_port_one'},
'segmentation_type': 'vlan',
@@ -253,6 +262,7 @@
self.assertEqual(self._sub_ports_dict_to_set([updated_sub_port]),
self._sub_ports_dict_to_set(trunk_sub_ports))
+ @decorators.idempotent_id('912044d8-e0c1-4c6c-ab4e-bc1cadc46c18')
def test_update_trunk_name_and_description(self):
new_name = 'pineapple'
new_description = 'This is a test trunk'
diff --git a/heat_tempest_plugin/tests/functional/test_encrypted_parameter.py b/heat_tempest_plugin/tests/functional/test_encrypted_parameter.py
index bfbd77b..0e7483e 100644
--- a/heat_tempest_plugin/tests/functional/test_encrypted_parameter.py
+++ b/heat_tempest_plugin/tests/functional/test_encrypted_parameter.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -43,6 +45,7 @@
value: { get_param: foo }
'''
+ @decorators.idempotent_id('d5bbf763-8eb9-4657-ad3f-e97405b6e1f2')
def test_db_encryption(self):
# Create a stack with the value of 'foo' to be encrypted
foo_param = 'my_encrypted_foo'
diff --git a/heat_tempest_plugin/tests/functional/test_encryption_vol_type.py b/heat_tempest_plugin/tests/functional/test_encryption_vol_type.py
index 2b98022..c0dd884 100644
--- a/heat_tempest_plugin/tests/functional/test_encryption_vol_type.py
+++ b/heat_tempest_plugin/tests/functional/test_encryption_vol_type.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
from heat_tempest_plugin.tests.functional import functional_base
@@ -73,6 +74,7 @@
self.assertEqual(my_encrypted_vol_type_tmpl_prop['control_location'],
phy_rsrc_specs.control_location)
+ @decorators.idempotent_id('a98de4ce-aa59-478b-a8ce-b5d818c76a68')
def test_create_update(self):
stack_identifier = self.stack_create(
template=test_encryption_vol_type)
diff --git a/heat_tempest_plugin/tests/functional/test_event_sinks.py b/heat_tempest_plugin/tests/functional/test_event_sinks.py
index a6e59eb..7cb1d7b 100644
--- a/heat_tempest_plugin/tests/functional/test_event_sinks.py
+++ b/heat_tempest_plugin/tests/functional/test_event_sinks.py
@@ -12,6 +12,7 @@
import uuid
+from tempest.lib import decorators
from zaqarclient.queues.v2 import client as zaqarclient
from heat_tempest_plugin.common import test
@@ -28,6 +29,7 @@
value: ok
'''
+ @decorators.idempotent_id('d0b72695-e97d-4aa1-bfaf-31c14b09ac87')
def test_events(self):
queue_id = str(uuid.uuid4())
environment = {'event_sinks': [{'type': 'zaqar-queue',
diff --git a/heat_tempest_plugin/tests/functional/test_external_ref.py b/heat_tempest_plugin/tests/functional/test_external_ref.py
index c54e453..d6a73ac 100644
--- a/heat_tempest_plugin/tests/functional/test_external_ref.py
+++ b/heat_tempest_plugin/tests/functional/test_external_ref.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -32,6 +34,7 @@
value: {get_resource: test1}
'''
+ @decorators.idempotent_id('45449bad-18ba-4148-82e6-a6bc1e9a9b04')
def test_create_with_external_ref(self):
stack_name = self._stack_rand_name()
stack_identifier = self.stack_create(
@@ -55,6 +58,7 @@
'output_key': 'str',
'output_value': 'foobar'}], stack.outputs)
+ @decorators.idempotent_id('fb16477c-e981-4ef9-a83b-c0acc162343a')
def test_update_with_external_ref(self):
stack_name = self._stack_rand_name()
stack_identifier = self.stack_create(
diff --git a/heat_tempest_plugin/tests/functional/test_hooks.py b/heat_tempest_plugin/tests/functional/test_hooks.py
index 78c58f3..91351fa 100644
--- a/heat_tempest_plugin/tests/functional/test_hooks.py
+++ b/heat_tempest_plugin/tests/functional/test_hooks.py
@@ -12,6 +12,8 @@
import yaml
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -27,6 +29,7 @@
'foo_step3': {'type': 'OS::Heat::RandomString',
'depends_on': 'foo_step2'}}}
+ @decorators.idempotent_id('f14cbe86-0392-474a-9f28-bb561745698d')
def test_hook_pre_create(self):
env = {'resource_registry':
{'resources':
@@ -58,6 +61,7 @@
stack_identifier, 'foo_step2', 'CREATE_COMPLETE')
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
+ @decorators.idempotent_id('75009076-96eb-43af-b4df-f002704737d2')
def test_hook_pre_update_nochange(self):
env = {'resource_registry':
{'resources':
@@ -99,6 +103,7 @@
self.assertEqual(res_before.physical_resource_id,
res_after.physical_resource_id)
+ @decorators.idempotent_id('9f03d1e0-a2d2-42fc-a9c6-47db05b9c8ed')
def test_hook_pre_update_replace(self):
env = {'resource_registry':
{'resources':
@@ -141,6 +146,7 @@
self.assertNotEqual(res_before.physical_resource_id,
res_after.physical_resource_id)
+ @decorators.idempotent_id('15c4f97d-5e06-40c6-83af-0e57d5afaff9')
def test_hook_pre_update_in_place(self):
env = {'resource_registry':
{'resources':
@@ -190,6 +196,7 @@
self.assertEqual(res_before.physical_resource_id,
res_after.physical_resource_id)
+ @decorators.idempotent_id('7d96b5f4-4aba-493d-b098-4beea4654a2b')
def test_hook_pre_create_nested(self):
files = {'nested.yaml': yaml.safe_dump(self.template)}
env = {'resource_registry':
@@ -231,6 +238,7 @@
nested_identifier, 'foo_step2', 'CREATE_COMPLETE')
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
+ @decorators.idempotent_id('cffc0783-3add-4f0c-ac66-03c90f6feeb0')
def test_hook_pre_create_wildcard(self):
env = {'resource_registry':
{'resources':
diff --git a/heat_tempest_plugin/tests/functional/test_lbaasv2.py b/heat_tempest_plugin/tests/functional/test_lbaasv2.py
index e33c5b9..3439179 100644
--- a/heat_tempest_plugin/tests/functional/test_lbaasv2.py
+++ b/heat_tempest_plugin/tests/functional/test_lbaasv2.py
@@ -11,6 +11,8 @@
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -88,6 +90,7 @@
if not self.is_network_extension_supported('lbaasv2'):
self.skipTest('LBaasv2 extension not available, skipping')
+ @decorators.idempotent_id('2f4a476c-cba7-448b-a7c1-85f7284f0293')
def test_create_update_loadbalancer(self):
parameters = {
'subnet': self.conf.fixed_subnet_name,
@@ -125,6 +128,7 @@
self.assertEqual(7777, output['connection_limit'])
self.assertEqual('updatedListener', output['description'])
+ @decorators.idempotent_id('104f59ae-a3c8-4c12-98e5-a7bc0007878d')
def test_add_delete_poolmember(self):
parameters = {
'subnet': self.conf.fixed_subnet_name,
diff --git a/heat_tempest_plugin/tests/functional/test_nova_server_networks.py b/heat_tempest_plugin/tests/functional/test_nova_server_networks.py
index 4c38260..32ed27a 100644
--- a/heat_tempest_plugin/tests/functional/test_nova_server_networks.py
+++ b/heat_tempest_plugin/tests/functional/test_nova_server_networks.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -126,6 +128,46 @@
value: {get_attr: [server, networks]}
'''
+server_with_no_nets_template = '''
+heat_template_version: 2016-04-08
+description: Test template to test nova server network updates.
+parameters:
+ flavor:
+ type: string
+ image:
+ type: string
+resources:
+ net:
+ type: OS::Neutron::Net
+ properties:
+ name: the_net
+ subnet:
+ type: OS::Neutron::Subnet
+ properties:
+ name: the_subnet
+ network: {get_resource: net}
+ cidr: 11.11.11.0/24
+ server:
+ type: OS::Nova::Server
+ properties:
+ image: {get_param: image}
+ flavor: {get_param: flavor}
+ networks: $NETWORKS
+outputs:
+ port0_id:
+ value: {get_attr: [server, addresses, the_net, 0, port]}
+ port1_id:
+ value: {get_attr: [server, addresses, the_net, 1, port]}
+ port2_id:
+ value: {get_attr: [server, addresses, the_net, 2, port]}
+ port0_ip_addr:
+ value: {get_attr: [server, addresses, the_net, 0, addr]}
+ port1_ip_addr:
+ value: {get_attr: [server, addresses, the_net, 1, addr]}
+ port2_ip_addr:
+ value: {get_attr: [server, addresses, the_net, 2, addr]}
+'''
+
class CreateServerTest(functional_base.FunctionalTestsBase):
@@ -133,6 +175,7 @@
stack = self.client.stacks.get(stack_identifier)
return self._stack_output(stack, output_key)
+ @decorators.idempotent_id('58ccf0aa-7531-4eaa-8ed5-38663a4defaa')
def test_create_server_with_subnet_fixed_ip_sec_group(self):
parms = {'flavor': self.conf.minimal_instance_type,
'image': self.conf.minimal_image_ref}
@@ -150,6 +193,7 @@
server = self.compute_client.servers.get(server_id)
self.assertEqual([{"name": "the_sg"}], server.security_groups)
+ @decorators.idempotent_id('12185eaa-927f-43f3-a525-0424c4eb9b5d')
def test_create_update_server_with_subnet(self):
parms = {'flavor': self.conf.minimal_instance_type,
'image': self.conf.minimal_image_ref}
@@ -173,6 +217,7 @@
self.assertNotIn('11.11.11', new_networks['the_net'][0])
self.assertIn('12.12.12', new_networks['the_net'][0])
+ @decorators.idempotent_id('19479c15-6b25-4865-8889-658566608bd9')
def test_create_server_with_port(self):
parms = {'flavor': self.conf.minimal_instance_type,
'image': self.conf.minimal_image_ref}
@@ -182,3 +227,212 @@
template=server_with_port_template,
stack_name='server_with_port',
parameters=parms)
+
+
+class UpdateServerNetworksTest(functional_base.FunctionalTestsBase):
+ def setUp(self):
+ super(UpdateServerNetworksTest, self).setUp()
+ self.params = {'flavor': self.conf.minimal_instance_type,
+ 'image': self.conf.minimal_image_ref}
+
+ def get_outputs(self, stack_identifier, output_key):
+ stack = self.client.stacks.get(stack_identifier)
+ return self._stack_output(stack, output_key)
+
+ @decorators.idempotent_id('c1a22dbf-3160-41b7-8d3f-62ca33fc35a8')
+ def test_create_update_server_swap_network_subnet(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - subnet: {get_resource: subnet}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='swap_network_subnet',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{subnet: {get_resource: subnet}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ @decorators.idempotent_id('cccfe612-1ab7-401f-a4c5-63372826a780')
+ def test_create_update_server_swap_network_port(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - port: <the_port_created_on_stack_create>
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='swap_network_port',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{port: ' + port0 + '}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ @decorators.idempotent_id('3eeb0dff-5d2d-4178-a4e6-06e4c26ce23a')
+ def test_create_update_server_swap_subnet_network(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - subnet: {get_resource: subnet}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{subnet: {get_resource: subnet}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='swap_subnet_network',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ @decorators.idempotent_id('647fda5d-fc0c-4eb1-9ce3-c4c537461324')
+ def test_create_update_server_add_subnet(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='add_subnet',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}, subnet: {get_resource: subnet}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ @decorators.idempotent_id('01c0f1cd-25b2-49b9-b4ac-fc4dd8937e42')
+ def test_create_update_server_add_same_fixed_ip(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - network: {get_resource: net}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ fixed_ip: <the_same_ip_already_allocated>
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='same_fixed_ip',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ port0_ip = self.get_outputs(stack_identifier, 'port0_ip_addr')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}, fixed_ip: ' + port0_ip + '}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ @decorators.idempotent_id('abc39cd6-7745-4314-ac04-85df532dd7c9')
+ def test_create_update_server_add_network(self):
+ '''Test updating stack with:
+
+ old_snippet
+ networks:
+ - subnet: {get_resource: subnet}
+ new_snippet
+ networks:
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+ '''
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', '[{subnet: {get_resource: subnet}}]')
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='add_network',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS',
+ '[{network: {get_resource: net}, subnet: {get_resource: subnet}}]')
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+
+ @decorators.idempotent_id('3f729e7e-a698-4ee3-8a5e-0db84f16d1e1')
+ def test_create_update_server_multi_networks_swaps(self):
+ '''Test updating stack with:
+
+ old_snippet:
+ networks:
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ fixed_ip: 11.11.11.33
+ - subnet: {get_resource: subnet}
+ new_snippet:
+ networks:
+ - subnet: {get_resource: subnet}
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+ '''
+ old_snippet = """
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ fixed_ip: 11.11.11.33
+ - subnet: {get_resource: subnet}
+"""
+ new_snippet = """
+ - subnet: {get_resource: subnet}
+ - network: {get_resource: net}
+ - network: {get_resource: net}
+ subnet: {get_resource: subnet}
+"""
+ template = server_with_no_nets_template.replace(
+ '$NETWORKS', old_snippet)
+ stack_identifier = self.stack_create(
+ template=template,
+ stack_name='multi_networks_swaps',
+ parameters=self.params)
+ port0 = self.get_outputs(stack_identifier, 'port0_id')
+ port1 = self.get_outputs(stack_identifier, 'port1_id')
+ port2 = self.get_outputs(stack_identifier, 'port2_id')
+ template_update = server_with_no_nets_template.replace(
+ '$NETWORKS', new_snippet)
+ self.update_stack(stack_identifier, template_update,
+ parameters=self.params)
+ self.assertEqual(port0, self.get_outputs(stack_identifier, 'port0_id'))
+ self.assertEqual(port1, self.get_outputs(stack_identifier, 'port1_id'))
+ self.assertEqual(port2, self.get_outputs(stack_identifier, 'port2_id'))
diff --git a/heat_tempest_plugin/tests/functional/test_octavia_lbaas.py b/heat_tempest_plugin/tests/functional/test_octavia_lbaas.py
new file mode 100644
index 0000000..b1e500c
--- /dev/null
+++ b/heat_tempest_plugin/tests/functional/test_octavia_lbaas.py
@@ -0,0 +1,101 @@
+# 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 heat_tempest_plugin.common import test
+from heat_tempest_plugin.tests.functional import functional_base
+
+
+@test.requires_resource_type('OS::Octavia::LoadBalancer')
+class LoadBalancerTest(functional_base.FunctionalTestsBase):
+ def setUp(self):
+ super(LoadBalancerTest, self).setUp()
+ self.template_name = 'octavia_lbaas.yaml'
+ self.member_template_name = 'lb_member.yaml'
+ self.sub_dir = 'templates'
+
+ def _create_stack(self):
+ self.parameters = {
+ 'flavor': self.conf.minimal_instance_type,
+ 'image': self.conf.minimal_image_ref,
+ 'network': self.conf.fixed_network_name,
+ 'subnet': self.conf.fixed_subnet_name
+ }
+ member_template = self._load_template(
+ __file__, self.member_template_name, self.sub_dir
+ )
+ self.files = {'lb_member.yaml': member_template}
+ self.env = {'resource_registry': {
+ 'OS::Test::PoolMember': 'lb_member.yaml'}}
+
+ self.template = self._load_template(__file__, self.template_name,
+ self.sub_dir)
+ return self.stack_create(template=self.template,
+ parameters=self.parameters,
+ files=self.files,
+ environment=self.env)
+
+ @decorators.idempotent_id('5d2c4452-4433-4438-899c-7711c01d3c50')
+ def test_create_update_loadbalancer(self):
+ stack_identifier = self._create_stack()
+ stack = self.client.stacks.get(stack_identifier)
+ output = self._stack_output(stack, 'loadbalancer')
+ self.assertEqual('ONLINE', output['operating_status'])
+ self.parameters['lb_algorithm'] = 'SOURCE_IP'
+
+ self.update_stack(stack_identifier,
+ template=self.template,
+ parameters=self.parameters,
+ files=self.files,
+ environment=self.env)
+ stack = self.client.stacks.get(stack_identifier)
+
+ output = self._stack_output(stack, 'loadbalancer')
+ self.assertEqual('ONLINE', output['operating_status'])
+ output = self._stack_output(stack, 'pool')
+ self.assertEqual('SOURCE_IP', output['lb_algorithm'])
+
+ @decorators.idempotent_id('970e91af-1be8-4990-837b-66f9b5aff2b9')
+ def test_add_delete_poolmember(self):
+ stack_identifier = self._create_stack()
+ stack = self.client.stacks.get(stack_identifier)
+ output = self._stack_output(stack, 'loadbalancer')
+ self.assertEqual('ONLINE', output['operating_status'])
+ output = self._stack_output(stack, 'pool')
+ self.assertEqual(1, len(output['members']))
+ # add pool member
+ self.parameters['member_count'] = 2
+ self.update_stack(stack_identifier,
+ template=self.template,
+ parameters=self.parameters,
+ files=self.files,
+ environment=self.env)
+ stack = self.client.stacks.get(stack_identifier)
+
+ output = self._stack_output(stack, 'loadbalancer')
+ self.assertEqual('ONLINE', output['operating_status'])
+ output = self._stack_output(stack, 'pool')
+ self.assertEqual(2, len(output['members']))
+ # delete pool member
+ self.parameters['member_count'] = 1
+ self.update_stack(stack_identifier,
+ template=self.template,
+ parameters=self.parameters,
+ files=self.files,
+ environment=self.env)
+ stack = self.client.stacks.get(stack_identifier)
+
+ output = self._stack_output(stack, 'loadbalancer')
+ self.assertEqual('ONLINE', output['operating_status'])
+ output = self._stack_output(stack, 'pool')
+ self.assertEqual(1, len(output['members']))
diff --git a/heat_tempest_plugin/tests/functional/test_os_wait_condition.py b/heat_tempest_plugin/tests/functional/test_os_wait_condition.py
index e19be4f..603b5e5 100644
--- a/heat_tempest_plugin/tests/functional/test_os_wait_condition.py
+++ b/heat_tempest_plugin/tests/functional/test_os_wait_condition.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -55,11 +57,11 @@
wc_notify --data-binary ''{"status": "SUCCESS", "reason":
"signal4", "data": "data4"}''
- # check signals with the same number
+ # check signals with the same ID
- wc_notify --data-binary ''{"status": "SUCCESS", "id": "5"}''
+ wc_notify --data-binary ''{"status": "SUCCESS", "id": "test5"}''
- wc_notify --data-binary ''{"status": "SUCCESS", "id": "5"}''
+ wc_notify --data-binary ''{"status": "SUCCESS", "id": "test5"}''
# loop for 20 signals without reasons and data
@@ -99,6 +101,7 @@
if not self.conf.minimal_instance_type:
raise self.skipException("No minimal flavor configured to test")
+ @decorators.idempotent_id('cc54ca6e-b91d-4ddd-80cc-24a886dfaaa0')
def test_create_stack_with_multi_signal_waitcondition(self):
params = {'flavor': self.conf.minimal_instance_type,
'image': self.conf.minimal_image_ref,
diff --git a/heat_tempest_plugin/tests/functional/test_preview.py b/heat_tempest_plugin/tests/functional/test_preview.py
index b1779dc..f1a6d72 100644
--- a/heat_tempest_plugin/tests/functional/test_preview.py
+++ b/heat_tempest_plugin/tests/functional/test_preview.py
@@ -10,9 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from heat_tempest_plugin.tests.functional import functional_base
from heatclient import exc
import six
+from tempest.lib import decorators
+
+from heat_tempest_plugin.tests.functional import functional_base
class StackPreviewTest(functional_base.FunctionalTestsBase):
@@ -88,6 +90,7 @@
self.assertEqual(stack_name, result['parameters']['OS::stack_name'])
self.assertEqual('abc', result['parameters']['incomming'])
+ @decorators.idempotent_id('4c2c062d-4723-42c0-a113-3307dd4ceb12')
def test_basic_pass(self):
stack_name = self._stack_rand_name()
result = self.client.stacks.preview(
@@ -114,6 +117,7 @@
self.assertEqual('abc', res['properties']['value'])
self.assertEqual([], res['required_by'])
+ @decorators.idempotent_id('54e69a54-762d-479e-a4f4-1fbf21af01c6')
def test_basic_fail(self):
stack_name = self._stack_rand_name()
@@ -131,6 +135,7 @@
': The Parameter (missing) was not provided.',
six.text_type(excp))
+ @decorators.idempotent_id('0449113c-ff90-4f2b-8825-27ea35c1983f')
def test_nested_pass(self):
"""Nested stacks need to recurse down the stacks."""
main_template = '''
@@ -187,6 +192,7 @@
self.assertEqual('abc', res['properties']['value'])
self.assertEqual([], res['required_by'])
+ @decorators.idempotent_id('6ca8ddfc-106f-4ecc-83f7-fca31d0c85ca')
def test_res_group_with_nested_template(self):
main_template = '''
heat_template_version: 2015-04-30
diff --git a/heat_tempest_plugin/tests/functional/test_remote_stack.py b/heat_tempest_plugin/tests/functional/test_remote_stack.py
index 4c53933..5e778e7 100644
--- a/heat_tempest_plugin/tests/functional/test_remote_stack.py
+++ b/heat_tempest_plugin/tests/functional/test_remote_stack.py
@@ -13,6 +13,7 @@
from heatclient import exc
import six
+from tempest.lib import decorators
from heat_tempest_plugin.tests.functional import functional_base
@@ -49,6 +50,7 @@
self.template = self.template.replace('RegionOne',
self.conf.region)
+ @decorators.idempotent_id('7e735c40-24fb-4ef8-8585-d1c68b344476')
def test_remote_stack_alone(self):
stack_id = self.stack_create(template=self.remote_template)
expected_resources = {'random1': 'OS::Heat::RandomString'}
@@ -57,6 +59,7 @@
output_value = self._stack_output(stack, 'remote_key')
self.assertEqual(32, len(output_value))
+ @decorators.idempotent_id('aeed20d1-ebda-4544-9ace-16b0c8fc24f6')
def test_stack_create(self):
files = {'remote_stack.yaml': self.remote_template}
stack_id = self.stack_create(files=files)
@@ -80,6 +83,7 @@
remote_resources = {'random1': 'OS::Heat::RandomString'}
self.assertEqual(remote_resources, self.list_resources(remote_id))
+ @decorators.idempotent_id('830bfeae-6d8a-4cb2-823d-d8b6c3a740ad')
def test_stack_create_bad_region(self):
tmpl_bad_region = self.template.replace(self.conf.region, 'DARKHOLE')
files = {'remote_stack.yaml': self.remote_template}
@@ -94,6 +98,7 @@
'orchestration service in DARKHOLE region not found"')
self.assertEqual(error_msg, six.text_type(ex))
+ @decorators.idempotent_id('b2190dfc-d223-4595-b168-6c42b0f3a3e5')
def test_stack_resource_validation_fail(self):
tmpl_bad_format = self.remote_template.replace('resources', 'resource')
files = {'remote_stack.yaml': tmpl_bad_format}
@@ -106,6 +111,7 @@
'invalid: resource"') % self.conf.region
self.assertEqual(error_msg, six.text_type(ex))
+ @decorators.idempotent_id('141f0478-121b-4e61-bde7-d5551bfd1fc2')
def test_stack_update(self):
files = {'remote_stack.yaml': self.remote_template}
stack_id = self.stack_create(files=files)
@@ -137,6 +143,7 @@
self.assertEqual(remote_resources,
self.list_resources(rstack.id))
+ @decorators.idempotent_id('50841af8-bdf5-4df6-a075-dc061ada6833')
def test_stack_suspend_resume(self):
files = {'remote_stack.yaml': self.remote_template}
stack_id = self.stack_create(files=files)
diff --git a/heat_tempest_plugin/tests/functional/test_resources_list.py b/heat_tempest_plugin/tests/functional/test_resources_list.py
index 0a182ad..16c941f 100644
--- a/heat_tempest_plugin/tests/functional/test_resources_list.py
+++ b/heat_tempest_plugin/tests/functional/test_resources_list.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -35,6 +37,7 @@
class ResourcesList(functional_base.FunctionalTestsBase):
+ @decorators.idempotent_id('b65b5c82-68b0-42c9-82a0-c0e74e9ad906')
def test_filtering_with_depend(self):
stack_identifier = self.stack_create(template=test_template_depend)
[test2] = self.client.resources.list(stack_identifier,
@@ -42,6 +45,7 @@
self.assertEqual('CREATE_COMPLETE', test2.resource_status)
+ @decorators.idempotent_id('97a65d53-b449-4a43-8283-42d43b165756')
def test_required_by(self):
stack_identifier = self.stack_create(template=test_template_depend)
[test1] = self.client.resources.list(stack_identifier,
diff --git a/heat_tempest_plugin/tests/functional/test_software_config.py b/heat_tempest_plugin/tests/functional/test_software_config.py
index 2f31b29..f034096 100644
--- a/heat_tempest_plugin/tests/functional/test_software_config.py
+++ b/heat_tempest_plugin/tests/functional/test_software_config.py
@@ -20,6 +20,7 @@
import yaml
from oslo_utils import timeutils
+from tempest.lib import decorators
from heat_tempest_plugin.common import exceptions
from heat_tempest_plugin.common import test
@@ -69,6 +70,7 @@
enable_cleanup = True
+ @decorators.idempotent_id('8ee231ff-f80a-4a17-a860-5cda87e18ad0')
def test_deployments_metadata(self):
parms = {'flavor': self.conf.minimal_instance_type,
'network': self.conf.fixed_network_name,
@@ -102,6 +104,7 @@
for config_stack in config_stacks:
self._wait_for_stack_status(config_stack, 'CREATE_COMPLETE')
+ @decorators.idempotent_id('bd539232-b999-4bec-b47d-ff4822fc8b82')
def test_deployments_timeout_failed(self):
parms = {'flavor': self.conf.minimal_instance_type,
'network': self.conf.fixed_network_name,
@@ -226,6 +229,7 @@
queue_id = %(queue_id)s
'''
+ @decorators.idempotent_id('3af97ced-bead-4629-b78a-97762719e990')
def test_signal_queues(self):
parms = {'flavor': self.conf.minimal_instance_type,
'network': self.conf.fixed_network_name,
diff --git a/heat_tempest_plugin/tests/functional/test_stack_events.py b/heat_tempest_plugin/tests/functional/test_stack_events.py
index 0db852e..185ca4f 100644
--- a/heat_tempest_plugin/tests/functional/test_stack_events.py
+++ b/heat_tempest_plugin/tests/functional/test_stack_events.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -42,6 +44,7 @@
self.assertIsNotNone(event.resource_status_reason)
self.assertIsNotNone(event.id)
+ @decorators.idempotent_id('620f4f7c-74f8-48a4-a8b0-d06d0337f133')
def test_event(self):
parameters = {}
diff --git a/heat_tempest_plugin/tests/functional/test_stack_outputs.py b/heat_tempest_plugin/tests/functional/test_stack_outputs.py
index f629a97..1b20b7b 100644
--- a/heat_tempest_plugin/tests/functional/test_stack_outputs.py
+++ b/heat_tempest_plugin/tests/functional/test_stack_outputs.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -35,6 +37,7 @@
value: { get_attr: [test_resource_b, output] }
'''
+ @decorators.idempotent_id('a886dd67-4506-4a37-82ae-43f0a7d83f35')
def test_outputs(self):
stack_identifier = self.stack_create(
template=self.template
@@ -89,6 +92,7 @@
value: {get_attr: [test_resource_b, output]}
'''
+ @decorators.idempotent_id('aea0e495-4c77-4033-8c43-3351e9cb7b48')
def test_outputs_update_new_resource(self):
stack_identifier = self.stack_create(template=self.before_template)
self.update_stack(stack_identifier, template=self.after_template)
@@ -133,6 +137,7 @@
value: { get_param: foo }
'''
+ @decorators.idempotent_id('993a403c-c6e2-475d-a65d-a82b8c9e0c22')
def test_output_error_nested(self):
stack_identifier = self.stack_create(
template=self.nested_template,
diff --git a/heat_tempest_plugin/tests/functional/test_stack_tags.py b/heat_tempest_plugin/tests/functional/test_stack_tags.py
index a270950..55c262d 100644
--- a/heat_tempest_plugin/tests/functional/test_stack_tags.py
+++ b/heat_tempest_plugin/tests/functional/test_stack_tags.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -31,6 +33,7 @@
value: {get_param: input}
'''
+ @decorators.idempotent_id('67332e51-b427-42d5-ad8d-fd2ec334f361')
def test_stack_tag(self):
# Stack create with stack tags
tags = 'foo,bar'
@@ -66,9 +69,10 @@
empty_tags_stack = self.client.stacks.get(stack_identifier)
self.assertIsNone(empty_tags_stack.tags)
+ @decorators.idempotent_id('5ed79584-0684-4f9c-ae8e-44a8f874ec79')
def test_hidden_stack(self):
# Stack create with hidden stack tag
- tags = 'foo,hidden'
+ tags = 'foo,%s' % self.conf.hidden_stack_tag
self.stack_create(
template=self.template,
tags=tags)
diff --git a/heat_tempest_plugin/tests/functional/test_template_validate.py b/heat_tempest_plugin/tests/functional/test_template_validate.py
index ed85443..e41f952 100644
--- a/heat_tempest_plugin/tests/functional/test_template_validate.py
+++ b/heat_tempest_plugin/tests/functional/test_template_validate.py
@@ -14,6 +14,7 @@
import six
from heatclient import exc
+from tempest.lib import decorators
from heat_tempest_plugin.tests.functional import functional_base
@@ -86,6 +87,7 @@
length: {get_param: aparam}
'''
+ @decorators.idempotent_id('b65a80c2-a507-4deb-9e7e-43181cc05211')
def test_template_validate_basic(self):
ret = self.client.stacks.validate(template=self.random_template)
expected = {'Description': 'the stack description',
@@ -102,6 +104,7 @@
'resource_registry': {u'resources': {}}}}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('bf27371d-e202-4bae-9f13-2ef137958517')
def test_template_validate_override_default(self):
env = {'parameters': {'aparam': 5}}
ret = self.client.stacks.validate(template=self.random_template,
@@ -121,6 +124,7 @@
'resource_registry': {u'resources': {}}}}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('0278e03d-ed50-4909-b29d-9c4267d3fcd6')
def test_template_validate_override_none(self):
env = {'resource_registry': {
'OS::Heat::RandomString': 'OS::Heat::None'}}
@@ -142,6 +146,7 @@
u'resources': {}}}}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('acb1435b-f1db-4427-9121-7e3144ddb81e')
def test_template_validate_basic_required_param(self):
tmpl = self.random_template.replace('default: 10', '')
ret = self.client.stacks.validate(template=tmpl)
@@ -158,6 +163,7 @@
'resource_registry': {u'resources': {}}}}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('7aac1feb-8256-4f70-8459-5e9780d28904')
def test_template_validate_fail_version(self):
fail_template = self.random_template.replace('2014-10-16', 'invalid')
ex = self.assertRaises(exc.HTTPBadRequest,
@@ -165,6 +171,7 @@
template=fail_template)
self.assertIn('The template version is invalid', six.text_type(ex))
+ @decorators.idempotent_id('6a6472d2-71fa-4ebe-a2b6-20878838555b')
def test_template_validate_parameter_groups(self):
ret = self.client.stacks.validate(template=self.random_template_groups)
expected = {'Description': 'the stack description',
@@ -198,6 +205,7 @@
'resource_registry': {u'resources': {}}}}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('5100cf18-f52a-47a2-880c-d540edad149f')
def test_template_validate_nested_off(self):
files = {'mynested.yaml': self.random_template}
ret = self.client.stacks.validate(template=self.parent_template,
@@ -218,6 +226,7 @@
u'resources': {}}}}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('480bcf64-25ae-49c7-b147-7cbc27d09cea')
def test_template_validate_nested_on(self):
files = {'mynested.yaml': self.random_template}
ret = self.client.stacks.validate(template=self.parent_template_noprop,
@@ -244,6 +253,7 @@
u'resources': {}}}}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('a0bb07f0-2e10-4226-a205-a7eb04df415f')
def test_template_validate_nested_on_multiple(self):
# parent_template -> nested_template -> random_template
nested_template = self.random_template.replace(
diff --git a/heat_tempest_plugin/tests/functional/test_templates.py b/heat_tempest_plugin/tests/functional/test_templates.py
index 95c6a01..5cb7b66 100644
--- a/heat_tempest_plugin/tests/functional/test_templates.py
+++ b/heat_tempest_plugin/tests/functional/test_templates.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
from heat_tempest_plugin.tests.functional import functional_base
@@ -38,6 +39,7 @@
}
}
+ @decorators.idempotent_id('ac6ebc41-bd6a-4df4-80e5-f4b9ae3b5506')
def test_get_stack_template(self):
stack_identifier = self.stack_create(
template=self.template
@@ -45,11 +47,13 @@
template_from_client = self.client.stacks.template(stack_identifier)
self.assertEqual(self.template, template_from_client)
+ @decorators.idempotent_id('9f9a2fc0-f029-4d1f-a2eb-f019b9f75944')
def test_resource_types(self):
resource_types = self.client.resource_types.list()
self.assertTrue(any(resource.resource_type == "OS::Heat::TestResource"
for resource in resource_types))
+ @decorators.idempotent_id('fafbdcd0-eec3-4e6f-9c88-1e4835d085cf')
def test_show_resource_template(self):
resource_details = self.client.resource_types.get(
resource_type="OS::Heat::TestResource"
diff --git a/heat_tempest_plugin/tests/functional/test_unicode_template.py b/heat_tempest_plugin/tests/functional/test_unicode_template.py
index 9184455..02bad65 100644
--- a/heat_tempest_plugin/tests/functional/test_unicode_template.py
+++ b/heat_tempest_plugin/tests/functional/test_unicode_template.py
@@ -10,6 +10,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest.lib import decorators
+
from heat_tempest_plugin.tests.functional import functional_base
@@ -61,6 +63,7 @@
self.assertEqual('OS::Heat::RandomString',
result['resource_type'])
+ @decorators.idempotent_id('871cc5dd-7550-494d-8c6d-9d549a8c0305')
def test_template_validate_basic(self):
ret = self.client.stacks.validate(template=self.random_template)
expected = {
@@ -82,6 +85,7 @@
}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('e84c76b8-a5e5-45e7-9c4b-4c160d1c385f')
def test_template_validate_override_default(self):
env = {'parameters': {u'\u53c2\u6570': 5}}
ret = self.client.stacks.validate(template=self.random_template,
@@ -106,6 +110,7 @@
}
self.assertEqual(expected, ret)
+ @decorators.idempotent_id('66338945-a3ae-4e3a-aa17-ab802ceb00b1')
def test_stack_preview(self):
result = self.client.stacks.preview(
template=self.random_template,
@@ -113,6 +118,7 @@
disable_rollback=True).to_dict()
self._assert_preview_results(result)
+ @decorators.idempotent_id('d2c4a10c-3cb4-4efd-889d-695a0acbd04f')
def test_create_stack(self):
stack_identifier = self.stack_create(template=self.random_template)
stack = self.client.stacks.get(stack_identifier)
diff --git a/heat_tempest_plugin/tests/functional/test_waitcondition.py b/heat_tempest_plugin/tests/functional/test_waitcondition.py
index 84d8ef1..b50c0a2 100644
--- a/heat_tempest_plugin/tests/functional/test_waitcondition.py
+++ b/heat_tempest_plugin/tests/functional/test_waitcondition.py
@@ -13,6 +13,7 @@
import json
from keystoneclient.v3 import client as keystoneclient
+from tempest.lib import decorators
from zaqarclient.queues.v2 import client as zaqarclient
from heat_tempest_plugin.tests.functional import functional_base
@@ -38,6 +39,7 @@
value: {'Fn::Select': ['data_id', {get_attr: [wait_condition, data]}]}
'''
+ @decorators.idempotent_id('90183f0d-9929-43a6-8fb6-b81003824c6d')
def test_signal_queues(self):
stack_identifier = self.stack_create(
template=self.template,
diff --git a/heat_tempest_plugin/tests/scenario/test_aodh_alarm.py b/heat_tempest_plugin/tests/scenario/test_aodh_alarm.py
index 3108c1e..4e25158 100644
--- a/heat_tempest_plugin/tests/scenario/test_aodh_alarm.py
+++ b/heat_tempest_plugin/tests/scenario/test_aodh_alarm.py
@@ -11,7 +11,9 @@
# under the License.
import datetime
+
from oslo_log import log as logging
+from tempest.lib import decorators
from heat_tempest_plugin.common import test
from heat_tempest_plugin.tests.scenario import scenario_base
@@ -35,6 +37,7 @@
actual))
return actual == expected
+ @decorators.idempotent_id('fc0f18a6-f65c-4df1-b9c5-e160dea59849')
def test_alarm(self):
"""Confirm we can create an alarm and trigger it."""
# create metric
diff --git a/heat_tempest_plugin/tests/scenario/test_autoscaling_lb.py b/heat_tempest_plugin/tests/scenario/test_autoscaling_lb.py
index e576867..23e27c7 100644
--- a/heat_tempest_plugin/tests/scenario/test_autoscaling_lb.py
+++ b/heat_tempest_plugin/tests/scenario/test_autoscaling_lb.py
@@ -14,6 +14,7 @@
import time
import requests
+from tempest.lib import decorators
from heat_tempest_plugin.common import test
from heat_tempest_plugin.tests.scenario import scenario_base
@@ -48,6 +49,7 @@
resp.add(r.text)
self.assertEqual(expected_num, len(resp))
+ @decorators.idempotent_id('48ddbc45-cef6-4640-acd6-7efc281833b9')
def test_autoscaling_loadbalancer_neutron(self):
"""Check work of AutoScaing and Neutron LBaaS v1 resource in Heat.
@@ -104,7 +106,7 @@
test.call_until_true(self.conf.build_timeout,
self.conf.build_interval,
self.check_autoscale_complete,
- asg.physical_resource_id, 2, sid, 'scale_up')
+ asg.physical_resource_id, 2, sid, 'asg')
# Check number of distinctive responses, must now be 2
self.check_num_responses(lb_url, 2)
diff --git a/heat_tempest_plugin/tests/scenario/test_autoscaling_lbv2.py b/heat_tempest_plugin/tests/scenario/test_autoscaling_lbv2.py
index 65fa91c..c3bda78 100644
--- a/heat_tempest_plugin/tests/scenario/test_autoscaling_lbv2.py
+++ b/heat_tempest_plugin/tests/scenario/test_autoscaling_lbv2.py
@@ -14,6 +14,7 @@
import time
import requests
+from tempest.lib import decorators
from heat_tempest_plugin.common import test
from heat_tempest_plugin.tests.scenario import scenario_base
@@ -50,6 +51,7 @@
break
self.assertEqual(expected_num, len(resp))
+ @decorators.idempotent_id('89459930-aa61-4557-989b-3429d3b3b612')
def test_autoscaling_loadbalancer_neutron(self):
"""Check work of AutoScaing and Neutron LBaaS v2 resource in Heat.
@@ -104,7 +106,7 @@
test.call_until_true(self.conf.build_timeout,
self.conf.build_interval,
self.check_autoscale_complete,
- asg.physical_resource_id, 2, sid, 'scale_up')
+ asg.physical_resource_id, 2, sid, 'asg')
# Check number of distinctive responses, must now be 2
self.check_num_responses(lb_url, 2)
diff --git a/heat_tempest_plugin/tests/scenario/test_base_resources.py b/heat_tempest_plugin/tests/scenario/test_base_resources.py
index e63242e..ddd8564 100644
--- a/heat_tempest_plugin/tests/scenario/test_base_resources.py
+++ b/heat_tempest_plugin/tests/scenario/test_base_resources.py
@@ -10,9 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+from heatclient.common import template_utils
+from tempest.lib import decorators
+
from heat_tempest_plugin.common import test
from heat_tempest_plugin.tests.scenario import scenario_base
-from heatclient.common import template_utils
class BasicResourcesTest(scenario_base.ScenarioTestsBase):
@@ -38,6 +40,7 @@
server_networks = self._stack_output(stack, 'server_networks')
self.assertIn(self.private_net_name, server_networks)
+ @decorators.idempotent_id('bd151ea4-2dcd-4440-9bf0-eff63a98e5d4')
def test_base_resources_integration(self):
"""Define test for base resources interation from core porjects
diff --git a/heat_tempest_plugin/tests/scenario/test_server_cfn_init.py b/heat_tempest_plugin/tests/scenario/test_server_cfn_init.py
index 5ea0fb9..963d1ad 100644
--- a/heat_tempest_plugin/tests/scenario/test_server_cfn_init.py
+++ b/heat_tempest_plugin/tests/scenario/test_server_cfn_init.py
@@ -12,6 +12,8 @@
import json
+from tempest.lib import decorators
+
from heat_tempest_plugin.common import exceptions
from heat_tempest_plugin.tests.scenario import scenario_base
@@ -92,6 +94,7 @@
self._log_console_output(servers=[server])
raise
+ @decorators.idempotent_id('3f7726fc-a41b-40ca-ab38-51e2973f146a')
def test_server_cfn_init(self):
"""Check cfn-init and cfn-signal availability on the created server.
diff --git a/heat_tempest_plugin/tests/scenario/test_server_signal.py b/heat_tempest_plugin/tests/scenario/test_server_signal.py
index a49a21b..1823087 100644
--- a/heat_tempest_plugin/tests/scenario/test_server_signal.py
+++ b/heat_tempest_plugin/tests/scenario/test_server_signal.py
@@ -13,6 +13,8 @@
import json
+from tempest.lib import decorators
+
from heat_tempest_plugin.common import exceptions
from heat_tempest_plugin.tests.scenario import scenario_base
@@ -27,6 +29,7 @@
'key_name': self.keypair_name,
'flavor': flavor,
'image': image,
+ 'public_net': self.conf.floating_network_name,
'timeout': self.conf.build_timeout,
'user_data_format': user_data_format
}
@@ -75,10 +78,12 @@
self.fail(
"Timed out waiting for %s to become reachable" % server_ip)
+ @decorators.idempotent_id('8da0f6cc-60e6-4298-9e54-e1f905c5552a')
def test_server_signal_userdata_format_raw(self):
self._test_server_signal(image=self.conf.minimal_image_ref,
flavor=self.conf.minimal_instance_type)
+ @decorators.idempotent_id('3d753d42-7c16-4a0e-8f73-875881826626')
def test_server_signal_userdata_format_software_config(self):
if not self.conf.image_ref:
raise self.skipException("No image configured to test")
diff --git a/heat_tempest_plugin/tests/scenario/test_server_software_config.py b/heat_tempest_plugin/tests/scenario/test_server_software_config.py
index 1546684..4d2f7dc 100644
--- a/heat_tempest_plugin/tests/scenario/test_server_software_config.py
+++ b/heat_tempest_plugin/tests/scenario/test_server_software_config.py
@@ -12,6 +12,7 @@
from heatclient.common import template_utils
import six
+from tempest.lib import decorators
from heat_tempest_plugin.tests.scenario import scenario_base
@@ -132,6 +133,7 @@
dep1_dep.updated_time,
dep1_dep.creation_time)
+ @decorators.idempotent_id('fb2afe23-d1a8-45fc-bf8d-b18fc8412972')
def test_server_software_config(self):
"""Check that passed files with scripts are executed on created server.
diff --git a/heat_tempest_plugin/tests/scenario/test_volumes.py b/heat_tempest_plugin/tests/scenario/test_volumes.py
index eea6e97..57d0936 100644
--- a/heat_tempest_plugin/tests/scenario/test_volumes.py
+++ b/heat_tempest_plugin/tests/scenario/test_volumes.py
@@ -14,6 +14,7 @@
from cinderclient import exceptions as cinder_exceptions
from oslo_log import log as logging
import six
+from tempest.lib import decorators
from heat_tempest_plugin.common import exceptions
from heat_tempest_plugin.tests.scenario import scenario_base
@@ -98,6 +99,7 @@
self.volume_client.volumes.get,
volume_id2)
+ @decorators.idempotent_id('c3416735-87bf-4478-85c5-b3823819eb19')
def test_cinder_volume_create_backup_restore(self):
"""Ensure the 'Snapshot' deletion policy works.
diff --git a/releasenotes/notes/support-check-uuid-aa577427e4d32e4b.yaml b/releasenotes/notes/support-check-uuid-aa577427e4d32e4b.yaml
new file mode 100644
index 0000000..053c240
--- /dev/null
+++ b/releasenotes/notes/support-check-uuid-aa577427e4d32e4b.yaml
@@ -0,0 +1,7 @@
+---
+other:
+ - |
+ We can now run check-uuid to check if we give tempest id for all tempest
+ tests (not includes tests which run with gabbits) by running
+ ``tox -e pep8``. Also now you can run ``tox -e uuidgen`` for automatically
+ add ids to tests.
diff --git a/requirements.txt b/requirements.txt
index 34fa1fd..43abf78 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,9 +1,8 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT
-keystoneauth1>=3.3.0 # Apache-2.0
-oslo.config>=5.1.0 # Apache-2.0
+keystoneauth1>=3.4.0 # Apache-2.0
+oslo.config>=5.2.0 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
oslo.messaging>=5.29.0 # Apache-2.0
os-collect-config>=5.0.0 # Apache-2.0
@@ -11,12 +10,12 @@
python-cinderclient>=3.3.0 # Apache-2.0
gnocchiclient>=3.3.1 # Apache-2.0
python-heatclient>=1.10.0 # Apache-2.0
-python-neutronclient>=6.3.0 # Apache-2.0
+python-neutronclient>=6.7.0 # Apache-2.0
python-novaclient>=9.1.0 # Apache-2.0
python-swiftclient>=3.2.0 # Apache-2.0
python-zaqarclient>=1.0.0 # Apache-2.0
testtools>=2.2.0 # MIT
testscenarios>=0.4 # Apache-2.0/BSD
tempest>=17.1.0 # Apache-2.0
-gabbi>=1.35.0 # Apache-2.0
+gabbi>=1.42.1 # Apache-2.0
kombu!=4.0.2,>=4.0.0 # BSD
diff --git a/test-requirements.txt b/test-requirements.txt
index 9f37a05..f6c0a00 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -4,5 +4,5 @@
# Hacking already pins down pep8, pyflakes and flake8
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
-openstackdocstheme>=1.17.0 # Apache-2.0
-sphinx!=1.6.6,>=1.6.2 # BSD
+openstackdocstheme>=1.18.1 # Apache-2.0
+sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
diff --git a/tox.ini b/tox.ini
index ece89c6..7b8aeec 100644
--- a/tox.ini
+++ b/tox.ini
@@ -12,7 +12,17 @@
testr run {posargs}
[testenv:pep8]
-commands = flake8
+setenv =
+ PYTHONPATH = .
+commands =
+ flake8
+ check-uuid --package heat_tempest_plugin
+
+[testenv:uuidgen]
+setenv =
+ PYTHONPATH = .
+commands =
+ check-uuid --fix --package heat_tempest_plugin
[testenv:docs]
deps = -r{toxinidir}/requirements.txt