Browse Source

Merge "Adds flavor profile API tests"

Zuul 2 months ago
parent
commit
40ef58e9aa

+ 10
- 0
octavia_tempest_plugin/common/constants.py View File

@@ -28,6 +28,7 @@ OPERATING_STATUS = 'operating_status'
28 28
 POOLS = 'pools'
29 29
 PROJECT_ID = 'project_id'
30 30
 PROVIDER = 'provider'
31
+PROVIDER_NAME = 'provider_name'
31 32
 PROVISIONING_STATUS = 'provisioning_status'
32 33
 REQUEST_ERRORS = 'request_errors'
33 34
 TOTAL_CONNECTIONS = 'total_connections'
@@ -77,6 +78,8 @@ HTTP_METHOD = 'http_method'
77 78
 URL_PATH = 'url_path'
78 79
 EXPECTED_CODES = 'expected_codes'
79 80
 
81
+FLAVOR_DATA = 'flavor_data'
82
+
80 83
 # Other constants
81 84
 ACTIVE = 'ACTIVE'
82 85
 ADMIN_STATE_UP_TRUE = 'true'
@@ -89,6 +92,8 @@ ONLINE = 'ONLINE'
89 92
 NO_MONITOR = 'NO_MONITOR'
90 93
 ERROR = 'ERROR'
91 94
 SORT = 'sort'
95
+SINGLE = 'SINGLE'
96
+ACTIVE_STANDBY = 'ACTIVE_STANDBY'
92 97
 
93 98
 # Protocols
94 99
 HTTP = 'HTTP'
@@ -185,6 +190,9 @@ AMPHORA_STATUSES = (
185 190
     STATUS_PENDING_DELETE, STATUS_DELETED, STATUS_ERROR
186 191
 )
187 192
 
193
+# Flavor capabilities
194
+LOADBALANCER_TOPOLOGY = 'loadbalancer_topology'
195
+
188 196
 # API valid fields
