From: Vasiliy Khomenko Date: Tue, 15 Jan 2013 00:22:00 +0000 (-0200) Subject: Add unit tests for Open vSwitch Quantum plugin X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=6c20e11491d91610cd1f6301f9c29cbb4dba5ac9;p=openstack-build%2Fneutron-build.git Add unit tests for Open vSwitch Quantum plugin OVSQuantumAgent missed unit tests for tunneling functionality. This change add these tests and couple of other minor tests. Implements: blueprint quantum-unittests Change-Id: I809711de8292ff7610b3fdb496c6bd043e7b6031 --- diff --git a/quantum/tests/unit/openvswitch/test_ovs_quantum_agent.py b/quantum/tests/unit/openvswitch/test_ovs_quantum_agent.py index a759a0b27..93d47c82e 100644 --- a/quantum/tests/unit/openvswitch/test_ovs_quantum_agent.py +++ b/quantum/tests/unit/openvswitch/test_ovs_quantum_agent.py @@ -137,12 +137,39 @@ class TestOvsQuantumAgent(unittest.TestCase): details = dict(exists=port_exists) with mock.patch.object(self.agent.plugin_rpc, 'update_device_down', return_value=details): - with mock.patch.object(self.agent, 'port_unbound') as func: + with mock.patch.object(self.agent, 'port_unbound') as port_unbound: self.assertFalse(self.agent.treat_devices_removed([{}])) - self.assertEqual(func.called, not port_exists) + self.assertEqual(port_unbound.called, not port_exists) def test_treat_devices_removed_unbinds_port(self): self.mock_treat_devices_removed(False) def test_treat_devices_removed_ignores_missing_port(self): self.mock_treat_devices_removed(False) + + def test_port_update(self): + port = {'id': 1, + 'network_id': 1, + 'admin_state_up': True} + with mock.patch.object(self.agent.int_br, 'get_vif_port_by_id', + return_value='2'): + with mock.patch.object(self.agent, 'port_bound') as port_bound: + self.agent.port_update(mock.Mock(), port=port) + self.assertTrue(port_bound.called) + + with mock.patch.object(self.agent, 'port_dead') as port_dead: + port['admin_state_up'] = False + self.agent.port_update(mock.Mock(), port=port) + self.assertTrue(port_dead.called) + + def test_process_network_ports(self): + reply = {'current': set(['tap0']), + 'removed': set(['eth0']), + 'added': set(['eth1'])} + with mock.patch.object(self.agent, 'treat_devices_added', + return_value=False) as device_added: + with mock.patch.object(self.agent, 'treat_devices_removed', + return_value=False) as device_removed: + self.assertFalse(self.agent.process_network_ports(reply)) + self.assertTrue(device_added.called) + self.assertTrue(device_removed.called) diff --git a/quantum/tests/unit/openvswitch/test_ovs_tunnel.py b/quantum/tests/unit/openvswitch/test_ovs_tunnel.py index a597193f3..dcc1d0fd1 100644 --- a/quantum/tests/unit/openvswitch/test_ovs_tunnel.py +++ b/quantum/tests/unit/openvswitch/test_ovs_tunnel.py @@ -20,13 +20,19 @@ import unittest import mox +from quantum.agent.linux import ip_lib from quantum.agent.linux import ovs_lib from quantum.agent.linux import utils +from quantum.agent import rpc +from quantum.openstack.common import cfg +from quantum.openstack.common import log from quantum.plugins.openvswitch.agent import ovs_quantum_agent +from quantum.plugins.openvswitch.common import constants + # Useful global dummy variables. NET_UUID = '3faeebfe-5d37-11e1-a64b-000c29d5f0a7' -LS_ID = '42' +LS_ID = 42 LV_ID = 42 LV_IDS = [42, 43] VIF_ID = '404deaec-5d37-11e1-a64b-000c29d5f0a8' @@ -36,6 +42,10 @@ VIF_PORT = ovs_lib.VifPort('port', OFPORT_NUM, VIF_ID, VIF_MAC, 'switch') VIF_PORTS = {LV_ID: VIF_PORT} LVM = ovs_quantum_agent.LocalVLANMapping(LV_ID, 'gre', None, LS_ID, VIF_PORTS) +LVM_FLAT = ovs_quantum_agent.LocalVLANMapping( + LV_ID, 'flat', 'net1', LS_ID, VIF_PORTS) +LVM_VLAN = ovs_quantum_agent.LocalVLANMapping( + LV_ID, 'vlan', 'net1', LS_ID, VIF_PORTS) BCAST_MAC = "01:00:00:00:00:00/01:00:00:00:00:00" @@ -51,14 +61,21 @@ class DummyVlanBinding: class TunnelTest(unittest.TestCase): - def setUp(self): + cfg.CONF.set_override('rpc_backend', + 'quantum.openstack.common.rpc.impl_fake') self.mox = mox.Mox() - self.INT_BRIDGE = 'integration_bridge' self.TUN_BRIDGE = 'tunnel_bridge' + self.MAP_TUN_BRIDGE = 'tunnel_bridge_mapping' + self.NET_MAPPING = {'net1': self.MAP_TUN_BRIDGE} self.INT_OFPORT = 11111 self.TUN_OFPORT = 22222 + self.MAP_TUN_OFPORT = 33333 + self.inta = self.mox.CreateMock(ip_lib.IPDevice) + self.intb = self.mox.CreateMock(ip_lib.IPDevice) + self.inta.link = self.mox.CreateMock(ip_lib.IpLinkCommand) + self.intb.link = self.mox.CreateMock(ip_lib.IpLinkCommand) self.mox.StubOutClassWithMocks(ovs_lib, 'OVSBridge') self.mock_int_bridge = ovs_lib.OVSBridge(self.INT_BRIDGE, 'sudo') @@ -66,6 +83,21 @@ class TunnelTest(unittest.TestCase): self.mock_int_bridge.remove_all_flows() self.mock_int_bridge.add_flow(priority=1, actions='normal') + self.mock_map_tun_bridge = ovs_lib.OVSBridge( + self.MAP_TUN_BRIDGE, 'sudo') + self.mock_map_tun_bridge.remove_all_flows() + self.mock_map_tun_bridge.add_flow(priority=1, actions='normal') + self.mock_int_bridge.delete_port('int-tunnel_bridge_mapping') + self.mock_map_tun_bridge.delete_port('phy-tunnel_bridge_mapping') + self.mock_int_bridge.add_port(self.inta) + self.mock_map_tun_bridge.add_port(self.intb) + self.inta.link.set_up() + self.intb.link.set_up() + + self.mock_int_bridge.add_flow(priority=2, in_port=None, actions='drop') + self.mock_map_tun_bridge.add_flow( + priority=2, in_port=None, actions='drop') + self.mock_tun_bridge = ovs_lib.OVSBridge(self.TUN_BRIDGE, 'sudo') self.mock_tun_bridge.reset_bridge() self.mock_int_bridge.add_patch_port( @@ -75,6 +107,19 @@ class TunnelTest(unittest.TestCase): self.mock_tun_bridge.remove_all_flows() self.mock_tun_bridge.add_flow(priority=1, actions='drop') + self.mox.StubOutWithMock(ip_lib, 'device_exists') + ip_lib.device_exists('tunnel_bridge_mapping', 'sudo').AndReturn(True) + ip_lib.device_exists( + 'int-tunnel_bridge_mapping', 'sudo').AndReturn(True) + + self.mox.StubOutWithMock(ip_lib.IpLinkCommand, 'delete') + ip_lib.IPDevice('int-tunnel_bridge_mapping').link.delete() + + self.mox.StubOutClassWithMocks(ip_lib, 'IPWrapper') + ip_lib.IPWrapper('sudo').add_veth( + 'int-tunnel_bridge_mapping', + 'phy-tunnel_bridge_mapping').AndReturn([self.inta, self.intb]) + self.mox.StubOutWithMock(utils, 'get_interface_mac') utils.get_interface_mac(self.INT_BRIDGE).AndReturn('000000000001') @@ -83,10 +128,9 @@ class TunnelTest(unittest.TestCase): def testConstruct(self): self.mox.ReplayAll() - b = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, self.TUN_BRIDGE, - '10.0.0.1', {}, + '10.0.0.1', self.NET_MAPPING, 'sudo', 2, True) self.mox.VerifyAll() @@ -103,10 +147,73 @@ class TunnelTest(unittest.TestCase): a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, self.TUN_BRIDGE, - '10.0.0.1', {}, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.available_local_vlans = set([LV_ID]) + a.provision_local_vlan(NET_UUID, constants.TYPE_GRE, None, LS_ID) + self.mox.VerifyAll() + + def testProvisionLocalVlanFlat(self): + action_string = 'strip_vlan,normal' + self.mock_map_tun_bridge.add_flow( + priority=4, in_port=self.MAP_TUN_OFPORT, + dl_vlan=LV_ID, actions=action_string) + + action_string = 'mod_vlan_vid:%s,normal' % LV_ID + self.mock_int_bridge.add_flow(priority=3, in_port=self.INT_OFPORT, + dl_vlan=65535, actions=action_string) + + self.mox.ReplayAll() + + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, 'sudo', 2, True) a.available_local_vlans = set([LV_ID]) - a.provision_local_vlan(NET_UUID, 'gre', None, LS_ID) + a.phys_brs['net1'] = self.mock_map_tun_bridge + a.phys_ofports['net1'] = self.MAP_TUN_OFPORT + a.int_ofports['net1'] = self.INT_OFPORT + a.provision_local_vlan(NET_UUID, constants.TYPE_FLAT, 'net1', LS_ID) + self.mox.VerifyAll() + + def testProvisionLocalVlanFlatFail(self): + self.mox.ReplayAll() + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.provision_local_vlan(NET_UUID, constants.TYPE_FLAT, 'net2', LS_ID) + self.mox.VerifyAll() + + def testProvisionLocalVlanVlan(self): + action_string = 'mod_vlan_vid:%s,normal' % LS_ID + self.mock_map_tun_bridge.add_flow( + priority=4, in_port=self.MAP_TUN_OFPORT, + dl_vlan=LV_ID, actions=action_string) + + action_string = 'mod_vlan_vid:%s,normal' % LS_ID + self.mock_int_bridge.add_flow(priority=3, in_port=self.INT_OFPORT, + dl_vlan=LV_ID, actions=action_string) + + self.mox.ReplayAll() + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.available_local_vlans = set([LV_ID]) + a.phys_brs['net1'] = self.mock_map_tun_bridge + a.phys_ofports['net1'] = self.MAP_TUN_OFPORT + a.int_ofports['net1'] = self.INT_OFPORT + a.provision_local_vlan(NET_UUID, constants.TYPE_VLAN, 'net1', LS_ID) + self.mox.VerifyAll() + + def testProvisionLocalVlanVlanFail(self): + self.mox.ReplayAll() + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.provision_local_vlan(NET_UUID, constants.TYPE_VLAN, 'net2', LS_ID) self.mox.VerifyAll() def testReclaimLocalVlan(self): @@ -117,7 +224,7 @@ class TunnelTest(unittest.TestCase): self.mox.ReplayAll() a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, self.TUN_BRIDGE, - '10.0.0.1', {}, + '10.0.0.1', self.NET_MAPPING, 'sudo', 2, True) a.available_local_vlans = set() a.local_vlan_map[NET_UUID] = LVM @@ -125,6 +232,50 @@ class TunnelTest(unittest.TestCase): self.assertTrue(LVM.vlan in a.available_local_vlans) self.mox.VerifyAll() + def testReclaimLocalVlanFlat(self): + self.mock_map_tun_bridge.delete_flows( + in_port=self.MAP_TUN_OFPORT, dl_vlan=LVM_FLAT.vlan) + + self.mock_int_bridge.delete_flows( + dl_vlan=65535, in_port=self.INT_OFPORT) + + self.mox.ReplayAll() + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.phys_brs['net1'] = self.mock_map_tun_bridge + a.phys_ofports['net1'] = self.MAP_TUN_OFPORT + a.int_ofports['net1'] = self.INT_OFPORT + + a.available_local_vlans = set() + a.local_vlan_map[NET_UUID] = LVM_FLAT + a.reclaim_local_vlan(NET_UUID, LVM_FLAT) + self.assertTrue(LVM_FLAT.vlan in a.available_local_vlans) + self.mox.VerifyAll() + + def testReclaimLocalVlanVLAN(self): + self.mock_map_tun_bridge.delete_flows( + in_port=self.MAP_TUN_OFPORT, dl_vlan=LVM_VLAN.vlan) + + self.mock_int_bridge.delete_flows( + dl_vlan=LV_ID, in_port=self.INT_OFPORT) + + self.mox.ReplayAll() + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.phys_brs['net1'] = self.mock_map_tun_bridge + a.phys_ofports['net1'] = self.MAP_TUN_OFPORT + a.int_ofports['net1'] = self.INT_OFPORT + + a.available_local_vlans = set() + a.local_vlan_map[NET_UUID] = LVM_VLAN + a.reclaim_local_vlan(NET_UUID, LVM_VLAN) + self.assertTrue(LVM_VLAN.vlan in a.available_local_vlans) + self.mox.VerifyAll() + def testPortBound(self): self.mock_int_bridge.set_db_attribute('Port', VIF_PORT.port_name, 'tag', str(LVM.vlan)) @@ -138,7 +289,7 @@ class TunnelTest(unittest.TestCase): self.mox.ReplayAll() a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, self.TUN_BRIDGE, - '10.0.0.1', {}, + '10.0.0.1', self.NET_MAPPING, 'sudo', 2, True) a.local_vlan_map[NET_UUID] = LVM a.port_bound(VIF_PORT, NET_UUID, 'gre', None, LS_ID) @@ -149,7 +300,7 @@ class TunnelTest(unittest.TestCase): self.mox.ReplayAll() a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, self.TUN_BRIDGE, - '10.0.0.1', {}, + '10.0.0.1', self.NET_MAPPING, 'sudo', 2, True) a.available_local_vlans = set([LV_ID]) a.local_vlan_map[NET_UUID] = LVM @@ -166,9 +317,77 @@ class TunnelTest(unittest.TestCase): self.mox.ReplayAll() a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, self.TUN_BRIDGE, - '10.0.0.1', {}, + '10.0.0.1', self.NET_MAPPING, 'sudo', 2, True) a.available_local_vlans = set([LV_ID]) a.local_vlan_map[NET_UUID] = LVM a.port_dead(VIF_PORT) self.mox.VerifyAll() + + def testTunnelUpdate(self): + self.mock_tun_bridge.add_tunnel_port('gre-1', '10.0.10.1') + self.mox.ReplayAll() + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.tunnel_update( + mox.MockAnything, tunnel_id='1', tunnel_ip='10.0.10.1') + self.mox.VerifyAll() + + def testTunnelUpdateSelf(self): + self.mox.ReplayAll() + a = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', self.NET_MAPPING, + 'sudo', 2, True) + a.tunnel_update( + mox.MockAnything, tunnel_id='1', tunnel_ip='10.0.0.1') + self.mox.VerifyAll() + + def testDaemonLoop(self): + reply2 = {'current': set(['tap0']), + 'added': set([]), + 'removed': set([])} + + reply3 = {'current': set(['tap2']), + 'added': set([]), + 'removed': set([])} + + self.mox.StubOutWithMock(log.ContextAdapter, 'exception') + log.ContextAdapter.exception( + _("Error in agent event loop")).AndRaise( + Exception('Fake exception to get out of the loop')) + + self.mox.StubOutWithMock( + ovs_quantum_agent.OVSQuantumAgent, 'update_ports') + ovs_quantum_agent.OVSQuantumAgent.update_ports(set()).AndReturn(reply2) + ovs_quantum_agent.OVSQuantumAgent.update_ports( + set(['tap0'])).AndReturn(reply3) + self.mox.StubOutWithMock( + ovs_quantum_agent.OVSQuantumAgent, 'process_network_ports') + ovs_quantum_agent.OVSQuantumAgent.process_network_ports( + {'current': set(['tap0']), + 'removed': set([]), + 'added': set([])}).AndReturn(False) + ovs_quantum_agent.OVSQuantumAgent.process_network_ports( + {'current': set(['tap0']), + 'removed': set([]), + 'added': set([])}).AndRaise( + Exception('Fake exception to get out of the loop')) + self.mox.ReplayAll() + q_agent = ovs_quantum_agent.OVSQuantumAgent(self.INT_BRIDGE, + self.TUN_BRIDGE, + '10.0.0.1', + self.NET_MAPPING, + 'sudo', 2, True) + + # Hack to test loop + # We start method and expect it will raise after 2nd loop + # If something goes wrong, mox.VerifyAll() will catch it + try: + q_agent.daemon_loop() + except: + pass + + self.mox.VerifyAll()