Add UT for LBaaS HAProxy driver
fixes bug 1137386 Change-Id: I791d09fc472fd8555f4030cfd1964e70ab9f2771
This commit is contained in:
parent
e4dd4f78cd
commit
193dbf6d1c
@ -17,12 +17,143 @@
|
|||||||
#
|
#
|
||||||
# @author: Oleg Bondarev (obondarev@mirantis.com)
|
# @author: Oleg Bondarev (obondarev@mirantis.com)
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import mock
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
|
from oslo.config import cfg as config
|
||||||
|
|
||||||
from quantum.plugins.services.agent_loadbalancer.drivers.haproxy import cfg
|
from quantum.plugins.services.agent_loadbalancer.drivers.haproxy import cfg
|
||||||
|
|
||||||
|
|
||||||
class TestHaproxyCfg(testtools.TestCase):
|
class TestHaproxyCfg(testtools.TestCase):
|
||||||
|
def test_save_config(self):
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch('quantum.plugins.services.agent_loadbalancer.'
|
||||||
|
'drivers.haproxy.cfg._build_global'),
|
||||||
|
mock.patch('quantum.plugins.services.agent_loadbalancer.'
|
||||||
|
'drivers.haproxy.cfg._build_defaults'),
|
||||||
|
mock.patch('quantum.plugins.services.agent_loadbalancer.'
|
||||||
|
'drivers.haproxy.cfg._build_frontend'),
|
||||||
|
mock.patch('quantum.plugins.services.agent_loadbalancer.'
|
||||||
|
'drivers.haproxy.cfg._build_backend'),
|
||||||
|
mock.patch('quantum.agent.linux.utils.replace_file')
|
||||||
|
) as (b_g, b_d, b_f, b_b, replace):
|
||||||
|
test_config = ['globals', 'defaults', 'frontend', 'backend']
|
||||||
|
b_g.return_value = [test_config[0]]
|
||||||
|
b_d.return_value = [test_config[1]]
|
||||||
|
b_f.return_value = [test_config[2]]
|
||||||
|
b_b.return_value = [test_config[3]]
|
||||||
|
|
||||||
|
cfg.save_config('test_path', mock.Mock())
|
||||||
|
replace.assert_called_once_with('test_path',
|
||||||
|
'\n'.join(test_config))
|
||||||
|
|
||||||
|
def test_build_global(self):
|
||||||
|
config.CONF.register_opt(config.StrOpt('user_group'))
|
||||||
|
config.CONF.set_override('user_group', 'test_group')
|
||||||
|
expected_opts = ['global',
|
||||||
|
'\tdaemon',
|
||||||
|
'\tuser nobody',
|
||||||
|
'\tgroup test_group',
|
||||||
|
'\tlog /dev/log local0',
|
||||||
|
'\tlog /dev/log local1 notice',
|
||||||
|
'\tstats socket test_path mode 0666 level user']
|
||||||
|
opts = cfg._build_global(mock.Mock(), 'test_path')
|
||||||
|
self.assertEqual(expected_opts, list(opts))
|
||||||
|
config.CONF.reset()
|
||||||
|
|
||||||
|
def test_build_defaults(self):
|
||||||
|
expected_opts = ['defaults',
|
||||||
|
'\tlog global',
|
||||||
|
'\tretries 3',
|
||||||
|
'\toption redispatch',
|
||||||
|
'\ttimeout connect 5000',
|
||||||
|
'\ttimeout client 50000',
|
||||||
|
'\ttimeout server 50000']
|
||||||
|
opts = cfg._build_defaults(mock.Mock())
|
||||||
|
self.assertEqual(expected_opts, list(opts))
|
||||||
|
config.CONF.reset()
|
||||||
|
|
||||||
|
def test_build_frontend(self):
|
||||||
|
test_config = {'vip': {'id': 'vip_id',
|
||||||
|
'protocol': 'HTTP',
|
||||||
|
'port': {'fixed_ips': [
|
||||||
|
{'ip_address': '10.0.0.2'}]
|
||||||
|
},
|
||||||
|
'protocol_port': 80,
|
||||||
|
'connection_limit': 2000,
|
||||||
|
},
|
||||||
|
'pool': {'id': 'pool_id'}}
|
||||||
|
expected_opts = ['frontend vip_id',
|
||||||
|
'\toption tcplog',
|
||||||
|
'\tbind 10.0.0.2:80',
|
||||||
|
'\tmode http',
|
||||||
|
'\tdefault_backend pool_id',
|
||||||
|
'\tmaxconn 2000',
|
||||||
|
'\toption forwardfor']
|
||||||
|
opts = cfg._build_frontend(test_config)
|
||||||
|
self.assertEqual(expected_opts, list(opts))
|
||||||
|
|
||||||
|
test_config['vip']['connection_limit'] = -1
|
||||||
|
expected_opts.remove('\tmaxconn 2000')
|
||||||
|
opts = cfg._build_frontend(test_config)
|
||||||
|
self.assertEqual(expected_opts, list(opts))
|
||||||
|
|
||||||
|
def test_build_backend(self):
|
||||||
|
test_config = {'pool': {'id': 'pool_id',
|
||||||
|
'protocol': 'HTTP',
|
||||||
|
'lb_method': 'ROUND_ROBIN'},
|
||||||
|
'members': [{'status': 'ACTIVE',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'id': 'member1_id',
|
||||||
|
'address': '10.0.0.3',
|
||||||
|
'protocol_port': 80,
|
||||||
|
'weight': 1}],
|
||||||
|
'healthmonitors': [{'status': 'ACTIVE',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'delay': 3,
|
||||||
|
'max_retries': 4,
|
||||||
|
'timeout': 2,
|
||||||
|
'type': 'TCP'}],
|
||||||
|
'vip': {'session_persistence': {'type': 'HTTP_COOKIE'}}}
|
||||||
|
expected_opts = ['backend pool_id',
|
||||||
|
'\tmode http',
|
||||||
|
'\tbalance roundrobin',
|
||||||
|
'\toption forwardfor',
|
||||||
|
'\ttimeout check 2s',
|
||||||
|
'\tcookie SRV insert indirect nocache',
|
||||||
|
'\tserver member1_id 10.0.0.3:80 weight 1 '
|
||||||
|
'check inter 3s fall 4 cookie 0']
|
||||||
|
opts = cfg._build_backend(test_config)
|
||||||
|
self.assertEqual(expected_opts, list(opts))
|
||||||
|
|
||||||
|
def test_get_server_health_option(self):
|
||||||
|
test_config = {'healthmonitors': [{'status': 'ERROR',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'delay': 3,
|
||||||
|
'max_retries': 4,
|
||||||
|
'timeout': 2,
|
||||||
|
'type': 'TCP',
|
||||||
|
'http_method': 'GET',
|
||||||
|
'url_path': '/',
|
||||||
|
'expected_codes': '200'}]}
|
||||||
|
self.assertEqual(('', []), cfg._get_server_health_option(test_config))
|
||||||
|
|
||||||
|
test_config['healthmonitors'][0]['status'] = 'ACTIVE'
|
||||||
|
self.assertEqual(('', []), cfg._get_server_health_option(test_config))
|
||||||
|
|
||||||
|
test_config['healthmonitors'][0]['admin_state_up'] = True
|
||||||
|
expected = (' check inter 3s fall 4', ['timeout check 2s'])
|
||||||
|
self.assertEqual(expected, cfg._get_server_health_option(test_config))
|
||||||
|
|
||||||
|
test_config['healthmonitors'][0]['type'] = 'HTTPS'
|
||||||
|
expected = (' check inter 3s fall 4',
|
||||||
|
['timeout check 2s',
|
||||||
|
'option httpchk GET /',
|
||||||
|
'http-check expect rstatus 200',
|
||||||
|
'option ssl-hello-chk'])
|
||||||
|
self.assertEqual(expected, cfg._get_server_health_option(test_config))
|
||||||
|
|
||||||
def test_has_http_cookie_persistence(self):
|
def test_has_http_cookie_persistence(self):
|
||||||
config = {'vip': {'session_persistence': {'type': 'HTTP_COOKIE'}}}
|
config = {'vip': {'session_persistence': {'type': 'HTTP_COOKIE'}}}
|
||||||
@ -53,3 +184,29 @@ class TestHaproxyCfg(testtools.TestCase):
|
|||||||
|
|
||||||
config = {'vip': {'session_persistence': {'type': 'UNSUPPORTED'}}}
|
config = {'vip': {'session_persistence': {'type': 'UNSUPPORTED'}}}
|
||||||
self.assertEqual(cfg._get_session_persistence(config), [])
|
self.assertEqual(cfg._get_session_persistence(config), [])
|
||||||
|
|
||||||
|
def test_expand_expected_codes(self):
|
||||||
|
exp_codes = ''
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes), set([]))
|
||||||
|
exp_codes = '200'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes), set(['200']))
|
||||||
|
exp_codes = '200, 201'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes),
|
||||||
|
set(['200', '201']))
|
||||||
|
exp_codes = '200, 201,202'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes),
|
||||||
|
set(['200', '201', '202']))
|
||||||
|
exp_codes = '200-202'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes),
|
||||||
|
set(['200', '201', '202']))
|
||||||
|
exp_codes = '200-202, 205'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes),
|
||||||
|
set(['200', '201', '202', '205']))
|
||||||
|
exp_codes = '200, 201-203'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes),
|
||||||
|
set(['200', '201', '202', '203']))
|
||||||
|
exp_codes = '200, 201-203, 205'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes),
|
||||||
|
set(['200', '201', '202', '203', '205']))
|
||||||
|
exp_codes = '201-200, 205'
|
||||||
|
self.assertEqual(cfg._expand_expected_codes(exp_codes), set(['205']))
|
||||||
|
@ -20,6 +20,7 @@ import contextlib
|
|||||||
import mock
|
import mock
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
|
from quantum.common import exceptions
|
||||||
from quantum.plugins.services.agent_loadbalancer.drivers.haproxy import (
|
from quantum.plugins.services.agent_loadbalancer.drivers.haproxy import (
|
||||||
namespace_driver
|
namespace_driver
|
||||||
)
|
)
|
||||||
@ -179,3 +180,70 @@ class TestHaproxyNSDriver(testtools.TestCase):
|
|||||||
socket.reset_mock()
|
socket.reset_mock()
|
||||||
self.assertEqual({}, self.driver.get_stats('pool_id'))
|
self.assertEqual({}, self.driver.get_stats('pool_id'))
|
||||||
self.assertFalse(socket.called)
|
self.assertFalse(socket.called)
|
||||||
|
|
||||||
|
def test_plug(self):
|
||||||
|
test_port = {'id': 'port_id',
|
||||||
|
'network_id': 'net_id',
|
||||||
|
'mac_address': 'mac_addr',
|
||||||
|
'fixed_ips': [{'ip_address': '10.0.0.2',
|
||||||
|
'subnet': {'cidr': 'cidr'}}]}
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch('quantum.agent.linux.ip_lib.device_exists'),
|
||||||
|
mock.patch('netaddr.IPNetwork'),
|
||||||
|
) as (dev_exists, ip_net):
|
||||||
|
self.vif_driver.get_device_name.return_value = 'test_interface'
|
||||||
|
dev_exists.return_value = False
|
||||||
|
ip_net.return_value = ip_net
|
||||||
|
ip_net.prefixlen = 24
|
||||||
|
|
||||||
|
self.driver._plug('test_ns', test_port)
|
||||||
|
self.vip_plug_callback.assert_called_once_with('plug', test_port)
|
||||||
|
self.assertTrue(dev_exists.called)
|
||||||
|
self.vif_driver.plug.assert_called_once_with('net_id', 'port_id',
|
||||||
|
'test_interface',
|
||||||
|
'mac_addr',
|
||||||
|
namespace='test_ns')
|
||||||
|
self.vif_driver.init_l3.assert_called_once_with('test_interface',
|
||||||
|
['10.0.0.2/24'],
|
||||||
|
namespace=
|
||||||
|
'test_ns')
|
||||||
|
|
||||||
|
dev_exists.return_value = True
|
||||||
|
self.assertRaises(exceptions.PreexistingDeviceFailure,
|
||||||
|
self.driver._plug, 'test_ns', test_port, False)
|
||||||
|
|
||||||
|
def test_unplug(self):
|
||||||
|
self.vif_driver.get_device_name.return_value = 'test_interface'
|
||||||
|
|
||||||
|
self.driver._unplug('test_ns', 'port_id')
|
||||||
|
self.vip_plug_callback.assert_called_once_with('unplug',
|
||||||
|
{'id': 'port_id'})
|
||||||
|
self.vif_driver.unplug('test_interface', namespace='test_ns')
|
||||||
|
|
||||||
|
def test_kill_pids_in_file(self):
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch('os.path.exists'),
|
||||||
|
mock.patch('__builtin__.open')
|
||||||
|
) as (path_exists, mock_open):
|
||||||
|
file_mock = mock.MagicMock()
|
||||||
|
mock_open.return_value = file_mock
|
||||||
|
file_mock.__enter__.return_value = file_mock
|
||||||
|
file_mock.__iter__.return_value = iter(['123'])
|
||||||
|
ns_wrapper = mock.Mock()
|
||||||
|
|
||||||
|
path_exists.return_value = False
|
||||||
|
namespace_driver.kill_pids_in_file(ns_wrapper, 'test_path')
|
||||||
|
path_exists.assert_called_once_with('test_path')
|
||||||
|
self.assertFalse(mock_open.called)
|
||||||
|
|
||||||
|
path_exists.return_value = True
|
||||||
|
ns_wrapper.netns.execute.side_effect = RuntimeError
|
||||||
|
namespace_driver.kill_pids_in_file(ns_wrapper, 'test_path')
|
||||||
|
ns_wrapper.netns.execute.assert_called_once_with(['kill', '-9',
|
||||||
|
'123'])
|
||||||
|
|
||||||
|
def test_get_state_file_path(self):
|
||||||
|
with mock.patch('os.makedirs') as mkdir:
|
||||||
|
path = self.driver._get_state_file_path('pool_id', 'conf')
|
||||||
|
self.assertEqual('/the/path/pool_id/conf', path)
|
||||||
|
mkdir.assert_called_once_with('/the/path/pool_id', 0755)
|
||||||
|
Loading…
Reference in New Issue
Block a user