Add UT coverage for attach_interface by port

Previously attach_interface tests in project/instances/tests.py
did not cover the case of attach_interface by port.
This commit adds UT for such cases.

Details:
- The second call of the mocked network_list_for_tenant retured
  an empty list. It sounds tricky to change the return value for
  network_list_for_tenant() in two calls, but this trick was used
  to skip the processing of port_field_data.
  This should return a same value for the two calls to test
  port_field_data() function.
- To test the behavior of attach_interface by "port",
  an unbound port (whose device_owner/device_id of the port is empty)
  is required, so this commit adds it to neutron_data.py.
- test_interface_attach_get() covers a list of choices when "By Port"
  is selected in the form.
- test_interface_attach_post_by_port() is added.

Related to the addition of an unbound port to neutron_data.py,
the following other tests are adjusted.
They assumed that all non-network ports are owned by servers,
but it is no longer true as an unbound port is added to the test data.
Note that associating an unbound port with a floating IP is a valid
operation in neutron, so there is no problem to adjust UTs.

- openstack_dashboard/dashboards/project/floating_ips/tests.py
- openstack_dashboard/test/unit/api/test_neutron.py

Related-Bug: #1943639
Change-Id: Ib0ee342463e5668858078db43c04fe0a1be6e995
This commit is contained in:
Akihiro Motoki 2022-02-25 15:31:41 +09:00 committed by Tatiana Ovchinnikova
parent a4718409f5
commit 516e57bc89
4 changed files with 75 additions and 22 deletions

View File

@ -90,7 +90,7 @@ class FloatingIpViewTests(test.TestCase):
for p in self._get_compute_ports():
for ip in p.fixed_ips:
targets.append(api.neutron.FloatingIpTarget(
p, ip['ip_address'], server_dict[p.device_id]))
p, ip['ip_address'], server_dict.get(p.device_id)))
return targets
@staticmethod

View File

@ -3054,11 +3054,14 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
'port_list_with_trunk_types')})
def test_interface_attach_get(self):
server = self.servers.first()
self.mock_network_list_for_tenant.side_effect = [
self.networks.list()[:1],
[],
]
self.mock_port_list_with_trunk_types.return_value = self.ports.list()
tenant_networks = [net for net in self.networks.list()
if not net['router:external']]
net1 = tenant_networks[0]
self.mock_network_list_for_tenant.return_value = tenant_networks
ports = self.ports.list()
# Pick up the first unbound port for check
unbound_port = [p for p in ports if not p.device_owner][0]
self.mock_port_list_with_trunk_types.return_value = ports
url = reverse('horizon:project:instances:attach_interface',
args=[server.id])
@ -3066,6 +3069,13 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
self.assertTemplateUsed(res,
'project/instances/attach_interface.html')
expected_label = (
'%(port_name)s (%(ip_address)s) - %(net_name)s'
% {'port_name': unbound_port.name_or_id,
'ip_address': unbound_port.fixed_ips[0]['ip_address'],
'net_name': net1.name_or_id}
)
self.assertContains(res, expected_label)
self.mock_network_list_for_tenant.assert_has_calls([
mock.call(helpers.IsHttpRequest(), self.tenant.id),
mock.call(helpers.IsHttpRequest(), self.tenant.id),
@ -3077,21 +3087,31 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
@helpers.create_mocks({api.neutron: ('network_list_for_tenant',
'port_list_with_trunk_types'),
api.nova: ('interface_attach',)})
def test_interface_attach_post(self):
def _test_interface_attach_post(self, by_port=False):
fixed_ip = '10.0.0.10'
server = self.servers.first()
network = self.networks.first()
self.mock_network_list_for_tenant.side_effect = [
[network],
[],
]
self.mock_port_list_with_trunk_types.return_value = self.ports.list()
ports = self.ports.list()
# Pick up the first unbound port for check
unbound_port = [p for p in ports if not p.device_owner][0]
self.mock_network_list_for_tenant.return_value = [network]
self.mock_port_list_with_trunk_types.return_value = ports
self.mock_interface_attach.return_value = None
form_data = {'instance_id': server.id,
'network': network.id,
'specification_method': 'network',
'fixed_ip': fixed_ip}
if by_port:
form_data = {
'instance_id': server.id,
'specification_method': 'port',
'port': unbound_port.id,
}
else:
form_data = {
'instance_id': server.id,
'specification_method': 'network',
'network': network.id,
'fixed_ip': fixed_ip,
}
url = reverse('horizon:project:instances:attach_interface',
args=[server.id])
@ -3107,9 +3127,20 @@ class ConsoleManagerTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
self.assertEqual(2, self.mock_network_list_for_tenant.call_count)
self.mock_port_list_with_trunk_types.assert_called_once_with(
helpers.IsHttpRequest(), tenant_id=self.tenant.id)
self.mock_interface_attach.assert_called_once_with(
helpers.IsHttpRequest(), server.id,
net_id=network.id, fixed_ip=fixed_ip, port_id=None)
if by_port:
self.mock_interface_attach.assert_called_once_with(
helpers.IsHttpRequest(), server.id,
net_id=None, fixed_ip=None, port_id=unbound_port.id)
else:
self.mock_interface_attach.assert_called_once_with(
helpers.IsHttpRequest(), server.id,
net_id=network.id, fixed_ip=fixed_ip, port_id=None)
def test_interface_attach_post_by_network(self):
self._test_interface_attach_post()
def test_interface_attach_post_by_port(self):
self._test_interface_attach_post(by_port=True)
@helpers.create_mocks({api.cinder: ('volume_list',)})
def test_volume_attach_get(self):

View File

@ -222,6 +222,26 @@ def data(TEST):
TEST.api_ports.add(port_dict)
TEST.ports.add(neutron.Port(port_dict))
# unbound port on 1st network
port_dict = {
'admin_state_up': True,
'device_id': '',
'device_owner': '',
'fixed_ips': [{'ip_address': '10.0.0.5',
'subnet_id': subnet_dict['id']}],
'id': 'a5aa0d62-cd5f-4e7d-b022-4ff63f981bcd',
'mac_address': 'fa:16:3e:ce:e0:f8',
'name': '',
'network_id': network_dict['id'],
'status': 'DOWN',
'tenant_id': network_dict['tenant_id'],
'binding:vnic_type': 'normal',
'binding:host_id': '',
'security_groups': [],
}
TEST.api_ports.add(port_dict)
TEST.ports.add(neutron.Port(port_dict))
# 2nd network.
network_dict = {'admin_state_up': True,
'id': '72c3ab6c-c80f-4341-9dc5-210fa31ac6c2',

View File

@ -2488,9 +2488,11 @@ class NeutronApiFloatingIpTests(test.APIMockTestCase):
return '%(id)s_%(addr)s' % param
def _get_target_name(self, port, ip=None):
param = {'svrid': port['device_id'],
'addr': ip or port['fixed_ips'][0]['ip_address']}
return 'server_%(svrid)s: %(addr)s' % param
ip_address = ip or port['fixed_ips'][0]['ip_address']
if port['device_id']:
return 'server_%s: %s' % (port['device_id'], ip_address)
else:
return ip_address
@override_settings(
OPENSTACK_NEUTRON_NETWORK={