
Now that we no longer support py27, we can use the standard library unittest.mock module instead of the third party mock lib. Change-Id: I67fcc16530f1c46eecb62e27eb7b88d1dee6f9df Signed-off-by: Takashi Natsume <takanattie@gmail.com>
423 lines
18 KiB
Python
423 lines
18 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import glob
|
|
import os.path
|
|
|
|
from unittest import mock
|
|
|
|
import testtools
|
|
|
|
from os_vif.internal.ip.api import ip as ip_lib
|
|
|
|
from vif_plug_ovs import exception
|
|
from vif_plug_ovs import linux_net
|
|
from vif_plug_ovs import privsep
|
|
|
|
|
|
class LinuxNetTest(testtools.TestCase):
|
|
|
|
def setUp(self):
|
|
super(LinuxNetTest, self).setUp()
|
|
|
|
privsep.vif_plug.set_client_mode(False)
|
|
|
|
@mock.patch.object(linux_net, "_arp_filtering")
|
|
@mock.patch.object(linux_net, "set_interface_state")
|
|
@mock.patch.object(linux_net, "_disable_ipv6")
|
|
@mock.patch.object(ip_lib, "add")
|
|
@mock.patch.object(ip_lib, "exists", return_value=False)
|
|
def test_ensure_bridge(self, mock_dev_exists, mock_add,
|
|
mock_disable_ipv6, mock_set_state,
|
|
mock_arp_filtering):
|
|
linux_net.ensure_bridge("br0")
|
|
|
|
mock_dev_exists.assert_called_once_with("br0")
|
|
mock_add.assert_called_once_with("br0", "bridge", ageing=0)
|
|
mock_disable_ipv6.assert_called_once_with("br0")
|
|
mock_set_state.assert_called_once_with("br0", "up")
|
|
mock_arp_filtering.assert_called_once_with("br0")
|
|
|
|
@mock.patch.object(linux_net, "_arp_filtering")
|
|
@mock.patch.object(linux_net, "set_interface_state")
|
|
@mock.patch.object(linux_net, "_disable_ipv6")
|
|
@mock.patch.object(ip_lib, "add")
|
|
@mock.patch.object(ip_lib, "exists", return_value=True)
|
|
def test_ensure_bridge_exists(self, mock_dev_exists, mock_add,
|
|
mock_disable_ipv6, mock_set_state,
|
|
mock_arp_filtering):
|
|
linux_net.ensure_bridge("br0")
|
|
|
|
mock_dev_exists.assert_called_once_with("br0")
|
|
mock_add.assert_not_called()
|
|
mock_disable_ipv6.assert_called_once_with("br0")
|
|
mock_set_state.assert_called_once_with("br0", "up")
|
|
mock_arp_filtering.assert_called_once_with("br0")
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch("os.path.exists")
|
|
def test__disable_ipv6(self, mock_exists, mock_open):
|
|
|
|
exists_path = "/proc/sys/net/ipv6/conf/br0/disable_ipv6"
|
|
mock_exists.return_value = False
|
|
|
|
linux_net._disable_ipv6("br0")
|
|
mock_exists.assert_called_once_with(exists_path)
|
|
mock_open.assert_not_called()
|
|
|
|
mock_exists.reset_mock()
|
|
mock_exists.return_value = True
|
|
linux_net._disable_ipv6("br0")
|
|
mock_exists.assert_called_once_with(exists_path)
|
|
mock_open.assert_called_once_with(exists_path, 'w')
|
|
|
|
@mock.patch.object(os.path, 'exists', return_value=True)
|
|
@mock.patch('builtins.open')
|
|
def test__arp_filtering(self, mock_open, *args):
|
|
mock_open.side_effect = mock.mock_open()
|
|
linux_net._arp_filtering("br0")
|
|
|
|
mock_open.assert_has_calls([
|
|
mock.call('/proc/sys/net/ipv4/conf/br0/arp_ignore', 'w'),
|
|
mock.call('/proc/sys/net/ipv4/conf/br0/arp_announce', 'w')])
|
|
mock_open.side_effect.return_value.write.assert_has_calls([
|
|
mock.call('1'),
|
|
mock.call('2')])
|
|
|
|
@mock.patch.object(ip_lib, "delete")
|
|
@mock.patch.object(ip_lib, "exists", return_value=False)
|
|
def test_delete_bridge_none(self, mock_dev_exists, mock_delete):
|
|
linux_net.delete_bridge("br0", "vnet1")
|
|
|
|
mock_delete.assert_not_called()
|
|
mock_dev_exists.assert_called_once_with("br0")
|
|
|
|
@mock.patch.object(linux_net, "set_interface_state")
|
|
@mock.patch.object(ip_lib, "delete")
|
|
@mock.patch.object(ip_lib, "exists", return_value=True)
|
|
def test_delete_bridge_exists(self, mock_dev_exists, mock_delete,
|
|
mock_set_state):
|
|
linux_net.delete_bridge("br0", "vnet1")
|
|
|
|
mock_dev_exists.assert_has_calls([mock.call("br0"),
|
|
mock.call("vnet1")])
|
|
mock_delete.assert_called_once_with("br0", check_exit_code=[0, 2, 254])
|
|
mock_set_state.assert_called_once_with("vnet1", "down")
|
|
|
|
@mock.patch.object(linux_net, "set_interface_state")
|
|
@mock.patch.object(ip_lib, "delete")
|
|
@mock.patch.object(ip_lib, "exists")
|
|
def test_delete_interface_not_present(self, mock_dev_exists, mock_delete,
|
|
mock_set_state):
|
|
mock_dev_exists.return_value = next(lambda: (yield True),
|
|
(yield False))
|
|
|
|
linux_net.delete_bridge("br0", "vnet1")
|
|
|
|
mock_dev_exists.assert_has_calls([mock.call("br0"),
|
|
mock.call("vnet1")])
|
|
mock_delete.assert_called_once_with("br0", check_exit_code=[0, 2, 254])
|
|
mock_set_state.assert_not_called()
|
|
|
|
@mock.patch.object(ip_lib, "set")
|
|
def test_add_bridge_port(self, mock_set):
|
|
linux_net.add_bridge_port("br0", "vnet1")
|
|
mock_set.assert_called_once_with("vnet1", master="br0")
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
def test_is_switchdev_ioerror(self, mock_isfile, mock_open):
|
|
mock_isfile.side_effect = [True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
[IOError()])
|
|
test_switchdev = linux_net._is_switchdev('pf_ifname')
|
|
self.assertEqual(test_switchdev, False)
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
def test_is_switchdev_empty(self, mock_isfile, mock_open):
|
|
mock_isfile.side_effect = [True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
[''])
|
|
open_calls = (
|
|
[mock.call('/sys/class/net/pf_ifname/phys_switch_id', 'r'),
|
|
mock.call().readline(),
|
|
mock.call().__exit__(None, None, None)])
|
|
test_switchdev = linux_net._is_switchdev('pf_ifname')
|
|
mock_open.assert_has_calls(open_calls)
|
|
self.assertEqual(test_switchdev, False)
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
def test_is_switchdev_positive(self, mock_isfile, mock_open):
|
|
mock_isfile.side_effect = [True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['pf_sw_id'])
|
|
open_calls = (
|
|
[mock.call('/sys/class/net/pf_ifname/phys_switch_id', 'r'),
|
|
mock.call().readline(),
|
|
mock.call().__exit__(None, None, None)])
|
|
test_switchdev = linux_net._is_switchdev('pf_ifname')
|
|
mock_open.assert_has_calls(open_calls)
|
|
self.assertEqual(test_switchdev, True)
|
|
|
|
def test_parse_vf_number(self):
|
|
self.assertEqual(linux_net._parse_vf_number("0"), "0")
|
|
self.assertEqual(linux_net._parse_vf_number("pf13vf42"), "42")
|
|
self.assertEqual(linux_net._parse_vf_number("VF19@PF13"), "19")
|
|
self.assertIsNone(linux_net._parse_vf_number("p7"))
|
|
self.assertIsNone(linux_net._parse_vf_number("pf31"))
|
|
self.assertIsNone(linux_net._parse_vf_number("g4rbl3d"))
|
|
|
|
def test_parse_pf_number(self):
|
|
self.assertIsNone(linux_net._parse_pf_number("0"))
|
|
self.assertEqual(linux_net._parse_pf_number("pf13vf42"), "13")
|
|
self.assertEqual(linux_net._parse_pf_number("VF19@PF13"), "13")
|
|
self.assertIsNone(linux_net._parse_pf_number("p7"))
|
|
self.assertEqual(linux_net._parse_pf_number("pf31"), "31")
|
|
self.assertIsNone(linux_net._parse_pf_number("g4rbl3d"))
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
@mock.patch.object(os, 'listdir')
|
|
@mock.patch.object(linux_net, "get_function_by_ifname")
|
|
def test_get_representor_port(self, mock_get_function_by_ifname,
|
|
mock_listdir, mock_isfile, mock_open):
|
|
mock_listdir.return_value = [
|
|
'pf_ifname', 'rep_vf_1', 'rep_vf_2'
|
|
]
|
|
mock_isfile.side_effect = [True, True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['pf_sw_id', 'pf_sw_id', '1', 'pf_sw_id', 'pf0vf2'])
|
|
# PCI IDs mocked:
|
|
# PF0: 0000:0a:00.0
|
|
# PF0VF1: 0000:0a:02.1 PF0VF2: 0000:0a:02.2
|
|
mock_get_function_by_ifname.side_effect = (
|
|
[("0000:0a:00.0", True),
|
|
("0000:0a:02.1", False),
|
|
("0000:0a:02.2", False), ("0000:0a:00.0", True)])
|
|
open_calls = (
|
|
[mock.call('/sys/class/net/pf_ifname/phys_switch_id', 'r'),
|
|
mock.call().readline(),
|
|
mock.call().__exit__(None, None, None),
|
|
mock.call('/sys/class/net/rep_vf_1/phys_switch_id', 'r'),
|
|
mock.call().readline(),
|
|
mock.call().__exit__(None, None, None),
|
|
mock.call('/sys/class/net/rep_vf_1/phys_port_name', 'r'),
|
|
mock.call().readline(),
|
|
mock.call().__exit__(None, None, None),
|
|
mock.call('/sys/class/net/rep_vf_2/phys_switch_id', 'r'),
|
|
mock.call().readline(),
|
|
mock.call().__exit__(None, None, None),
|
|
mock.call('/sys/class/net/rep_vf_2/phys_port_name', 'r'),
|
|
mock.call().readline(),
|
|
mock.call().__exit__(None, None, None)])
|
|
ifname = linux_net.get_representor_port('pf_ifname', '2')
|
|
mock_open.assert_has_calls(open_calls)
|
|
self.assertEqual('rep_vf_2', ifname)
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
@mock.patch.object(os, 'listdir')
|
|
@mock.patch.object(linux_net, "get_function_by_ifname")
|
|
def test_get_representor_port_2_pfs(
|
|
self, mock_get_function_by_ifname, mock_listdir, mock_isfile,
|
|
mock_open):
|
|
mock_listdir.return_value = [
|
|
'pf_ifname1', 'pf_ifname2', 'rep_pf1_vf_1', 'rep_pf1_vf_2',
|
|
'rep_pf2_vf_1', 'rep_pf2_vf_2',
|
|
]
|
|
mock_isfile.side_effect = [True, True, True, True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['pf_sw_id',
|
|
'pf_sw_id', 'VF1@PF1', 'pf_sw_id', 'vf2@pf1',
|
|
'pf_sw_id', 'pf2vf1', 'pf_sw_id', 'pf2vf2'])
|
|
# PCI IDs mocked:
|
|
# PF1: 0000:0a:00.1 PF2: 0000:0a:00.2
|
|
# PF1VF1: 0000:0a:02.1 PF1VF2: 0000:0a:02.2
|
|
# PF2VF1: 0000:0a:04.1 PF2VF2: 0000:0a:04.2
|
|
mock_get_function_by_ifname.side_effect = (
|
|
[("0000:0a:00.1", True), ("0000:0a:00.2", True),
|
|
("0000:0a:02.1", False), ("0000:0a:00.2", True),
|
|
("0000:0a:02.2", False), ("0000:0a:00.2", True),
|
|
("0000:0a:04.1", False), ("0000:0a:00.2", True),
|
|
("0000:0a:04.2", False), ("0000:0a:00.2", True)])
|
|
ifname = linux_net.get_representor_port('pf_ifname2', '2')
|
|
self.assertEqual('rep_pf2_vf_2', ifname)
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
@mock.patch.object(os, 'listdir')
|
|
@mock.patch.object(linux_net, "get_function_by_ifname")
|
|
def test_get_representor_port_not_found(
|
|
self, mock_get_function_by_ifname, mock_listdir, mock_isfile,
|
|
mock_open):
|
|
mock_listdir.return_value = [
|
|
'pf_ifname', 'rep_vf_1', 'rep_vf_2'
|
|
]
|
|
mock_isfile.side_effect = [True, True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['pf_sw_id', 'pf_sw_id', '1', 'pf_sw_id', '2'])
|
|
# PCI IDs mocked:
|
|
# PF0: 0000:0a:00.0
|
|
# PF0VF1: 0000:0a:02.1 PF0VF2: 0000:0a:02.2
|
|
mock_get_function_by_ifname.side_effect = (
|
|
[("0000:0a:00.0", True),
|
|
("0000:0a:02.1", False),
|
|
("0000:0a:02.2", False)])
|
|
self.assertRaises(
|
|
exception.RepresentorNotFound,
|
|
linux_net.get_representor_port,
|
|
'pf_ifname', '3'),
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
@mock.patch.object(os, 'listdir')
|
|
@mock.patch.object(linux_net, "get_function_by_ifname")
|
|
def test_get_representor_port_exception_io_error(
|
|
self, mock_get_function_by_ifname, mock_listdir, mock_isfile,
|
|
mock_open):
|
|
mock_listdir.return_value = [
|
|
'pf_ifname', 'rep_vf_1', 'rep_vf_2'
|
|
]
|
|
mock_isfile.side_effect = [True, True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['pf_sw_id', 'pf_sw_id', IOError(), 'pf_sw_id', '2'])
|
|
# PCI IDs mocked:
|
|
# PF0: 0000:0a:00.0
|
|
# PF0VF1: 0000:0a:02.1 PF0VF2: 0000:0a:02.2
|
|
mock_get_function_by_ifname.side_effect = (
|
|
[("0000:0a:00.0", True),
|
|
("0000:0a:02.1", False),
|
|
("0000:0a:02.2", False), ("0000:0a:00.0", True)])
|
|
self.assertRaises(
|
|
exception.RepresentorNotFound,
|
|
linux_net.get_representor_port,
|
|
'pf_ifname', '3')
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
@mock.patch.object(os, 'listdir')
|
|
@mock.patch.object(linux_net, "get_function_by_ifname")
|
|
def test_get_representor_port_exception_value_error(
|
|
self, mock_get_function_by_ifname, mock_listdir, mock_isfile,
|
|
mock_open):
|
|
mock_listdir.return_value = [
|
|
'pf_ifname', 'rep_vf_1', 'rep_vf_2'
|
|
]
|
|
mock_isfile.side_effect = [True, True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['pf_sw_id', 'pf_sw_id', '1', 'pf_sw_id', 'a'])
|
|
# PCI IDs mocked:
|
|
# PF0: 0000:0a:00.0
|
|
# PF0VF1: 0000:0a:02.1 PF0VF2: 0000:0a:02.2
|
|
mock_get_function_by_ifname.side_effect = (
|
|
[("0000:0a:00.0", True),
|
|
("0000:0a:02.1", False),
|
|
("0000:0a:02.2", False)])
|
|
self.assertRaises(
|
|
exception.RepresentorNotFound,
|
|
linux_net.get_representor_port,
|
|
'pf_ifname', '3')
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
@mock.patch.object(os, 'listdir')
|
|
def test_physical_function_inferface_name(
|
|
self, mock_listdir, mock_isfile, mock_open):
|
|
mock_listdir.return_value = ['foo', 'bar']
|
|
mock_isfile.side_effect = [True, True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['', 'valid_switch'])
|
|
ifname = linux_net.get_ifname_by_pci_address(
|
|
'0000:00:00.1', pf_interface=True, switchdev=False)
|
|
self.assertEqual(ifname, 'foo')
|
|
|
|
@mock.patch('builtins.open')
|
|
@mock.patch.object(os.path, 'isfile')
|
|
@mock.patch.object(os, 'listdir')
|
|
def test_physical_function_inferface_name_with_switchdev(
|
|
self, mock_listdir, mock_isfile, mock_open):
|
|
mock_listdir.return_value = ['foo', 'bar']
|
|
mock_isfile.side_effect = [True, True]
|
|
mock_open.return_value.__enter__ = lambda s: s
|
|
readline_mock = mock_open.return_value.readline
|
|
readline_mock.side_effect = (
|
|
['', 'valid_switch'])
|
|
ifname = linux_net.get_ifname_by_pci_address(
|
|
'0000:00:00.1', pf_interface=True, switchdev=True)
|
|
self.assertEqual(ifname, 'bar')
|
|
|
|
@mock.patch.object(os, 'listdir')
|
|
def test_get_ifname_by_pci_address_exception(self, mock_listdir):
|
|
mock_listdir.side_effect = OSError('No such file or directory')
|
|
self.assertRaises(
|
|
exception.PciDeviceNotFoundById,
|
|
linux_net.get_ifname_by_pci_address,
|
|
'0000:00:00.1'
|
|
)
|
|
|
|
@mock.patch.object(os, 'readlink')
|
|
@mock.patch.object(glob, 'iglob')
|
|
def test_vf_number_found(self, mock_iglob, mock_readlink):
|
|
mock_iglob.return_value = [
|
|
'/sys/bus/pci/devices/0000:00:00.1/physfn/virtfn3',
|
|
]
|
|
mock_readlink.return_value = '../../0000:00:00.1'
|
|
vf_num = linux_net.get_vf_num_by_pci_address('0000:00:00.1')
|
|
self.assertEqual(vf_num, '3')
|
|
|
|
@mock.patch.object(os, 'readlink')
|
|
@mock.patch.object(glob, 'iglob')
|
|
def test_vf_number_not_found(self, mock_iglob, mock_readlink):
|
|
mock_iglob.return_value = [
|
|
'/sys/bus/pci/devices/0000:00:00.1/physfn/virtfn3',
|
|
]
|
|
mock_readlink.return_value = '../../0000:00:00.2'
|
|
self.assertRaises(
|
|
exception.PciDeviceNotFoundById,
|
|
linux_net.get_vf_num_by_pci_address,
|
|
'0000:00:00.1'
|
|
)
|
|
|
|
@mock.patch.object(os, 'readlink')
|
|
@mock.patch.object(glob, 'iglob')
|
|
def test_get_vf_num_by_pci_address_exception(
|
|
self, mock_iglob, mock_readlink):
|
|
mock_iglob.return_value = [
|
|
'/sys/bus/pci/devices/0000:00:00.1/physfn/virtfn3',
|
|
]
|
|
mock_readlink.side_effect = OSError('No such file or directory')
|
|
self.assertRaises(
|
|
exception.PciDeviceNotFoundById,
|
|
linux_net.get_vf_num_by_pci_address,
|
|
'0000:00:00.1'
|
|
)
|