Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 2 | # not use this file except in compliance with the License. You may obtain |
| 3 | # a copy of the License at |
| 4 | # |
| 5 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 6 | # |
| 7 | # Unless required by applicable law or agreed to in writing, software |
| 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 10 | # License for the specific language governing permissions and limitations |
| 11 | # under the License. |
| 12 | |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 13 | from heat_integrationtests.functional import functional_base |
| 14 | |
| 15 | test_template_one_resource = { |
| 16 | 'heat_template_version': '2013-05-23', |
| 17 | 'description': 'Test template to create one instance.', |
| 18 | 'resources': { |
| 19 | 'test1': { |
| 20 | 'type': 'OS::Heat::TestResource', |
| 21 | 'properties': { |
| 22 | 'value': 'Test1', |
| 23 | 'fail': False, |
| 24 | 'update_replace': False, |
| 25 | 'wait_secs': 0 |
| 26 | } |
| 27 | } |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | test_template_two_resource = { |
| 32 | 'heat_template_version': '2013-05-23', |
| 33 | 'description': 'Test template to create two instance.', |
| 34 | 'resources': { |
| 35 | 'test1': { |
| 36 | 'type': 'OS::Heat::TestResource', |
| 37 | 'properties': { |
| 38 | 'value': 'Test1', |
| 39 | 'fail': False, |
| 40 | 'update_replace': False, |
| 41 | 'wait_secs': 0 |
| 42 | } |
| 43 | }, |
| 44 | 'test2': { |
| 45 | 'type': 'OS::Heat::TestResource', |
| 46 | 'properties': { |
| 47 | 'value': 'Test1', |
| 48 | 'fail': False, |
| 49 | 'update_replace': False, |
| 50 | 'wait_secs': 0 |
| 51 | } |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | |
Steven Hardy | e6de2d6 | 2015-12-07 15:59:09 +0000 | [diff] [blame] | 57 | class UpdatePreviewBase(functional_base.FunctionalTestsBase): |
| 58 | |
| 59 | def assert_empty_sections(self, changes, empty_sections): |
| 60 | for section in empty_sections: |
| 61 | self.assertEqual([], changes[section]) |
| 62 | |
| 63 | |
| 64 | class UpdatePreviewStackTest(UpdatePreviewBase): |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 65 | |
Steven Hardy | 09ae1b0 | 2016-01-18 11:31:52 +0000 | [diff] [blame] | 66 | def test_add_resource(self): |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 67 | self.stack_identifier = self.stack_create( |
| 68 | template=test_template_one_resource) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 69 | result = self.preview_update_stack(self.stack_identifier, |
| 70 | test_template_two_resource) |
| 71 | changes = result['resource_changes'] |
| 72 | |
| 73 | unchanged = changes['unchanged'][0]['resource_name'] |
| 74 | self.assertEqual('test1', unchanged) |
| 75 | |
| 76 | added = changes['added'][0]['resource_name'] |
| 77 | self.assertEqual('test2', added) |
| 78 | |
Steven Hardy | e6de2d6 | 2015-12-07 15:59:09 +0000 | [diff] [blame] | 79 | self.assert_empty_sections(changes, ['updated', 'replaced', 'deleted']) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 80 | |
| 81 | def test_no_change(self): |
Steven Hardy | 09ae1b0 | 2016-01-18 11:31:52 +0000 | [diff] [blame] | 82 | self.stack_identifier = self.stack_create( |
| 83 | template=test_template_one_resource) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 84 | result = self.preview_update_stack(self.stack_identifier, |
| 85 | test_template_one_resource) |
| 86 | changes = result['resource_changes'] |
| 87 | |
| 88 | unchanged = changes['unchanged'][0]['resource_name'] |
| 89 | self.assertEqual('test1', unchanged) |
| 90 | |
Steven Hardy | e6de2d6 | 2015-12-07 15:59:09 +0000 | [diff] [blame] | 91 | self.assert_empty_sections( |
| 92 | changes, ['updated', 'replaced', 'deleted', 'added']) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 93 | |
| 94 | def test_update_resource(self): |
Steven Hardy | 09ae1b0 | 2016-01-18 11:31:52 +0000 | [diff] [blame] | 95 | self.stack_identifier = self.stack_create( |
| 96 | template=test_template_one_resource) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 97 | test_template_updated_resource = { |
| 98 | 'heat_template_version': '2013-05-23', |
| 99 | 'description': 'Test template to create one instance.', |
| 100 | 'resources': { |
| 101 | 'test1': { |
| 102 | 'type': 'OS::Heat::TestResource', |
| 103 | 'properties': { |
| 104 | 'value': 'Test1 foo', |
| 105 | 'fail': False, |
| 106 | 'update_replace': False, |
| 107 | 'wait_secs': 0 |
| 108 | } |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | result = self.preview_update_stack(self.stack_identifier, |
| 114 | test_template_updated_resource) |
| 115 | changes = result['resource_changes'] |
| 116 | |
| 117 | updated = changes['updated'][0]['resource_name'] |
| 118 | self.assertEqual('test1', updated) |
| 119 | |
Steven Hardy | e6de2d6 | 2015-12-07 15:59:09 +0000 | [diff] [blame] | 120 | self.assert_empty_sections( |
| 121 | changes, ['added', 'unchanged', 'replaced', 'deleted']) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 122 | |
| 123 | def test_replaced_resource(self): |
Steven Hardy | 09ae1b0 | 2016-01-18 11:31:52 +0000 | [diff] [blame] | 124 | self.stack_identifier = self.stack_create( |
| 125 | template=test_template_one_resource) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 126 | new_template = { |
| 127 | 'heat_template_version': '2013-05-23', |
| 128 | 'description': 'Test template to create one instance.', |
| 129 | 'resources': { |
| 130 | 'test1': { |
| 131 | 'type': 'OS::Heat::TestResource', |
| 132 | 'properties': { |
| 133 | 'update_replace': True, |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | } |
| 138 | |
Steven Hardy | 09ae1b0 | 2016-01-18 11:31:52 +0000 | [diff] [blame] | 139 | result = self.preview_update_stack(self.stack_identifier, new_template) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 140 | changes = result['resource_changes'] |
| 141 | |
| 142 | replaced = changes['replaced'][0]['resource_name'] |
| 143 | self.assertEqual('test1', replaced) |
| 144 | |
Steven Hardy | e6de2d6 | 2015-12-07 15:59:09 +0000 | [diff] [blame] | 145 | self.assert_empty_sections( |
| 146 | changes, ['added', 'unchanged', 'updated', 'deleted']) |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 147 | |
| 148 | def test_delete_resource(self): |
Steven Hardy | 09ae1b0 | 2016-01-18 11:31:52 +0000 | [diff] [blame] | 149 | self.stack_identifier = self.stack_create( |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 150 | template=test_template_two_resource) |
Steven Hardy | 09ae1b0 | 2016-01-18 11:31:52 +0000 | [diff] [blame] | 151 | result = self.preview_update_stack(self.stack_identifier, |
Jason Dunsmore | b5aa902 | 2015-09-09 16:57:04 -0500 | [diff] [blame] | 152 | test_template_one_resource) |
| 153 | changes = result['resource_changes'] |
| 154 | |
| 155 | unchanged = changes['unchanged'][0]['resource_name'] |
| 156 | self.assertEqual('test1', unchanged) |
| 157 | |
| 158 | deleted = changes['deleted'][0]['resource_name'] |
| 159 | self.assertEqual('test2', deleted) |
| 160 | |
Steven Hardy | e6de2d6 | 2015-12-07 15:59:09 +0000 | [diff] [blame] | 161 | self.assert_empty_sections(changes, ['updated', 'replaced', 'added']) |
| 162 | |
| 163 | |
| 164 | class UpdatePreviewStackTestNested(UpdatePreviewBase): |
| 165 | template_nested_parent = ''' |
| 166 | heat_template_version: 2016-04-08 |
| 167 | resources: |
| 168 | nested1: |
| 169 | type: nested1.yaml |
| 170 | ''' |
| 171 | |
| 172 | template_nested1 = ''' |
| 173 | heat_template_version: 2016-04-08 |
| 174 | resources: |
| 175 | nested2: |
| 176 | type: nested2.yaml |
| 177 | ''' |
| 178 | |
| 179 | template_nested2 = ''' |
| 180 | heat_template_version: 2016-04-08 |
| 181 | resources: |
| 182 | random: |
| 183 | type: OS::Heat::RandomString |
| 184 | ''' |
| 185 | |
| 186 | template_nested2_2 = ''' |
| 187 | heat_template_version: 2016-04-08 |
| 188 | resources: |
| 189 | random: |
| 190 | type: OS::Heat::RandomString |
| 191 | random2: |
| 192 | type: OS::Heat::RandomString |
| 193 | ''' |
| 194 | |
| 195 | def _get_by_resource_name(self, changes, name, action): |
| 196 | filtered_l = [x for x in changes[action] |
| 197 | if x['resource_name'] == name] |
| 198 | self.assertEqual(1, len(filtered_l)) |
| 199 | return filtered_l[0] |
| 200 | |
| 201 | def test_nested_resources_nochange(self): |
| 202 | files = {'nested1.yaml': self.template_nested1, |
| 203 | 'nested2.yaml': self.template_nested2} |
| 204 | self.stack_identifier = self.stack_create( |
| 205 | template=self.template_nested_parent, files=files) |
| 206 | result = self.preview_update_stack( |
| 207 | self.stack_identifier, |
| 208 | template=self.template_nested_parent, |
| 209 | files=files, show_nested=True) |
| 210 | changes = result['resource_changes'] |
| 211 | |
| 212 | # The nested random resource should be unchanged, but we always |
| 213 | # update nested stacks even when there are no changes |
| 214 | self.assertEqual(1, len(changes['unchanged'])) |
| 215 | self.assertEqual('random', changes['unchanged'][0]['resource_name']) |
| 216 | self.assertEqual('nested2', changes['unchanged'][0]['parent_resource']) |
| 217 | |
| 218 | self.assertEqual(2, len(changes['updated'])) |
| 219 | u_nested1 = self._get_by_resource_name(changes, 'nested1', 'updated') |
| 220 | self.assertNotIn('parent_resource', u_nested1) |
| 221 | u_nested2 = self._get_by_resource_name(changes, 'nested2', 'updated') |
| 222 | self.assertEqual('nested1', u_nested2['parent_resource']) |
| 223 | |
| 224 | self.assert_empty_sections(changes, ['replaced', 'deleted', 'added']) |
| 225 | |
| 226 | def test_nested_resources_add(self): |
| 227 | files = {'nested1.yaml': self.template_nested1, |
| 228 | 'nested2.yaml': self.template_nested2} |
| 229 | self.stack_identifier = self.stack_create( |
| 230 | template=self.template_nested_parent, files=files) |
| 231 | files['nested2.yaml'] = self.template_nested2_2 |
| 232 | result = self.preview_update_stack( |
| 233 | self.stack_identifier, |
| 234 | template=self.template_nested_parent, |
| 235 | files=files, show_nested=True) |
| 236 | changes = result['resource_changes'] |
| 237 | |
| 238 | # The nested random resource should be unchanged, but we always |
| 239 | # update nested stacks even when there are no changes |
| 240 | self.assertEqual(1, len(changes['unchanged'])) |
| 241 | self.assertEqual('random', changes['unchanged'][0]['resource_name']) |
| 242 | self.assertEqual('nested2', changes['unchanged'][0]['parent_resource']) |
| 243 | |
| 244 | self.assertEqual(1, len(changes['added'])) |
| 245 | self.assertEqual('random2', changes['added'][0]['resource_name']) |
| 246 | self.assertEqual('nested2', changes['added'][0]['parent_resource']) |
| 247 | |
| 248 | self.assert_empty_sections(changes, ['replaced', 'deleted']) |
| 249 | |
| 250 | def test_nested_resources_delete(self): |
| 251 | files = {'nested1.yaml': self.template_nested1, |
| 252 | 'nested2.yaml': self.template_nested2_2} |
| 253 | self.stack_identifier = self.stack_create( |
| 254 | template=self.template_nested_parent, files=files) |
| 255 | files['nested2.yaml'] = self.template_nested2 |
| 256 | result = self.preview_update_stack( |
| 257 | self.stack_identifier, |
| 258 | template=self.template_nested_parent, |
| 259 | files=files, show_nested=True) |
| 260 | changes = result['resource_changes'] |
| 261 | |
| 262 | # The nested random resource should be unchanged, but we always |
| 263 | # update nested stacks even when there are no changes |
| 264 | self.assertEqual(1, len(changes['unchanged'])) |
| 265 | self.assertEqual('random', changes['unchanged'][0]['resource_name']) |
| 266 | self.assertEqual('nested2', changes['unchanged'][0]['parent_resource']) |
| 267 | |
| 268 | self.assertEqual(1, len(changes['deleted'])) |
| 269 | self.assertEqual('random2', changes['deleted'][0]['resource_name']) |
| 270 | self.assertEqual('nested2', changes['deleted'][0]['parent_resource']) |
| 271 | |
| 272 | self.assert_empty_sections(changes, ['replaced', 'added']) |
| 273 | |
| 274 | def test_nested_resources_replace(self): |
| 275 | files = {'nested1.yaml': self.template_nested1, |
| 276 | 'nested2.yaml': self.template_nested2} |
| 277 | self.stack_identifier = self.stack_create( |
| 278 | template=self.template_nested_parent, files=files) |
| 279 | parent_none = self.template_nested_parent.replace( |
| 280 | 'nested1.yaml', 'OS::Heat::None') |
| 281 | result = self.preview_update_stack( |
| 282 | self.stack_identifier, |
| 283 | template=parent_none, |
| 284 | show_nested=True) |
| 285 | changes = result['resource_changes'] |
| 286 | |
| 287 | # The nested random resource should be unchanged, but we always |
| 288 | # update nested stacks even when there are no changes |
| 289 | self.assertEqual(1, len(changes['replaced'])) |
| 290 | self.assertEqual('nested1', changes['replaced'][0]['resource_name']) |
| 291 | |
| 292 | self.assertEqual(2, len(changes['deleted'])) |
| 293 | d_random = self._get_by_resource_name(changes, 'random', 'deleted') |
| 294 | self.assertEqual('nested2', d_random['parent_resource']) |
| 295 | d_nested2 = self._get_by_resource_name(changes, 'nested2', 'deleted') |
| 296 | self.assertEqual('nested1', d_nested2['parent_resource']) |
| 297 | |
| 298 | self.assert_empty_sections(changes, ['updated', 'unchanged', 'added']) |