189 197
 SHOW_LOAD_BALANCER_RESPONSE_FIELDS = (
190 198
     ADMIN_STATE_UP, CREATED_AT, DESCRIPTION, FLAVOR_ID, ID, LISTENERS, NAME,
@@ -232,3 +240,5 @@ SHOW_AMPHORA_RESPONSE_FIELDS = [
232 240
     VRRP_PORT_ID, HA_PORT_ID, CERT_EXPIRATION, CERT_BUSY, ROLE, STATUS,
233 241
     VRRP_INTERFACE, VRRP_ID, VRRP_PRIORITY, CACHED_ZONE
234 242
 ]
243
+
244
+SHOW_FLAVOR_PROFILE_FIELDS = [ID, NAME, PROVIDER_NAME, FLAVOR_DATA]

+ 45
- 0
octavia_tempest_plugin/services/load_balancer/v2/flavor_profile_client.py View File

@@ -13,8 +13,12 @@
13 13
 #   under the License.
14 14
 #
15 15
 
16
+from oslo_log import log as logging
17
+from tempest.lib import exceptions
18
+
16 19
 from octavia_tempest_plugin.services.load_balancer.v2 import base_client
17 20
 
21
+LOG = logging.getLogger(__name__)
18 22
 Unset = base_client.Unset
19 23
 
20 24
 
@@ -216,3 +220,44 @@ class FlavorProfileClient(base_client.BaseLBaaSClient):
216 220
         """
217 221
         return self._delete_obj(obj_id=flavorprofile_id,
218 222
                                 ignore_errors=ignore_errors)
223
+
224
+    def cleanup_flavor_profile(self, flavorprofile_id):
225
+        """Delete a flavor profile for tempest cleanup.
226
+
227
+           We cannot use the cleanup_flavorprofile method as flavor profiles
228
+           do not have a provisioning_status.
229
+
230
+        :param flavorprofile_id: The flavor profile ID to delete.
231
+        :raises AssertionError: if the expected_code isn't a valid http success
232
+                                response code
233
+        :raises BadRequest: If a 400 response code is received
234
+        :raises Conflict: If a 409 response code is received
235
+        :raises Forbidden: If a 403 response code is received
236
+        :raises Gone: If a 410 response code is received
237
+        :raises InvalidContentType: If a 415 response code is received
238
+        :raises InvalidHTTPResponseBody: The response body wasn't valid JSON
239
+        :raises InvalidHttpSuccessCode: if the read code isn't an expected
240
+                                        http success code
241
+        :raises NotImplemented: If a 501 response code is received
242
+        :raises OverLimit: If a 413 response code is received and over_limit is
243
+                           not in the response body
244
+        :raises RateLimitExceeded: If a 413 response code is received and
245
+                                   over_limit is in the response body
246
+        :raises ServerFault: If a 500 response code is received
247
+        :raises Unauthorized: If a 401 response code is received
248
+        :raises UnexpectedContentType: If the content-type of the response
249
+                                       isn't an expect type
250
+        :raises UnexpectedResponseCode: If a response code above 400 is
251
+                                        received and it doesn't fall into any
252
+                                        of the handled checks
253
+        :raises UnprocessableEntity: If a 422 response code is received and
254
+                                     couldn't be parsed
255
+        :returns: None if ignore_errors is True, the response status code
256
+                  if not.
257
+        """
258
+        try:
259
+            self._delete_obj(obj_id=flavorprofile_id)
260
+        except exceptions.NotFound:
261
+            # Already gone, cleanup complete
262
+            LOG.info("Flavor profile %s is already gone. "
263
+                     "Cleanup considered complete.", flavorprofile_id)

+ 435
- 0
octavia_tempest_plugin/tests/api/v2/test_flavor_profile.py View File

@@ -0,0 +1,435 @@
1
+#    Copyright 2019 Rackspace US Inc.  All rights reserved.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+
15
+import copy
16
+from operator import itemgetter
17
+from uuid import UUID
18
+
19
+from oslo_serialization import jsonutils
20
+from tempest import config
21
+from tempest.lib.common.utils import data_utils
22
+from tempest.lib import decorators
23
+from tempest.lib import exceptions
24
+
25
+from octavia_tempest_plugin.common import constants as const
26
+from octavia_tempest_plugin.tests import test_base
27
+
28
+CONF = config.CONF
29
+
30
+
31
+class FlavorProfileAPITest(test_base.LoadBalancerBaseTest):
32
+    """Test the flavor profile object API."""
33
+
34
+    @decorators.idempotent_id('d0e3a08e-d58a-4460-83ed-34307ca04cde')
35
+    def test_flavor_profile_create(self):
36
+        """Tests flavor profile create and basic show APIs.
37
+
38
+        * Tests that users without the loadbalancer admin role cannot
39
+          create flavor profiles.
40
+        * Create a fully populated flavor profile.
41
+        * Validate the response reflects the requested values.
42
+        """
43
+        # We have to do this here as the api_version and clients are not
44
+        # setup in time to use a decorator or the skip_checks mixin
45
+        if not self.lb_admin_flavor_profile_client.is_version_supported(
46
+                self.api_version, '2.6'):
47
+            raise self.skipException('Flavor profiles are only available on '
48
+                                     'Octavia API version 2.6 or newer.')
49
+
50
+        flavor_profile_name = data_utils.rand_name(
51
+            "lb_admin_flavorprofile1-create")
52
+        flavor_data = {const.LOADBALANCER_TOPOLOGY: const.SINGLE}
53
+        flavor_data_json = jsonutils.dumps(flavor_data)
54
+
55
+        flavor_profile_kwargs = {
56
+            const.NAME: flavor_profile_name,
57
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
58
+            const.FLAVOR_DATA: flavor_data_json
59
+        }
60
+
61
+        # Test that a user without the load balancer admin role cannot
62
+        # create a flavor profile
63
+        if CONF.load_balancer.RBAC_test_type == const.ADVANCED:
64
+            self.assertRaises(
65
+                exceptions.Forbidden,
66
+                self.os_primary.flavor_profile_client.create_flavor_profile,
67
+                **flavor_profile_kwargs)
68
+
69
+        # Happy path
70
+        flavor_profile = (
71
+            self.lb_admin_flavor_profile_client.create_flavor_profile(
72
+                **flavor_profile_kwargs))
73
+        self.addCleanup(
74
+            self.lb_admin_flavor_profile_client.cleanup_flavor_profile,
75
+            flavor_profile[const.ID])
76
+
77
+        UUID(flavor_profile[const.ID])
78
+        self.assertEqual(flavor_profile_name, flavor_profile[const.NAME])
79
+        self.assertEqual(CONF.load_balancer.provider,
80
+                         flavor_profile[const.PROVIDER_NAME])
81
+        self.assertEqual(flavor_data_json, flavor_profile[const.FLAVOR_DATA])
82
+
83
+    @decorators.idempotent_id('c4e17fdf-849a-4132-93ae-dfca21ce4444')
84
+    def test_flavor_profile_list(self):
85
+        """Tests flavor profile list API and field filtering.
86
+
87
+        * Create three flavor profiles.
88
+        * Validates that non-admin accounts cannot list the flavor profiles.
89
+        * List the flavor profiles using the default sort order.
90
+        * List the flavor profiles using descending sort order.
91
+        * List the flavor profiles using ascending sort order.
92
+        * List the flavor profiles returning one field at a time.
93
+        * List the flavor profiles returning two fields.
94
+        * List the flavor profiles filtering to one of the three.
95
+        * List the flavor profiles filtered, one field, and sorted.
96
+        """
97
+        # We have to do this here as the api_version and clients are not
98
+        # setup in time to use a decorator or the skip_checks mixin
99
+        if not self.lb_admin_flavor_profile_client.is_version_supported(
100
+                self.api_version, '2.6'):
101
+            raise self.skipException('Flavor profiles are only available on '
102
+                                     'Octavia API version 2.6 or newer.')
103
+
104
+        # Create flavor profile 1
105
+        flavor_profile1_name = data_utils.rand_name(
106
+            "lb_admin_flavorprofile-list-1")
107
+        flavor_data1 = {const.LOADBALANCER_TOPOLOGY: const.SINGLE}
108
+        flavor_data1_json = jsonutils.dumps(flavor_data1)
109
+
110
+        flavor_profile1_kwargs = {
111
+            const.NAME: flavor_profile1_name,
112
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
113
+            const.FLAVOR_DATA: flavor_data1_json
114
+        }
115
+        flavor_profile1 = (
116
+            self.lb_admin_flavor_profile_client.create_flavor_profile(
117
+                **flavor_profile1_kwargs))
118
+        self.addCleanup(
119
+            self.lb_admin_flavor_profile_client.cleanup_flavor_profile,
120
+            flavor_profile1[const.ID])
121
+
122
+        # Create flavor profile 2
123
+        flavor_profile2_name = data_utils.rand_name(
124
+            "lb_admin_flavorprofile-list-2")
125
+        flavor_data2 = {const.LOADBALANCER_TOPOLOGY: const.ACTIVE_STANDBY}
126
+        flavor_data2_json = jsonutils.dumps(flavor_data2)
127
+
128
+        flavor_profile2_kwargs = {
129
+            const.NAME: flavor_profile2_name,
130
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
131
+            const.FLAVOR_DATA: flavor_data2_json
132
+        }
133
+        flavor_profile2 = (
134
+            self.lb_admin_flavor_profile_client.create_flavor_profile(
135
+                **flavor_profile2_kwargs))
136
+        self.addCleanup(
137
+            self.lb_admin_flavor_profile_client.cleanup_flavor_profile,
138
+            flavor_profile2[const.ID])
139
+
140
+        # Create flavor profile 3
141
+        flavor_profile3_name = data_utils.rand_name(
142
+            "lb_admin_flavorprofile-list-3")
143
+        flavor_data3 = {const.LOADBALANCER_TOPOLOGY: const.SINGLE}
144
+        flavor_data3_json = jsonutils.dumps(flavor_data3)
145
+
146
+        flavor_profile3_kwargs = {
147
+            const.NAME: flavor_profile3_name,
148
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
149
+            const.FLAVOR_DATA: flavor_data3_json
150
+        }
151
+        flavor_profile3 = (
152
+            self.lb_admin_flavor_profile_client.create_flavor_profile(
153
+                **flavor_profile3_kwargs))
154
+        self.addCleanup(
155
+            self.lb_admin_flavor_profile_client.cleanup_flavor_profile,
156
+            flavor_profile3[const.ID])
157
+
158
+        # default sort order (by ID) reference list
159
+        ref_id_list_asc = [flavor_profile1[const.ID],
160
+                           flavor_profile2[const.ID],
161
+                           flavor_profile3[const.ID]]
162
+        ref_id_list_dsc = copy.deepcopy(ref_id_list_asc)
163
+        ref_id_list_asc.sort()
164
+        ref_id_list_dsc.sort(reverse=True)
165
+
166
+        # Test that a user without the load balancer admin role cannot
167
+        # list flavor profiles.
168
+        if CONF.load_balancer.RBAC_test_type == const.ADVANCED:
169
+            self.assertRaises(
170
+                exceptions.Forbidden,
171
+                self.os_primary.flavor_profile_client.list_flavor_profiles)
172
+
173
+        # Check the default sort order (by ID)
174
+        profiles = self.lb_admin_flavor_profile_client.list_flavor_profiles()
175
+        # Remove flavor profiles not used in this test
176
+        profiles = [prof for prof in profiles
177
+                    if 'lb_admin_flavorprofile-list' in prof[const.NAME]]
178
+        self.assertEqual(3, len(profiles))
179
+        self.assertEqual(ref_id_list_asc[0], profiles[0][const.ID])
180
+        self.assertEqual(ref_id_list_asc[1], profiles[1][const.ID])
181
+        self.assertEqual(ref_id_list_asc[2], profiles[2][const.ID])
182
+
183
+        # Check the descending sort order by name
184
+        profiles = self.lb_admin_flavor_profile_client.list_flavor_profiles(
185
+            query_params='{sort}={name}:{order}'.format(
186
+                sort=const.SORT, name=const.NAME, order=const.DESC))
187
+        # Remove flavor profiles not used in this test
188
+        profiles = [prof for prof in profiles
189
+                    if 'lb_admin_flavorprofile-list' in prof[const.NAME]]
190
+        self.assertEqual(3, len(profiles))
191
+        self.assertEqual(flavor_profile3_name, profiles[0][const.NAME])
192
+        self.assertEqual(flavor_profile2_name, profiles[1][const.NAME])
193
+        self.assertEqual(flavor_profile1_name, profiles[2][const.NAME])
194
+
195
+        # Check the ascending sort order by name
196
+        profiles = self.lb_admin_flavor_profile_client.list_flavor_profiles(
197
+            query_params='{sort}={name}:{order}'.format(
198
+                sort=const.SORT, name=const.NAME, order=const.ASC))
199
+        # Remove flavor profiles not used in this test
200
+        profiles = [prof for prof in profiles
201
+                    if 'lb_admin_flavorprofile-list' in prof[const.NAME]]
202
+        self.assertEqual(3, len(profiles))
203
+        self.assertEqual(flavor_profile1_name, profiles[0][const.NAME])
204
+        self.assertEqual(flavor_profile2_name, profiles[1][const.NAME])
205
+        self.assertEqual(flavor_profile3_name, profiles[2][const.NAME])
206
+
207
+        ref_profiles = [flavor_profile1, flavor_profile2, flavor_profile3]
208
+        sorted_profiles = sorted(ref_profiles, key=itemgetter(const.ID))
209
+
210
+        # Test fields
211
+        flavor_profile_client = self.lb_admin_flavor_profile_client
212
+        for field in const.SHOW_FLAVOR_PROFILE_FIELDS:
213
+            profiles = flavor_profile_client.list_flavor_profiles(
214
+                query_params='{fields}={field}&{fields}={name}'.format(
215
+                    fields=const.FIELDS, field=field, name=const.NAME))
216
+            # Remove flavor profiles not used in this test
217
+            profiles = [prof for prof in profiles
218
+                        if 'lb_admin_flavorprofile-list' in prof[const.NAME]]
219
+
220
+            self.assertEqual(3, len(profiles))
221
+            self.assertEqual(sorted_profiles[0][field], profiles[0][field])
222
+            self.assertEqual(sorted_profiles[1][field], profiles[1][field])
223
+            self.assertEqual(sorted_profiles[2][field], profiles[2][field])
224
+
225
+        # Test filtering
226
+        profile = self.lb_admin_flavor_profile_client.list_flavor_profiles(
227
+            query_params='{name}={prof_name}'.format(
228
+                name=const.NAME,
229
+                prof_name=flavor_profile2[const.NAME]))
230
+        self.assertEqual(1, len(profile))
231
+        self.assertEqual(flavor_profile2[const.ID], profile[0][const.ID])
232
+
233
+        # Test combined params
234
+        profiles = self.lb_admin_flavor_profile_client.list_flavor_profiles(
235
+            query_params='{provider_name}={provider}&{fields}={name}&'
236
+                         '{sort}={ID}:{desc}'.format(
237
+                             provider_name=const.PROVIDER_NAME,
238
+                             provider=CONF.load_balancer.provider,
239
+                             fields=const.FIELDS, name=const.NAME,
240
+                             sort=const.SORT, ID=const.ID,
241
+                             desc=const.DESC))
242
+        # Remove flavor profiles not used in this test
243
+        profiles = [prof for prof in profiles
244
+                    if 'lb_admin_flavorprofile-list' in prof[const.NAME]]
245
+        self.assertEqual(3, len(profiles))
246
+        self.assertEqual(1, len(profiles[0]))
247
+        self.assertEqual(sorted_profiles[2][const.NAME],
248
+                         profiles[0][const.NAME])
249
+        self.assertEqual(sorted_profiles[1][const.NAME],
250
+                         profiles[1][const.NAME])
251
+        self.assertEqual(sorted_profiles[0][const.NAME],
252
+                         profiles[2][const.NAME])
253
+
254
+    @decorators.idempotent_id('a2c2ff9a-fce1-42fd-8cfd-56dea31610f6')
255
+    def test_flavor_profile_show(self):
256
+        """Tests flavor profile show API.
257
+
258
+        * Create a fully populated flavor profile.
259
+        * Show flavor profile details.
260
+        * Validate the show reflects the requested values.
261
+        * Validates that non-lb-admin accounts cannot see the flavor profile.
262
+        """
263
+        # We have to do this here as the api_version and clients are not
264
+        # setup in time to use a decorator or the skip_checks mixin
265
+        if not self.lb_admin_flavor_profile_client.is_version_supported(
266
+                self.api_version, '2.6'):
267
+            raise self.skipException('Flavor profiles are only available on '
268
+                                     'Octavia API version 2.6 or newer.')
269
+
270
+        flavor_profile_name = data_utils.rand_name(
271
+            "lb_admin_flavorprofile1-show")
272
+        flavor_data = {const.LOADBALANCER_TOPOLOGY: const.ACTIVE_STANDBY}
273
+        flavor_data_json = jsonutils.dumps(flavor_data)
274
+
275
+        flavor_profile_kwargs = {
276
+            const.NAME: flavor_profile_name,
277
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
278
+            const.FLAVOR_DATA: flavor_data_json
279
+        }
280
+
281
+        flavor_profile = (
282
+            self.lb_admin_flavor_profile_client.create_flavor_profile(
283
+                **flavor_profile_kwargs))
284
+        self.addCleanup(
285
+            self.lb_admin_flavor_profile_client.cleanup_flavor_profile,
286
+            flavor_profile[const.ID])
287
+
288
+        # Test that a user without the load balancer admin role cannot
289
+        # show a flavor profile
290
+        if CONF.load_balancer.RBAC_test_type == const.ADVANCED:
291
+            self.assertRaises(
292
+                exceptions.Forbidden,
293
+                self.os_primary.flavor_profile_client.show_flavor_profile,
294
+                flavor_profile[const.ID])
295
+
296
+        result = (
297
+            self.lb_admin_flavor_profile_client.show_flavor_profile(
298
+                flavor_profile[const.ID]))
299
+
300
+        self.assertEqual(flavor_profile_name, result[const.NAME])
301
+        self.assertEqual(CONF.load_balancer.provider,
302
+                         result[const.PROVIDER_NAME])
303
+        self.assertEqual(flavor_data_json, result[const.FLAVOR_DATA])
304
+
305
+    @decorators.idempotent_id('32a2e285-8dfc-485f-a450-a4d450d3c3ec')
306
+    def test_flavor_profile_update(self):
307
+        """Tests flavor profile update API.
308
+
309
+        * Create a fully populated flavor profile.
310
+        * Show flavor profile details.
311
+        * Validate the show reflects the initial values.
312
+        * Validates that non-admin accounts cannot update the flavor profile.
313
+        * Update the flavor profile details.
314
+        * Show flavor profile details.
315
+        * Validate the show reflects the updated values.
316
+        """
317
+
318
+        # We have to do this here as the api_version and clients are not
319
+        # setup in time to use a decorator or the skip_checks mixin
320
+        if not self.lb_admin_flavor_profile_client.is_version_supported(
321
+                self.api_version, '2.6'):
322
+            raise self.skipException('Flavor profiles are only available on '
323
+                                     'Octavia API version 2.6 or newer.')
324
+
325
+        flavor_profile_name = data_utils.rand_name(
326
+            "lb_admin_flavorprofile1-update")
327
+        flavor_data = {const.LOADBALANCER_TOPOLOGY: const.SINGLE}
328
+        flavor_data_json = jsonutils.dumps(flavor_data)
329
+
330
+        flavor_profile_kwargs = {
331
+            const.NAME: flavor_profile_name,
332
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
333
+            const.FLAVOR_DATA: flavor_data_json
334
+        }
335
+
336
+        flavor_profile = (
337
+            self.lb_admin_flavor_profile_client.create_flavor_profile(
338
+                **flavor_profile_kwargs))
339
+        self.addCleanup(
340
+            self.lb_admin_flavor_profile_client.cleanup_flavor_profile,
341
+            flavor_profile[const.ID])
342
+
343
+        self.assertEqual(flavor_profile_name, flavor_profile[const.NAME])
344
+        self.assertEqual(CONF.load_balancer.provider,
345
+                         flavor_profile[const.PROVIDER_NAME])
346
+        self.assertEqual(flavor_data_json, flavor_profile[const.FLAVOR_DATA])
347
+
348
+        flavor_profile_name2 = data_utils.rand_name(
349
+            "lb_admin_flavorprofile1-update2")
350
+        flavor_data2 = {const.LOADBALANCER_TOPOLOGY: const.ACTIVE_STANDBY}
351
+        flavor_data2_json = jsonutils.dumps(flavor_data2)
352
+
353
+        # TODO(johnsom) Figure out a reliable second provider
354
+        flavor_profile_updated_kwargs = {
355
+            const.NAME: flavor_profile_name2,
356
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
357
+            const.FLAVOR_DATA: flavor_data2_json
358
+        }
359
+
360
+        # Test that a user without the load balancer admin role cannot
361
+        # create a flavor profile
362
+        if CONF.load_balancer.RBAC_test_type == const.ADVANCED:
363
+            self.assertRaises(
364
+                exceptions.Forbidden,
365
+                self.os_primary.flavor_profile_client.update_flavor_profile,
366
+                flavor_profile[const.ID], **flavor_profile_updated_kwargs)
367
+
368
+        result = self.lb_admin_flavor_profile_client.update_flavor_profile(
369
+            flavor_profile[const.ID], **flavor_profile_updated_kwargs)
370
+
371
+        self.assertEqual(flavor_profile_name2, result[const.NAME])
372
+        self.assertEqual(CONF.load_balancer.provider,
373
+                         result[const.PROVIDER_NAME])
374
+        self.assertEqual(flavor_data2_json, result[const.FLAVOR_DATA])
375
+
376
+        # Check that a show reflects the new values
377
+        get_result = (
378
+            self.lb_admin_flavor_profile_client.show_flavor_profile(
379
+                flavor_profile[const.ID]))
380
+
381
+        self.assertEqual(flavor_profile_name2, get_result[const.NAME])
382
+        self.assertEqual(CONF.load_balancer.provider,
383
+                         get_result[const.PROVIDER_NAME])
384
+        self.assertEqual(flavor_data2_json, get_result[const.FLAVOR_DATA])
385
+
386
+    @decorators.idempotent_id('4c2eaacf-c2c8-422a-b7dc-a30ceba6bcd4')
387
+    def test_flavor_profile_delete(self):
388
+        """Tests flavor profile create and delete APIs.
389
+
390
+        * Creates a flavor profile.
391
+        * Validates that other accounts cannot delete the flavor profile.
392
+        * Deletes the flavor profile.
393
+        * Validates the flavor profile is in the DELETED state.
394
+        """
395
+        # We have to do this here as the api_version and clients are not
396
+        # setup in time to use a decorator or the skip_checks mixin
397
+        if not self.lb_admin_flavor_profile_client.is_version_supported(
398
+                self.api_version, '2.6'):
399
+            raise self.skipException('Flavor profiles are only available on '
400
+                                     'Octavia API version 2.6 or newer.')
401
+
402
+        flavor_profile_name = data_utils.rand_name(
403
+            "lb_admin_flavorprofile1-delete")
404
+        flavor_data = {const.LOADBALANCER_TOPOLOGY: const.SINGLE}
405
+        flavor_data_json = jsonutils.dumps(flavor_data)
406
+
407
+        flavor_profile_kwargs = {
408
+            const.NAME: flavor_profile_name,
409
+            const.PROVIDER_NAME: CONF.load_balancer.provider,
410
+            const.FLAVOR_DATA: flavor_data_json
411
+        }
412
+
413
+        flavor_profile = (
414
+            self.lb_admin_flavor_profile_client.create_flavor_profile(
415
+                **flavor_profile_kwargs))
416
+        self.addCleanup(
417
+            self.lb_admin_flavor_profile_client.cleanup_flavor_profile,
418
+            flavor_profile[const.ID])
419
+
420
+        # Test that a user without the load balancer admin role cannot
421
+        # delete a flavor profile
422
+        if CONF.load_balancer.RBAC_test_type == const.ADVANCED:
423
+            self.assertRaises(
424
+                exceptions.Forbidden,
425
+                self.os_primary.flavor_profile_client.delete_flavor_profile,
426
+                flavor_profile[const.ID])
427
+
428
+        # Happy path
429
+        self.lb_admin_flavor_profile_client.delete_flavor_profile(
430
+            flavor_profile[const.ID])
431
+
432
+        self.assertRaises(
433
+            exceptions.NotFound,
434
+            self.lb_admin_flavor_profile_client.show_flavor_profile,
435
+            flavor_profile[const.ID])

+ 2
- 0
octavia_tempest_plugin/tests/test_base.py View File

@@ -122,6 +122,8 @@ class LoadBalancerBaseTest(test.BaseTestCase):
122 122
         cls.mem_l7policy_client = cls.os_roles_lb_member.l7policy_client
123 123
         cls.mem_l7rule_client = cls.os_roles_lb_member.l7rule_client
124 124
         cls.mem_amphora_client = cls.os_roles_lb_member.amphora_client
125
+        cls.lb_admin_flavor_profile_client = (
126
+            cls.os_roles_lb_admin.flavor_profile_client)
125 127
 
126 128
     @classmethod
127 129
     def resource_setup(cls):

Loading…
Cancel
Save