Merge "Add reno for Tempest v15.0.0"
diff --git a/releasenotes/notes/add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml b/releasenotes/notes/add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml
new file mode 100644
index 0000000..67f9541
--- /dev/null
+++ b/releasenotes/notes/add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add the list security groups by server API to the servers_client
+ library. This feature enables the possibility to list security
+ groups for a server instance.
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 0a9db46..c3c88a5 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -101,7 +101,7 @@
# check some extensions for the flavor create/show/detail response
self.assertEqual(flavor['swap'], '')
self.assertEqual(int(flavor['rxtx_factor']), 1)
- self.assertEqual(int(flavor['OS-FLV-EXT-DATA:ephemeral']), 0)
+ self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'], 0)
self.assertEqual(flavor['os-flavor-access:is_public'], True)
flavor_name = data_utils.rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 39797f7..3ffd238 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -45,7 +45,6 @@
def setup_clients(cls):
super(LiveBlockMigrationTestJSON, cls).setup_clients()
cls.admin_hosts_client = cls.os_adm.hosts_client
- cls.admin_servers_client = cls.os_adm.servers_client
cls.admin_migration_client = cls.os_adm.migrations_client
@classmethod
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index 21f5c68..aa75348 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -31,7 +31,6 @@
super(MigrationsAdminTest, cls).setup_clients()
cls.client = cls.os_adm.migrations_client
cls.flavors_admin_client = cls.os_adm.flavors_client
- cls.admin_servers_client = cls.os_adm.servers_client
@decorators.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f')
def test_list_migrations(self):
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index b53ced9..5220c97 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -66,7 +66,7 @@
flavor_id = self._get_unused_flavor_id()
quota_set = self.quotas_client.show_quota_set(
self.tenant_id)['quota_set']
- ram = int(quota_set['ram'])
+ ram = quota_set['ram']
if ram == -1:
raise self.skipException("ram quota set is -1,"
" cannot test overlimit")
@@ -94,7 +94,7 @@
flavor_id = self._get_unused_flavor_id()
quota_set = self.quotas_client.show_quota_set(
self.tenant_id)['quota_set']
- vcpus = int(quota_set['cores'])
+ vcpus = quota_set['cores']
if vcpus == -1:
raise self.skipException("cores quota set is -1,"
" cannot test overlimit")
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index 5f2444a..e4f4846 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -38,12 +38,6 @@
if not CONF.compute_feature_enabled.swap_volume:
raise cls.skipException("Swapping volumes is not supported.")
- @classmethod
- def setup_clients(cls):
- super(TestVolumeSwap, cls).setup_clients()
- # We need the admin client for performing the update (swap) volume call
- cls.servers_admin_client = cls.os_adm.servers_client
-
@decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813')
@test.services('volume')
def test_volume_swap(self):
@@ -58,7 +52,7 @@
# Attach "volume1" to server
self.attach_volume(server, volume1)
# Swap volume from "volume1" to "volume2"
- self.servers_admin_client.update_attached_volume(
+ self.admin_servers_client.update_attached_volume(
server['id'], volume1['id'], volumeId=volume2['id'])
waiters.wait_for_volume_status(self.volumes_client,
volume1['id'], 'available')
diff --git a/tempest/api/compute/admin/test_volumes_negative.py b/tempest/api/compute/admin/test_volumes_negative.py
index 1f85c18..ecb9092 100644
--- a/tempest/api/compute/admin/test_volumes_negative.py
+++ b/tempest/api/compute/admin/test_volumes_negative.py
@@ -32,11 +32,6 @@
raise cls.skipException(skip_msg)
@classmethod
- def setup_clients(cls):
- super(VolumesAdminNegativeTest, cls).setup_clients()
- cls.servers_admin_client = cls.os_adm.servers_client
-
- @classmethod
def resource_setup(cls):
super(VolumesAdminNegativeTest, cls).resource_setup()
cls.server = cls.create_test_server(wait_until='ACTIVE')
@@ -46,7 +41,7 @@
volume = self.create_volume()
nonexistent_volume = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
- self.servers_admin_client.update_attached_volume,
+ self.admin_servers_client.update_attached_volume,
self.server['id'], nonexistent_volume,
volumeId=volume['id'])
@@ -58,6 +53,6 @@
nonexistent_volume = data_utils.rand_uuid()
self.assertRaises(lib_exc.BadRequest,
- self.servers_admin_client.update_attached_volume,
+ self.admin_servers_client.update_attached_volume,
self.server['id'], volume['id'],
volumeId=nonexistent_volume)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index c636894..df03b97 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -468,6 +468,7 @@
cls.availability_zone_admin_client = (
cls.os_adm.availability_zone_client)
cls.admin_flavors_client = cls.os_adm.flavors_client
+ cls.admin_servers_client = cls.os_adm.servers_client
def create_flavor(self, ram, vcpus, disk, name=None,
is_public='True', **kwargs):
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index b9ae0c6..21b4b1c 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -41,11 +41,11 @@
max_meta = limits['absolute']['maxImageMeta']
# No point in running this test if there is no limit.
- if int(max_meta) == -1:
+ if max_meta == -1:
raise self.skipException('no limit for maxImageMeta')
# Create server should fail, since we are passing > metadata Limit!
- max_meta_data = int(max_meta) + 1
+ max_meta_data = max_meta + 1
meta_data = {}
for xx in range(max_meta_data):
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index e070336..349bfda 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -144,3 +144,31 @@
['security_group'])
self.assertEqual(s_new_name, fetched_group['name'])
self.assertEqual(s_new_des, fetched_group['description'])
+
+ @test.idempotent_id('79517d60-535a-438f-af3d-e6feab1cbea7')
+ @test.services('network')
+ def test_list_security_groups_by_server(self):
+ # Create a couple security groups that we will use
+ # for the server resource this test creates
+ sg = self.create_security_group()
+ sg2 = self.create_security_group()
+ assigned_security_groups_ids = [sg['id'], sg2['id']]
+ # Create server and add the security group created
+ # above to the server we just created
+ server_id = self.create_test_server(wait_until='ACTIVE')['id']
+ # add security groups to server
+ self.servers_client.add_security_group(server_id, name=sg['name'])
+ self.servers_client.add_security_group(server_id, name=sg2['name'])
+
+ # list security groups for a server
+ fetched_groups = (
+ self.servers_client.list_security_groups_by_server(
+ server_id)['security_groups'])
+ fetched_security_groups_ids = [i['id'] for i in fetched_groups]
+ # verifying the security groups ids in list
+ missing_security_groups =\
+ [p for p in assigned_security_groups_ids
+ if p not in fetched_security_groups_ids]
+ self.assertEmpty(missing_security_groups,
+ "Failed to find security_groups %s in fetched list" %
+ ', '.join(missing_security_groups))
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 04fe11f..3f6abab 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -1,4 +1,4 @@
-# Copyright 2016 OpenStack Foundation
+# Copyright 2016-2017 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -26,6 +26,11 @@
CONF = config.CONF
+if six.PY2:
+ ord_func = ord
+else:
+ ord_func = int
+
class NoVNCConsoleTestJSON(base.BaseV2ComputeTest):
@@ -60,14 +65,19 @@
resp = urllib3.PoolManager().request('GET', vnc_url)
# Make sure that the GET request was accepted by the novncproxy
self.assertEqual(resp.status, 200, 'Got a Bad HTTP Response on the '
- 'initial call: ' + str(resp.status))
+ 'initial call: ' + six.text_type(resp.status))
# Do some basic validation to make sure it is an expected HTML document
- self.assertTrue('<html>' in resp.data and '</html>' in resp.data,
- 'Not a valid html document in the response.')
+ resp_data = resp.data.decode()
+ self.assertIn('<html>', resp_data,
+ 'Not a valid html document in the response.')
+ self.assertIn('</html>', resp_data,
+ 'Not a valid html document in the response.')
# Just try to make sure we got JavaScript back for noVNC, since we
# won't actually use it since not inside of a browser
- self.assertTrue('noVNC' in resp.data and '<script' in resp.data,
- 'Not a valid noVNC javascript html document.')
+ self.assertIn('noVNC', resp_data,
+ 'Not a valid noVNC javascript html document.')
+ self.assertIn('<script', resp_data,
+ 'Not a valid noVNC javascript html document.')
def _validate_rfb_negotiation(self):
"""Verify we can connect to novnc and do the websocket connection."""
@@ -82,14 +92,14 @@
int(data[8:11], base=10)))
self.assertTrue(version >= 3.3, 'Bad RFB Version: ' + str(version))
# Send our RFB version to the server, which we will just go with 3.3
- self._websocket.send_frame(str(data))
+ self._websocket.send_frame(data)
# Get the sever authentication type and make sure None is supported
data = self._websocket.receive_frame()
self.assertIsNotNone(data, 'Expected authentication type None.')
self.assertGreaterEqual(
len(data), 2, 'Expected authentication type None.')
self.assertIn(
- 1, [ord(data[i + 1]) for i in range(ord(data[0]))],
+ 1, [ord_func(data[i + 1]) for i in range(ord_func(data[0]))],
'Expected authentication type None.')
# Send to the server that we only support authentication type None
self._websocket.send_frame(six.int2byte(1))
@@ -98,7 +108,7 @@
self.assertEqual(
len(data), 4, 'Server did not think security was successful.')
self.assertEqual(
- [ord(i) for i in data], [0, 0, 0, 0],
+ [ord_func(i) for i in data], [0, 0, 0, 0],
'Server did not think security was successful.')
# Say to leave the desktop as shared as part of client initialization
self._websocket.send_frame(six.int2byte(1))
@@ -121,12 +131,12 @@
def _validate_websocket_upgrade(self):
self.assertTrue(
- self._websocket.response.startswith('HTTP/1.1 101 Switching '
- 'Protocols\r\n'),
+ self._websocket.response.startswith(b'HTTP/1.1 101 Switching '
+ b'Protocols\r\n'),
'Did not get the expected 101 on the websockify call: '
- + str(len(self._websocket.response)))
+ + six.text_type(self._websocket.response))
self.assertTrue(
- self._websocket.response.find('Server: WebSockify') > 0,
+ self._websocket.response.find(b'Server: WebSockify') > 0,
'Did not get the expected WebSocket HTTP Response.')
def _create_websocket(self, url):
@@ -187,8 +197,8 @@
# frames less than 125 bytes here (for the negotiation) and
# that only the 2nd byte contains the length, and since the
# server doesn't do masking, we can just read the data length
- if ord(header[1]) & 127 > 0:
- return self._socket.recv(ord(header[1]) & 127)
+ if ord_func(header[1]) & 127 > 0:
+ return self._socket.recv(ord_func(header[1]) & 127)
def send_frame(self, data):
"""Wrapper for sending data to add in the WebSocket frame format."""
@@ -205,7 +215,7 @@
frame_bytes.append(mask[i])
# Mask each of the actual data bytes that we are going to send
for i in range(len(data)):
- frame_bytes.append(ord(data[i]) ^ mask[i % 4])
+ frame_bytes.append(ord_func(data[i]) ^ mask[i % 4])
# Convert our integer list to a binary array of bytes
frame_bytes = struct.pack('!%iB' % len(frame_bytes), * frame_bytes)
self._socket.sendall(frame_bytes)
@@ -233,9 +243,9 @@
# We are choosing to use binary even though browser may do Base64
reqdata += 'Sec-WebSocket-Protocol: binary\r\n\r\n'
# Send the HTTP GET request and get the response back
- self._socket.sendall(reqdata)
+ self._socket.sendall(reqdata.encode('utf8'))
self.response = data = self._socket.recv(4096)
# Loop through & concatenate all of the data in the response body
- while len(data) > 0 and self.response.find('\r\n\r\n') < 0:
+ while len(data) > 0 and self.response.find(b'\r\n\r\n') < 0:
data = self._socket.recv(4096)
self.response += data
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index 957d24a..90b9da4 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -97,7 +97,7 @@
max_file_limit = limits['absolute']['maxPersonality']
if max_file_limit == -1:
raise self.skipException("No limit for personality files")
- for i in range(0, int(max_file_limit) + 1):
+ for i in range(0, max_file_limit + 1):
path = 'etc/test' + str(i) + '.txt'
personality.append({'path': path,
'contents': base64.encode_as_text(
@@ -117,7 +117,7 @@
if max_file_limit == -1:
raise self.skipException("No limit for personality files")
person = []
- for i in range(0, int(max_file_limit)):
+ for i in range(0, max_file_limit):
# NOTE(andreaf) The cirros disk image is blank before boot
# so we can only inject safely to /
path = '/test' + str(i) + '.txt'
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index 40d0746..01fd9ef 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -31,11 +31,6 @@
if not CONF.compute_feature_enabled.live_migration:
raise cls.skipException("Live migration is not enabled")
- @classmethod
- def setup_clients(cls):
- super(LiveBlockMigrationNegativeTestJSON, cls).setup_clients()
- cls.admin_servers_client = cls.os_adm.servers_client
-
def _migrate_server_to(self, server_id, dest_host):
bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration
self.admin_servers_client.live_migrate_server(
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 5a83ae3..e8222bf 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -114,7 +114,7 @@
volume_default = quota_set_default['volumes']
self.admin_quotas_client.update_quota_set(
- project_id, volumes=(int(volume_default) + 5))
+ project_id, volumes=(volume_default + 5))
self.admin_quotas_client.delete_quota_set(project_id)
quota_set_new = (self.admin_quotas_client.show_quota_set(project_id)
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index 1dce7e0..5f590bc 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -17,6 +17,7 @@
from tempest.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
+from tempest import test
class ExtraSpecsNegativeV2Test(base.BaseVolumeAdminTest):
@@ -27,6 +28,7 @@
extra_specs = {"spec1": "val1"}
cls.volume_type = cls.create_volume_type(extra_specs=extra_specs)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1')
def test_update_no_body(self):
# Should not update volume type extra specs with no body
@@ -35,6 +37,7 @@
self.admin_volume_types_client.update_volume_type_extra_specs,
self.volume_type['id'], "spec1", None)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('25e5a0ee-89b3-4c53-8310-236f76c75365')
def test_update_nonexistent_extra_spec_id(self):
# Should not update volume type extra specs with nonexistent id.
@@ -45,6 +48,7 @@
self.volume_type['id'], data_utils.rand_uuid(),
extra_spec)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('9bf7a657-b011-4aec-866d-81c496fbe5c8')
def test_update_none_extra_spec_id(self):
# Should not update volume type extra specs with none id.
@@ -54,6 +58,7 @@
self.admin_volume_types_client.update_volume_type_extra_specs,
self.volume_type['id'], None, extra_spec)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('a77dfda2-9100-448e-9076-ed1711f4bdfc')
def test_update_multiple_extra_spec(self):
# Should not update volume type extra specs with multiple specs as
@@ -65,6 +70,7 @@
self.volume_type['id'], list(extra_spec)[0],
extra_spec)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545')
def test_create_nonexistent_type_id(self):
# Should not create volume type extra spec for nonexistent volume
@@ -75,6 +81,7 @@
self.admin_volume_types_client.create_volume_type_extra_specs,
data_utils.rand_uuid(), extra_specs)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('c821bdc8-43a4-4bf4-86c8-82f3858d5f7d')
def test_create_none_body(self):
# Should not create volume type extra spec for none POST body.
@@ -83,6 +90,7 @@
self.admin_volume_types_client.create_volume_type_extra_specs,
self.volume_type['id'], None)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('bc772c71-1ed4-4716-b945-8b5ed0f15e87')
def test_create_invalid_body(self):
# Should not create volume type extra spec for invalid POST body.
@@ -91,6 +99,7 @@
self.admin_volume_types_client.create_volume_type_extra_specs,
self.volume_type['id'], extra_specs=['invalid'])
+ @test.attr(type=['negative'])
@decorators.idempotent_id('031cda8b-7d23-4246-8bf6-bbe73fd67074')
def test_delete_nonexistent_volume_type_id(self):
# Should not delete volume type extra spec for nonexistent
@@ -100,6 +109,7 @@
self.admin_volume_types_client.delete_volume_type_extra_specs,
data_utils.rand_uuid(), "spec1")
+ @test.attr(type=['negative'])
@decorators.idempotent_id('dee5cf0c-cdd6-4353-b70c-e847050d71fb')
def test_list_nonexistent_volume_type_id(self):
# Should not list volume type extra spec for nonexistent type id.
@@ -108,6 +118,7 @@
self.admin_volume_types_client.list_volume_types_extra_specs,
data_utils.rand_uuid())
+ @test.attr(type=['negative'])
@decorators.idempotent_id('9f402cbd-1838-4eb4-9554-126a6b1908c9')
def test_get_nonexistent_volume_type_id(self):
# Should not get volume type extra spec for nonexistent type id.
@@ -116,6 +127,7 @@
self.admin_volume_types_client.show_volume_type_extra_specs,
data_utils.rand_uuid(), "spec1")
+ @test.attr(type=['negative'])
@decorators.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753')
def test_get_nonexistent_extra_spec_id(self):
# Should not get volume type extra spec for nonexistent extra spec
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index 1e68848..a3d91b0 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -47,6 +47,7 @@
self.snapshots_client.create_snapshot,
volume_id=None, display_name=s_name)
+ @test.attr(type=['negative'])
@decorators.idempotent_id('677863d1-34f9-456d-b6ac-9924f667a7f4')
def test_volume_from_snapshot_decreasing_size(self):
# Creates a volume a snapshot passing a size different from the source
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index f16ef88..adff244 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -19,6 +19,8 @@
from oslo_serialization import jsonutils as json
from six.moves.urllib import parse as urllib
+from tempest.lib.api_schema.response.compute.v2_1 import \
+ security_groups as security_groups_schema
from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
from tempest.lib.api_schema.response.compute.v2_16 import servers as schemav216
from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219
@@ -717,3 +719,16 @@
http://developer.openstack.org/api-ref-compute-v2.1.html#removeFixedIp
"""
return self.action(server_id, 'removeFixedIp', **kwargs)
+
+ def list_security_groups_by_server(self, server_id):
+ """Lists security groups for a server.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref-compute-v2.1.html#listSecurityGroupsByServer
+ """
+ resp, body = self.get("servers/%s/os-security-groups" % server_id)
+ body = json.loads(body)
+ self.validate_response(security_groups_schema.list_security_groups,
+ resp, body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py
index adfaaf2..b563ab2 100644
--- a/tempest/tests/lib/services/compute/test_servers_client.py
+++ b/tempest/tests/lib/services/compute/test_servers_client.py
@@ -172,6 +172,14 @@
"traceback": "fake-trace-back"
}
+ FAKE_SECURITY_GROUPS = [{
+ "description": "default",
+ "id": "3fb26eb3-581b-4420-9963-b0879a026506",
+ "name": "default",
+ "rules": [],
+ "tenant_id": "openstack"
+ }]
+
FAKE_INSTANCE_WITH_EVENTS = copy.deepcopy(FAKE_INSTANCE_ACTIONS)
FAKE_INSTANCE_WITH_EVENTS['events'] = [FAKE_INSTANCE_ACTION_EVENTS]
@@ -1009,3 +1017,17 @@
server_id=self.server_id,
type='fake-console-type'
)
+
+ def test_list_security_groups_by_server_with_str_body(self):
+ self._test_list_security_groups_by_server()
+
+ def test_list_security_groups_by_server_with_bytes_body(self):
+ self._test_list_security_groups_by_server(True)
+
+ def _test_list_security_groups_by_server(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_security_groups_by_server,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ {'security_groups': self.FAKE_SECURITY_GROUPS},
+ server_id=self.server_id,
+ )