From 17d868572d9da79498f4ac87bdf95e2b0ccb42b5 Mon Sep 17 00:00:00 2001 From: ricolin Date: Fri, 22 Dec 2017 15:18:09 +0800 Subject: [PATCH] Clear heat inner functionaltests This patch remove regression tests from heat tempest plugin. We already maintain those tests in heat. Also remove AutoscalingLoadBalancerTest and ReloadOnSighupTest since we don't test anymore. Depends-On: Ief31dc961bc108e2863119598dfb16581a38e9cf Change-Id: I022077c92bc10e908c7fe549ed555ad0194e0704 --- heat_tempest_plugin/config.py | 12 - .../tests/functional/test_admin_actions.py | 101 -- .../tests/functional/test_autoscaling.py | 752 -------------- .../tests/functional/test_aws_stack.py | 201 ---- .../tests/functional/test_cancel_update.py | 61 -- .../functional/test_conditional_exposure.py | 157 --- .../tests/functional/test_conditions.py | 619 ----------- .../tests/functional/test_create_update.py | 710 ------------- .../functional/test_default_parameters.py | 92 -- .../tests/functional/test_delete.py | 42 - .../tests/functional/test_env_merge.py | 95 -- .../tests/functional/test_heat_autoscaling.py | 215 ---- .../functional/test_immutable_parameters.py | 141 --- .../tests/functional/test_instance_group.py | 500 --------- .../tests/functional/test_nested_get_attr.py | 165 --- .../tests/functional/test_notifications.py | 194 ---- .../tests/functional/test_preview_update.py | 298 ------ .../tests/functional/test_purge.py | 51 - .../tests/functional/test_reload_on_sighup.py | 142 --- .../functional/test_replace_deprecated.py | 92 -- .../tests/functional/test_resource_chain.py | 167 --- .../tests/functional/test_resource_group.py | 695 ------------- .../functional/test_simultaneous_update.py | 93 -- .../tests/functional/test_snapshot_restore.py | 76 -- .../test_software_deployment_group.py | 150 --- .../tests/functional/test_stack_cancel.py | 92 -- .../functional/test_swiftsignal_update.py | 46 - .../functional/test_template_resource.py | 982 ------------------ .../tests/functional/test_templates.py | 18 +- .../tests/functional/test_translation.py | 117 --- .../functional/test_update_restricted.py | 166 --- .../tests/functional/test_validation.py | 92 -- 32 files changed, 2 insertions(+), 7332 deletions(-) delete mode 100644 heat_tempest_plugin/tests/functional/test_admin_actions.py delete mode 100644 heat_tempest_plugin/tests/functional/test_autoscaling.py delete mode 100644 heat_tempest_plugin/tests/functional/test_aws_stack.py delete mode 100644 heat_tempest_plugin/tests/functional/test_cancel_update.py delete mode 100644 heat_tempest_plugin/tests/functional/test_conditional_exposure.py delete mode 100644 heat_tempest_plugin/tests/functional/test_conditions.py delete mode 100644 heat_tempest_plugin/tests/functional/test_create_update.py delete mode 100644 heat_tempest_plugin/tests/functional/test_default_parameters.py delete mode 100644 heat_tempest_plugin/tests/functional/test_delete.py delete mode 100644 heat_tempest_plugin/tests/functional/test_env_merge.py delete mode 100644 heat_tempest_plugin/tests/functional/test_heat_autoscaling.py delete mode 100644 heat_tempest_plugin/tests/functional/test_immutable_parameters.py delete mode 100644 heat_tempest_plugin/tests/functional/test_instance_group.py delete mode 100644 heat_tempest_plugin/tests/functional/test_nested_get_attr.py delete mode 100644 heat_tempest_plugin/tests/functional/test_notifications.py delete mode 100644 heat_tempest_plugin/tests/functional/test_preview_update.py delete mode 100644 heat_tempest_plugin/tests/functional/test_purge.py delete mode 100644 heat_tempest_plugin/tests/functional/test_reload_on_sighup.py delete mode 100644 heat_tempest_plugin/tests/functional/test_replace_deprecated.py delete mode 100644 heat_tempest_plugin/tests/functional/test_resource_chain.py delete mode 100644 heat_tempest_plugin/tests/functional/test_resource_group.py delete mode 100644 heat_tempest_plugin/tests/functional/test_simultaneous_update.py delete mode 100644 heat_tempest_plugin/tests/functional/test_snapshot_restore.py delete mode 100644 heat_tempest_plugin/tests/functional/test_software_deployment_group.py delete mode 100644 heat_tempest_plugin/tests/functional/test_stack_cancel.py delete mode 100644 heat_tempest_plugin/tests/functional/test_swiftsignal_update.py delete mode 100644 heat_tempest_plugin/tests/functional/test_template_resource.py delete mode 100644 heat_tempest_plugin/tests/functional/test_translation.py delete mode 100644 heat_tempest_plugin/tests/functional/test_update_restricted.py delete mode 100644 heat_tempest_plugin/tests/functional/test_validation.py diff --git a/heat_tempest_plugin/config.py b/heat_tempest_plugin/config.py index 6d2ead6..d658a98 100644 --- a/heat_tempest_plugin/config.py +++ b/heat_tempest_plugin/config.py @@ -122,9 +122,6 @@ HeatGroup = [ default=60, help="Timeout in seconds to wait for output from ssh " "channel."), - cfg.IntOpt('tenant_network_mask_bits', - default=28, - help="The mask bits for tenant ipv4 subnets"), cfg.BoolOpt('skip_scenario_tests', default=False, help="Skip all scenario tests"), @@ -153,15 +150,6 @@ HeatGroup = [ default=120, help="Timeout in seconds to wait for connectivity to " "server."), - cfg.IntOpt('sighup_timeout', - default=120, - help="Timeout in seconds to wait for adding or removing child " - "process after receiving of sighup signal"), - cfg.IntOpt('sighup_config_edit_retries', - default=10, - help='Count of retries to edit config file during sighup. If ' - 'another worker already edit config file, file can be ' - 'busy, so need to wait and try edit file again.'), cfg.StrOpt('heat_config_notify_script', default=('heat-config-notify'), help="Path to the script heat-config-notify"), diff --git a/heat_tempest_plugin/tests/functional/test_admin_actions.py b/heat_tempest_plugin/tests/functional/test_admin_actions.py deleted file mode 100644 index 757b03c..0000000 --- a/heat_tempest_plugin/tests/functional/test_admin_actions.py +++ /dev/null @@ -1,101 +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 heat_tempest_plugin.tests.functional import functional_base - -# Simple stack -test_template = { - 'heat_template_version': '2013-05-23', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1' - } - } - } -} - -# Nested stack -rsg_template = { - 'heat_template_version': '2013-05-23', - 'resources': { - 'random_group': { - 'type': 'OS::Heat::ResourceGroup', - 'properties': { - 'count': 2, - 'resource_def': { - 'type': 'OS::Heat::RandomString', - 'properties': { - 'length': 30, - 'salt': 'initial' - } - } - } - } - } -} - - -class AdminActionsTest(functional_base.FunctionalTestsBase): - - def setUp(self): - super(AdminActionsTest, self).setUp() - if not self.conf.admin_username or not self.conf.admin_password: - self.skipTest('No admin creds found, skipping') - - def create_stack_setup_admin_client(self, template=test_template): - # Create the stack with the default user - self.stack_identifier = self.stack_create(template=template) - - # Setup admin clients - self.setup_clients_for_admin() - - def test_admin_simple_stack_actions(self): - self.create_stack_setup_admin_client() - - updated_template = test_template.copy() - props = updated_template['resources']['test1']['properties'] - props['value'] = 'new_value' - - # Update, suspend and resume stack - self.update_stack(self.stack_identifier, - template=updated_template) - self.stack_suspend(self.stack_identifier) - self.stack_resume(self.stack_identifier) - - # List stack resources - initial_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(self.stack_identifier)) - # Delete stack - self._stack_delete(self.stack_identifier) - - def test_admin_complex_stack_actions(self): - self.create_stack_setup_admin_client(template=rsg_template) - - updated_template = rsg_template.copy() - props = updated_template['resources']['random_group']['properties'] - props['count'] = 3 - - # Update, suspend and resume stack - self.update_stack(self.stack_identifier, - template=updated_template) - self.stack_suspend(self.stack_identifier) - self.stack_resume(self.stack_identifier) - - # List stack resources - resources = {'random_group': 'OS::Heat::ResourceGroup'} - self.assertEqual(resources, - self.list_resources(self.stack_identifier)) - # Delete stack - self._stack_delete(self.stack_identifier) diff --git a/heat_tempest_plugin/tests/functional/test_autoscaling.py b/heat_tempest_plugin/tests/functional/test_autoscaling.py deleted file mode 100644 index d266646..0000000 --- a/heat_tempest_plugin/tests/functional/test_autoscaling.py +++ /dev/null @@ -1,752 +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 -import json - -from heatclient import exc -from oslo_log import log as logging -import six -from testtools import matchers - -from heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - - -LOG = logging.getLogger(__name__) - - -class AutoscalingGroupTest(functional_base.FunctionalTestsBase): - - template = ''' -{ - "AWSTemplateFormatVersion" : "2010-09-09", - "Description" : "Template to create multiple instances.", - "Parameters" : {"size": {"Type": "String", "Default": "1"}, - "AZ": {"Type": "String", "Default": "nova"}, - "image": {"Type": "String"}, - "flavor": {"Type": "String"}, - "user_data": {"Type": "String", "Default": "jsconfig data"}}, - "Resources": { - "JobServerGroup": { - "Type" : "AWS::AutoScaling::AutoScalingGroup", - "Properties" : { - "AvailabilityZones" : [{"Ref": "AZ"}], - "LaunchConfigurationName" : { "Ref" : "JobServerConfig" }, - "MinSize" : {"Ref": "size"}, - "MaxSize" : "20" - } - }, - - "JobServerConfig" : { - "Type" : "AWS::AutoScaling::LaunchConfiguration", - "Metadata": {"foo": "bar"}, - "Properties": { - "ImageId" : {"Ref": "image"}, - "InstanceType" : {"Ref": "flavor"}, - "SecurityGroups" : [ "sg-1" ], - "UserData" : {"Ref": "user_data"} - } - } - }, - "Outputs": { - "InstanceList": {"Value": { - "Fn::GetAtt": ["JobServerGroup", "InstanceList"]}}, - "JobServerConfigRef": {"Value": { - "Ref": "JobServerConfig"}} - } -} -''' - - instance_template = ''' -heat_template_version: 2013-05-23 -parameters: - ImageId: {type: string} - InstanceType: {type: string} - SecurityGroups: {type: comma_delimited_list} - UserData: {type: string} - Tags: {type: comma_delimited_list, default: "x,y"} - -resources: - random1: - type: OS::Heat::RandomString - properties: - salt: {get_param: UserData} -outputs: - PublicIp: {value: {get_attr: [random1, value]}} - AvailabilityZone: {value: 'not-used11'} - PrivateDnsName: {value: 'not-used12'} - PublicDnsName: {value: 'not-used13'} - PrivateIp: {value: 'not-used14'} -''' - - # This is designed to fail. - bad_instance_template = ''' -heat_template_version: 2013-05-23 -parameters: - ImageId: {type: string} - InstanceType: {type: string} - SecurityGroups: {type: comma_delimited_list} - UserData: {type: string} - Tags: {type: comma_delimited_list, default: "x,y"} - -resources: - random1: - type: OS::Heat::RandomString - depends_on: waiter - ready_poster: - type: AWS::CloudFormation::WaitConditionHandle - waiter: - type: AWS::CloudFormation::WaitCondition - properties: - Handle: {get_resource: ready_poster} - Timeout: 1 -outputs: - PublicIp: - value: {get_attr: [random1, value]} -''' - - def setUp(self): - super(AutoscalingGroupTest, self).setUp() - if not self.conf.minimal_image_ref: - raise self.skipException("No minimal image configured to test") - if not self.conf.instance_type: - raise self.skipException("No flavor configured to test") - - def assert_instance_count(self, stack, expected_count): - inst_list = self._stack_output(stack, 'InstanceList') - self.assertEqual(expected_count, len(inst_list.split(','))) - - def _assert_instance_state(self, nested_identifier, - num_complete, num_failed): - for res in self.client.resources.list(nested_identifier): - if 'COMPLETE' in res.resource_status: - num_complete = num_complete - 1 - elif 'FAILED' in res.resource_status: - num_failed = num_failed - 1 - self.assertEqual(0, num_failed) - self.assertEqual(0, num_complete) - - -class AutoscalingGroupBasicTest(AutoscalingGroupTest): - - def test_basic_create_works(self): - """Make sure the working case is good. - - Note this combines test_override_aws_ec2_instance into this test as - well, which is: - If AWS::EC2::Instance is overridden, AutoScalingGroup will - automatically use that overridden resource type. - """ - - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 4, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - stack_identifier = self.stack_create(template=self.template, - files=files, environment=env) - initial_resources = { - 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration', - 'JobServerGroup': 'AWS::AutoScaling::AutoScalingGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 4) - - def test_size_updates_work(self): - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 2, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - stack_identifier = self.stack_create(template=self.template, - files=files, - environment=env) - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 2) - - # Increase min size to 5 - env2 = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 5, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - self.update_stack(stack_identifier, self.template, - environment=env2, files=files) - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 5) - - def test_update_group_replace(self): - """Test case for ensuring non-updatable props case a replacement. - - Make sure that during a group update the non-updatable - properties cause a replacement. - """ - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': - {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': '1', - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - stack_identifier = self.stack_create(template=self.template, - files=files, - environment=env) - rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup') - orig_asg_id = rsrc.physical_resource_id - - env2 = {'resource_registry': - {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': '1', - 'AZ': 'wibble', - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type, - 'user_data': 'new data'}} - self.update_stack(stack_identifier, self.template, - environment=env2, files=files) - - # replacement will cause the resource physical_resource_id to change. - rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup') - self.assertNotEqual(orig_asg_id, rsrc.physical_resource_id) - - def test_create_instance_error_causes_group_error(self): - """Test create failing a resource in the instance group. - - If a resource in an instance group fails to be created, the instance - group itself will fail and the broken inner resource will remain. - """ - stack_name = self._stack_rand_name() - files = {'provider.yaml': self.bad_instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 2, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - self.client.stacks.create( - stack_name=stack_name, - template=self.template, - files=files, - disable_rollback=True, - parameters={}, - environment=env - ) - self.addCleanup(self._stack_delete, stack_name) - stack = self.client.stacks.get(stack_name) - stack_identifier = '%s/%s' % (stack_name, stack.id) - self._wait_for_stack_status(stack_identifier, 'CREATE_FAILED') - initial_resources = { - 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration', - 'JobServerGroup': 'AWS::AutoScaling::AutoScalingGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - self._assert_instance_state(nested_ident, 0, 2) - - def test_update_instance_error_causes_group_error(self): - """Test update failing a resource in the instance group. - - If a resource in an instance group fails to be created during an - update, the instance group itself will fail and the broken inner - resource will remain. - """ - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 2, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - stack_identifier = self.stack_create(template=self.template, - files=files, - environment=env) - initial_resources = { - 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration', - 'JobServerGroup': 'AWS::AutoScaling::AutoScalingGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 2) - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - self._assert_instance_state(nested_ident, 2, 0) - initial_list = [res.resource_name - for res in self.client.resources.list(nested_ident)] - - env['parameters']['size'] = 3 - files2 = {'provider.yaml': self.bad_instance_template} - self.client.stacks.update( - stack_id=stack_identifier, - template=self.template, - files=files2, - disable_rollback=True, - parameters={}, - environment=env - ) - self._wait_for_stack_status(stack_identifier, 'UPDATE_FAILED') - - # assert that there are 3 bad instances - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - - # 2 resources should be in update failed, and one create failed. - for res in self.client.resources.list(nested_ident): - if res.resource_name in initial_list: - self._wait_for_resource_status(nested_ident, - res.resource_name, - 'UPDATE_FAILED') - else: - self._wait_for_resource_status(nested_ident, - res.resource_name, - 'CREATE_FAILED') - - def test_group_suspend_resume(self): - - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 4, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - stack_identifier = self.stack_create(template=self.template, - files=files, environment=env) - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - - self.stack_suspend(stack_identifier) - self._wait_for_all_resource_status(nested_ident, 'SUSPEND_COMPLETE') - - self.stack_resume(stack_identifier) - self._wait_for_all_resource_status(nested_ident, 'RESUME_COMPLETE') - - -class AutoscalingGroupUpdatePolicyTest(AutoscalingGroupTest): - - def ig_tmpl_with_updt_policy(self): - templ = json.loads(copy.deepcopy(self.template)) - up = {"AutoScalingRollingUpdate": { - "MinInstancesInService": "1", - "MaxBatchSize": "2", - "PauseTime": "PT1S"}} - templ['Resources']['JobServerGroup']['UpdatePolicy'] = up - return templ - - def update_instance_group(self, updt_template, - num_updates_expected_on_updt, - num_creates_expected_on_updt, - num_deletes_expected_on_updt): - - # setup stack from the initial template - files = {'provider.yaml': self.instance_template} - size = 10 - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': size, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - stack_name = self._stack_rand_name() - stack_identifier = self.stack_create( - stack_name=stack_name, - template=self.ig_tmpl_with_updt_policy(), - files=files, - environment=env) - stack = self.client.stacks.get(stack_identifier) - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - - # test that physical resource name of launch configuration is used - conf_name = self._stack_output(stack, 'JobServerConfigRef') - conf_name_pattern = '%s-JobServerConfig-[a-zA-Z0-9]+$' % stack_name - self.assertThat(conf_name, - matchers.MatchesRegex(conf_name_pattern)) - - # test the number of instances created - self.assert_instance_count(stack, size) - # saves info from initial list of instances for comparison later - init_instances = self.client.resources.list(nested_ident) - init_names = [inst.resource_name for inst in init_instances] - - # test stack update - self.update_stack(stack_identifier, updt_template, - environment=env, files=files) - updt_stack = self.client.stacks.get(stack_identifier) - - # test that the launch configuration is replaced - updt_conf_name = self._stack_output(updt_stack, 'JobServerConfigRef') - self.assertThat(updt_conf_name, - matchers.MatchesRegex(conf_name_pattern)) - self.assertNotEqual(conf_name, updt_conf_name) - - # test that the group size are the same - updt_instances = self.client.resources.list(nested_ident) - updt_names = [inst.resource_name for inst in updt_instances] - self.assertEqual(len(init_names), len(updt_names)) - for res in updt_instances: - self.assertEqual('UPDATE_COMPLETE', res.resource_status) - - # test that the appropriate number of instance names are the same - matched_names = set(updt_names) & set(init_names) - self.assertEqual(num_updates_expected_on_updt, len(matched_names)) - - # test that the appropriate number of new instances are created - self.assertEqual(num_creates_expected_on_updt, - len(set(updt_names) - set(init_names))) - - # test that the appropriate number of instances are deleted - self.assertEqual(num_deletes_expected_on_updt, - len(set(init_names) - set(updt_names))) - - # test that the older instances are the ones being deleted - if num_deletes_expected_on_updt > 0: - deletes_expected = init_names[:num_deletes_expected_on_updt] - self.assertNotIn(deletes_expected, updt_names) - - def test_instance_group_update_replace(self): - """Test simple update replace. - - Test update replace with no conflict in batch size and minimum - instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - grp = updt_template['Resources']['JobServerGroup'] - policy = grp['UpdatePolicy']['AutoScalingRollingUpdate'] - policy['MinInstancesInService'] = '1' - policy['MaxBatchSize'] = '3' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=10, - num_creates_expected_on_updt=0, - num_deletes_expected_on_updt=0) - - def test_instance_group_update_replace_with_adjusted_capacity(self): - """Test update replace with capacity adjustment. - - Test update replace with capacity adjustment due to conflict in batch - size and minimum instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - grp = updt_template['Resources']['JobServerGroup'] - policy = grp['UpdatePolicy']['AutoScalingRollingUpdate'] - policy['MinInstancesInService'] = '8' - policy['MaxBatchSize'] = '4' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=8, - num_creates_expected_on_updt=2, - num_deletes_expected_on_updt=2) - - def test_instance_group_update_replace_huge_batch_size(self): - """Test update replace with a huge batch size.""" - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['AutoScalingRollingUpdate'] - policy['MinInstancesInService'] = '0' - policy['MaxBatchSize'] = '20' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=10, - num_creates_expected_on_updt=0, - num_deletes_expected_on_updt=0) - - def test_instance_group_update_replace_huge_min_in_service(self): - """Update replace with huge number of minimum instances in service.""" - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['AutoScalingRollingUpdate'] - policy['MinInstancesInService'] = '20' - policy['MaxBatchSize'] = '1' - policy['PauseTime'] = 'PT0S' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=9, - num_creates_expected_on_updt=1, - num_deletes_expected_on_updt=1) - - def test_instance_group_update_no_replace(self): - """Test simple update only and no replace. - - Test simple update only and no replace (i.e. updated instance flavor - in Launch Configuration) with no conflict in batch size and - minimum instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['AutoScalingRollingUpdate'] - policy['MinInstancesInService'] = '1' - policy['MaxBatchSize'] = '3' - policy['PauseTime'] = 'PT0S' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['InstanceType'] = self.conf.minimal_instance_type - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=10, - num_creates_expected_on_updt=0, - num_deletes_expected_on_updt=0) - - def test_instance_group_update_no_replace_with_adjusted_capacity(self): - """Test update only and no replace with capacity adjustment. - - Test update only and no replace (i.e. updated instance flavor in - Launch Configuration) with capacity adjustment due to conflict in - batch size and minimum instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['AutoScalingRollingUpdate'] - policy['MinInstancesInService'] = '8' - policy['MaxBatchSize'] = '4' - policy['PauseTime'] = 'PT0S' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['InstanceType'] = self.conf.minimal_instance_type - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=8, - num_creates_expected_on_updt=2, - num_deletes_expected_on_updt=2) - - -class AutoScalingSignalTest(AutoscalingGroupTest): - - template = ''' -{ - "AWSTemplateFormatVersion" : "2010-09-09", - "Description" : "Template to create multiple instances.", - "Parameters" : {"size": {"Type": "String", "Default": "1"}, - "AZ": {"Type": "String", "Default": "nova"}, - "image": {"Type": "String"}, - "flavor": {"Type": "String"}}, - "Resources": { - "custom_lb": { - "Type": "AWS::EC2::Instance", - "Properties": { - "ImageId": {"Ref": "image"}, - "InstanceType": {"Ref": "flavor"}, - "UserData": "foo", - "SecurityGroups": [ "sg-1" ], - "Tags": [] - }, - "Metadata": { - "IPs": {"Fn::GetAtt": ["JobServerGroup", "InstanceList"]} - } - }, - "JobServerGroup": { - "Type" : "AWS::AutoScaling::AutoScalingGroup", - "Properties" : { - "AvailabilityZones" : [{"Ref": "AZ"}], - "LaunchConfigurationName" : { "Ref" : "JobServerConfig" }, - "DesiredCapacity" : {"Ref": "size"}, - "MinSize" : "0", - "MaxSize" : "20" - } - }, - "JobServerConfig" : { - "Type" : "AWS::AutoScaling::LaunchConfiguration", - "Metadata": {"foo": "bar"}, - "Properties": { - "ImageId" : {"Ref": "image"}, - "InstanceType" : {"Ref": "flavor"}, - "SecurityGroups" : [ "sg-1" ], - "UserData" : "jsconfig data" - } - }, - "ScaleUpPolicy" : { - "Type" : "AWS::AutoScaling::ScalingPolicy", - "Properties" : { - "AdjustmentType" : "ChangeInCapacity", - "AutoScalingGroupName" : { "Ref" : "JobServerGroup" }, - "Cooldown" : "0", - "ScalingAdjustment": "1" - } - }, - "ScaleDownPolicy" : { - "Type" : "AWS::AutoScaling::ScalingPolicy", - "Properties" : { - "AdjustmentType" : "ChangeInCapacity", - "AutoScalingGroupName" : { "Ref" : "JobServerGroup" }, - "Cooldown" : "0", - "ScalingAdjustment" : "-2" - } - } - }, - "Outputs": { - "InstanceList": {"Value": { - "Fn::GetAtt": ["JobServerGroup", "InstanceList"]}} - } -} -''' - - lb_template = ''' -heat_template_version: 2013-05-23 -parameters: - ImageId: {type: string} - InstanceType: {type: string} - SecurityGroups: {type: comma_delimited_list} - UserData: {type: string} - Tags: {type: comma_delimited_list, default: "x,y"} - -resources: -outputs: - PublicIp: {value: "not-used"} - AvailabilityZone: {value: 'not-used1'} - PrivateDnsName: {value: 'not-used2'} - PublicDnsName: {value: 'not-used3'} - PrivateIp: {value: 'not-used4'} - -''' - - def setUp(self): - super(AutoScalingSignalTest, self).setUp() - self.build_timeout = self.conf.build_timeout - self.build_interval = self.conf.build_interval - self.files = {'provider.yaml': self.instance_template, - 'lb.yaml': self.lb_template} - self.env = {'resource_registry': - {'resources': - {'custom_lb': {'AWS::EC2::Instance': 'lb.yaml'}}, - 'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 2, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - def check_instance_count(self, stack_identifier, expected): - md = self.client.resources.metadata(stack_identifier, 'custom_lb') - actual_md = len(md['IPs'].split(',')) - if actual_md != expected: - LOG.warning('check_instance_count exp:%d, meta:%s' % (expected, - md['IPs'])) - return False - - stack = self.client.stacks.get(stack_identifier) - inst_list = self._stack_output(stack, 'InstanceList') - actual = len(inst_list.split(',')) - if actual != expected: - LOG.warning('check_instance_count exp:%d, act:%s' % (expected, - inst_list)) - return actual == expected - - def test_scaling_meta_update(self): - """Use heatclient to signal the up and down policy. - - Then confirm that the metadata in the custom_lb is updated each - time. - """ - stack_identifier = self.stack_create(template=self.template, - files=self.files, - environment=self.env) - - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 2)) - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - # Scale up one, Trigger alarm - self.client.resources.signal(stack_identifier, 'ScaleUpPolicy') - self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE') - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 3)) - - # Scale down two, Trigger alarm - self.client.resources.signal(stack_identifier, 'ScaleDownPolicy') - self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE') - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 1)) - - def test_signal_with_policy_update(self): - """Prove that an updated policy is used in the next signal.""" - - stack_identifier = self.stack_create(template=self.template, - files=self.files, - environment=self.env) - - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 2)) - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - # Scale up one, Trigger alarm - self.client.resources.signal(stack_identifier, 'ScaleUpPolicy') - self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE') - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 3)) - - # increase the adjustment to "+2" and remove the DesiredCapacity - # so we don't go from 3 to 2. - new_template = self.template.replace( - '"ScalingAdjustment": "1"', - '"ScalingAdjustment": "2"').replace( - '"DesiredCapacity" : {"Ref": "size"},', '') - - self.update_stack(stack_identifier, template=new_template, - environment=self.env, files=self.files) - - # Scale up two, Trigger alarm - self.client.resources.signal(stack_identifier, 'ScaleUpPolicy') - self._wait_for_stack_status(nested_ident, 'UPDATE_COMPLETE') - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 5)) - - def test_signal_during_suspend(self): - """Prove that a signal will fail when the stack is in suspend.""" - - stack_identifier = self.stack_create(template=self.template, - files=self.files, - environment=self.env) - - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 2)) - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - - # suspend the top level stack. - self.client.actions.suspend(stack_id=stack_identifier) - - # Wait for stack to reach SUSPEND_COMPLETE - self._wait_for_stack_status(stack_identifier, 'SUSPEND_COMPLETE') - - # Send a signal and an exception will raise - ex = self.assertRaises(exc.BadRequest, - self.client.resources.signal, - stack_identifier, 'ScaleUpPolicy') - - error_msg = 'Signal resource during SUSPEND is not supported' - self.assertIn(error_msg, six.text_type(ex)) - ev = self.wait_for_event_with_reason( - stack_identifier, - reason='Cannot signal resource during SUSPEND', - rsrc_name='ScaleUpPolicy') - self.assertEqual('SUSPEND_COMPLETE', ev[0].resource_status) - - # still SUSPEND_COMPLETE (not gone to UPDATE_COMPLETE) - self._wait_for_stack_status(nested_ident, 'SUSPEND_COMPLETE') - self._wait_for_stack_status(stack_identifier, 'SUSPEND_COMPLETE') - # still 2 instances. - self.assertTrue(test.call_until_true( - self.build_timeout, self.build_interval, - self.check_instance_count, stack_identifier, 2)) diff --git a/heat_tempest_plugin/tests/functional/test_aws_stack.py b/heat_tempest_plugin/tests/functional/test_aws_stack.py deleted file mode 100644 index 03beb1f..0000000 --- a/heat_tempest_plugin/tests/functional/test_aws_stack.py +++ /dev/null @@ -1,201 +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 hashlib -import json -import random - -from six.moves.urllib import parse -from swiftclient import utils as swiftclient_utils -import yaml - -from heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - - -class AwsStackTest(functional_base.FunctionalTestsBase): - test_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - the_nested: - Type: AWS::CloudFormation::Stack - Properties: - TemplateURL: the.yaml - Parameters: - KeyName: foo -Outputs: - output_foo: - Value: {"Fn::GetAtt": [the_nested, Outputs.Foo]} -''' - - nested_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - KeyName: - Type: String -Outputs: - Foo: - Value: bar -''' - - update_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - KeyName: - Type: String -Outputs: - Foo: - Value: foo -''' - - nested_with_res_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - KeyName: - Type: String -Resources: - NestedResource: - Type: OS::Heat::RandomString -Outputs: - Foo: - Value: {"Fn::GetAtt": [NestedResource, value]} -''' - - def setUp(self): - super(AwsStackTest, self).setUp() - if not self.is_service_available('object-store'): - self.skipTest('object-store service not available, skipping') - self.object_container_name = test.rand_name() - self.project_id = self.identity_client.project_id - self.swift_key = hashlib.sha224( - str(random.getrandbits(256)).encode('ascii')).hexdigest()[:32] - key_header = 'x-container-meta-temp-url-key' - self.object_client.put_container(self.object_container_name, - {key_header: self.swift_key}) - self.addCleanup(self.object_client.delete_container, - self.object_container_name) - - def publish_template(self, contents, cleanup=True): - oc = self.object_client - - # post the object - oc.put_object(self.object_container_name, 'template.yaml', contents) - if cleanup: - self.addCleanup(oc.delete_object, - self.object_container_name, - 'template.yaml') - path = '/v1/AUTH_%s/%s/%s' % (self.project_id, - self.object_container_name, - 'template.yaml') - timeout = self.conf.build_timeout * 10 - tempurl = swiftclient_utils.generate_temp_url(path, timeout, - self.swift_key, 'GET') - sw_url = parse.urlparse(oc.url) - return '%s://%s%s' % (sw_url.scheme, sw_url.netloc, tempurl) - - def test_nested_stack_create(self): - url = self.publish_template(self.nested_template) - self.template = self.test_template.replace('the.yaml', url) - stack_identifier = self.stack_create(template=self.template) - stack = self.client.stacks.get(stack_identifier) - self.assert_resource_is_a_stack(stack_identifier, 'the_nested') - self.assertEqual('bar', self._stack_output(stack, 'output_foo')) - - def test_nested_stack_create_with_timeout(self): - url = self.publish_template(self.nested_template) - self.template = self.test_template.replace('the.yaml', url) - timeout_template = yaml.safe_load(self.template) - props = timeout_template['Resources']['the_nested']['Properties'] - props['TimeoutInMinutes'] = '50' - - stack_identifier = self.stack_create( - template=timeout_template) - stack = self.client.stacks.get(stack_identifier) - self.assert_resource_is_a_stack(stack_identifier, 'the_nested') - self.assertEqual('bar', self._stack_output(stack, 'output_foo')) - - def test_nested_stack_adopt_ok(self): - url = self.publish_template(self.nested_with_res_template) - self.template = self.test_template.replace('the.yaml', url) - adopt_data = { - "resources": { - "the_nested": { - "resource_id": "test-res-id", - "resources": { - "NestedResource": { - "type": "OS::Heat::RandomString", - "resource_id": "test-nested-res-id", - "resource_data": {"value": "goopie"} - } - } - } - }, - "environment": {"parameters": {}}, - "template": yaml.safe_load(self.template) - } - - stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data)) - - self.assert_resource_is_a_stack(stack_identifier, 'the_nested') - stack = self.client.stacks.get(stack_identifier) - self.assertEqual('goopie', self._stack_output(stack, 'output_foo')) - - def test_nested_stack_adopt_fail(self): - url = self.publish_template(self.nested_with_res_template) - self.template = self.test_template.replace('the.yaml', url) - adopt_data = { - "resources": { - "the_nested": { - "resource_id": "test-res-id", - "resources": { - } - } - }, - "environment": {"parameters": {}}, - "template": yaml.safe_load(self.template) - } - - stack_identifier = self.stack_adopt(adopt_data=json.dumps(adopt_data), - wait_for_status='ADOPT_FAILED') - rsrc = self.client.resources.get(stack_identifier, 'the_nested') - self.assertEqual('ADOPT_FAILED', rsrc.resource_status) - - def test_nested_stack_update(self): - url = self.publish_template(self.nested_template) - self.template = self.test_template.replace('the.yaml', url) - stack_identifier = self.stack_create(template=self.template) - original_nested_id = self.assert_resource_is_a_stack( - stack_identifier, 'the_nested') - stack = self.client.stacks.get(stack_identifier) - self.assertEqual('bar', self._stack_output(stack, 'output_foo')) - - new_template = yaml.safe_load(self.template) - props = new_template['Resources']['the_nested']['Properties'] - props['TemplateURL'] = self.publish_template(self.update_template, - cleanup=False) - - self.update_stack(stack_identifier, new_template) - - # Expect the physical resource name staying the same after update, - # so that the nested was actually updated instead of replaced. - new_nested_id = self.assert_resource_is_a_stack( - stack_identifier, 'the_nested') - self.assertEqual(original_nested_id, new_nested_id) - updt_stack = self.client.stacks.get(stack_identifier) - self.assertEqual('foo', self._stack_output(updt_stack, 'output_foo')) - - def test_nested_stack_suspend_resume(self): - url = self.publish_template(self.nested_template) - self.template = self.test_template.replace('the.yaml', url) - stack_identifier = self.stack_create(template=self.template) - self.stack_suspend(stack_identifier) - self.stack_resume(stack_identifier) diff --git a/heat_tempest_plugin/tests/functional/test_cancel_update.py b/heat_tempest_plugin/tests/functional/test_cancel_update.py deleted file mode 100644 index 4a8938a..0000000 --- a/heat_tempest_plugin/tests/functional/test_cancel_update.py +++ /dev/null @@ -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 heat_tempest_plugin.tests.functional import functional_base - - -class CancelUpdateTest(functional_base.FunctionalTestsBase): - - template = ''' -heat_template_version: '2013-05-23' -parameters: - InstanceType: - type: string - ImageId: - type: string - network: - type: string -resources: - port: - type: OS::Neutron::Port - properties: - network: {get_param: network} - Server: - type: OS::Nova::Server - properties: - flavor_update_policy: REPLACE - image: {get_param: ImageId} - flavor: {get_param: InstanceType} - networks: - - port: {get_resource: port} -''' - - def setUp(self): - super(CancelUpdateTest, self).setUp() - if not self.conf.minimal_image_ref: - raise self.skipException("No minimal image configured to test") - if not self.conf.minimal_instance_type: - raise self.skipException("No minimal flavor configured to test.") - - def test_cancel_update_server_with_port(self): - parameters = {'InstanceType': self.conf.minimal_instance_type, - 'ImageId': self.conf.minimal_image_ref, - 'network': self.conf.fixed_network_name} - - stack_identifier = self.stack_create(template=self.template, - parameters=parameters) - parameters['InstanceType'] = self.conf.instance_type - self.update_stack(stack_identifier, self.template, - parameters=parameters, - expected_status='UPDATE_IN_PROGRESS') - - self.cancel_update_stack(stack_identifier) diff --git a/heat_tempest_plugin/tests/functional/test_conditional_exposure.py b/heat_tempest_plugin/tests/functional/test_conditional_exposure.py deleted file mode 100644 index dd4329b..0000000 --- a/heat_tempest_plugin/tests/functional/test_conditional_exposure.py +++ /dev/null @@ -1,157 +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 heatclient import exc -import keystoneclient - -from heat_tempest_plugin.tests.functional import functional_base - - -class ServiceBasedExposureTest(functional_base.FunctionalTestsBase): - # NOTE(pas-ha) if we ever decide to install Sahara on Heat - # functional gate, this must be changed to other not-installed - # but in principle supported service - unavailable_service = 'Sahara' - unavailable_template = """ -heat_template_version: 2015-10-15 -parameters: - instance_type: - type: string -resources: - not_available: - type: OS::Sahara::NodeGroupTemplate - properties: - plugin_name: fake - hadoop_version: 0.1 - flavor: {get_param: instance_type} - node_processes: [] -""" - - def setUp(self): - super(ServiceBasedExposureTest, self).setUp() - # check that Sahara endpoint is available - if self._is_sahara_deployed(): - self.skipTest("Sahara is actually deployed, " - "can not run negative tests on " - "Sahara resources availability.") - - def _is_sahara_deployed(self): - try: - self.identity_client.get_endpoint_url('data-processing', - self.conf.region) - except keystoneclient.exceptions.EndpointNotFound: - return False - return True - - def test_unavailable_resources_not_listed(self): - resources = self.client.resource_types.list() - self.assertFalse(any(self.unavailable_service in r.resource_type - for r in resources)) - - def test_unavailable_resources_not_created(self): - stack_name = self._stack_rand_name() - parameters = {'instance_type': self.conf.minimal_instance_type} - ex = self.assertRaises(exc.HTTPBadRequest, - self.client.stacks.create, - stack_name=stack_name, - parameters=parameters, - template=self.unavailable_template) - self.assertIn('ResourceTypeUnavailable', ex.message.decode('utf-8')) - self.assertIn('OS::Sahara::NodeGroupTemplate', - ex.message.decode('utf-8')) - - -class RoleBasedExposureTest(functional_base.FunctionalTestsBase): - - fl_tmpl = """ -heat_template_version: 2015-10-15 - -resources: - not4everyone: - type: OS::Nova::Flavor - properties: - ram: 20000 - vcpus: 10 -""" - - cvt_tmpl = """ -heat_template_version: 2015-10-15 - -resources: - cvt: - type: OS::Cinder::VolumeType - properties: - name: cvt_test -""" - - host_aggr_tmpl = """ -heat_template_version: 2015-10-15 -parameters: - az: - type: string - default: nova -resources: - cvt: - type: OS::Nova::HostAggregate - properties: - name: aggregate_test - availability_zone: {get_param: az} -""" - - scenarios = [ - ('r_nova_flavor', dict( - stack_name='s_nova_flavor', - template=fl_tmpl, - forbidden_r_type="OS::Nova::Flavor", - test_creation=True)), - ('r_nova_host_aggregate', dict( - stack_name='s_nova_ost_aggregate', - template=host_aggr_tmpl, - forbidden_r_type="OS::Nova::HostAggregate", - test_creation=True)), - ('r_cinder_vtype', dict( - stack_name='s_cinder_vtype', - template=cvt_tmpl, - forbidden_r_type="OS::Cinder::VolumeType", - test_creation=True)), - ('r_cinder_vtype_encrypt', dict( - forbidden_r_type="OS::Cinder::EncryptedVolumeType", - test_creation=False)), - ('r_neutron_qos', dict( - forbidden_r_type="OS::Neutron::QoSPolicy", - test_creation=False)), - ('r_neutron_qos_bandwidth_limit', dict( - forbidden_r_type="OS::Neutron::QoSBandwidthLimitRule", - test_creation=False)), - ('r_manila_share_type', dict( - forbidden_r_type="OS::Manila::ShareType", - test_creation=False)) - ] - - def test_non_admin_forbidden_create_resources(self): - """Fail to create resource w/o admin role. - - Integration tests job runs as normal OpenStack user, - and the resources above are configured to require - admin role in default policy file of Heat. - """ - if self.test_creation: - ex = self.assertRaises(exc.Forbidden, - self.client.stacks.create, - stack_name=self.stack_name, - template=self.template) - self.assertIn(self.forbidden_r_type, ex.message.decode('utf-8')) - - def test_forbidden_resource_not_listed(self): - resources = self.client.resource_types.list() - self.assertNotIn(self.forbidden_r_type, - (r.resource_type for r in resources)) diff --git a/heat_tempest_plugin/tests/functional/test_conditions.py b/heat_tempest_plugin/tests/functional/test_conditions.py deleted file mode 100644 index 106a4ca..0000000 --- a/heat_tempest_plugin/tests/functional/test_conditions.py +++ /dev/null @@ -1,619 +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 heat_tempest_plugin.tests.functional import functional_base - - -cfn_template = ''' -AWSTemplateFormatVersion: 2010-09-09 -Parameters: - env_type: - Default: test - Type: String - AllowedValues: [prod, test] - zone: - Type: String - Default: beijing -Conditions: - Prod: {"Fn::Equals" : [{Ref: env_type}, "prod"]} - Test: - Fn::Not: - - Fn::Equals: - - Ref: env_type - - prod - Beijing_Prod: - Fn::And: - - Fn::Equals: - - Ref: env_type - - prod - - Fn::Equals: - - Ref: zone - - beijing - Xian_Zone: - Fn::Equals: - - Ref: zone - - xian - Xianyang_Zone: - Fn::Equals: - - Ref: zone - - xianyang - Fujian_Zone: - Fn::Or: - - Fn::Equals: - - Ref: zone - - fuzhou - - Fn::Equals: - - Ref: zone - - xiamen - Fujian_Prod: - Fn::And: - - Fujian_Zone - - Prod - Shannxi_Provice: - Fn::Or: - - Xian_Zone - - Xianyang_Zone - Not_Shannxi: - Fn::Not: [Shannxi_Provice] -Resources: - test_res: - Type: OS::Heat::TestResource - Properties: - value: {"Fn::If": ["Prod", "env_is_prod", "env_is_test"]} - prod_res: - Type: OS::Heat::TestResource - Properties: - value: prod_res - Condition: Prod - test_res1: - Type: OS::Heat::TestResource - Properties: - value: just in test env - Condition: Test - beijing_prod_res: - Type: OS::Heat::TestResource - Properties: - value: beijing_prod_res - Condition: Beijing_Prod - fujian_res: - Type: OS::Heat::TestResource - Condition: Fujian_Zone - Properties: - value: fujian_res - fujian_prod_res: - Type: OS::Heat::TestResource - Condition: Fujian_Prod - Properties: - value: fujian_prod_res - shannxi_res: - Type: OS::Heat::TestResource - Condition: Shannxi_Provice - Properties: - value: shannxi_res - not_shannxi_res: - Type: OS::Heat::TestResource - Condition: Not_Shannxi - Properties: - value: not_shannxi_res -Outputs: - res_value: - Value: {"Fn::GetAtt": [prod_res, output]} - Condition: Prod - test_res_value: - Value: {"Fn::GetAtt": [test_res, output]} - prod_resource: - Value: {"Fn::If": [Prod, {Ref: prod_res}, 'no_prod_res']} - test_res1_value: - Value: {"Fn::If": [Test, {"Fn::GetAtt": [test_res1, output]}, - 'no_test_res1']} - beijing_prod_res: - Value: {"Fn::If": [Beijing_Prod, {Ref: beijing_prod_res}, 'no_prod_res']} -''' - -hot_template = ''' -heat_template_version: 2016-10-14 -parameters: - env_type: - default: test - type: string - constraints: - - allowed_values: [prod, test] - zone: - type: string - default: beijing -conditions: - prod: {equals : [{get_param: env_type}, "prod"]} - test: - not: - equals: - - get_param: env_type - - prod - beijing_prod: - and: - - equals: - - get_param: zone - - beijing - - equals: - - get_param: env_type - - prod - xian_zone: - equals: - - get_param: zone - - xian - xianyang_zone: - equals: - - get_param: zone - - xianyang - fujian_zone: - or: - - equals: - - get_param: zone - - fuzhou - - equals: - - get_param: zone - - xiamen - fujian_prod: - and: - - fujian_zone - - prod - shannxi_provice: - or: - - xian_zone - - xianyang_zone - not_shannxi: - not: shannxi_provice -resources: - test_res: - type: OS::Heat::TestResource - properties: - value: {if: ["prod", "env_is_prod", "env_is_test"]} - prod_res: - type: OS::Heat::TestResource - properties: - value: prod_res - condition: prod - test_res1: - type: OS::Heat::TestResource - properties: - value: just in test env - condition: test - beijing_prod_res: - type: OS::Heat::TestResource - properties: - value: beijing_prod_res - condition: beijing_prod - fujian_res: - type: OS::Heat::TestResource - condition: fujian_zone - properties: - value: fujian_res - fujian_prod_res: - type: OS::Heat::TestResource - condition: fujian_prod - properties: - value: fujian_prod_res - shannxi_res: - type: OS::Heat::TestResource - condition: shannxi_provice - properties: - value: shannxi_res - not_shannxi_res: - type: OS::Heat::TestResource - condition: not_shannxi - properties: - value: not_shannxi_res -outputs: - res_value: - value: {get_attr: [prod_res, output]} - condition: prod - test_res_value: - value: {get_attr: [test_res, output]} - prod_resource: - value: {if: [prod, {get_resource: prod_res}, 'no_prod_res']} - test_res1_value: - value: {if: [test, {get_attr: [test_res1, output]}, 'no_test_res1']} - beijing_prod_res: - value: {if: [beijing_prod, {get_resource: beijing_prod_res}, - 'no_prod_res']} -''' - -before_rename_tmpl = ''' -heat_template_version: 2016-10-14 -parameters: - env_type: - default: test - type: string -conditions: - cd1: {equals : [{get_param: env_type}, "prod"]} -resources: - test: - type: OS::Heat::TestResource - properties: - value: {if: [cd1, 'prod', 'test']} -''' - -after_rename_tmpl = ''' -heat_template_version: 2016-10-14 -parameters: - env_type: - default: prod - type: string -conditions: - cd2: {equals : [{get_param: env_type}, "prod"]} -resources: - test: - type: OS::Heat::TestResource - properties: - value: {if: [cd2, 'prod', 'test']} - test2: - type: OS::Heat::TestResource - properties: - value: {if: [cd2, 'prod', 'test']} -''' - -fail_rename_tmpl = ''' -heat_template_version: 2016-10-14 -parameters: - env_type: - default: prod - type: string -conditions: - cd3: {equals : [{get_param: env_type}, "prod"]} -resources: - test: - type: OS::Heat::TestResource - properties: - value: {if: [cd3, 'prod', 'test']} - test2: - type: OS::Heat::TestResource - properties: - value: {if: [cd3, 'prod', 'test']} - test_fail: - type: OS::Heat::TestResource - properties: - fail: True - depends_on: [test, test2] -''' - -recover_rename_tmpl = ''' -heat_template_version: 2016-10-14 -parameters: - env_type: - default: prod - type: string -conditions: - cd3: {equals : [{get_param: env_type}, "prod"]} -resources: - test2: - type: OS::Heat::TestResource - properties: - value: {if: [cd3, 'prod', 'test']} - test_fail: - type: OS::Heat::TestResource - properties: - fail: False - depends_on: [test2] -''' - - -class CreateUpdateResConditionTest(functional_base.FunctionalTestsBase): - - def res_assert_for_prod(self, resources, bj_prod=True, fj_zone=False, - shannxi_provice=False): - res_names = [res.resource_name for res in resources] - if bj_prod: - self.assertEqual(4, len(resources)) - self.assertIn('beijing_prod_res', res_names) - self.assertIn('not_shannxi_res', res_names) - elif fj_zone: - self.assertEqual(5, len(resources)) - self.assertIn('fujian_res', res_names) - self.assertNotIn('beijing_prod_res', res_names) - self.assertIn('not_shannxi_res', res_names) - self.assertIn('fujian_prod_res', res_names) - elif shannxi_provice: - self.assertEqual(3, len(resources)) - self.assertIn('shannxi_res', res_names) - else: - self.assertEqual(3, len(resources)) - self.assertIn('not_shannxi_res', res_names) - self.assertIn('prod_res', res_names) - self.assertIn('test_res', res_names) - - def res_assert_for_test(self, resources, fj_zone=False, - shannxi_provice=False): - res_names = [res.resource_name for res in resources] - - if fj_zone: - self.assertEqual(4, len(resources)) - self.assertIn('fujian_res', res_names) - self.assertIn('not_shannxi_res', res_names) - elif shannxi_provice: - self.assertEqual(3, len(resources)) - self.assertNotIn('fujian_res', res_names) - self.assertIn('shannxi_res', res_names) - else: - self.assertEqual(3, len(resources)) - self.assertIn('not_shannxi_res', res_names) - self.assertIn('test_res', res_names) - self.assertIn('test_res1', res_names) - self.assertNotIn('prod_res', res_names) - - def output_assert_for_prod(self, stack_id, bj_prod=True): - output = self.client.stacks.output_show(stack_id, - 'res_value')['output'] - self.assertEqual('prod_res', output['output_value']) - - test_res_value = self.client.stacks.output_show( - stack_id, 'test_res_value')['output'] - self.assertEqual('env_is_prod', test_res_value['output_value']) - - prod_resource = self.client.stacks.output_show( - stack_id, 'prod_resource')['output'] - self.assertNotEqual('no_prod_res', prod_resource['output_value']) - - test_res_output = self.client.stacks.output_show( - stack_id, 'test_res1_value')['output'] - self.assertEqual('no_test_res1', test_res_output['output_value']) - - beijing_prod_res = self.client.stacks.output_show( - stack_id, 'beijing_prod_res')['output'] - if bj_prod: - self.assertNotEqual('no_prod_res', - beijing_prod_res['output_value']) - else: - self.assertEqual('no_prod_res', beijing_prod_res['output_value']) - - def output_assert_for_test(self, stack_id): - output = self.client.stacks.output_show(stack_id, - 'res_value')['output'] - self.assertIsNone(output['output_value']) - - test_res_value = self.client.stacks.output_show( - stack_id, 'test_res_value')['output'] - self.assertEqual('env_is_test', test_res_value['output_value']) - - prod_resource = self.client.stacks.output_show( - stack_id, 'prod_resource')['output'] - self.assertEqual('no_prod_res', prod_resource['output_value']) - - test_res_output = self.client.stacks.output_show( - stack_id, 'test_res1_value')['output'] - self.assertEqual('just in test env', - test_res_output['output_value']) - - beijing_prod_res = self.client.stacks.output_show( - stack_id, 'beijing_prod_res')['output'] - self.assertEqual('no_prod_res', beijing_prod_res['output_value']) - - def test_stack_create_update_cfn_template_test_to_prod(self): - stack_identifier = self.stack_create(template=cfn_template) - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources) - self.output_assert_for_test(stack_identifier) - - parms = {'zone': 'fuzhou'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources, fj_zone=True) - self.output_assert_for_test(stack_identifier) - - parms = {'zone': 'xianyang'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources, shannxi_provice=True) - self.output_assert_for_test(stack_identifier) - - parms = {'env_type': 'prod'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources) - self.output_assert_for_prod(stack_identifier) - - parms = {'env_type': 'prod', - 'zone': 'shanghai'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, False) - self.output_assert_for_prod(stack_identifier, False) - - parms = {'env_type': 'prod', - 'zone': 'xiamen'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, bj_prod=False, fj_zone=True) - self.output_assert_for_prod(stack_identifier, False) - - parms = {'env_type': 'prod', - 'zone': 'xianyang'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False, - shannxi_provice=True) - self.output_assert_for_prod(stack_identifier, False) - - def test_stack_create_update_cfn_template_prod_to_test(self): - parms = {'env_type': 'prod'} - stack_identifier = self.stack_create(template=cfn_template, - parameters=parms) - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources) - self.output_assert_for_prod(stack_identifier) - - parms = {'zone': 'xiamen', - 'env_type': 'prod'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, bj_prod=False, fj_zone=True) - self.output_assert_for_prod(stack_identifier, bj_prod=False) - - parms = {'zone': 'xianyang', - 'env_type': 'prod'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False, - shannxi_provice=True) - self.output_assert_for_prod(stack_identifier, bj_prod=False) - - parms = {'zone': 'shanghai', - 'env_type': 'prod'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, bj_prod=False, fj_zone=False, - shannxi_provice=False) - self.output_assert_for_prod(stack_identifier, bj_prod=False) - - parms = {'env_type': 'test'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources) - self.output_assert_for_test(stack_identifier) - - parms = {'env_type': 'test', - 'zone': 'fuzhou'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources, fj_zone=True) - self.output_assert_for_test(stack_identifier) - - parms = {'env_type': 'test', - 'zone': 'xianyang'} - self.update_stack(stack_identifier, - template=cfn_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources, fj_zone=False, - shannxi_provice=True) - self.output_assert_for_test(stack_identifier) - - def test_stack_create_update_hot_template_test_to_prod(self): - stack_identifier = self.stack_create(template=hot_template) - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources) - self.output_assert_for_test(stack_identifier) - - parms = {'zone': 'xianyang'} - self.update_stack(stack_identifier, - template=hot_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources, shannxi_provice=True) - self.output_assert_for_test(stack_identifier) - - parms = {'env_type': 'prod'} - self.update_stack(stack_identifier, - template=hot_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources) - self.output_assert_for_prod(stack_identifier) - - parms = {'env_type': 'prod', - 'zone': 'shanghai'} - self.update_stack(stack_identifier, - template=hot_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, False) - self.output_assert_for_prod(stack_identifier, False) - - parms = {'env_type': 'prod', - 'zone': 'xianyang'} - self.update_stack(stack_identifier, - template=hot_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, False, shannxi_provice=True) - self.output_assert_for_prod(stack_identifier, False) - - def test_stack_create_update_hot_template_prod_to_test(self): - parms = {'env_type': 'prod'} - stack_identifier = self.stack_create(template=hot_template, - parameters=parms) - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources) - self.output_assert_for_prod(stack_identifier) - - parms = {'env_type': 'prod', - 'zone': 'xianyang'} - self.update_stack(stack_identifier, - template=hot_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_prod(resources, False, shannxi_provice=True) - self.output_assert_for_prod(stack_identifier, False) - - parms = {'env_type': 'test'} - self.update_stack(stack_identifier, - template=hot_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources) - self.output_assert_for_test(stack_identifier) - - parms = {'env_type': 'test', - 'zone': 'xianyang'} - self.update_stack(stack_identifier, - template=hot_template, - parameters=parms) - - resources = self.client.resources.list(stack_identifier) - self.res_assert_for_test(resources, fj_zone=False, - shannxi_provice=True) - self.output_assert_for_test(stack_identifier) - - def test_condition_rename(self): - stack_identifier = self.stack_create(template=before_rename_tmpl) - self.update_stack(stack_identifier, template=after_rename_tmpl) - self.update_stack(stack_identifier, template=fail_rename_tmpl, - expected_status='UPDATE_FAILED') - self.update_stack(stack_identifier, template=recover_rename_tmpl) diff --git a/heat_tempest_plugin/tests/functional/test_create_update.py b/heat_tempest_plugin/tests/functional/test_create_update.py deleted file mode 100644 index 46b1837..0000000 --- a/heat_tempest_plugin/tests/functional/test_create_update.py +++ /dev/null @@ -1,710 +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 -import json - -from heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - -test_template_one_resource = { - 'heat_template_version': 'pike', - 'description': 'Test template to create one instance.', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 1, - 'action_wait_secs': {'create': 1}, - 'client_name': 'nova', - 'entity_name': 'servers', - } - } - } -} - -test_template_two_resource = { - 'heat_template_version': 'pike', - 'description': 'Test template to create two instance.', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0, - 'action_wait_secs': {'update': 1} - } - }, - 'test2': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0 - } - } - } -} - - -def _change_rsrc_properties(template, rsrcs, values): - modified_template = copy.deepcopy(template) - for rsrc_name in rsrcs: - rsrc_prop = modified_template['resources'][ - rsrc_name]['properties'] - for prop in rsrc_prop: - if prop in values: - rsrc_prop[prop] = values[prop] - return modified_template - - -class CreateStackTest(functional_base.FunctionalTestsBase): - def test_create_rollback(self): - values = {'fail': True, 'value': 'test_create_rollback'} - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], values) - - self.stack_create( - template=template, - expected_status='ROLLBACK_COMPLETE', - disable_rollback=False) - - -class UpdateStackTest(functional_base.FunctionalTestsBase): - - provider_template = { - 'heat_template_version': '2013-05-23', - 'description': 'foo', - 'resources': { - 'test1': { - 'type': 'My::TestResource' - } - } - } - - provider_group_template = ''' -heat_template_version: 2013-05-23 -parameters: - count: - type: number - default: 2 -resources: - test_group: - type: OS::Heat::ResourceGroup - properties: - count: {get_param: count} - resource_def: - type: My::TestResource -''' - - update_userdata_template = ''' -heat_template_version: 2014-10-16 -parameters: - flavor: - type: string - user_data: - type: string - image: - type: string - network: - type: string - -resources: - server: - type: OS::Nova::Server - properties: - image: {get_param: image} - flavor: {get_param: flavor} - networks: [{network: {get_param: network} }] - user_data_format: SOFTWARE_CONFIG - user_data: {get_param: user_data} -''' - - fail_param_template = ''' -heat_template_version: 2014-10-16 -parameters: - do_fail: - type: boolean - default: False -resources: - aresource: - type: OS::Heat::TestResource - properties: - value: Test - fail: {get_param: do_fail} - wait_secs: 1 -''' - - def test_stack_update_nochange(self): - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], - {'value': 'test_no_change'}) - stack_identifier = self.stack_create( - template=template) - expected_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(expected_resources, - self.list_resources(stack_identifier)) - - # Update with no changes, resources should be unchanged - self.update_stack(stack_identifier, template) - self.assertEqual(expected_resources, - self.list_resources(stack_identifier)) - - def test_stack_in_place_update(self): - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], - {'value': 'test_in_place'}) - stack_identifier = self.stack_create( - template=template) - expected_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(expected_resources, - self.list_resources(stack_identifier)) - resource = self.client.resources.list(stack_identifier) - initial_phy_id = resource[0].physical_resource_id - - tmpl_update = _change_rsrc_properties( - test_template_one_resource, ['test1'], - {'value': 'test_in_place_update'}) - # Update the Value - self.update_stack(stack_identifier, tmpl_update) - resource = self.client.resources.list(stack_identifier) - # By default update_in_place - self.assertEqual(initial_phy_id, - resource[0].physical_resource_id) - - def test_stack_update_replace(self): - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], - {'value': 'test_replace'}) - stack_identifier = self.stack_create( - template=template) - expected_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(expected_resources, - self.list_resources(stack_identifier)) - resource = self.client.resources.list(stack_identifier) - initial_phy_id = resource[0].physical_resource_id - - # Update the value and also set update_replace prop - tmpl_update = _change_rsrc_properties( - test_template_one_resource, ['test1'], - {'value': 'test_in_place_update', 'update_replace': True}) - self.update_stack(stack_identifier, tmpl_update) - resource = self.client.resources.list(stack_identifier) - # update Replace - self.assertNotEqual(initial_phy_id, - resource[0].physical_resource_id) - - def test_stack_update_add_remove(self): - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], - {'value': 'test_add_remove'}) - stack_identifier = self.stack_create( - template=template) - initial_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - tmpl_update = _change_rsrc_properties( - test_template_two_resource, ['test1', 'test2'], - {'value': 'test_add_remove_update'}) - # Add one resource via a stack update - self.update_stack(stack_identifier, tmpl_update) - updated_resources = {'test1': 'OS::Heat::TestResource', - 'test2': 'OS::Heat::TestResource'} - self.assertEqual(updated_resources, - self.list_resources(stack_identifier)) - - # Then remove it by updating with the original template - self.update_stack(stack_identifier, template) - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - def test_stack_update_rollback(self): - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], - {'value': 'test_update_rollback'}) - stack_identifier = self.stack_create( - template=template) - initial_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - tmpl_update = _change_rsrc_properties( - test_template_two_resource, ['test1', 'test2'], - {'value': 'test_update_rollback', 'fail': True}) - # stack update, also set failure - self.update_stack(stack_identifier, tmpl_update, - expected_status='ROLLBACK_COMPLETE', - disable_rollback=False) - # since stack update failed only the original resource is present - updated_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(updated_resources, - self.list_resources(stack_identifier)) - - def test_stack_update_from_failed(self): - # Prove it's possible to update from an UPDATE_FAILED state - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], - {'value': 'test_update_failed'}) - stack_identifier = self.stack_create( - template=template) - initial_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - tmpl_update = _change_rsrc_properties( - test_template_one_resource, ['test1'], {'fail': True}) - # Update with bad template, we should fail - self.update_stack(stack_identifier, tmpl_update, - expected_status='UPDATE_FAILED') - # but then passing a good template should succeed - self.update_stack(stack_identifier, test_template_two_resource) - updated_resources = {'test1': 'OS::Heat::TestResource', - 'test2': 'OS::Heat::TestResource'} - self.assertEqual(updated_resources, - self.list_resources(stack_identifier)) - - def test_stack_update_provider(self): - template = _change_rsrc_properties( - test_template_one_resource, ['test1'], - {'value': 'test_provider_template'}) - files = {'provider.template': json.dumps(template)} - env = {'resource_registry': - {'My::TestResource': 'provider.template'}} - stack_identifier = self.stack_create( - template=self.provider_template, - files=files, - environment=env - ) - - initial_resources = {'test1': 'My::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - # Prove the resource is backed by a nested stack, save the ID - nested_identifier = self.assert_resource_is_a_stack(stack_identifier, - 'test1') - nested_id = nested_identifier.split('/')[-1] - - # Then check the expected resources are in the nested stack - nested_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - tmpl_update = _change_rsrc_properties( - test_template_two_resource, ['test1', 'test2'], - {'value': 'test_provider_template'}) - # Add one resource via a stack update by changing the nested stack - files['provider.template'] = json.dumps(tmpl_update) - self.update_stack(stack_identifier, self.provider_template, - environment=env, files=files) - - # Parent resources should be unchanged and the nested stack - # should have been updated in-place without replacement - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - rsrc = self.client.resources.get(stack_identifier, 'test1') - self.assertEqual(rsrc.physical_resource_id, nested_id) - - # Then check the expected resources are in the nested stack - nested_resources = {'test1': 'OS::Heat::TestResource', - 'test2': 'OS::Heat::TestResource'} - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - - def test_stack_update_alias_type(self): - env = {'resource_registry': - {'My::TestResource': 'OS::Heat::RandomString', - 'My::TestResource2': 'OS::Heat::RandomString'}} - stack_identifier = self.stack_create( - template=self.provider_template, - environment=env - ) - p_res = self.client.resources.get(stack_identifier, 'test1') - self.assertEqual('My::TestResource', p_res.resource_type) - - initial_resources = {'test1': 'My::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - res = self.client.resources.get(stack_identifier, 'test1') - # Modify the type of the resource alias to My::TestResource2 - tmpl_update = copy.deepcopy(self.provider_template) - tmpl_update['resources']['test1']['type'] = 'My::TestResource2' - self.update_stack(stack_identifier, tmpl_update, environment=env) - res_a = self.client.resources.get(stack_identifier, 'test1') - self.assertEqual(res.physical_resource_id, res_a.physical_resource_id) - self.assertEqual(res.attributes['value'], res_a.attributes['value']) - - def test_stack_update_alias_changes(self): - env = {'resource_registry': - {'My::TestResource': 'OS::Heat::RandomString'}} - stack_identifier = self.stack_create( - template=self.provider_template, - environment=env - ) - p_res = self.client.resources.get(stack_identifier, 'test1') - self.assertEqual('My::TestResource', p_res.resource_type) - - initial_resources = {'test1': 'My::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - res = self.client.resources.get(stack_identifier, 'test1') - # Modify the resource alias to point to a different type - env = {'resource_registry': - {'My::TestResource': 'OS::Heat::TestResource'}} - self.update_stack(stack_identifier, template=self.provider_template, - environment=env) - res_a = self.client.resources.get(stack_identifier, 'test1') - self.assertNotEqual(res.physical_resource_id, - res_a.physical_resource_id) - - def test_stack_update_provider_type(self): - template = _change_rsrc_properties( - test_template_one_resource, ['test1'], - {'value': 'test_provider_template'}) - files = {'provider.template': json.dumps(template)} - env = {'resource_registry': - {'My::TestResource': 'provider.template', - 'My::TestResource2': 'provider.template'}} - stack_identifier = self.stack_create( - template=self.provider_template, - files=files, - environment=env - ) - p_res = self.client.resources.get(stack_identifier, 'test1') - self.assertEqual('My::TestResource', p_res.resource_type) - - initial_resources = {'test1': 'My::TestResource'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - # Prove the resource is backed by a nested stack, save the ID - nested_identifier = self.assert_resource_is_a_stack(stack_identifier, - 'test1') - nested_id = nested_identifier.split('/')[-1] - - # Then check the expected resources are in the nested stack - nested_resources = {'test1': 'OS::Heat::TestResource'} - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - n_res = self.client.resources.get(nested_identifier, 'test1') - - # Modify the type of the provider resource to My::TestResource2 - tmpl_update = copy.deepcopy(self.provider_template) - tmpl_update['resources']['test1']['type'] = 'My::TestResource2' - self.update_stack(stack_identifier, tmpl_update, - environment=env, files=files) - p_res = self.client.resources.get(stack_identifier, 'test1') - self.assertEqual('My::TestResource2', p_res.resource_type) - - # Parent resources should be unchanged and the nested stack - # should have been updated in-place without replacement - self.assertEqual({u'test1': u'My::TestResource2'}, - self.list_resources(stack_identifier)) - rsrc = self.client.resources.get(stack_identifier, 'test1') - self.assertEqual(rsrc.physical_resource_id, nested_id) - - # Then check the expected resources are in the nested stack - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - n_res2 = self.client.resources.get(nested_identifier, 'test1') - self.assertEqual(n_res.physical_resource_id, - n_res2.physical_resource_id) - - def test_stack_update_provider_group(self): - """Test two-level nested update.""" - - # Create a ResourceGroup (which creates a nested stack), - # containing provider resources (which create a nested - # stack), thus exercising an update which traverses - # two levels of nesting. - template = _change_rsrc_properties( - test_template_one_resource, ['test1'], - {'value': 'test_provider_group_template'}) - files = {'provider.template': json.dumps(template)} - env = {'resource_registry': - {'My::TestResource': 'provider.template'}} - - stack_identifier = self.stack_create( - template=self.provider_group_template, - files=files, - environment=env - ) - - initial_resources = {'test_group': 'OS::Heat::ResourceGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - # Prove the resource is backed by a nested stack, save the ID - nested_identifier = self.assert_resource_is_a_stack(stack_identifier, - 'test_group') - - # Then check the expected resources are in the nested stack - nested_resources = {'0': 'My::TestResource', - '1': 'My::TestResource'} - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - - for n_rsrc in nested_resources: - rsrc = self.client.resources.get(nested_identifier, n_rsrc) - provider_stack = self.client.stacks.get(rsrc.physical_resource_id) - provider_identifier = '%s/%s' % (provider_stack.stack_name, - provider_stack.id) - provider_resources = {u'test1': u'OS::Heat::TestResource'} - self.assertEqual(provider_resources, - self.list_resources(provider_identifier)) - - tmpl_update = _change_rsrc_properties( - test_template_two_resource, ['test1', 'test2'], - {'value': 'test_provider_group_template'}) - # Add one resource via a stack update by changing the nested stack - files['provider.template'] = json.dumps(tmpl_update) - self.update_stack(stack_identifier, self.provider_group_template, - environment=env, files=files) - - # Parent resources should be unchanged and the nested stack - # should have been updated in-place without replacement - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - # Resource group stack should also be unchanged (but updated) - nested_stack = self.client.stacks.get(nested_identifier) - self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status) - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - - for n_rsrc in nested_resources: - rsrc = self.client.resources.get(nested_identifier, n_rsrc) - provider_stack = self.client.stacks.get(rsrc.physical_resource_id) - provider_identifier = '%s/%s' % (provider_stack.stack_name, - provider_stack.id) - provider_resources = {'test1': 'OS::Heat::TestResource', - 'test2': 'OS::Heat::TestResource'} - self.assertEqual(provider_resources, - self.list_resources(provider_identifier)) - - def test_stack_update_with_replacing_userdata(self): - """Test case for updating userdata of instance. - - Confirm that we can update userdata of instance during updating stack - by the user of member role. - - Make sure that a resource that inherits from StackUser can be deleted - during updating stack. - """ - if not self.conf.minimal_image_ref: - raise self.skipException("No minimal image configured to test") - if not self.conf.minimal_instance_type: - raise self.skipException("No flavor configured to test") - - parms = {'flavor': self.conf.minimal_instance_type, - 'image': self.conf.minimal_image_ref, - 'network': self.conf.fixed_network_name, - 'user_data': ''} - - stack_identifier = self.stack_create( - template=self.update_userdata_template, - parameters=parms - ) - - parms_updated = parms - parms_updated['user_data'] = 'two' - self.update_stack( - stack_identifier, - template=self.update_userdata_template, - parameters=parms_updated) - - def test_stack_update_provider_group_patch(self): - '''Test two-level nested update with PATCH''' - template = _change_rsrc_properties( - test_template_one_resource, ['test1'], - {'value': 'test_provider_group_template'}) - files = {'provider.template': json.dumps(template)} - env = {'resource_registry': - {'My::TestResource': 'provider.template'}} - - stack_identifier = self.stack_create( - template=self.provider_group_template, - files=files, - environment=env - ) - - initial_resources = {'test_group': 'OS::Heat::ResourceGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - # Prove the resource is backed by a nested stack, save the ID - nested_identifier = self.assert_resource_is_a_stack(stack_identifier, - 'test_group') - - # Then check the expected resources are in the nested stack - nested_resources = {'0': 'My::TestResource', - '1': 'My::TestResource'} - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - - # increase the count, pass only the paramter, no env or template - params = {'count': 3} - self.update_stack(stack_identifier, parameters=params, existing=True) - - # Parent resources should be unchanged and the nested stack - # should have been updated in-place without replacement - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - # Resource group stack should also be unchanged (but updated) - nested_stack = self.client.stacks.get(nested_identifier) - self.assertEqual('UPDATE_COMPLETE', nested_stack.stack_status) - # Add a resource, as we should have added one - nested_resources['2'] = 'My::TestResource' - self.assertEqual(nested_resources, - self.list_resources(nested_identifier)) - - def test_stack_update_from_failed_patch(self): - '''Test PATCH update from a failed state.''' - - # Start with empty template - stack_identifier = self.stack_create( - template='heat_template_version: 2014-10-16') - - # Update with a good template, but bad parameter - self.update_stack(stack_identifier, - template=self.fail_param_template, - parameters={'do_fail': True}, - expected_status='UPDATE_FAILED') - - # PATCH update, only providing the parameter - self.update_stack(stack_identifier, - parameters={'do_fail': False}, - existing=True) - self.assertEqual({u'aresource': u'OS::Heat::TestResource'}, - self.list_resources(stack_identifier)) - - def test_stack_update_with_new_env(self): - """Update handles new resource types in the environment. - - If a resource type appears during an update and the update fails, - retrying the update is able to find the type properly in the - environment. - """ - stack_identifier = self.stack_create( - template=test_template_one_resource) - - # Update with a new resource and make the update fails - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], {'fail': True}) - template['resources']['test2'] = {'type': 'My::TestResource'} - template['resources']['test1']['depends_on'] = 'test2' - env = {'resource_registry': - {'My::TestResource': 'OS::Heat::TestResource'}} - self.update_stack(stack_identifier, - template=template, - environment=env, - expected_status='UPDATE_FAILED') - - # Fixing the template should fix the stack - template = _change_rsrc_properties(template, - ['test1'], {'fail': False}) - self.update_stack(stack_identifier, - template=template, - environment=env) - self.assertEqual({'test1': 'OS::Heat::TestResource', - 'test2': 'My::TestResource'}, - self.list_resources(stack_identifier)) - - def test_stack_update_with_new_version(self): - """Update handles new template version in failure. - - If a stack update fails while changing the template version, update is - able to handle the new version fine. - """ - stack_identifier = self.stack_create( - template=test_template_one_resource) - - # Update with a new function and make the update fails - template = _change_rsrc_properties(test_template_two_resource, - ['test1'], {'fail': True}) - - template['heat_template_version'] = '2015-10-15' - template['resources']['test2']['properties']['value'] = { - 'list_join': [',', ['a'], ['b']]} - self.update_stack(stack_identifier, - template=template, - expected_status='UPDATE_FAILED') - - template = _change_rsrc_properties(template, - ['test2'], {'value': 'Test2'}) - self.update_stack(stack_identifier, - template=template, - expected_status='UPDATE_FAILED') - self._stack_delete(stack_identifier) - - def test_stack_update_with_old_version(self): - """Update handles old template version in failure. - - If a stack update fails while changing the template version, update is - able to handle the old version fine. - """ - template = _change_rsrc_properties( - test_template_one_resource, - ['test1'], {'value': {'list_join': [',', ['a'], ['b']]}}) - template['heat_template_version'] = '2015-10-15' - stack_identifier = self.stack_create( - template=template) - - # Update with a new function and make the update fails - template = _change_rsrc_properties(test_template_one_resource, - ['test1'], {'fail': True}) - self.update_stack(stack_identifier, - template=template, - expected_status='UPDATE_FAILED') - self._stack_delete(stack_identifier) - - def test_stack_update_with_conditions(self): - """Update manages new conditions added. - - When a new resource is added during updates, the stacks handles the new - conditions correctly, and doesn't fail to load them while the update is - still in progress. - """ - stack_identifier = self.stack_create( - template=test_template_one_resource) - - updated_template = copy.deepcopy(test_template_two_resource) - updated_template['conditions'] = {'cond1': True} - updated_template['resources']['test3'] = { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': {'if': ['cond1', 'val3', 'val4']} - } - } - test2_props = updated_template['resources']['test2']['properties'] - test2_props['action_wait_secs'] = {'create': 30} - - self.update_stack(stack_identifier, - template=updated_template, - expected_status='UPDATE_IN_PROGRESS') - - def check_resources(): - resources = self.list_resources(stack_identifier) - if len(resources) < 2: - return False - self.assertIn('test3', resources) - return True - - self.assertTrue(test.call_until_true(20, 2, check_resources)) diff --git a/heat_tempest_plugin/tests/functional/test_default_parameters.py b/heat_tempest_plugin/tests/functional/test_default_parameters.py deleted file mode 100644 index 24aa6e4..0000000 --- a/heat_tempest_plugin/tests/functional/test_default_parameters.py +++ /dev/null @@ -1,92 +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 yaml - -from heat_tempest_plugin.tests.functional import functional_base - - -class DefaultParametersTest(functional_base.FunctionalTestsBase): - - template = ''' -heat_template_version: 2013-05-23 -parameters: - length: - type: string - default: 40 -resources: - random1: - type: nested_random.yaml - random2: - type: OS::Heat::RandomString - properties: - length: {get_param: length} -outputs: - random1: - value: {get_attr: [random1, random1_value]} - random2: - value: {get_resource: random2} -''' - nested_template = ''' -heat_template_version: 2013-05-23 -parameters: - length: - type: string - default: 50 -resources: - random1: - type: OS::Heat::RandomString - properties: - length: {get_param: length} -outputs: - random1_value: - value: {get_resource: random1} -''' - - scenarios = [ - ('none', dict(param=None, default=None, temp_def=True, - expect1=50, expect2=40)), - ('default', dict(param=None, default=12, temp_def=True, - expect1=12, expect2=12)), - ('both', dict(param=15, default=12, temp_def=True, - expect1=12, expect2=15)), - ('no_temp_default', dict(param=None, default=12, temp_def=False, - expect1=12, expect2=12)), - ] - - def test_defaults(self): - env = {'parameters': {}, 'parameter_defaults': {}} - if self.param: - env['parameters'] = {'length': self.param} - if self.default: - env['parameter_defaults'] = {'length': self.default} - - if not self.temp_def: - # remove the default from the parameter in the nested template. - ntempl = yaml.safe_load(self.nested_template) - del ntempl['parameters']['length']['default'] - nested_template = yaml.safe_dump(ntempl) - else: - nested_template = self.nested_template - - stack_identifier = self.stack_create( - template=self.template, - files={'nested_random.yaml': nested_template}, - environment=env - ) - - stack = self.client.stacks.get(stack_identifier) - for out in stack.outputs: - if out['output_key'] == 'random1': - self.assertEqual(self.expect1, len(out['output_value'])) - if out['output_key'] == 'random2': - self.assertEqual(self.expect2, len(out['output_value'])) diff --git a/heat_tempest_plugin/tests/functional/test_delete.py b/heat_tempest_plugin/tests/functional/test_delete.py deleted file mode 100644 index 20266d6..0000000 --- a/heat_tempest_plugin/tests/functional/test_delete.py +++ /dev/null @@ -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. - -import time - -from heat_tempest_plugin.tests.functional import functional_base - - -class DeleteInProgressTest(functional_base.FunctionalTestsBase): - - root_template = ''' -heat_template_version: 2013-05-23 -resources: - rg: - type: OS::Heat::ResourceGroup - properties: - count: 125 - resource_def: - type: empty.yaml -''' - - empty_template = ''' -heat_template_version: 2013-05-23 -resources: -''' - - def test_delete_nested_stacks_create_in_progress(self): - files = {'empty.yaml': self.empty_template} - identifier = self.stack_create(template=self.root_template, - files=files, - expected_status='CREATE_IN_PROGRESS') - time.sleep(20) - self._stack_delete(identifier) diff --git a/heat_tempest_plugin/tests/functional/test_env_merge.py b/heat_tempest_plugin/tests/functional/test_env_merge.py deleted file mode 100644 index 68ec035..0000000 --- a/heat_tempest_plugin/tests/functional/test_env_merge.py +++ /dev/null @@ -1,95 +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 heat_tempest_plugin.tests.functional import functional_base - - -TEMPLATE = ''' - heat_template_version: 2015-04-30 - parameters: - p0: - type: string - default: CORRECT - p1: - type: string - default: INCORRECT - p2: - type: string - default: INCORRECT - resources: - r1: - type: test::R1 - r2: - type: test::R2 - r3a: - type: test::R3 - r3b: - type: test::R3 -''' - -ENV_1 = ''' - parameters: - p1: CORRECT - p2: INCORRECT-E1 - resource_registry: - test::R1: OS::Heat::RandomString - test::R2: BROKEN - test::R3: OS::Heat::None -''' - -ENV_2 = ''' - parameters: - p2: CORRECT - resource_registry: - test::R2: OS::Heat::RandomString - resources: - r3b: - test::R3: OS::Heat::RandomString -''' - - -class EnvironmentMergingTests(functional_base.FunctionalTestsBase): - - def test_server_environment_merging(self): - - # Setup - files = {'env1.yaml': ENV_1, 'env2.yaml': ENV_2} - environment_files = ['env1.yaml', 'env2.yaml'] - - # Test - stack_id = self.stack_create(stack_name='env_merge', - template=TEMPLATE, - files=files, - environment_files=environment_files) - - # Verify - - # Since there is no environment show, the registry overriding - # is partially verified by there being no error. If it wasn't - # working, test::R2 would remain mapped to BROKEN in env1. - - # Sanity check - resources = self.list_resources(stack_id) - self.assertEqual(4, len(resources)) - - # Verify the parameters are correctly set - stack = self.client.stacks.get(stack_id) - self.assertEqual('CORRECT', stack.parameters['p0']) - self.assertEqual('CORRECT', stack.parameters['p1']) - self.assertEqual('CORRECT', stack.parameters['p2']) - - # Verify that r3b has been overridden into a RandomString - # by checking to see that it has a value - r3b = self.client.resources.get(stack_id, 'r3b') - r3b_attrs = r3b.attributes - self.assertIn('value', r3b_attrs) diff --git a/heat_tempest_plugin/tests/functional/test_heat_autoscaling.py b/heat_tempest_plugin/tests/functional/test_heat_autoscaling.py deleted file mode 100644 index a83c7fe..0000000 --- a/heat_tempest_plugin/tests/functional/test_heat_autoscaling.py +++ /dev/null @@ -1,215 +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 heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - - -class HeatAutoscalingTest(functional_base.FunctionalTestsBase): - template = ''' -heat_template_version: 2014-10-16 - -resources: - random_group: - type: OS::Heat::AutoScalingGroup - properties: - cooldown: 0 - desired_capacity: 3 - max_size: 5 - min_size: 2 - resource: - type: OS::Heat::RandomString - - scale_up_policy: - type: OS::Heat::ScalingPolicy - properties: - adjustment_type: change_in_capacity - auto_scaling_group_id: { get_resource: random_group } - scaling_adjustment: 1 - - scale_down_policy: - type: OS::Heat::ScalingPolicy - properties: - adjustment_type: change_in_capacity - auto_scaling_group_id: { get_resource: random_group } - scaling_adjustment: -1 - -outputs: - all_values: - value: {get_attr: [random_group, outputs_list, value]} - value_0: - value: {get_attr: [random_group, resource.0.value]} - value_1: - value: {get_attr: [random_group, resource.1.value]} - value_2: - value: {get_attr: [random_group, resource.2.value]} - asg_size: - value: {get_attr: [random_group, current_size]} -''' - - template_nested = ''' -heat_template_version: 2014-10-16 - -resources: - random_group: - type: OS::Heat::AutoScalingGroup - properties: - desired_capacity: 3 - max_size: 5 - min_size: 2 - resource: - type: randomstr.yaml - -outputs: - all_values: - value: {get_attr: [random_group, outputs_list, random_str]} - value_0: - value: {get_attr: [random_group, resource.0.random_str]} - value_1: - value: {get_attr: [random_group, resource.1.random_str]} - value_2: - value: {get_attr: [random_group, resource.2.random_str]} -''' - - template_randomstr = ''' -heat_template_version: 2013-05-23 - -resources: - random_str: - type: OS::Heat::RandomString - -outputs: - random_str: - value: {get_attr: [random_str, value]} -''' - - def _assert_output_values(self, stack_id): - stack = self.client.stacks.get(stack_id) - all_values = self._stack_output(stack, 'all_values') - self.assertEqual(3, len(all_values)) - self.assertEqual(all_values[0], self._stack_output(stack, 'value_0')) - self.assertEqual(all_values[1], self._stack_output(stack, 'value_1')) - self.assertEqual(all_values[2], self._stack_output(stack, 'value_2')) - - def test_asg_scale_up_max_size(self): - stack_id = self.stack_create(template=self.template, - expected_status='CREATE_COMPLETE') - stack = self.client.stacks.get(stack_id) - asg_size = self._stack_output(stack, 'asg_size') - # Ensure that initial desired capacity is met - self.assertEqual(3, asg_size) - - # send scale up signals and ensure that asg honors max_size - asg = self.client.resources.get(stack_id, 'random_group') - max_size = 5 - for num in range(asg_size+1, max_size+2): - expected_resources = num if num <= max_size else max_size - self.client.resources.signal(stack_id, 'scale_up_policy') - self.assertTrue( - test.call_until_true(self.conf.build_timeout, - self.conf.build_interval, - self.check_autoscale_complete, - asg.physical_resource_id, - expected_resources, stack_id, - 'scale_up_policy')) - - def test_asg_scale_down_min_size(self): - stack_id = self.stack_create(template=self.template, - expected_status='CREATE_COMPLETE') - stack = self.client.stacks.get(stack_id) - asg_size = self._stack_output(stack, 'asg_size') - # Ensure that initial desired capacity is met - self.assertEqual(3, asg_size) - - # send scale down signals and ensure that asg honors min_size - asg = self.client.resources.get(stack_id, 'random_group') - min_size = 2 - for num in range(asg_size-1, 0, -1): - expected_resources = num if num >= min_size else min_size - self.client.resources.signal(stack_id, 'scale_down_policy') - self.assertTrue( - test.call_until_true(self.conf.build_timeout, - self.conf.build_interval, - self.check_autoscale_complete, - asg.physical_resource_id, - expected_resources, stack_id, - 'scale_down_policy')) - - def test_asg_cooldown(self): - cooldown_tmpl = self.template.replace('cooldown: 0', - 'cooldown: 60') - stack_id = self.stack_create(template=cooldown_tmpl, - expected_status='CREATE_COMPLETE') - stack = self.client.stacks.get(stack_id) - asg_size = self._stack_output(stack, 'asg_size') - # Ensure that initial desired capacity is met - self.assertEqual(3, asg_size) - - # send scale up signal. - # Since cooldown is in effect, number of resources should not change - asg = self.client.resources.get(stack_id, 'random_group') - expected_resources = 3 - self.client.resources.signal(stack_id, 'scale_up_policy') - self.assertTrue( - test.call_until_true(self.conf.build_timeout, - self.conf.build_interval, - self.check_autoscale_complete, - asg.physical_resource_id, - expected_resources, stack_id, - 'scale_up_policy')) - - def test_path_attrs(self): - stack_id = self.stack_create(template=self.template) - expected_resources = {'random_group': 'OS::Heat::AutoScalingGroup', - 'scale_up_policy': 'OS::Heat::ScalingPolicy', - 'scale_down_policy': 'OS::Heat::ScalingPolicy'} - self.assertEqual(expected_resources, self.list_resources(stack_id)) - self._assert_output_values(stack_id) - - def test_path_attrs_nested(self): - files = {'randomstr.yaml': self.template_randomstr} - stack_id = self.stack_create(template=self.template_nested, - files=files) - expected_resources = {'random_group': 'OS::Heat::AutoScalingGroup'} - self.assertEqual(expected_resources, self.list_resources(stack_id)) - self._assert_output_values(stack_id) - - -class AutoScalingGroupUpdateWithNoChanges(functional_base.FunctionalTestsBase): - - template = ''' -heat_template_version: 2013-05-23 - -resources: - test_group: - type: OS::Heat::AutoScalingGroup - properties: - desired_capacity: 0 - max_size: 0 - min_size: 0 - resource: - type: OS::Heat::RandomString - test_policy: - type: OS::Heat::ScalingPolicy - properties: - adjustment_type: change_in_capacity - auto_scaling_group_id: { get_resource: test_group } - scaling_adjustment: 1 -''' - - def test_as_group_update_without_resource_changes(self): - stack_identifier = self.stack_create(template=self.template) - new_template = self.template.replace( - 'scaling_adjustment: 1', - 'scaling_adjustment: 2') - - self.update_stack(stack_identifier, template=new_template) diff --git a/heat_tempest_plugin/tests/functional/test_immutable_parameters.py b/heat_tempest_plugin/tests/functional/test_immutable_parameters.py deleted file mode 100644 index f031c01..0000000 --- a/heat_tempest_plugin/tests/functional/test_immutable_parameters.py +++ /dev/null @@ -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 heat_tempest_plugin.tests.functional import functional_base -from heatclient import exc as heat_exceptions - - -class ImmutableParametersTest(functional_base.FunctionalTestsBase): - - template_param_has_no_immutable_field = ''' -heat_template_version: 2014-10-16 -parameters: - param1: - type: string - default: default_value -outputs: - param1_output: - description: 'parameter 1 details' - value: { get_param: param1 } -''' - - template_param_has_immutable_field = ''' -heat_template_version: 2014-10-16 -parameters: - param1: - type: string - default: default_value - immutable: false -outputs: - param1_output: - description: 'parameter 1 details' - value: { get_param: param1 } -''' - - def test_no_immutable_param_field(self): - param1_create_value = 'value1' - create_parameters = {"param1": param1_create_value} - - stack_identifier = self.stack_create( - template=self.template_param_has_no_immutable_field, - parameters=create_parameters - ) - stack = self.client.stacks.get(stack_identifier) - - # Verify the value of the parameter - self.assertEqual(param1_create_value, - self._stack_output(stack, 'param1_output')) - - param1_update_value = 'value2' - update_parameters = {"param1": param1_update_value} - - self.update_stack( - stack_identifier, - template=self.template_param_has_no_immutable_field, - parameters=update_parameters) - - stack = self.client.stacks.get(stack_identifier) - - # Verify the value of the updated parameter - self.assertEqual(param1_update_value, - self._stack_output(stack, 'param1_output')) - - def test_immutable_param_field_allowed(self): - param1_create_value = 'value1' - create_parameters = {"param1": param1_create_value} - - stack_identifier = self.stack_create( - template=self.template_param_has_immutable_field, - parameters=create_parameters - ) - stack = self.client.stacks.get(stack_identifier) - - # Verify the value of the parameter - self.assertEqual(param1_create_value, - self._stack_output(stack, 'param1_output')) - - param1_update_value = 'value2' - update_parameters = {"param1": param1_update_value} - - self.update_stack( - stack_identifier, - template=self.template_param_has_immutable_field, - parameters=update_parameters) - stack = self.client.stacks.get(stack_identifier) - - # Verify the value of the updated parameter - self.assertEqual(param1_update_value, - self._stack_output(stack, 'param1_output')) - - # Ensure stack is not in a failed state - self.assertEqual('UPDATE_COMPLETE', stack.stack_status) - - def test_immutable_param_field_error(self): - param1_create_value = 'value1' - create_parameters = {"param1": param1_create_value} - - # Toggle the immutable field to preclude updating - immutable_true = self.template_param_has_immutable_field.replace( - 'immutable: false', 'immutable: true') - - stack_identifier = self.stack_create( - template=immutable_true, - parameters=create_parameters - ) - stack = self.client.stacks.get(stack_identifier) - - param1_update_value = 'value2' - update_parameters = {"param1": param1_update_value} - - # Verify the value of the parameter - self.assertEqual(param1_create_value, - self._stack_output(stack, 'param1_output')) - - # Attempt to update the stack with a new parameter value - try: - self.update_stack( - stack_identifier, - template=immutable_true, - parameters=update_parameters) - except heat_exceptions.HTTPBadRequest as exc: - exp = ('The following parameters are immutable and may not be ' - 'updated: param1') - self.assertIn(exp, str(exc)) - - stack = self.client.stacks.get(stack_identifier) - - # Ensure stack is not in a failed state - self.assertEqual('CREATE_COMPLETE', stack.stack_status) - - # Ensure immutable parameter has not changed - self.assertEqual(param1_create_value, - self._stack_output(stack, 'param1_output')) diff --git a/heat_tempest_plugin/tests/functional/test_instance_group.py b/heat_tempest_plugin/tests/functional/test_instance_group.py deleted file mode 100644 index c0bb7e8..0000000 --- a/heat_tempest_plugin/tests/functional/test_instance_group.py +++ /dev/null @@ -1,500 +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 -import json - -from testtools import matchers - -from heat_tempest_plugin.tests.functional import functional_base - - -class InstanceGroupTest(functional_base.FunctionalTestsBase): - - template = ''' -{ - "AWSTemplateFormatVersion" : "2010-09-09", - "Description" : "Template to create multiple instances.", - "Parameters" : {"size": {"Type": "String", "Default": "1"}, - "AZ": {"Type": "String", "Default": "nova"}, - "image": {"Type": "String"}, - "flavor": {"Type": "String"}, - "user_data": {"Type": "String", "Default": "jsconfig data"}}, - "Resources": { - "JobServerGroup": { - "Type": "OS::Heat::InstanceGroup", - "Properties": { - "LaunchConfigurationName" : {"Ref": "JobServerConfig"}, - "Size" : {"Ref": "size"}, - "AvailabilityZones" : [{"Ref": "AZ"}] - } - }, - - "JobServerConfig" : { - "Type" : "AWS::AutoScaling::LaunchConfiguration", - "Metadata": {"foo": "bar"}, - "Properties": { - "ImageId" : {"Ref": "image"}, - "InstanceType" : {"Ref": "flavor"}, - "SecurityGroups" : [ "sg-1" ], - "UserData" : {"Ref": "user_data"} - } - } - }, - "Outputs": { - "InstanceList": {"Value": { - "Fn::GetAtt": ["JobServerGroup", "InstanceList"]}}, - "JobServerConfigRef": {"Value": { - "Ref": "JobServerConfig"}} - } -} -''' - - instance_template = ''' -heat_template_version: 2013-05-23 -parameters: - ImageId: {type: string} - InstanceType: {type: string} - SecurityGroups: {type: comma_delimited_list} - UserData: {type: string} - Tags: {type: comma_delimited_list} - -resources: - random1: - type: OS::Heat::RandomString - properties: - salt: {get_param: UserData} -outputs: - PublicIp: - value: {get_attr: [random1, value]} -''' - - # This is designed to fail. - bad_instance_template = ''' -heat_template_version: 2013-05-23 -parameters: - ImageId: {type: string} - InstanceType: {type: string} - SecurityGroups: {type: comma_delimited_list} - UserData: {type: string} - Tags: {type: comma_delimited_list} - -resources: - random1: - type: OS::Heat::RandomString - depends_on: waiter - ready_poster: - type: AWS::CloudFormation::WaitConditionHandle - waiter: - type: AWS::CloudFormation::WaitCondition - properties: - Handle: {Ref: ready_poster} - Timeout: 1 -outputs: - PublicIp: - value: {get_attr: [random1, value]} -''' - - def setUp(self): - super(InstanceGroupTest, self).setUp() - if not self.conf.minimal_image_ref: - raise self.skipException("No minimal image configured to test") - if not self.conf.instance_type: - raise self.skipException("No flavor configured to test") - - def assert_instance_count(self, stack, expected_count): - inst_list = self._stack_output(stack, 'InstanceList') - self.assertEqual(expected_count, len(inst_list.split(','))) - - def _assert_instance_state(self, nested_identifier, - num_complete, num_failed): - for res in self.client.resources.list(nested_identifier): - if 'COMPLETE' in res.resource_status: - num_complete = num_complete - 1 - elif 'FAILED' in res.resource_status: - num_failed = num_failed - 1 - self.assertEqual(0, num_failed) - self.assertEqual(0, num_complete) - - -class InstanceGroupBasicTest(InstanceGroupTest): - - def test_basic_create_works(self): - """Make sure the working case is good. - - Note this combines test_override_aws_ec2_instance into this test as - well, which is: - If AWS::EC2::Instance is overridden, InstanceGroup will automatically - use that overridden resource type. - """ - - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 4, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - stack_identifier = self.stack_create(template=self.template, - files=files, environment=env) - initial_resources = { - 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration', - 'JobServerGroup': 'OS::Heat::InstanceGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 4) - - def test_size_updates_work(self): - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 2, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - stack_identifier = self.stack_create(template=self.template, - files=files, - environment=env) - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 2) - - # Increase min size to 5 - env2 = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 5, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - self.update_stack(stack_identifier, self.template, - environment=env2, files=files) - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 5) - - def test_update_group_replace(self): - """Test case for ensuring non-updatable props case a replacement. - - Make sure that during a group update the non-updatable properties cause - a replacement. - """ - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': - {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 1, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - stack_identifier = self.stack_create(template=self.template, - files=files, - environment=env) - rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup') - orig_asg_id = rsrc.physical_resource_id - - env2 = {'resource_registry': - {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': '2', - 'AZ': 'wibble', - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type, - 'user_data': 'new data'}} - self.update_stack(stack_identifier, self.template, - environment=env2, files=files) - - # replacement will cause the resource physical_resource_id to change. - rsrc = self.client.resources.get(stack_identifier, 'JobServerGroup') - self.assertNotEqual(orig_asg_id, rsrc.physical_resource_id) - - def test_create_instance_error_causes_group_error(self): - """Test create failing a resource in the instance group. - - If a resource in an instance group fails to be created, the instance - group itself will fail and the broken inner resource will remain. - """ - stack_name = self._stack_rand_name() - files = {'provider.yaml': self.bad_instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 2, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - self.client.stacks.create( - stack_name=stack_name, - template=self.template, - files=files, - disable_rollback=True, - parameters={}, - environment=env - ) - self.addCleanup(self._stack_delete, stack_name) - stack = self.client.stacks.get(stack_name) - stack_identifier = '%s/%s' % (stack_name, stack.id) - self._wait_for_stack_status(stack_identifier, 'CREATE_FAILED') - initial_resources = { - 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration', - 'JobServerGroup': 'OS::Heat::InstanceGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - self._assert_instance_state(nested_ident, 0, 2) - - def test_update_instance_error_causes_group_error(self): - """Test update failing a resource in the instance group. - - If a resource in an instance group fails to be created during an - update, the instance group itself will fail and the broken inner - resource will remain. - """ - files = {'provider.yaml': self.instance_template} - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': 2, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.instance_type}} - - stack_identifier = self.stack_create(template=self.template, - files=files, - environment=env) - initial_resources = { - 'JobServerConfig': 'AWS::AutoScaling::LaunchConfiguration', - 'JobServerGroup': 'OS::Heat::InstanceGroup'} - self.assertEqual(initial_resources, - self.list_resources(stack_identifier)) - - stack = self.client.stacks.get(stack_identifier) - self.assert_instance_count(stack, 2) - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - self._assert_instance_state(nested_ident, 2, 0) - initial_list = [res.resource_name - for res in self.client.resources.list(nested_ident)] - - env['parameters']['size'] = 3 - files2 = {'provider.yaml': self.bad_instance_template} - self.client.stacks.update( - stack_id=stack_identifier, - template=self.template, - files=files2, - disable_rollback=True, - parameters={}, - environment=env - ) - self._wait_for_stack_status(stack_identifier, 'UPDATE_FAILED') - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - # assert that there are 3 bad instances - # 2 resources should be in update failed, and one create failed. - for res in self.client.resources.list(nested_ident): - if res.resource_name in initial_list: - self._wait_for_resource_status(nested_ident, - res.resource_name, - 'UPDATE_FAILED') - else: - self._wait_for_resource_status(nested_ident, - res.resource_name, - 'CREATE_FAILED') - - -class InstanceGroupUpdatePolicyTest(InstanceGroupTest): - - def ig_tmpl_with_updt_policy(self): - templ = json.loads(copy.deepcopy(self.template)) - up = {"RollingUpdate": { - "MinInstancesInService": "1", - "MaxBatchSize": "2", - "PauseTime": "PT1S"}} - templ['Resources']['JobServerGroup']['UpdatePolicy'] = up - return templ - - def update_instance_group(self, updt_template, - num_updates_expected_on_updt, - num_creates_expected_on_updt, - num_deletes_expected_on_updt, - update_replace): - - # setup stack from the initial template - files = {'provider.yaml': self.instance_template} - size = 5 - env = {'resource_registry': {'AWS::EC2::Instance': 'provider.yaml'}, - 'parameters': {'size': size, - 'image': self.conf.minimal_image_ref, - 'flavor': self.conf.minimal_instance_type}} - stack_name = self._stack_rand_name() - stack_identifier = self.stack_create( - stack_name=stack_name, - template=self.ig_tmpl_with_updt_policy(), - files=files, - environment=env) - stack = self.client.stacks.get(stack_identifier) - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'JobServerGroup') - - # test that physical resource name of launch configuration is used - conf_name = self._stack_output(stack, 'JobServerConfigRef') - conf_name_pattern = '%s-JobServerConfig-[a-zA-Z0-9]+$' % stack_name - self.assertThat(conf_name, - matchers.MatchesRegex(conf_name_pattern)) - - # test the number of instances created - self.assert_instance_count(stack, size) - # saves info from initial list of instances for comparison later - init_instances = self.client.resources.list(nested_ident) - init_names = [inst.resource_name for inst in init_instances] - - # test stack update - self.update_stack(stack_identifier, updt_template, - environment=env, files=files) - updt_stack = self.client.stacks.get(stack_identifier) - - # test that the launch configuration is replaced - updt_conf_name = self._stack_output(updt_stack, 'JobServerConfigRef') - self.assertThat(updt_conf_name, - matchers.MatchesRegex(conf_name_pattern)) - self.assertNotEqual(conf_name, updt_conf_name) - - # test that the group size are the same - updt_instances = self.client.resources.list(nested_ident) - updt_names = [inst.resource_name for inst in updt_instances] - self.assertEqual(len(init_names), len(updt_names)) - for res in updt_instances: - self.assertEqual('UPDATE_COMPLETE', res.resource_status) - - # test that the appropriate number of instance names are the same - matched_names = set(updt_names) & set(init_names) - self.assertEqual(num_updates_expected_on_updt, len(matched_names)) - - # test that the appropriate number of new instances are created - self.assertEqual(num_creates_expected_on_updt, - len(set(updt_names) - set(init_names))) - - # test that the appropriate number of instances are deleted - self.assertEqual(num_deletes_expected_on_updt, - len(set(init_names) - set(updt_names))) - - # test that the older instances are the ones being deleted - if num_deletes_expected_on_updt > 0: - deletes_expected = init_names[:num_deletes_expected_on_updt] - self.assertNotIn(deletes_expected, updt_names) - - def test_instance_group_update_replace(self): - """Test simple update replace with no conflict. - - Test simple update replace with no conflict in batch size and - minimum instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - grp = updt_template['Resources']['JobServerGroup'] - policy = grp['UpdatePolicy']['RollingUpdate'] - policy['MinInstancesInService'] = '1' - policy['MaxBatchSize'] = '3' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=5, - num_creates_expected_on_updt=0, - num_deletes_expected_on_updt=0, - update_replace=True) - - def test_instance_group_update_replace_with_adjusted_capacity(self): - """Test update replace with capacity adjustment. - - Test update replace with capacity adjustment due to conflict in - batch size and minimum instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - grp = updt_template['Resources']['JobServerGroup'] - policy = grp['UpdatePolicy']['RollingUpdate'] - policy['MinInstancesInService'] = '4' - policy['MaxBatchSize'] = '4' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=2, - num_creates_expected_on_updt=3, - num_deletes_expected_on_updt=3, - update_replace=True) - - def test_instance_group_update_replace_huge_batch_size(self): - """Test update replace with a huge batch size.""" - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['RollingUpdate'] - policy['MinInstancesInService'] = '0' - policy['MaxBatchSize'] = '20' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=5, - num_creates_expected_on_updt=0, - num_deletes_expected_on_updt=0, - update_replace=True) - - def test_instance_group_update_replace_huge_min_in_service(self): - """Update replace with huge number of minimum instances in service.""" - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['RollingUpdate'] - policy['MinInstancesInService'] = '20' - policy['MaxBatchSize'] = '2' - policy['PauseTime'] = 'PT0S' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['UserData'] = 'new data' - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=3, - num_creates_expected_on_updt=2, - num_deletes_expected_on_updt=2, - update_replace=True) - - def test_instance_group_update_no_replace(self): - """Test simple update only and no replace with no conflict. - - Test simple update only and no replace (i.e. updated instance flavor - in Launch Configuration) with no conflict in batch size and - minimum instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['RollingUpdate'] - policy['MinInstancesInService'] = '1' - policy['MaxBatchSize'] = '3' - policy['PauseTime'] = 'PT0S' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['InstanceType'] = self.conf.instance_type - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=5, - num_creates_expected_on_updt=0, - num_deletes_expected_on_updt=0, - update_replace=False) - - def test_instance_group_update_no_replace_with_adjusted_capacity(self): - """Test update only and no replace with capacity adjustment. - - Test update only and no replace (i.e. updated instance flavor in - Launch Configuration) with capacity adjustment due to conflict in - batch size and minimum instances in service. - """ - updt_template = self.ig_tmpl_with_updt_policy() - group = updt_template['Resources']['JobServerGroup'] - policy = group['UpdatePolicy']['RollingUpdate'] - policy['MinInstancesInService'] = '4' - policy['MaxBatchSize'] = '4' - policy['PauseTime'] = 'PT0S' - config = updt_template['Resources']['JobServerConfig'] - config['Properties']['InstanceType'] = self.conf.instance_type - - self.update_instance_group(updt_template, - num_updates_expected_on_updt=2, - num_creates_expected_on_updt=3, - num_deletes_expected_on_updt=3, - update_replace=False) diff --git a/heat_tempest_plugin/tests/functional/test_nested_get_attr.py b/heat_tempest_plugin/tests/functional/test_nested_get_attr.py deleted file mode 100644 index 57f65e2..0000000 --- a/heat_tempest_plugin/tests/functional/test_nested_get_attr.py +++ /dev/null @@ -1,165 +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. - -# Using nested get_attr functions isn't a good idea - in particular, this -# actually working depends on correct dependencies between the two resources -# whose attributes are being fetched, and these dependencies are non-local to -# where the get_attr calls are used. Nevertheless, it did sort-of work, and -# this test will help keep it that way. - -from heat_tempest_plugin.tests.functional import functional_base - - -initial_template = ''' -heat_template_version: ocata -resources: - dict_resource: - type: OS::Heat::Value - properties: - value: - blarg: wibble - foo: bar - baz: quux - fred: barney - # These dependencies are required because we only want to read the - # attribute values for a given resource once, and therefore we do so in - # dependency order. This is necessarily true for a convergence traversal, - # but also happens when we're fetching the resource attributes e.g. to show - # the output values. The key1/key2 attribute values must be stored before - # we attempt to calculate the dep_attrs for dict_resource in order to - # correctly determine which attributes of dict_resource are used. - depends_on: - - key1 - - key2 - - indirect_key3_dep - key1: - type: OS::Heat::Value - properties: - value: blarg - key2: - type: OS::Heat::Value - properties: - value: foo - key3: - type: OS::Heat::Value - properties: - value: fred - value1: - type: OS::Heat::Value - properties: - value: - get_attr: - - dict_resource - - value - - {get_attr: [key1, value]} - indirect_key3_dep: - type: OS::Heat::Value - properties: - value: ignored - depends_on: key3 -outputs: - value1: - value: {get_attr: [value1, value]} - value2: - value: {get_attr: [dict_resource, value, {get_attr: [key2, value]}]} - value3: - value: {get_attr: [dict_resource, value, {get_attr: [key3, value]}]} -''' - -update_template = ''' -heat_template_version: ocata -resources: - dict_resource: - type: OS::Heat::Value - properties: - value: - blarg: wibble - foo: bar - baz: quux - fred: barney - depends_on: - - key1 - - key2 - - indirect_key3_dep - - key4 - key1: - type: OS::Heat::Value - properties: - value: foo - key2: - type: OS::Heat::Value - properties: - value: fred - key3: - type: OS::Heat::Value - properties: - value: blarg - key4: - type: OS::Heat::Value - properties: - value: baz - value1: - type: OS::Heat::Value - properties: - value: - get_attr: - - dict_resource - - value - - {get_attr: [key1, value]} - value4: - type: OS::Heat::Value - properties: - value: - get_attr: - - dict_resource - - value - - {get_attr: [key4, value]} - indirect_key3_dep: - type: OS::Heat::Value - properties: - value: ignored - depends_on: key3 -outputs: - value1: - value: {get_attr: [value1, value]} - value2: - value: {get_attr: [dict_resource, value, {get_attr: [key2, value]}]} - value3: - value: {get_attr: [dict_resource, value, {get_attr: [key3, value]}]} - value4: - value: {get_attr: [value4, value]} -''' - - -class NestedGetAttrTest(functional_base.FunctionalTestsBase): - def assertOutput(self, value, stack_identifier, key): - op = self.client.stacks.output_show(stack_identifier, key)['output'] - self.assertEqual(key, op['output_key']) - if 'output_error' in op: - raise Exception(op['output_error']) - self.assertEqual(value, op['output_value']) - - def test_nested_get_attr_create(self): - stack_identifier = self.stack_create(template=initial_template) - - self.assertOutput('wibble', stack_identifier, 'value1') - self.assertOutput('bar', stack_identifier, 'value2') - self.assertOutput('barney', stack_identifier, 'value3') - - def test_nested_get_attr_update(self): - stack_identifier = self.stack_create(template=initial_template) - self.update_stack(stack_identifier, template=update_template) - - self.assertOutput('bar', stack_identifier, 'value1') - self.assertOutput('barney', stack_identifier, 'value2') - self.assertOutput('wibble', stack_identifier, 'value3') - self.assertOutput('quux', stack_identifier, 'value4') diff --git a/heat_tempest_plugin/tests/functional/test_notifications.py b/heat_tempest_plugin/tests/functional/test_notifications.py deleted file mode 100644 index 7a74cdb..0000000 --- a/heat_tempest_plugin/tests/functional/test_notifications.py +++ /dev/null @@ -1,194 +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 kombu -from oslo_config import cfg -from oslo_messaging._drivers import common -from oslo_messaging import transport -import requests - -from heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - -BASIC_NOTIFICATIONS = [ - 'orchestration.stack.create.start', - 'orchestration.stack.create.end', - 'orchestration.stack.update.start', - 'orchestration.stack.update.end', - 'orchestration.stack.suspend.start', - 'orchestration.stack.suspend.end', - 'orchestration.stack.resume.start', - 'orchestration.stack.resume.end', - 'orchestration.stack.delete.start', - 'orchestration.stack.delete.end' -] - -ASG_NOTIFICATIONS = [ - 'orchestration.autoscaling.start', - 'orchestration.autoscaling.end' -] - - -def get_url(conf): - conf = conf.oslo_messaging_rabbit - return 'amqp://%s:%s@%s:%s/' % (conf.rabbit_userid, - conf.rabbit_password, - conf.rabbit_host, - conf.rabbit_port) - - -class NotificationHandler(object): - def __init__(self, stack_id, events=None): - self._notifications = [] - self.stack_id = stack_id - self.events = events - - def process_message(self, body, message): - notification = common.deserialize_msg(body) - if notification['payload']['stack_name'] == self.stack_id: - if self.events is not None: - if notification['event_type'] in self.events: - self.notifications.append(notification['event_type']) - else: - self.notifications.append(notification['event_type']) - message.ack() - - def clear(self): - self._notifications = [] - - @property - def notifications(self): - return self._notifications - - -class NotificationTest(functional_base.FunctionalTestsBase): - - basic_template = ''' -heat_template_version: 2013-05-23 -resources: - random1: - type: OS::Heat::RandomString -''' - update_basic_template = ''' -heat_template_version: 2013-05-23 -resources: - random1: - type: OS::Heat::RandomString - random2: - type: OS::Heat::RandomString -''' - - asg_template = ''' -heat_template_version: 2013-05-23 -resources: - asg: - type: OS::Heat::AutoScalingGroup - properties: - resource: - type: OS::Heat::RandomString - min_size: 1 - desired_capacity: 2 - max_size: 3 - - scale_up_policy: - type: OS::Heat::ScalingPolicy - properties: - adjustment_type: change_in_capacity - auto_scaling_group_id: {get_resource: asg} - cooldown: 0 - scaling_adjustment: 1 - - scale_down_policy: - type: OS::Heat::ScalingPolicy - properties: - adjustment_type: change_in_capacity - auto_scaling_group_id: {get_resource: asg} - cooldown: 0 - scaling_adjustment: '-1' - -outputs: - scale_up_url: - value: {get_attr: [scale_up_policy, alarm_url]} - scale_dn_url: - value: {get_attr: [scale_down_policy, alarm_url]} -''' - - def setUp(self): - super(NotificationTest, self).setUp() - self.exchange = kombu.Exchange('heat', 'topic', durable=False) - queue = kombu.Queue(exchange=self.exchange, - routing_key='notifications.info', - exclusive=True) - self.conn = kombu.Connection(get_url( - transport.get_transport(cfg.CONF).conf)) - self.ch = self.conn.channel() - self.queue = queue(self.ch) - self.queue.declare() - - def consume_events(self, handler, count): - self.conn.drain_events() - return len(handler.notifications) == count - - def test_basic_notifications(self): - # disable cleanup so we can call _stack_delete() directly. - stack_identifier = self.stack_create(template=self.basic_template, - enable_cleanup=False) - self.update_stack(stack_identifier, - template=self.update_basic_template) - self.stack_suspend(stack_identifier) - self.stack_resume(stack_identifier) - self._stack_delete(stack_identifier) - - handler = NotificationHandler(stack_identifier.split('/')[0]) - - with self.conn.Consumer(self.queue, - callbacks=[handler.process_message], - auto_declare=False): - try: - while True: - self.conn.drain_events(timeout=1) - except Exception: - pass - - for n in BASIC_NOTIFICATIONS: - self.assertIn(n, handler.notifications) - - def test_asg_notifications(self): - stack_identifier = self.stack_create(template=self.asg_template) - - for output in self.client.stacks.get(stack_identifier).outputs: - if output['output_key'] == 'scale_dn_url': - scale_down_url = output['output_value'] - else: - scale_up_url = output['output_value'] - - notifications = [] - handler = NotificationHandler(stack_identifier.split('/')[0], - ASG_NOTIFICATIONS) - - with self.conn.Consumer(self.queue, - callbacks=[handler.process_message], - auto_declare=False): - - requests.post(scale_up_url, verify=self.verify_cert) - self.assertTrue( - test.call_until_true(20, 0, self.consume_events, handler, 2)) - notifications += handler.notifications - - handler.clear() - requests.post(scale_down_url, verify=self.verify_cert) - self.assertTrue( - test.call_until_true(20, 0, self.consume_events, handler, 2)) - notifications += handler.notifications - - self.assertEqual(2, notifications.count(ASG_NOTIFICATIONS[0])) - self.assertEqual(2, notifications.count(ASG_NOTIFICATIONS[1])) diff --git a/heat_tempest_plugin/tests/functional/test_preview_update.py b/heat_tempest_plugin/tests/functional/test_preview_update.py deleted file mode 100644 index a4d293f..0000000 --- a/heat_tempest_plugin/tests/functional/test_preview_update.py +++ /dev/null @@ -1,298 +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 heat_tempest_plugin.tests.functional import functional_base - -test_template_one_resource = { - 'heat_template_version': '2013-05-23', - 'description': 'Test template to create one instance.', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0 - } - } - } -} - -test_template_two_resource = { - 'heat_template_version': '2013-05-23', - 'description': 'Test template to create two instance.', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0 - } - }, - 'test2': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0 - } - } - } -} - - -class UpdatePreviewBase(functional_base.FunctionalTestsBase): - - def assert_empty_sections(self, changes, empty_sections): - for section in empty_sections: - self.assertEqual([], changes[section]) - - -class UpdatePreviewStackTest(UpdatePreviewBase): - - def test_add_resource(self): - self.stack_identifier = self.stack_create( - template=test_template_one_resource) - result = self.preview_update_stack(self.stack_identifier, - test_template_two_resource) - changes = result['resource_changes'] - - unchanged = changes['unchanged'][0]['resource_name'] - self.assertEqual('test1', unchanged) - - added = changes['added'][0]['resource_name'] - self.assertEqual('test2', added) - - self.assert_empty_sections(changes, ['updated', 'replaced', 'deleted']) - - def test_no_change(self): - self.stack_identifier = self.stack_create( - template=test_template_one_resource) - result = self.preview_update_stack(self.stack_identifier, - test_template_one_resource) - changes = result['resource_changes'] - - unchanged = changes['unchanged'][0]['resource_name'] - self.assertEqual('test1', unchanged) - - self.assert_empty_sections( - changes, ['updated', 'replaced', 'deleted', 'added']) - - def test_update_resource(self): - self.stack_identifier = self.stack_create( - template=test_template_one_resource) - test_template_updated_resource = { - 'heat_template_version': '2013-05-23', - 'description': 'Test template to create one instance.', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1 foo', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0 - } - } - } - } - - result = self.preview_update_stack(self.stack_identifier, - test_template_updated_resource) - changes = result['resource_changes'] - - updated = changes['updated'][0]['resource_name'] - self.assertEqual('test1', updated) - - self.assert_empty_sections( - changes, ['added', 'unchanged', 'replaced', 'deleted']) - - def test_replaced_resource(self): - self.stack_identifier = self.stack_create( - template=test_template_one_resource) - new_template = { - 'heat_template_version': '2013-05-23', - 'description': 'Test template to create one instance.', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'update_replace': True, - } - } - } - } - - result = self.preview_update_stack(self.stack_identifier, new_template) - changes = result['resource_changes'] - - replaced = changes['replaced'][0]['resource_name'] - self.assertEqual('test1', replaced) - - self.assert_empty_sections( - changes, ['added', 'unchanged', 'updated', 'deleted']) - - def test_delete_resource(self): - self.stack_identifier = self.stack_create( - template=test_template_two_resource) - result = self.preview_update_stack(self.stack_identifier, - test_template_one_resource) - changes = result['resource_changes'] - - unchanged = changes['unchanged'][0]['resource_name'] - self.assertEqual('test1', unchanged) - - deleted = changes['deleted'][0]['resource_name'] - self.assertEqual('test2', deleted) - - self.assert_empty_sections(changes, ['updated', 'replaced', 'added']) - - -class UpdatePreviewStackTestNested(UpdatePreviewBase): - template_nested_parent = ''' -heat_template_version: 2016-04-08 -resources: - nested1: - type: nested1.yaml -''' - - template_nested1 = ''' -heat_template_version: 2016-04-08 -resources: - nested2: - type: nested2.yaml -''' - - template_nested2 = ''' -heat_template_version: 2016-04-08 -resources: - random: - type: OS::Heat::RandomString -''' - - template_nested2_2 = ''' -heat_template_version: 2016-04-08 -resources: - random: - type: OS::Heat::RandomString - random2: - type: OS::Heat::RandomString -''' - - def _get_by_resource_name(self, changes, name, action): - filtered_l = [x for x in changes[action] - if x['resource_name'] == name] - self.assertEqual(1, len(filtered_l)) - return filtered_l[0] - - def test_nested_resources_nochange(self): - files = {'nested1.yaml': self.template_nested1, - 'nested2.yaml': self.template_nested2} - self.stack_identifier = self.stack_create( - template=self.template_nested_parent, files=files) - result = self.preview_update_stack( - self.stack_identifier, - template=self.template_nested_parent, - files=files, show_nested=True) - changes = result['resource_changes'] - - # The nested random resource should be unchanged, but we always - # update nested stacks even when there are no changes - self.assertEqual(1, len(changes['unchanged'])) - self.assertEqual('random', changes['unchanged'][0]['resource_name']) - self.assertEqual('nested2', changes['unchanged'][0]['parent_resource']) - - self.assertEqual(2, len(changes['updated'])) - u_nested1 = self._get_by_resource_name(changes, 'nested1', 'updated') - self.assertNotIn('parent_resource', u_nested1) - u_nested2 = self._get_by_resource_name(changes, 'nested2', 'updated') - self.assertEqual('nested1', u_nested2['parent_resource']) - - self.assert_empty_sections(changes, ['replaced', 'deleted', 'added']) - - def test_nested_resources_add(self): - files = {'nested1.yaml': self.template_nested1, - 'nested2.yaml': self.template_nested2} - self.stack_identifier = self.stack_create( - template=self.template_nested_parent, files=files) - files['nested2.yaml'] = self.template_nested2_2 - result = self.preview_update_stack( - self.stack_identifier, - template=self.template_nested_parent, - files=files, show_nested=True) - changes = result['resource_changes'] - - # The nested random resource should be unchanged, but we always - # update nested stacks even when there are no changes - self.assertEqual(1, len(changes['unchanged'])) - self.assertEqual('random', changes['unchanged'][0]['resource_name']) - self.assertEqual('nested2', changes['unchanged'][0]['parent_resource']) - - self.assertEqual(1, len(changes['added'])) - self.assertEqual('random2', changes['added'][0]['resource_name']) - self.assertEqual('nested2', changes['added'][0]['parent_resource']) - - self.assert_empty_sections(changes, ['replaced', 'deleted']) - - def test_nested_resources_delete(self): - files = {'nested1.yaml': self.template_nested1, - 'nested2.yaml': self.template_nested2_2} - self.stack_identifier = self.stack_create( - template=self.template_nested_parent, files=files) - files['nested2.yaml'] = self.template_nested2 - result = self.preview_update_stack( - self.stack_identifier, - template=self.template_nested_parent, - files=files, show_nested=True) - changes = result['resource_changes'] - - # The nested random resource should be unchanged, but we always - # update nested stacks even when there are no changes - self.assertEqual(1, len(changes['unchanged'])) - self.assertEqual('random', changes['unchanged'][0]['resource_name']) - self.assertEqual('nested2', changes['unchanged'][0]['parent_resource']) - - self.assertEqual(1, len(changes['deleted'])) - self.assertEqual('random2', changes['deleted'][0]['resource_name']) - self.assertEqual('nested2', changes['deleted'][0]['parent_resource']) - - self.assert_empty_sections(changes, ['replaced', 'added']) - - def test_nested_resources_replace(self): - files = {'nested1.yaml': self.template_nested1, - 'nested2.yaml': self.template_nested2} - self.stack_identifier = self.stack_create( - template=self.template_nested_parent, files=files) - parent_none = self.template_nested_parent.replace( - 'nested1.yaml', 'OS::Heat::None') - result = self.preview_update_stack( - self.stack_identifier, - template=parent_none, - show_nested=True) - changes = result['resource_changes'] - - # The nested random resource should be unchanged, but we always - # update nested stacks even when there are no changes - self.assertEqual(1, len(changes['replaced'])) - self.assertEqual('nested1', changes['replaced'][0]['resource_name']) - - self.assertEqual(2, len(changes['deleted'])) - d_random = self._get_by_resource_name(changes, 'random', 'deleted') - self.assertEqual('nested2', d_random['parent_resource']) - d_nested2 = self._get_by_resource_name(changes, 'nested2', 'deleted') - self.assertEqual('nested1', d_nested2['parent_resource']) - - self.assert_empty_sections(changes, ['updated', 'unchanged', 'added']) diff --git a/heat_tempest_plugin/tests/functional/test_purge.py b/heat_tempest_plugin/tests/functional/test_purge.py deleted file mode 100644 index 1dd4ff8..0000000 --- a/heat_tempest_plugin/tests/functional/test_purge.py +++ /dev/null @@ -1,51 +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 time - -from oslo_concurrency import processutils - -from heat_tempest_plugin.tests.functional import functional_base - - -class PurgeTest(functional_base.FunctionalTestsBase): - template = ''' -heat_template_version: 2014-10-16 -parameters: -resources: - test_resource: - type: OS::Heat::TestResource -''' - - def test_purge(self): - stack_identifier = self.stack_create(template=self.template) - self._stack_delete(stack_identifier) - stacks = dict((stack.id, stack) for stack in - self.client.stacks.list(show_deleted=True)) - self.assertIn(stack_identifier.split('/')[1], stacks) - time.sleep(1) - cmd = "heat-manage purge_deleted 0" - processutils.execute(cmd, shell=True) - stacks = dict((stack.id, stack) for stack in - self.client.stacks.list(show_deleted=True)) - self.assertNotIn(stack_identifier.split('/')[1], stacks) - - # Test with tags - stack_identifier = self.stack_create(template=self.template, - tags="foo,bar") - self._stack_delete(stack_identifier) - time.sleep(1) - cmd = "heat-manage purge_deleted 0" - processutils.execute(cmd, shell=True) - stacks = dict((stack.id, stack) for stack in - self.client.stacks.list(show_deleted=True)) - self.assertNotIn(stack_identifier.split('/')[1], stacks) diff --git a/heat_tempest_plugin/tests/functional/test_reload_on_sighup.py b/heat_tempest_plugin/tests/functional/test_reload_on_sighup.py deleted file mode 100644 index 81da958..0000000 --- a/heat_tempest_plugin/tests/functional/test_reload_on_sighup.py +++ /dev/null @@ -1,142 +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 re -import subprocess -import time - -import eventlet - -from oslo_concurrency import processutils -from six.moves import configparser - -from heat_tempest_plugin.tests.functional import functional_base - - -class ReloadOnSighupTest(functional_base.FunctionalTestsBase): - - def setUp(self): - self.config_file = "/etc/heat/heat.conf" - super(ReloadOnSighupTest, self).setUp() - - def _is_mod_wsgi_daemon(self, service): - process = ''.join(['wsgi:', - service[:9]]).replace('_', '-').encode('utf-8') - s = subprocess.Popen(["ps", "ax"], stdout=subprocess.PIPE) - for x in s.stdout: - if re.search(process, x): - return True - - def _set_config_value(self, service, key, value): - config = configparser.ConfigParser() - - # NOTE(prazumovsky): If there are several workers, there can be - # situation, when one thread opens self.config_file for writing - # (so config_file erases with opening), in that moment other thread - # intercepts to this file and try to set config option value, i.e. - # write to file, which is already erased by first thread, so, - # NoSectionError raised. So, should wait until first thread writes to - # config_file. - retries_count = self.conf.sighup_config_edit_retries - while True: - config.read(self.config_file) - try: - config.set(service, key, str(value)) - except configparser.NoSectionError: - if retries_count <= 0: - raise - retries_count -= 1 - eventlet.sleep(1) - else: - break - - with open(self.config_file, 'w') as f: - config.write(f) - - def _get_config_value(self, service, key): - config = configparser.ConfigParser() - config.read(self.config_file) - val = config.get(service, key) - return val - - def _get_heat_api_pids(self, service): - # get the pids of all heat-api processes - if service == "heat_api": - process = "heat-api|grep -Ev 'grep|cloudwatch|cfn'" - else: - process = "%s|grep -Ev 'grep'" % service.replace('_', '-') - cmd = "ps -ef|grep %s|awk '{print $2}'" % process - out, err = processutils.execute(cmd, shell=True) - self.assertIsNotNone(out, "heat-api service not running. %s" % err) - pids = filter(None, out.split('\n')) - - # get the parent pids of all heat-api processes - cmd = "ps -ef|grep %s|awk '{print $3}'" % process - out, _ = processutils.execute(cmd, shell=True) - parent_pids = filter(None, out.split('\n')) - - heat_api_parent = list(set(pids) & set(parent_pids))[0] - heat_api_children = list(set(pids) - set(parent_pids)) - - return heat_api_parent, heat_api_children - - def _change_config(self, service, old_workers, new_workers): - pre_reload_parent, pre_reload_children = self._get_heat_api_pids( - service) - self.assertEqual(old_workers, len(pre_reload_children)) - - # change the config values - self._set_config_value(service, 'workers', new_workers) - cmd = "kill -HUP %s" % pre_reload_parent - processutils.execute(cmd, shell=True) - - # wait till heat-api reloads - start_time = time.time() - while time.time() - start_time < self.conf.sighup_timeout: - post_reload_parent, post_reload_children = self._get_heat_api_pids( - service) - intersect = set(post_reload_children) & set(pre_reload_children) - if (new_workers == len(post_reload_children) - and pre_reload_parent == post_reload_parent - and intersect == set()): - break - eventlet.sleep(1) - self.assertEqual(pre_reload_parent, post_reload_parent) - self.assertEqual(new_workers, len(post_reload_children)) - # test if all child processes are newly created - self.assertEqual(set(post_reload_children) & set(pre_reload_children), - set()) - - def _reload(self, service): - old_workers = int(self._get_config_value(service, 'workers')) - new_workers = old_workers + 1 - self.addCleanup(self._set_config_value, service, 'workers', - old_workers) - - self._change_config(service, old_workers, new_workers) - # revert all the changes made - self._change_config(service, new_workers, old_workers) - - def _reload_on_sighup(self, service): - if not self._is_mod_wsgi_daemon(service): - self._reload(service) - else: - self.skipTest('Skipping Test, Service running under httpd.') - - def test_api_reload_on_sighup(self): - self._reload_on_sighup('heat_api') - - def test_api_cfn_reload_on_sighup(self): - self._reload_on_sighup('heat_api_cfn') - - def test_api_cloudwatch_on_sighup(self): - self._reload_on_sighup('heat_api_cloudwatch') diff --git a/heat_tempest_plugin/tests/functional/test_replace_deprecated.py b/heat_tempest_plugin/tests/functional/test_replace_deprecated.py deleted file mode 100644 index 0eee3f1..0000000 --- a/heat_tempest_plugin/tests/functional/test_replace_deprecated.py +++ /dev/null @@ -1,92 +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 yaml - -from heat_tempest_plugin.tests.functional import functional_base - - -class ReplaceDeprecatedResourceTest(functional_base.FunctionalTestsBase): - template = ''' -heat_template_version: "2013-05-23" -parameters: - flavor: - type: string - image: - type: string - network: - type: string - -resources: - config: - type: OS::Heat::SoftwareConfig - properties: - config: xxxx - - server: - type: OS::Nova::Server - properties: - image: {get_param: image} - flavor: {get_param: flavor} - networks: [{network: {get_param: network} }] - user_data_format: SOFTWARE_CONFIG - dep: - type: OS::Heat::SoftwareDeployments - properties: - config: {get_resource: config} - servers: {'0': {get_resource: server}} - signal_transport: NO_SIGNAL -outputs: - server: - value: {get_resource: server} -''' - - deployment_group_snippet = ''' -type: OS::Heat::SoftwareDeploymentGroup -properties: - config: {get_resource: config} - servers: {'0': {get_resource: server}} - signal_transport: NO_SIGNAL -''' - enable_cleanup = True - - def test_replace_software_deployments(self): - parms = {'flavor': self.conf.minimal_instance_type, - 'network': self.conf.fixed_network_name, - 'image': self.conf.minimal_image_ref - } - deployments_template = yaml.safe_load(self.template) - stack_identifier = self.stack_create( - parameters=parms, - template=deployments_template, - enable_cleanup=self.enable_cleanup) - expected_resources = {'config': 'OS::Heat::SoftwareConfig', - 'dep': 'OS::Heat::SoftwareDeployments', - 'server': 'OS::Nova::Server'} - resource = self.client.resources.get(stack_identifier, 'server') - self.assertEqual(expected_resources, - self.list_resources(stack_identifier)) - initial_phy_id = resource.physical_resource_id - resources = deployments_template['resources'] - resources['dep'] = yaml.safe_load(self.deployment_group_snippet) - self.update_stack( - stack_identifier, - deployments_template, - parameters=parms) - resource = self.client.resources.get(stack_identifier, 'server') - self.assertEqual(initial_phy_id, - resource.physical_resource_id) - expected_new_resources = {'config': 'OS::Heat::SoftwareConfig', - 'dep': 'OS::Heat::SoftwareDeploymentGroup', - 'server': 'OS::Nova::Server'} - self.assertEqual(expected_new_resources, - self.list_resources(stack_identifier)) diff --git a/heat_tempest_plugin/tests/functional/test_resource_chain.py b/heat_tempest_plugin/tests/functional/test_resource_chain.py deleted file mode 100644 index 06ec8ff..0000000 --- a/heat_tempest_plugin/tests/functional/test_resource_chain.py +++ /dev/null @@ -1,167 +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 heat_tempest_plugin.tests.functional import functional_base - - -TEMPLATE_SIMPLE = ''' -heat_template_version: 2016-04-08 -parameters: - string-length: - type: number -resources: - my-chain: - type: OS::Heat::ResourceChain - properties: - resources: ['OS::Heat::RandomString', 'OS::Heat::RandomString'] - resource_properties: - length: { get_param: string-length } -outputs: - resource-ids: - value: { get_attr: [my-chain, refs] } - resource-0-value: - value: { get_attr: [my-chain, resource.0, value] } - all-resource-attrs: - value: { get_attr: [my-chain, attributes, value] } -''' - -TEMPLATE_PARAM_DRIVEN = ''' -heat_template_version: 2016-04-08 -parameters: - chain-types: - type: comma_delimited_list -resources: - my-chain: - type: OS::Heat::ResourceChain - properties: - resources: { get_param: chain-types } -''' - - -class ResourceChainTests(functional_base.FunctionalTestsBase): - - def test_create(self): - # Test - params = {'string-length': 8} - stack_id = self.stack_create(template=TEMPLATE_SIMPLE, - parameters=params) - - # Verify - stack = self.client.stacks.get(stack_id) - self.assertIsNotNone(stack) - - # Top-level resource for chain - expected = {'my-chain': 'OS::Heat::ResourceChain'} - found = self.list_resources(stack_id) - self.assertEqual(expected, found) - - # Nested stack exists and has two resources - nested_id = self.group_nested_identifier(stack_id, 'my-chain') - expected = {'0': 'OS::Heat::RandomString', - '1': 'OS::Heat::RandomString'} - found = self.list_resources(nested_id) - self.assertEqual(expected, found) - - # Outputs - resource_ids = self._stack_output(stack, 'resource-ids') - self.assertIsNotNone(resource_ids) - self.assertEqual(2, len(resource_ids)) - - resource_value = self._stack_output(stack, 'resource-0-value') - self.assertIsNotNone(resource_value) - self.assertEqual(8, len(resource_value)) # from parameter - - resource_attrs = self._stack_output(stack, 'all-resource-attrs') - self.assertIsNotNone(resource_attrs) - self.assertIsInstance(resource_attrs, dict) - self.assertEqual(2, len(resource_attrs)) - self.assertEqual(8, len(resource_attrs['0'])) - self.assertEqual(8, len(resource_attrs['1'])) - - def test_update(self): - # Setup - params = {'string-length': 8} - stack_id = self.stack_create(template=TEMPLATE_SIMPLE, - parameters=params) - - update_tmpl = ''' - heat_template_version: 2016-04-08 - parameters: - string-length: - type: number - resources: - my-chain: - type: OS::Heat::ResourceChain - properties: - resources: ['OS::Heat::None'] - ''' - - # Test - self.update_stack(stack_id, template=update_tmpl, parameters=params) - - # Verify - # Nested stack only has the None resource - nested_id = self.group_nested_identifier(stack_id, 'my-chain') - expected = {'0': 'OS::Heat::None'} - found = self.list_resources(nested_id) - self.assertEqual(expected, found) - - def test_update_resources(self): - params = {'chain-types': 'OS::Heat::None'} - - stack_id = self.stack_create(template=TEMPLATE_PARAM_DRIVEN, - parameters=params) - - nested_id = self.group_nested_identifier(stack_id, 'my-chain') - expected = {'0': 'OS::Heat::None'} - found = self.list_resources(nested_id) - self.assertEqual(expected, found) - - params = {'chain-types': 'OS::Heat::None,OS::Heat::None'} - self.update_stack(stack_id, template=TEMPLATE_PARAM_DRIVEN, - parameters=params) - - expected = {'0': 'OS::Heat::None', '1': 'OS::Heat::None'} - found = self.list_resources(nested_id) - self.assertEqual(expected, found) - - def test_resources_param_driven(self): - # Setup - params = {'chain-types': - 'OS::Heat::None,OS::Heat::RandomString,OS::Heat::None'} - - # Test - stack_id = self.stack_create(template=TEMPLATE_PARAM_DRIVEN, - parameters=params) - - # Verify - nested_id = self.group_nested_identifier(stack_id, 'my-chain') - expected = {'0': 'OS::Heat::None', - '1': 'OS::Heat::RandomString', - '2': 'OS::Heat::None'} - found = self.list_resources(nested_id) - self.assertEqual(expected, found) - - def test_resources_env_defined(self): - # Setup - env = {'parameters': {'chain-types': 'OS::Heat::None'}} - - # Test - stack_id = self.stack_create(template=TEMPLATE_PARAM_DRIVEN, - environment=env) - - # Verify - nested_id = self.group_nested_identifier(stack_id, 'my-chain') - expected = {'0': 'OS::Heat::None'} - found = self.list_resources(nested_id) - self.assertEqual(expected, found) diff --git a/heat_tempest_plugin/tests/functional/test_resource_group.py b/heat_tempest_plugin/tests/functional/test_resource_group.py deleted file mode 100644 index aea1bda..0000000 --- a/heat_tempest_plugin/tests/functional/test_resource_group.py +++ /dev/null @@ -1,695 +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 -import json - -from heatclient import exc -import six -import yaml - -from heat_tempest_plugin.tests.functional import functional_base - - -class ResourceGroupTest(functional_base.FunctionalTestsBase): - template = ''' -heat_template_version: 2013-05-23 -resources: - random_group: - type: OS::Heat::ResourceGroup - properties: - count: 0 - resource_def: - type: My::RandomString - properties: - length: 30 - salt: initial -outputs: - random1: - value: {get_attr: [random_group, resource.0.value]} - random2: - value: {get_attr: [random_group, resource.1.value]} - all_values: - value: {get_attr: [random_group, value]} -''' - - def test_resource_group_zero_novalidate(self): - # Nested resources should be validated only when size > 0 - # This allows features to be disabled via size=0 without - # triggering validation of nested resource custom constraints - # e.g images etc in the nested schema. - nested_template_fail = ''' -heat_template_version: 2013-05-23 -parameters: - length: - type: string - default: 50 - salt: - type: string - default: initial -resources: - random: - type: OS::Heat::RandomString - properties: - length: BAD -''' - - files = {'provider.yaml': nested_template_fail} - env = {'resource_registry': - {'My::RandomString': 'provider.yaml'}} - stack_identifier = self.stack_create( - template=self.template, - files=files, - environment=env - ) - - self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'}, - self.list_resources(stack_identifier)) - - # Check we created an empty nested stack - nested_identifier = self.group_nested_identifier(stack_identifier, - 'random_group') - self.assertEqual({}, self.list_resources(nested_identifier)) - - # Prove validation works for non-zero create/update - template_two_nested = self.template.replace("count: 0", "count: 2") - expected_err = ("resources.random_group.resources." - "0.resources.random: : " - "Value 'BAD' is not an integer") - ex = self.assertRaises(exc.HTTPBadRequest, self.update_stack, - stack_identifier, template_two_nested, - environment=env, files=files) - self.assertIn(expected_err, six.text_type(ex)) - - ex = self.assertRaises(exc.HTTPBadRequest, self.stack_create, - template=template_two_nested, - environment=env, files=files) - self.assertIn(expected_err, six.text_type(ex)) - - def _validate_resources(self, stack_identifier, expected_count): - resources = self.list_group_resources(stack_identifier, - 'random_group') - self.assertEqual(expected_count, len(resources)) - expected_resources = dict( - (str(idx), 'My::RandomString') - for idx in range(expected_count)) - - self.assertEqual(expected_resources, resources) - - def test_create(self): - def validate_output(stack, output_key, length): - output_value = self._stack_output(stack, output_key) - self.assertEqual(length, len(output_value)) - return output_value - # verify that the resources in resource group are identically - # configured, resource names and outputs are appropriate. - env = {'resource_registry': - {'My::RandomString': 'OS::Heat::RandomString'}} - create_template = self.template.replace("count: 0", "count: 2") - stack_identifier = self.stack_create(template=create_template, - environment=env) - self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'}, - self.list_resources(stack_identifier)) - - # validate count, type and name of resources in a resource group. - self._validate_resources(stack_identifier, 2) - - # validate outputs - stack = self.client.stacks.get(stack_identifier) - outputs = [] - outputs.append(validate_output(stack, 'random1', 30)) - outputs.append(validate_output(stack, 'random2', 30)) - self.assertEqual(outputs, self._stack_output(stack, 'all_values')) - - def test_update_increase_decrease_count(self): - # create stack with resource group count 2 - env = {'resource_registry': - {'My::RandomString': 'OS::Heat::RandomString'}} - create_template = self.template.replace("count: 0", "count: 2") - stack_identifier = self.stack_create(template=create_template, - environment=env) - self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'}, - self.list_resources(stack_identifier)) - # verify that the resource group has 2 resources - self._validate_resources(stack_identifier, 2) - - # increase the resource group count to 5 - update_template = self.template.replace("count: 0", "count: 5") - self.update_stack(stack_identifier, update_template, environment=env) - # verify that the resource group has 5 resources - self._validate_resources(stack_identifier, 5) - - # decrease the resource group count to 3 - update_template = self.template.replace("count: 0", "count: 3") - self.update_stack(stack_identifier, update_template, environment=env) - # verify that the resource group has 3 resources - self._validate_resources(stack_identifier, 3) - - def test_update_removal_policies(self): - rp_template = ''' -heat_template_version: 2014-10-16 -resources: - random_group: - type: OS::Heat::ResourceGroup - properties: - count: 5 - removal_policies: [] - resource_def: - type: OS::Heat::RandomString -''' - - # create stack with resource group, initial count 5 - stack_identifier = self.stack_create(template=rp_template) - self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'}, - self.list_resources(stack_identifier)) - group_resources = self.list_group_resources(stack_identifier, - 'random_group') - expected_resources = {u'0': u'OS::Heat::RandomString', - u'1': u'OS::Heat::RandomString', - u'2': u'OS::Heat::RandomString', - u'3': u'OS::Heat::RandomString', - u'4': u'OS::Heat::RandomString'} - self.assertEqual(expected_resources, group_resources) - - # Remove three, specifying the middle resources to be removed - update_template = rp_template.replace( - 'removal_policies: []', - 'removal_policies: [{resource_list: [\'1\', \'2\', \'3\']}]') - self.update_stack(stack_identifier, update_template) - group_resources = self.list_group_resources(stack_identifier, - 'random_group') - expected_resources = {u'0': u'OS::Heat::RandomString', - u'4': u'OS::Heat::RandomString', - u'5': u'OS::Heat::RandomString', - u'6': u'OS::Heat::RandomString', - u'7': u'OS::Heat::RandomString'} - self.assertEqual(expected_resources, group_resources) - - def test_props_update(self): - """Test update of resource_def properties behaves as expected.""" - - env = {'resource_registry': - {'My::RandomString': 'OS::Heat::RandomString'}} - template_one = self.template.replace("count: 0", "count: 1") - stack_identifier = self.stack_create(template=template_one, - environment=env) - self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'}, - self.list_resources(stack_identifier)) - - initial_nested_ident = self.group_nested_identifier(stack_identifier, - 'random_group') - self.assertEqual({'0': 'My::RandomString'}, - self.list_resources(initial_nested_ident)) - # get the resource id - res = self.client.resources.get(initial_nested_ident, '0') - initial_res_id = res.physical_resource_id - - # change the salt (this should replace the RandomString but - # not the nested stack or resource group. - template_salt = template_one.replace("salt: initial", "salt: more") - self.update_stack(stack_identifier, template_salt, environment=env) - updated_nested_ident = self.group_nested_identifier(stack_identifier, - 'random_group') - self.assertEqual(initial_nested_ident, updated_nested_ident) - - # compare the resource id, we expect a change. - res = self.client.resources.get(updated_nested_ident, '0') - updated_res_id = res.physical_resource_id - self.assertNotEqual(initial_res_id, updated_res_id) - - def test_update_nochange(self): - """Test update with no properties change.""" - - env = {'resource_registry': - {'My::RandomString': 'OS::Heat::RandomString'}} - template_one = self.template.replace("count: 0", "count: 2") - stack_identifier = self.stack_create(template=template_one, - environment=env) - self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'}, - self.list_resources(stack_identifier)) - - initial_nested_ident = self.group_nested_identifier(stack_identifier, - 'random_group') - self.assertEqual({'0': 'My::RandomString', '1': 'My::RandomString'}, - self.list_resources(initial_nested_ident)) - # get the output - stack0 = self.client.stacks.get(stack_identifier) - initial_rand = self._stack_output(stack0, 'random1') - - template_copy = copy.deepcopy(template_one) - self.update_stack(stack_identifier, template_copy, environment=env) - updated_nested_ident = self.group_nested_identifier(stack_identifier, - 'random_group') - self.assertEqual(initial_nested_ident, updated_nested_ident) - - # compare the random number, we expect no change. - stack1 = self.client.stacks.get(stack_identifier) - updated_rand = self._stack_output(stack1, 'random1') - self.assertEqual(initial_rand, updated_rand) - - def test_update_nochange_resource_needs_update(self): - """Test update when the resource definition has changed. - - Test the scenario when the ResourceGroup update happens without - any changed properties, this can happen if the definition of - a contained provider resource changes (files map changes), then - the group and underlying nested stack should end up updated. - """ - - random_templ1 = ''' -heat_template_version: 2013-05-23 -parameters: - length: - type: string - default: not-used - salt: - type: string - default: not-used -resources: - random1: - type: OS::Heat::RandomString - properties: - salt: initial -outputs: - value: - value: {get_attr: [random1, value]} -''' - files1 = {'my_random.yaml': random_templ1} - - random_templ2 = random_templ1.replace('salt: initial', - 'salt: more') - files2 = {'my_random.yaml': random_templ2} - - env = {'resource_registry': - {'My::RandomString': 'my_random.yaml'}} - - template_one = self.template.replace("count: 0", "count: 2") - stack_identifier = self.stack_create(template=template_one, - environment=env, - files=files1) - self.assertEqual({u'random_group': u'OS::Heat::ResourceGroup'}, - self.list_resources(stack_identifier)) - self.assertEqual(files1, self.client.stacks.files(stack_identifier)) - - initial_nested_ident = self.group_nested_identifier(stack_identifier, - 'random_group') - self.assertEqual({'0': 'My::RandomString', '1': 'My::RandomString'}, - self.list_resources(initial_nested_ident)) - # get the output - stack0 = self.client.stacks.get(stack_identifier) - initial_rand = self._stack_output(stack0, 'random1') - - # change the environment so we use a different TemplateResource. - # note "files2". - self.update_stack(stack_identifier, template_one, - environment=env, files=files2) - updated_nested_ident = self.group_nested_identifier(stack_identifier, - 'random_group') - self.assertEqual(initial_nested_ident, updated_nested_ident) - self.assertEqual(files2, self.client.stacks.files(stack_identifier)) - - # compare the output, we expect a change. - stack1 = self.client.stacks.get(stack_identifier) - updated_rand = self._stack_output(stack1, 'random1') - self.assertNotEqual(initial_rand, updated_rand) - - -class ResourceGroupTestNullParams(functional_base.FunctionalTestsBase): - template = ''' -heat_template_version: 2013-05-23 -parameters: - param: - type: empty -resources: - random_group: - type: OS::Heat::ResourceGroup - properties: - count: 1 - resource_def: - type: My::RandomString - properties: - param: {get_param: param} -outputs: - val: - value: {get_attr: [random_group, val]} -''' - - nested_template_file = ''' -heat_template_version: 2013-05-23 -parameters: - param: - type: empty -outputs: - val: - value: {get_param: param} -''' - - scenarios = [ - ('string_empty', dict( - param='', - p_type='string', - )), - ('boolean_false', dict( - param=False, - p_type='boolean', - )), - ('number_zero', dict( - param=0, - p_type='number', - )), - ('comma_delimited_list', dict( - param=[], - p_type='comma_delimited_list', - )), - ('json_empty', dict( - param={}, - p_type='json', - )), - ] - - def test_create_pass_zero_parameter(self): - templ = self.template.replace('type: empty', - 'type: %s' % self.p_type) - n_t_f = self.nested_template_file.replace('type: empty', - 'type: %s' % self.p_type) - files = {'provider.yaml': n_t_f} - env = {'resource_registry': - {'My::RandomString': 'provider.yaml'}} - stack_identifier = self.stack_create( - template=templ, - files=files, - environment=env, - parameters={'param': self.param} - ) - stack = self.client.stacks.get(stack_identifier) - self.assertEqual(self.param, self._stack_output(stack, 'val')[0]) - - -class ResourceGroupAdoptTest(functional_base.FunctionalTestsBase): - """Prove that we can do resource group adopt.""" - - main_template = ''' -heat_template_version: "2013-05-23" -resources: - group1: - type: OS::Heat::ResourceGroup - properties: - count: 2 - resource_def: - type: OS::Heat::RandomString -outputs: - test0: - value: {get_attr: [group1, resource.0.value]} - test1: - value: {get_attr: [group1, resource.1.value]} -''' - - def _yaml_to_json(self, yaml_templ): - return yaml.safe_load(yaml_templ) - - def test_adopt(self): - data = { - "resources": { - "group1": { - "status": "COMPLETE", - "name": "group1", - "resource_data": {}, - "metadata": {}, - "resource_id": "test-group1-id", - "action": "CREATE", - "type": "OS::Heat::ResourceGroup", - "resources": { - "0": { - "status": "COMPLETE", - "name": "0", - "resource_data": {"value": "goopie"}, - "resource_id": "ID-0", - "action": "CREATE", - "type": "OS::Heat::RandomString", - "metadata": {} - }, - "1": { - "status": "COMPLETE", - "name": "1", - "resource_data": {"value": "different"}, - "resource_id": "ID-1", - "action": "CREATE", - "type": "OS::Heat::RandomString", - "metadata": {} - } - } - } - }, - "environment": {"parameters": {}}, - "template": yaml.safe_load(self.main_template) - } - stack_identifier = self.stack_adopt( - adopt_data=json.dumps(data)) - - self.assert_resource_is_a_stack(stack_identifier, 'group1') - stack = self.client.stacks.get(stack_identifier) - self.assertEqual('goopie', self._stack_output(stack, 'test0')) - self.assertEqual('different', self._stack_output(stack, 'test1')) - - -class ResourceGroupErrorResourceTest(functional_base.FunctionalTestsBase): - template = ''' -heat_template_version: "2013-05-23" -resources: - group1: - type: OS::Heat::ResourceGroup - properties: - count: 2 - resource_def: - type: fail.yaml -''' - nested_templ = ''' -heat_template_version: "2013-05-23" -resources: - oops: - type: OS::Heat::TestResource - properties: - fail: true - wait_secs: 2 -''' - - def test_fail(self): - stack_identifier = self.stack_create( - template=self.template, - files={'fail.yaml': self.nested_templ}, - expected_status='CREATE_FAILED', - enable_cleanup=False) - stack = self.client.stacks.get(stack_identifier) - - self.assertEqual('CREATE_FAILED', stack.stack_status) - self.client.stacks.delete(stack_identifier) - self._wait_for_stack_status( - stack_identifier, 'DELETE_COMPLETE', - success_on_not_found=True) - - -class ResourceGroupUpdatePolicyTest(functional_base.FunctionalTestsBase): - - template = ''' -heat_template_version: '2015-04-30' -resources: - random_group: - type: OS::Heat::ResourceGroup - update_policy: - rolling_update: - min_in_service: 1 - max_batch_size: 2 - pause_time: 1 - properties: - count: 10 - resource_def: - type: OS::Heat::TestResource - properties: - value: initial - update_replace: False -''' - - def update_resource_group(self, update_template, - updated, created, deleted): - stack_identifier = self.stack_create(template=self.template) - group_resources = self.list_group_resources(stack_identifier, - 'random_group', - minimal=False) - - init_names = [res.physical_resource_id for res in group_resources] - - self.update_stack(stack_identifier, update_template) - group_resources = self.list_group_resources(stack_identifier, - 'random_group', - minimal=False) - - updt_names = [res.physical_resource_id for res in group_resources] - - matched_names = set(updt_names) & set(init_names) - - self.assertEqual(updated, len(matched_names)) - - self.assertEqual(created, len(set(updt_names) - set(init_names))) - - self.assertEqual(deleted, len(set(init_names) - set(updt_names))) - - def test_resource_group_update(self): - """Test rolling update with no conflict. - - Simple rolling update with no conflict in batch size - and minimum instances in service. - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '1' - policy['max_batch_size'] = '3' - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - - self.update_resource_group(updt_template, - updated=10, - created=0, - deleted=0) - - def test_resource_group_update_replace(self): - """Test rolling update(replace)with no conflict. - - Simple rolling update replace with no conflict in batch size - and minimum instances in service. - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '1' - policy['max_batch_size'] = '3' - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - res_def['properties']['update_replace'] = True - - self.update_resource_group(updt_template, - updated=0, - created=10, - deleted=10) - - def test_resource_group_update_scaledown(self): - """Test rolling update with scaledown. - - Simple rolling update with reduced size. - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '1' - policy['max_batch_size'] = '3' - grp['properties']['count'] = 6 - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - - self.update_resource_group(updt_template, - updated=6, - created=0, - deleted=4) - - def test_resource_group_update_scaleup(self): - """Test rolling update with scaleup. - - Simple rolling update with increased size. - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '1' - policy['max_batch_size'] = '3' - grp['properties']['count'] = 12 - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - - self.update_resource_group(updt_template, - updated=10, - created=2, - deleted=0) - - def test_resource_group_update_adjusted(self): - """Test rolling update with enough available resources - - Update with capacity adjustment with enough resources. - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '8' - policy['max_batch_size'] = '4' - grp['properties']['count'] = 6 - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - - self.update_resource_group(updt_template, - updated=6, - created=0, - deleted=4) - - def test_resource_group_update_with_adjusted_capacity(self): - """Test rolling update with capacity adjustment. - - Rolling update with capacity adjustment due to conflict in - batch size and minimum instances in service. - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '8' - policy['max_batch_size'] = '4' - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - - self.update_resource_group(updt_template, - updated=10, - created=0, - deleted=0) - - def test_resource_group_update_huge_batch_size(self): - """Test rolling update with huge batch size. - - Rolling Update with a huge batch size(more than - current size). - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '0' - policy['max_batch_size'] = '20' - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - self.update_resource_group(updt_template, - updated=10, - created=0, - deleted=0) - - def test_resource_group_update_huge_min_in_service(self): - """Test rolling update with huge minimum capacity. - - Rolling Update with a huge number of minimum instances - in service. - """ - updt_template = yaml.safe_load(copy.deepcopy(self.template)) - grp = updt_template['resources']['random_group'] - policy = grp['update_policy']['rolling_update'] - policy['min_in_service'] = '20' - policy['max_batch_size'] = '1' - res_def = grp['properties']['resource_def'] - res_def['properties']['value'] = 'updated' - - self.update_resource_group(updt_template, - updated=10, - created=0, - deleted=0) diff --git a/heat_tempest_plugin/tests/functional/test_simultaneous_update.py b/heat_tempest_plugin/tests/functional/test_simultaneous_update.py deleted file mode 100644 index 3cfbeaa..0000000 --- a/heat_tempest_plugin/tests/functional/test_simultaneous_update.py +++ /dev/null @@ -1,93 +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 -import time - -from heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - -_test_template = { - 'heat_template_version': 'pike', - 'description': 'Test template to create two resources.', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0, - } - }, - 'test2': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'fail': False, - 'update_replace': False, - 'wait_secs': 0, - 'action_wait_secs': { - 'create': 30, - } - }, - 'depends_on': ['test1'] - } - } -} - - -def get_templates(fail=False, delay_s=None): - before = copy.deepcopy(_test_template) - - after = copy.deepcopy(before) - for r in after['resources'].values(): - r['properties']['value'] = 'Test2' - - before_props = before['resources']['test2']['properties'] - before_props['fail'] = fail - if delay_s is not None: - before_props['action_wait_secs']['create'] = delay_s - - return before, after - - -class SimultaneousUpdateStackTest(functional_base.FunctionalTestsBase): - - @test.requires_convergence - def test_retrigger_success(self): - before, after = get_templates() - stack_id = self.stack_create(template=before, - expected_status='CREATE_IN_PROGRESS') - time.sleep(10) - - self.update_stack(stack_id, after) - - @test.requires_convergence - def test_retrigger_failure(self): - before, after = get_templates(fail=True) - stack_id = self.stack_create(template=before, - expected_status='CREATE_IN_PROGRESS') - time.sleep(10) - - self.update_stack(stack_id, after) - - @test.requires_convergence - def test_retrigger_timeout(self): - before, after = get_templates(delay_s=70) - stack_id = self.stack_create(template=before, - expected_status='CREATE_IN_PROGRESS', - timeout=1) - time.sleep(50) - - self.update_stack(stack_id, after) diff --git a/heat_tempest_plugin/tests/functional/test_snapshot_restore.py b/heat_tempest_plugin/tests/functional/test_snapshot_restore.py deleted file mode 100644 index 3616c8f..0000000 --- a/heat_tempest_plugin/tests/functional/test_snapshot_restore.py +++ /dev/null @@ -1,76 +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 heat_tempest_plugin.tests.functional import functional_base - - -class StackSnapshotRestoreTest(functional_base.FunctionalTestsBase): - - def setUp(self): - super(StackSnapshotRestoreTest, self).setUp() - if not self.conf.minimal_image_ref: - raise self.skipException("No image configured to test") - - if not self.conf.minimal_instance_type: - raise self.skipException( - "No minimal_instance_type configured to test") - - self.assign_keypair() - - def test_stack_snapshot_restore(self): - template = ''' -heat_template_version: ocata -parameters: - keyname: - type: string - flavor: - type: string - image: - type: string - network: - type: string -resources: - my_port: - type: OS::Neutron::Port - properties: - network: {get_param: network} - my_server: - type: OS::Nova::Server - properties: - image: {get_param: image} - flavor: {get_param: flavor} - key_name: {get_param: keyname} - networks: [{port: {get_resource: my_port} }] - -''' - - def get_server_image(server_id): - server = self.compute_client.servers.get(server_id) - return server.image['id'] - - parameters = {'keyname': self.keypair_name, - 'flavor': self.conf.minimal_instance_type, - 'image': self.conf.minimal_image_ref, - 'network': self.conf.fixed_network_name} - stack_identifier = self.stack_create(template=template, - parameters=parameters) - server_resource = self.client.resources.get( - stack_identifier, 'my_server') - server_id = server_resource.physical_resource_id - prev_image_id = get_server_image(server_id) - - # Do snapshot and restore - snapshot_id = self.stack_snapshot(stack_identifier) - self.stack_restore(stack_identifier, snapshot_id) - - self.assertNotEqual(prev_image_id, get_server_image(server_id)) diff --git a/heat_tempest_plugin/tests/functional/test_software_deployment_group.py b/heat_tempest_plugin/tests/functional/test_software_deployment_group.py deleted file mode 100644 index a298419..0000000 --- a/heat_tempest_plugin/tests/functional/test_software_deployment_group.py +++ /dev/null @@ -1,150 +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 heat_tempest_plugin.tests.functional import functional_base - - -class SoftwareDeploymentGroupTest(functional_base.FunctionalTestsBase): - sd_template = ''' -heat_template_version: 2016-10-14 - -parameters: - input: - type: string - default: foo_input - -resources: - config: - type: OS::Heat::SoftwareConfig - properties: - group: script - inputs: - - name: foo - - deployment: - type: OS::Heat::SoftwareDeploymentGroup - properties: - config: {get_resource: config} - input_values: - foo: {get_param: input} - servers: - '0': dummy0 - '1': dummy1 - '2': dummy2 - '3': dummy3 -''' - - sd_template_with_upd_policy = ''' -heat_template_version: 2016-10-14 - -parameters: - input: - type: string - default: foo_input - -resources: - config: - type: OS::Heat::SoftwareConfig - properties: - group: script - inputs: - - name: foo - - deployment: - type: OS::Heat::SoftwareDeploymentGroup - update_policy: - rolling_update: - max_batch_size: 2 - pause_time: 1 - properties: - config: {get_resource: config} - input_values: - foo: {get_param: input} - servers: - '0': dummy0 - '1': dummy1 - '2': dummy2 - '3': dummy3 -''' - enable_cleanup = True - - def deployment_crud(self, template): - stack_identifier = self.stack_create( - template=template, - enable_cleanup=self.enable_cleanup, - expected_status='CREATE_IN_PROGRESS') - self._wait_for_resource_status( - stack_identifier, 'deployment', 'CREATE_IN_PROGRESS') - - # Wait for all deployment resources to become IN_PROGRESS, since only - # IN_PROGRESS resources get signalled - nested_identifier = self.assert_resource_is_a_stack( - stack_identifier, 'deployment') - self._wait_for_stack_status(nested_identifier, 'CREATE_IN_PROGRESS') - self._wait_for_all_resource_status(nested_identifier, - 'CREATE_IN_PROGRESS') - group_resources = self.list_group_resources( - stack_identifier, 'deployment', minimal=False) - - self.assertEqual(4, len(group_resources)) - self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE', - signal_required=True, - resources_to_signal=group_resources) - - created_group_resources = self.list_group_resources( - stack_identifier, 'deployment', minimal=False) - self.assertEqual(4, len(created_group_resources)) - self.check_input_values(created_group_resources, 'foo', 'foo_input') - - self.update_stack(stack_identifier, - template=template, - environment={'parameters': {'input': 'input2'}}, - expected_status='UPDATE_IN_PROGRESS') - nested_identifier = self.assert_resource_is_a_stack( - stack_identifier, 'deployment') - self._wait_for_stack_status(stack_identifier, 'UPDATE_COMPLETE', - signal_required=True, - resources_to_signal=group_resources) - - self.check_input_values(created_group_resources, 'foo', 'input2') - - # We explicitly test delete here, vs just via cleanup and check - # the nested stack is gone - self._stack_delete(stack_identifier) - self._wait_for_stack_status( - nested_identifier, 'DELETE_COMPLETE', - success_on_not_found=True) - - def test_deployment_crud(self): - self.deployment_crud(self.sd_template) - - def test_deployment_crud_with_rolling_update(self): - self.deployment_crud(self.sd_template_with_upd_policy) - - def test_deployments_create_delete_in_progress(self): - stack_identifier = self.stack_create( - template=self.sd_template, - enable_cleanup=self.enable_cleanup, - expected_status='CREATE_IN_PROGRESS') - self._wait_for_resource_status( - stack_identifier, 'deployment', 'CREATE_IN_PROGRESS') - nested_identifier = self.assert_resource_is_a_stack( - stack_identifier, 'deployment') - group_resources = self.list_group_resources( - stack_identifier, 'deployment', minimal=False) - - self.assertEqual(4, len(group_resources)) - # Now test delete while the stacks are still IN_PROGRESS - self._stack_delete(stack_identifier) - self._wait_for_stack_status( - nested_identifier, 'DELETE_COMPLETE', - success_on_not_found=True) diff --git a/heat_tempest_plugin/tests/functional/test_stack_cancel.py b/heat_tempest_plugin/tests/functional/test_stack_cancel.py deleted file mode 100644 index ba5e989..0000000 --- a/heat_tempest_plugin/tests/functional/test_stack_cancel.py +++ /dev/null @@ -1,92 +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 -import eventlet - -from heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - - -template = { - 'heat_template_version': 'pike', - 'resources': { - 'test1': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - 'action_wait_secs': { - 'update': 30, - } - } - }, - 'test2': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': 'Test1', - }, - 'depends_on': ['test1'] - }, - } -} - - -def get_templates(delay_s=None): - before = copy.deepcopy(template) - after = copy.deepcopy(before) - for r in after['resources'].values(): - r['properties']['value'] = 'Test2' - - if delay_s: - before_props = before['resources']['test1']['properties'] - before_props['action_wait_secs']['create'] = delay_s - return before, after - - -class StackCancelTest(functional_base.FunctionalTestsBase): - - def _test_cancel_update(self, rollback=True, - expected_status='ROLLBACK_COMPLETE'): - before, after = get_templates() - stack_id = self.stack_create(template=before) - self.update_stack(stack_id, template=after, - expected_status='UPDATE_IN_PROGRESS') - self._wait_for_resource_status(stack_id, 'test1', 'UPDATE_IN_PROGRESS') - self.cancel_update_stack(stack_id, rollback, expected_status) - return stack_id - - def test_cancel_update_with_rollback(self): - self._test_cancel_update() - - def test_cancel_update_without_rollback(self): - stack_id = self._test_cancel_update(rollback=False, - expected_status='UPDATE_FAILED') - self.assertTrue(test.call_until_true( - 60, 2, self.verify_resource_status, - stack_id, 'test1', 'UPDATE_COMPLETE')) - eventlet.sleep(2) - self.assertTrue(self.verify_resource_status(stack_id, 'test2', - 'CREATE_COMPLETE')) - - def test_cancel_create_without_rollback(self): - before, after = get_templates(delay_s=30) - stack_id = self.stack_create(template=before, - expected_status='CREATE_IN_PROGRESS') - self._wait_for_resource_status(stack_id, 'test1', 'CREATE_IN_PROGRESS') - self.cancel_update_stack(stack_id, rollback=False, - expected_status='CREATE_FAILED') - self.assertTrue(test.call_until_true( - 60, 2, self.verify_resource_status, - stack_id, 'test1', 'CREATE_COMPLETE')) - eventlet.sleep(2) - self.assertTrue(self.verify_resource_status(stack_id, 'test2', - 'INIT_COMPLETE')) diff --git a/heat_tempest_plugin/tests/functional/test_swiftsignal_update.py b/heat_tempest_plugin/tests/functional/test_swiftsignal_update.py deleted file mode 100644 index 604e592..0000000 --- a/heat_tempest_plugin/tests/functional/test_swiftsignal_update.py +++ /dev/null @@ -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 heat_tempest_plugin.tests.functional import functional_base - -test_template = ''' -heat_template_version: 2014-10-16 - -resources: - signal_handle: - type: "OS::Heat::SwiftSignalHandle" - -outputs: - signal_curl: - value: { get_attr: ['signal_handle', 'curl_cli'] } - description: Swift signal cURL - - signal_url: - value: { get_attr: ['signal_handle', 'endpoint'] } - description: Swift signal URL -''' - - -class SwiftSignalHandleUpdateTest(functional_base.FunctionalTestsBase): - - def test_stack_update_same_template_replace_no_url(self): - if not self.is_service_available('object-store'): - self.skipTest('object-store service not available, skipping') - stack_identifier = self.stack_create(template=test_template) - stack = self.client.stacks.get(stack_identifier) - orig_url = self._stack_output(stack, 'signal_url') - orig_curl = self._stack_output(stack, 'signal_curl') - self.update_stack(stack_identifier, test_template) - stack = self.client.stacks.get(stack_identifier) - self.assertEqual(orig_url, self._stack_output(stack, 'signal_url')) - self.assertEqual(orig_curl, self._stack_output(stack, 'signal_curl')) diff --git a/heat_tempest_plugin/tests/functional/test_template_resource.py b/heat_tempest_plugin/tests/functional/test_template_resource.py deleted file mode 100644 index a7cc808..0000000 --- a/heat_tempest_plugin/tests/functional/test_template_resource.py +++ /dev/null @@ -1,982 +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 json - -from heatclient import exc as heat_exceptions -import six -import yaml - -from heat_tempest_plugin.common import test -from heat_tempest_plugin.tests.functional import functional_base - - -class TemplateResourceTest(functional_base.FunctionalTestsBase): - """Prove that we can use the registry in a nested provider.""" - - template = ''' -heat_template_version: 2013-05-23 -resources: - secret1: - type: OS::Heat::RandomString -outputs: - secret-out: - value: { get_attr: [secret1, value] } -''' - nested_templ = ''' -heat_template_version: 2013-05-23 -resources: - secret2: - type: OS::Heat::RandomString -outputs: - value: - value: { get_attr: [secret2, value] } -''' - - env_templ = ''' -resource_registry: - "OS::Heat::RandomString": nested.yaml -''' - - def test_nested_env(self): - main_templ = ''' -heat_template_version: 2013-05-23 -resources: - secret1: - type: My::NestedSecret -outputs: - secret-out: - value: { get_attr: [secret1, value] } -''' - - nested_templ = ''' -heat_template_version: 2013-05-23 -resources: - secret2: - type: My::Secret -outputs: - value: - value: { get_attr: [secret2, value] } -''' - - env_templ = ''' -resource_registry: - "My::Secret": "OS::Heat::RandomString" - "My::NestedSecret": nested.yaml -''' - - stack_identifier = self.stack_create( - template=main_templ, - files={'nested.yaml': nested_templ}, - environment=env_templ) - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'secret1') - # prove that resource.parent_resource is populated. - sec2 = self.client.resources.get(nested_ident, 'secret2') - self.assertEqual('secret1', sec2.parent_resource) - - def test_no_infinite_recursion(self): - """Prove that we can override a python resource. - - And use that resource within the template resource. - """ - stack_identifier = self.stack_create( - template=self.template, - files={'nested.yaml': self.nested_templ}, - environment=self.env_templ) - self.assert_resource_is_a_stack(stack_identifier, 'secret1') - - def test_nested_stack_delete_then_delete_parent_stack(self): - """Check the robustness of stack deletion. - - This tests that if you manually delete a nested - stack, the parent stack is still deletable. - """ - # disable cleanup so we can call _stack_delete() directly. - stack_identifier = self.stack_create( - template=self.template, - files={'nested.yaml': self.nested_templ}, - environment=self.env_templ, - enable_cleanup=False) - - nested_ident = self.assert_resource_is_a_stack(stack_identifier, - 'secret1') - - self._stack_delete(nested_ident) - self._stack_delete(stack_identifier) - - def test_change_in_file_path(self): - stack_identifier = self.stack_create( - template=self.template, - files={'nested.yaml': self.nested_templ}, - environment=self.env_templ) - stack = self.client.stacks.get(stack_identifier) - secret_out1 = self._stack_output(stack, 'secret-out') - - nested_templ_2 = ''' -heat_template_version: 2013-05-23 -resources: - secret2: - type: OS::Heat::RandomString -outputs: - value: - value: freddy -''' - env_templ_2 = ''' -resource_registry: - "OS::Heat::RandomString": new/nested.yaml -''' - self.update_stack(stack_identifier, - template=self.template, - files={'new/nested.yaml': nested_templ_2}, - environment=env_templ_2) - stack = self.client.stacks.get(stack_identifier) - secret_out2 = self._stack_output(stack, 'secret-out') - self.assertNotEqual(secret_out1, secret_out2) - self.assertEqual('freddy', secret_out2) - - -class NestedAttributesTest(functional_base.FunctionalTestsBase): - """Prove that we can use the template resource references.""" - - main_templ = ''' -heat_template_version: 2014-10-16 -resources: - secret2: - type: My::NestedSecret -outputs: - old_way: - value: { get_attr: [secret2, nested_str]} - test_attr1: - value: { get_attr: [secret2, resource.secret1, value]} - test_attr2: - value: { get_attr: [secret2, resource.secret1.value]} - test_ref: - value: { get_resource: secret2 } -''' - - env_templ = ''' -resource_registry: - "My::NestedSecret": nested.yaml -''' - - def test_stack_ref(self): - nested_templ = ''' -heat_template_version: 2014-10-16 -resources: - secret1: - type: OS::Heat::RandomString -outputs: - nested_str: - value: {get_attr: [secret1, value]} -''' - stack_identifier = self.stack_create( - template=self.main_templ, - files={'nested.yaml': nested_templ}, - environment=self.env_templ) - self.assert_resource_is_a_stack(stack_identifier, 'secret2') - stack = self.client.stacks.get(stack_identifier) - test_ref = self._stack_output(stack, 'test_ref') - self.assertIn('arn:openstack:heat:', test_ref) - - def test_transparent_ref(self): - """Test using nested resource more transparently. - - With the addition of OS::stack_id we can now use the nested resource - more transparently. - """ - - nested_templ = ''' -heat_template_version: 2014-10-16 -resources: - secret1: - type: OS::Heat::RandomString -outputs: - OS::stack_id: - value: {get_resource: secret1} - nested_str: - value: {get_attr: [secret1, value]} -''' - stack_identifier = self.stack_create( - template=self.main_templ, - files={'nested.yaml': nested_templ}, - environment=self.env_templ) - self.assert_resource_is_a_stack(stack_identifier, 'secret2') - stack = self.client.stacks.get(stack_identifier) - test_ref = self._stack_output(stack, 'test_ref') - test_attr = self._stack_output(stack, 'old_way') - - self.assertNotIn('arn:openstack:heat', test_ref) - self.assertEqual(test_attr, test_ref) - - def test_nested_attributes(self): - nested_templ = ''' -heat_template_version: 2014-10-16 -resources: - secret1: - type: OS::Heat::RandomString -outputs: - nested_str: - value: {get_attr: [secret1, value]} -''' - stack_identifier = self.stack_create( - template=self.main_templ, - files={'nested.yaml': nested_templ}, - environment=self.env_templ) - self.assert_resource_is_a_stack(stack_identifier, 'secret2') - stack = self.client.stacks.get(stack_identifier) - old_way = self._stack_output(stack, 'old_way') - test_attr1 = self._stack_output(stack, 'test_attr1') - test_attr2 = self._stack_output(stack, 'test_attr2') - - self.assertEqual(old_way, test_attr1) - self.assertEqual(old_way, test_attr2) - - -class TemplateResourceFacadeTest(functional_base.FunctionalTestsBase): - """Prove that we can use ResourceFacade in a HOT template.""" - - main_template = ''' -heat_template_version: 2013-05-23 -resources: - the_nested: - type: the.yaml - metadata: - foo: bar -outputs: - value: - value: {get_attr: [the_nested, output]} -''' - - nested_templ = ''' -heat_template_version: 2013-05-23 -resources: - test: - type: OS::Heat::TestResource - properties: - value: {"Fn::Select": [foo, {resource_facade: metadata}]} -outputs: - output: - value: {get_attr: [test, output]} - ''' - - def test_metadata(self): - stack_identifier = self.stack_create( - template=self.main_template, - files={'the.yaml': self.nested_templ}) - stack = self.client.stacks.get(stack_identifier) - value = self._stack_output(stack, 'value') - self.assertEqual('bar', value) - - -class TemplateResourceUpdateTest(functional_base.FunctionalTestsBase): - """Prove that we can do template resource updates.""" - - main_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - the_nested: - Type: the.yaml - Properties: - one: my_name - two: your_name -Outputs: - identifier: - Value: {Ref: the_nested} - value: - Value: {'Fn::GetAtt': [the_nested, the_str]} -''' - - main_template_change_prop = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - the_nested: - Type: the.yaml - Properties: - one: updated_name - two: your_name - -Outputs: - identifier: - Value: {Ref: the_nested} - value: - Value: {'Fn::GetAtt': [the_nested, the_str]} -''' - - main_template_add_prop = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - the_nested: - Type: the.yaml - Properties: - one: my_name - two: your_name - three: third_name - -Outputs: - identifier: - Value: {Ref: the_nested} - value: - Value: {'Fn::GetAtt': [the_nested, the_str]} -''' - - main_template_remove_prop = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - the_nested: - Type: the.yaml - Properties: - one: my_name - -Outputs: - identifier: - Value: {Ref: the_nested} - value: - Value: {'Fn::GetAtt': [the_nested, the_str]} -''' - - initial_tmpl = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: foo - Type: String - two: - Default: bar - Type: String - -Resources: - NestedResource: - Type: OS::Heat::RandomString - Properties: - salt: {Ref: one} -Outputs: - the_str: - Value: {'Fn::GetAtt': [NestedResource, value]} -''' - - prop_change_tmpl = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: yikes - Type: String - two: - Default: foo - Type: String -Resources: - NestedResource: - Type: OS::Heat::RandomString - Properties: - salt: {Ref: two} -Outputs: - the_str: - Value: {'Fn::GetAtt': [NestedResource, value]} -''' - - prop_add_tmpl = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: yikes - Type: String - two: - Default: foo - Type: String - three: - Default: bar - Type: String - -Resources: - NestedResource: - Type: OS::Heat::RandomString - Properties: - salt: {Ref: three} -Outputs: - the_str: - Value: {'Fn::GetAtt': [NestedResource, value]} -''' - - prop_remove_tmpl = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: yikes - Type: String - -Resources: - NestedResource: - Type: OS::Heat::RandomString - Properties: - salt: {Ref: one} -Outputs: - the_str: - Value: {'Fn::GetAtt': [NestedResource, value]} -''' - - attr_change_tmpl = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: foo - Type: String - two: - Default: bar - Type: String - -Resources: - NestedResource: - Type: OS::Heat::RandomString - Properties: - salt: {Ref: one} -Outputs: - the_str: - Value: {'Fn::GetAtt': [NestedResource, value]} - something_else: - Value: just_a_string -''' - - content_change_tmpl = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: foo - Type: String - two: - Default: bar - Type: String - -Resources: - NestedResource: - Type: OS::Heat::RandomString - Properties: - salt: yum -Outputs: - the_str: - Value: {'Fn::GetAtt': [NestedResource, value]} -''' - - EXPECTED = (UPDATE, NOCHANGE) = ('update', 'nochange') - scenarios = [ - ('no_changes', dict(template=main_template, - provider=initial_tmpl, - expect=NOCHANGE)), - ('main_tmpl_change', dict(template=main_template_change_prop, - provider=initial_tmpl, - expect=UPDATE)), - ('provider_change', dict(template=main_template, - provider=content_change_tmpl, - expect=UPDATE)), - ('provider_props_change', dict(template=main_template, - provider=prop_change_tmpl, - expect=UPDATE)), - ('provider_props_add', dict(template=main_template_add_prop, - provider=prop_add_tmpl, - expect=UPDATE)), - ('provider_props_remove', dict(template=main_template_remove_prop, - provider=prop_remove_tmpl, - expect=NOCHANGE)), - ('provider_attr_change', dict(template=main_template, - provider=attr_change_tmpl, - expect=NOCHANGE)), - ] - - def test_template_resource_update_template_schema(self): - stack_identifier = self.stack_create( - template=self.main_template, - files={'the.yaml': self.initial_tmpl}) - stack = self.client.stacks.get(stack_identifier) - initial_id = self._stack_output(stack, 'identifier') - initial_val = self._stack_output(stack, 'value') - - self.update_stack(stack_identifier, - self.template, - files={'the.yaml': self.provider}) - stack = self.client.stacks.get(stack_identifier) - self.assertEqual(initial_id, - self._stack_output(stack, 'identifier')) - if self.expect == self.NOCHANGE: - self.assertEqual(initial_val, - self._stack_output(stack, 'value')) - else: - self.assertNotEqual(initial_val, - self._stack_output(stack, 'value')) - - -class TemplateResourceUpdateFailedTest(functional_base.FunctionalTestsBase): - """Prove that we can do updates on a nested stack to fix a stack.""" - - main_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - keypair: - Type: OS::Nova::KeyPair - Properties: - name: replace-this - save_private_key: false - server: - Type: server_fail.yaml - DependsOn: keypair -''' - nested_templ = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - RealRandom: - Type: OS::Heat::RandomString -''' - - def setUp(self): - super(TemplateResourceUpdateFailedTest, self).setUp() - self.assign_keypair() - - def test_update_on_failed_create(self): - # create a stack with "server" dependent on "keypair", but - # keypair fails, so "server" is not created properly. - # We then fix the template and it should succeed. - broken_templ = self.main_template.replace('replace-this', - self.keypair_name) - stack_identifier = self.stack_create( - template=broken_templ, - files={'server_fail.yaml': self.nested_templ}, - expected_status='CREATE_FAILED') - - fixed_templ = self.main_template.replace('replace-this', - test.rand_name()) - self.update_stack(stack_identifier, - fixed_templ, - files={'server_fail.yaml': self.nested_templ}) - - -class TemplateResourceAdoptTest(functional_base.FunctionalTestsBase): - """Prove that we can do template resource adopt/abandon.""" - - main_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - the_nested: - Type: the.yaml - Properties: - one: my_name -Outputs: - identifier: - Value: {Ref: the_nested} - value: - Value: {'Fn::GetAtt': [the_nested, the_str]} -''' - - nested_templ = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: foo - Type: String -Resources: - RealRandom: - Type: OS::Heat::RandomString - Properties: - salt: {Ref: one} -Outputs: - the_str: - Value: {'Fn::GetAtt': [RealRandom, value]} -''' - - def _yaml_to_json(self, yaml_templ): - return yaml.safe_load(yaml_templ) - - def test_abandon(self): - stack_identifier = self.stack_create( - template=self.main_template, - files={'the.yaml': self.nested_templ}, - enable_cleanup=False - ) - - info = self.stack_abandon(stack_id=stack_identifier) - self.assertEqual(self._yaml_to_json(self.main_template), - info['template']) - self.assertEqual(self._yaml_to_json(self.nested_templ), - info['resources']['the_nested']['template']) - # TODO(james combs): Implement separate test cases for export - # once export REST API is available. Also test reverse order - # of invocation: export -> abandon AND abandon -> export - - def test_adopt(self): - data = { - 'resources': { - 'the_nested': { - "type": "the.yaml", - "resources": { - "RealRandom": { - "type": "OS::Heat::RandomString", - 'resource_data': {'value': 'goopie'}, - 'resource_id': 'froggy' - } - } - } - }, - "environment": {"parameters": {}}, - "template": yaml.safe_load(self.main_template) - } - - stack_identifier = self.stack_adopt( - adopt_data=json.dumps(data), - files={'the.yaml': self.nested_templ}) - - self.assert_resource_is_a_stack(stack_identifier, 'the_nested') - stack = self.client.stacks.get(stack_identifier) - self.assertEqual('goopie', self._stack_output(stack, 'value')) - - -class TemplateResourceCheckTest(functional_base.FunctionalTestsBase): - """Prove that we can do template resource check.""" - - main_template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - the_nested: - Type: the.yaml - Properties: - one: my_name -Outputs: - identifier: - Value: {Ref: the_nested} - value: - Value: {'Fn::GetAtt': [the_nested, the_str]} -''' - - nested_templ = ''' -HeatTemplateFormatVersion: '2012-12-12' -Parameters: - one: - Default: foo - Type: String -Resources: - RealRandom: - Type: OS::Heat::RandomString - Properties: - salt: {Ref: one} -Outputs: - the_str: - Value: {'Fn::GetAtt': [RealRandom, value]} -''' - - def test_check(self): - stack_identifier = self.stack_create( - template=self.main_template, - files={'the.yaml': self.nested_templ} - ) - - self.client.actions.check(stack_id=stack_identifier) - self._wait_for_stack_status(stack_identifier, 'CHECK_COMPLETE') - - -class TemplateResourceErrorMessageTest(functional_base.FunctionalTestsBase): - """Prove that nested stack errors don't suck.""" - - template = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - victim: - Type: fail.yaml -''' - nested_templ = ''' -HeatTemplateFormatVersion: '2012-12-12' -Resources: - oops: - Type: OS::Heat::TestResource - Properties: - fail: true - wait_secs: 2 -''' - - def test_fail(self): - stack_identifier = self.stack_create( - template=self.template, - files={'fail.yaml': self.nested_templ}, - expected_status='CREATE_FAILED') - stack = self.client.stacks.get(stack_identifier) - - exp_path = 'resources.victim.resources.oops' - exp_msg = 'Test Resource failed oops' - exp = 'Resource CREATE failed: ValueError: %s: %s' % (exp_path, - exp_msg) - self.assertEqual(exp, stack.stack_status_reason) - - -class TemplateResourceSuspendResumeTest(functional_base.FunctionalTestsBase): - """Prove that we can do template resource suspend/resume.""" - - main_template = ''' -heat_template_version: 2014-10-16 -parameters: -resources: - the_nested: - type: the.yaml -''' - - nested_templ = ''' -heat_template_version: 2014-10-16 -resources: - test_random_string: - type: OS::Heat::RandomString -''' - - def test_suspend_resume(self): - """Basic test for template resource suspend resume.""" - stack_identifier = self.stack_create( - template=self.main_template, - files={'the.yaml': self.nested_templ} - ) - - self.stack_suspend(stack_identifier=stack_identifier) - self.stack_resume(stack_identifier=stack_identifier) - - -class ValidateFacadeTest(functional_base.FunctionalTestsBase): - """Prove that nested stack errors don't suck.""" - - template = ''' -heat_template_version: 2015-10-15 -resources: - thisone: - type: OS::Thingy - properties: - one: pre - two: post -outputs: - one: - value: {get_attr: [thisone, here-it-is]} -''' - templ_facade = ''' -heat_template_version: 2015-04-30 -parameters: - one: - type: string - two: - type: string -outputs: - here-it-is: - value: noop -''' - env = ''' -resource_registry: - OS::Thingy: facade.yaml - resources: - thisone: - OS::Thingy: concrete.yaml -''' - - def setUp(self): - super(ValidateFacadeTest, self).setUp() - self.client = self.orchestration_client - - def test_missing_param(self): - templ_missing_parameter = ''' -heat_template_version: 2015-04-30 -parameters: - one: - type: string -resources: - str: - type: OS::Heat::RandomString -outputs: - here-it-is: - value: - not-important -''' - try: - self.stack_create( - template=self.template, - environment=self.env, - files={'facade.yaml': self.templ_facade, - 'concrete.yaml': templ_missing_parameter}, - expected_status='CREATE_FAILED') - except heat_exceptions.HTTPBadRequest as exc: - exp = ('ERROR: Required property two for facade ' - 'OS::Thingy missing in provider') - self.assertEqual(exp, six.text_type(exc)) - - def test_missing_output(self): - templ_missing_output = ''' -heat_template_version: 2015-04-30 -parameters: - one: - type: string - two: - type: string -resources: - str: - type: OS::Heat::RandomString -''' - try: - self.stack_create( - template=self.template, - environment=self.env, - files={'facade.yaml': self.templ_facade, - 'concrete.yaml': templ_missing_output}, - expected_status='CREATE_FAILED') - except heat_exceptions.HTTPBadRequest as exc: - exp = ('ERROR: Attribute here-it-is for facade ' - 'OS::Thingy missing in provider') - self.assertEqual(exp, six.text_type(exc)) - - -class TemplateResourceNewParamTest(functional_base.FunctionalTestsBase): - - main_template = ''' -heat_template_version: 2013-05-23 -resources: - my_resource: - type: resource.yaml - properties: - value1: foo -''' - nested_templ = ''' -heat_template_version: 2013-05-23 -parameters: - value1: - type: string -resources: - test: - type: OS::Heat::TestResource - properties: - value: {get_param: value1} -''' - main_template_update = ''' -heat_template_version: 2013-05-23 -resources: - my_resource: - type: resource.yaml - properties: - value1: foo - value2: foo -''' - nested_templ_update_fail = ''' -heat_template_version: 2013-05-23 -parameters: - value1: - type: string - value2: - type: string -resources: - test: - type: OS::Heat::TestResource - properties: - fail: True - value: - str_replace: - template: VAL1-VAL2 - params: - VAL1: {get_param: value1} - VAL2: {get_param: value2} -''' - nested_templ_update = ''' -heat_template_version: 2013-05-23 -parameters: - value1: - type: string - value2: - type: string -resources: - test: - type: OS::Heat::TestResource - properties: - value: - str_replace: - template: VAL1-VAL2 - params: - VAL1: {get_param: value1} - VAL2: {get_param: value2} -''' - - def test_update(self): - stack_identifier = self.stack_create( - template=self.main_template, - files={'resource.yaml': self.nested_templ}) - - # Make the update fails with the new parameter inserted. - self.update_stack( - stack_identifier, - self.main_template_update, - files={'resource.yaml': self.nested_templ_update_fail}, - expected_status='UPDATE_FAILED') - - # Fix the update, it should succeed now. - self.update_stack( - stack_identifier, - self.main_template_update, - files={'resource.yaml': self.nested_templ_update}) - - -class TemplateResourceRemovedParamTest(functional_base.FunctionalTestsBase): - - main_template = ''' -heat_template_version: 2013-05-23 -parameters: - value1: - type: string - default: foo -resources: - my_resource: - type: resource.yaml - properties: - value1: {get_param: value1} -''' - nested_templ = ''' -heat_template_version: 2013-05-23 -parameters: - value1: - type: string - default: foo -resources: - test: - type: OS::Heat::TestResource - properties: - value: {get_param: value1} -''' - main_template_update = ''' -heat_template_version: 2013-05-23 -resources: - my_resource: - type: resource.yaml -''' - nested_templ_update = ''' -heat_template_version: 2013-05-23 -parameters: - value1: - type: string - default: foo - value2: - type: string - default: bar -resources: - test: - type: OS::Heat::TestResource - properties: - value: - str_replace: - template: VAL1-VAL2 - params: - VAL1: {get_param: value1} - VAL2: {get_param: value2} -''' - - def test_update(self): - stack_identifier = self.stack_create( - template=self.main_template, - environment={'parameters': {'value1': 'spam'}}, - files={'resource.yaml': self.nested_templ}) - - self.update_stack( - stack_identifier, - self.main_template_update, - environment={'parameter_defaults': {'value2': 'egg'}}, - files={'resource.yaml': self.nested_templ_update}, existing=True) diff --git a/heat_tempest_plugin/tests/functional/test_templates.py b/heat_tempest_plugin/tests/functional/test_templates.py index bfcf8bf..95c6a01 100644 --- a/heat_tempest_plugin/tests/functional/test_templates.py +++ b/heat_tempest_plugin/tests/functional/test_templates.py @@ -18,9 +18,8 @@ class TemplateAPITest(functional_base.FunctionalTestsBase): """This will test the following template calls: 1. Get the template content for the specific stack - 2. List template versions - 3. List resource types - 4. Show resource details for OS::Heat::TestResource + 2. List resource types + 3. Show resource details for OS::Heat::TestResource """ template = { @@ -46,19 +45,6 @@ class TemplateAPITest(functional_base.FunctionalTestsBase): template_from_client = self.client.stacks.template(stack_identifier) self.assertEqual(self.template, template_from_client) - def test_template_version(self): - template_versions = self.client.template_versions.list() - supported_template_versions = ["2013-05-23", "2014-10-16", - "2015-04-30", "2015-10-15", - "2012-12-12", "2010-09-09", - "2016-04-08", "2016-10-14", "newton", - "2017-02-24", "ocata", - "2017-09-01", "pike", - "2018-03-02", "queens"] - for template in template_versions: - self.assertIn(template.version.split(".")[1], - supported_template_versions) - def test_resource_types(self): resource_types = self.client.resource_types.list() self.assertTrue(any(resource.resource_type == "OS::Heat::TestResource" diff --git a/heat_tempest_plugin/tests/functional/test_translation.py b/heat_tempest_plugin/tests/functional/test_translation.py deleted file mode 100644 index 484663b..0000000 --- a/heat_tempest_plugin/tests/functional/test_translation.py +++ /dev/null @@ -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 heat_tempest_plugin.tests.functional import functional_base - -template_subnet_old_network = """ -heat_template_version: 2016-10-14 -parameters: - net_cidr: - type: string -resources: - net: - type: OS::Neutron::Net - subnet: - type: OS::Neutron::Subnet - properties: - cidr: { get_param: net_cidr } - network_id: { get_resource: net } -""" - -template_with_get_attr = """ -heat_template_version: 2016-10-14 -description: Test template to create/update subnet with translation -parameters: - net_cidr: - type: string -resources: - net: - type: OS::Neutron::Net - net_value: - type: OS::Heat::Value - properties: - value: { get_resource: net } - subnet: - type: OS::Neutron::Subnet - properties: - network: { get_attr: [net_value, value] } - cidr: { get_param: net_cidr } -""" - -template_value_from_nested_stack_main = """ -heat_template_version: 2016-10-14 -parameters: - flavor: - type: string - image: - type: string - public_net: - type: string -resources: - network_settings: - type: network.yaml - properties: - public_net: { get_param: public_net } - server: - type: OS::Nova::Server - properties: - flavor: { get_param: flavor } - image: { get_param: image } - networks: { get_attr: [network_settings, networks] } -""" - -template_value_from_nested_stack_network = """ -heat_template_version: 2016-10-14 -parameters: - public_net: - type: string -outputs: - networks: - value: - - uuid: { get_param: public_net } -""" - - -class TestTranslation(functional_base.FunctionalTestsBase): - - def test_create_update_subnet_old_network(self): - # Just create and update where network is translated properly. - env = {'parameters': {'net_cidr': '11.11.11.0/24'}} - stack_identifier = self.stack_create( - template=template_subnet_old_network, - environment=env) - env = {'parameters': {'net_cidr': '11.11.12.0/24'}} - self.update_stack(stack_identifier, - template=template_subnet_old_network, - environment=env) - - def test_create_update_translation_with_get_attr(self): - # Check create and update successful for translation function value. - env = {'parameters': {'net_cidr': '11.11.11.0/24'}} - stack_identifier = self.stack_create( - template=template_with_get_attr, - environment=env) - env = {'parameters': {'net_cidr': '11.11.12.0/24'}} - self.update_stack(stack_identifier, - template=template_with_get_attr, - environment=env) - - def test_value_from_nested_stack(self): - env = {'parameters': { - 'flavor': self.conf.minimal_instance_type, - 'image': self.conf.minimal_image_ref, - 'public_net': self.conf.fixed_network_name - }} - self.stack_create( - template=template_value_from_nested_stack_main, - environment=env, - files={'network.yaml': template_value_from_nested_stack_network}) diff --git a/heat_tempest_plugin/tests/functional/test_update_restricted.py b/heat_tempest_plugin/tests/functional/test_update_restricted.py deleted file mode 100644 index 83cb280..0000000 --- a/heat_tempest_plugin/tests/functional/test_update_restricted.py +++ /dev/null @@ -1,166 +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 time - -from heat_tempest_plugin.tests.functional import functional_base - -test_template = { - 'heat_template_version': '2013-05-23', - 'description': 'Test template to create one instance.', - 'resources': { - 'bar': { - 'type': 'OS::Heat::TestResource', - 'properties': { - 'value': '1234', - 'update_replace': False, - } - } - } -} - -env_both_restrict = {u'resource_registry': { - u'resources': { - 'bar': {'restricted_actions': ['update', 'replace']} - } -} -} - -env_replace_restrict = {u'resource_registry': { - u'resources': { - '*ar': {'restricted_actions': 'replace'} - } -} -} - -reason_update_restrict = 'update is restricted for resource.' -reason_replace_restrict = 'replace is restricted for resource.' - - -class UpdateRestrictedStackTest(functional_base.FunctionalTestsBase): - - def _check_for_restriction_reason(self, events, - reason, num_expected=1): - matched = [e for e in events - if e.resource_status_reason == reason] - return len(matched) == num_expected - - def test_update(self): - stack_identifier = self.stack_create(template=test_template) - - update_template = test_template.copy() - props = update_template['resources']['bar']['properties'] - props['value'] = '4567' - - # check update fails - with 'both' restricted - self.update_stack(stack_identifier, update_template, - env_both_restrict, - expected_status='UPDATE_FAILED') - - self.assertTrue(self.verify_resource_status(stack_identifier, 'bar', - 'CREATE_COMPLETE')) - resource_events = self.client.events.list(stack_identifier, 'bar') - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_update_restrict)) - - # Ensure the timestamp changes, since this will be very quick - time.sleep(1) - - # check update succeeds - with only 'replace' restricted - self.update_stack(stack_identifier, update_template, - env_replace_restrict, - expected_status='UPDATE_COMPLETE') - - self.assertTrue(self.verify_resource_status(stack_identifier, 'bar', - 'UPDATE_COMPLETE')) - resource_events = self.client.events.list(stack_identifier, 'bar') - self.assertFalse( - self._check_for_restriction_reason(resource_events, - reason_update_restrict, 2)) - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_replace_restrict, 0)) - - def test_replace(self): - stack_identifier = self.stack_create(template=test_template) - - update_template = test_template.copy() - props = update_template['resources']['bar']['properties'] - props['update_replace'] = True - - # check replace fails - with 'both' restricted - self.update_stack(stack_identifier, update_template, - env_both_restrict, - expected_status='UPDATE_FAILED') - - self.assertTrue(self.verify_resource_status(stack_identifier, 'bar', - 'CREATE_COMPLETE')) - resource_events = self.client.events.list(stack_identifier, 'bar') - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_replace_restrict)) - - # Ensure the timestamp changes, since this will be very quick - time.sleep(1) - - # check replace fails - with only 'replace' restricted - self.update_stack(stack_identifier, update_template, - env_replace_restrict, - expected_status='UPDATE_FAILED') - - self.assertTrue(self.verify_resource_status(stack_identifier, 'bar', - 'CREATE_COMPLETE')) - resource_events = self.client.events.list(stack_identifier, 'bar') - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_replace_restrict, 2)) - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_update_restrict, 0)) - - def test_update_type_changed(self): - stack_identifier = self.stack_create(template=test_template) - - update_template = test_template.copy() - rsrc = update_template['resources']['bar'] - rsrc['type'] = 'OS::Heat::None' - - # check replace fails - with 'both' restricted - self.update_stack(stack_identifier, update_template, - env_both_restrict, - expected_status='UPDATE_FAILED') - - self.assertTrue(self.verify_resource_status(stack_identifier, 'bar', - 'CREATE_COMPLETE')) - resource_events = self.client.events.list(stack_identifier, 'bar') - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_replace_restrict)) - - # Ensure the timestamp changes, since this will be very quick - time.sleep(1) - - # check replace fails - with only 'replace' restricted - self.update_stack(stack_identifier, update_template, - env_replace_restrict, - expected_status='UPDATE_FAILED') - - self.assertTrue(self.verify_resource_status(stack_identifier, 'bar', - 'CREATE_COMPLETE')) - resource_events = self.client.events.list(stack_identifier, 'bar') - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_replace_restrict, 2)) - self.assertTrue( - self._check_for_restriction_reason(resource_events, - reason_update_restrict, 0)) diff --git a/heat_tempest_plugin/tests/functional/test_validation.py b/heat_tempest_plugin/tests/functional/test_validation.py deleted file mode 100644 index ab1762e..0000000 --- a/heat_tempest_plugin/tests/functional/test_validation.py +++ /dev/null @@ -1,92 +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 heat_tempest_plugin.tests.functional import functional_base - - -class StackValidationTest(functional_base.FunctionalTestsBase): - - def setUp(self): - super(StackValidationTest, self).setUp() - if not self.conf.minimal_image_ref: - raise self.skipException("No image configured to test") - - if not self.conf.minimal_instance_type: - raise self.skipException( - "No minimal_instance_type configured to test") - - self.assign_keypair() - - def test_stack_validate_provider_references_parent_resource(self): - template = ''' -heat_template_version: 2014-10-16 -parameters: - keyname: - type: string - flavor: - type: string - image: - type: string - network: - type: string -resources: - config: - type: My::Config - properties: - server: {get_resource: server} - - server: - type: OS::Nova::Server - properties: - image: {get_param: image} - flavor: {get_param: flavor} - key_name: {get_param: keyname} - networks: [{network: {get_param: network} }] - user_data_format: SOFTWARE_CONFIG - -''' - config_template = ''' -heat_template_version: 2014-10-16 -parameters: - server: - type: string -resources: - config: - type: OS::Heat::SoftwareConfig - - deployment: - type: OS::Heat::SoftwareDeployment - properties: - config: - get_resource: config - server: - get_param: server -''' - files = {'provider.yaml': config_template} - env = {'resource_registry': - {'My::Config': 'provider.yaml'}} - parameters = {'keyname': self.keypair_name, - 'flavor': self.conf.minimal_instance_type, - 'image': self.conf.minimal_image_ref, - 'network': self.conf.fixed_network_name} - # Note we don't wait for CREATE_COMPLETE, because we're using a - # minimal image without the tools to apply the config. - # The point of the test is just to prove that validation won't - # falsely prevent stack creation starting, ref bug #1407100 - # Note that we can be sure My::Config will stay IN_PROGRESS as - # there's no signal sent to the deployment - self.stack_create(template=template, - files=files, - environment=env, - parameters=parameters, - expected_status='CREATE_IN_PROGRESS')