# Copyright 2015 Hewlett-Packard Development Company, L.P. # Copyright (c) 2015 Rackspace # # 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 binascii import random import socket from unittest import mock from oslo_config import cfg from oslo_config import fixture as oslo_fixture from octavia.amphorae.drivers.health import heartbeat_udp from octavia.common import exceptions from octavia.tests.unit import base FAKE_ID = 1 KEY = 'TEST' IP = '192.0.2.10' PORT = random.randrange(1, 9000) RLIMIT = random.randrange(1, 100) FAKE_ADDRINFO = ( socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP, '', (IP, PORT) ) HEALTH_DRIVER = 'health_logger' STATS_DRIVER = 'stats_logger' class TestHeartbeatUDP(base.TestCase): def setUp(self): super(TestHeartbeatUDP, self).setUp() self.health_update = mock.Mock() self.stats_update = mock.Mock() self.conf = oslo_fixture.Config(cfg.CONF) self.conf.config(group="health_manager", heartbeat_key=KEY) self.conf.config(group="health_manager", bind_ip=IP) self.conf.config(group="health_manager", bind_port=PORT) self.conf.config(group="health_manager", sock_rlimit=0) self.conf.config(group="health_manager", health_update_driver=HEALTH_DRIVER) self.conf.config(group="health_manager", stats_update_driver=STATS_DRIVER) @mock.patch('stevedore.driver.DriverManager') def test_update_health_func(self, driver_manager): obj = {'id': 1} heartbeat_udp.update_health(obj, '192.0.2.1') driver_manager.assert_called_once_with( invoke_on_load=True, name='health_logger', namespace='octavia.amphora.health_update_drivers' ) driver_manager().driver.update_health.assert_called_once_with( obj, '192.0.2.1') @mock.patch('stevedore.driver.DriverManager') def test_update_stats_func(self, driver_manager): obj = {'id': 1} heartbeat_udp.update_stats(obj, '192.0.2.1') driver_manager.assert_called_once_with( invoke_on_load=True, name='stats_logger', namespace='octavia.amphora.stats_update_drivers' ) driver_manager().driver.update_stats.assert_called_once_with( obj, '192.0.2.1') @mock.patch('socket.getaddrinfo') @mock.patch('socket.socket') def test_update(self, mock_socket, mock_getaddrinfo): socket_mock = mock.MagicMock() mock_socket.return_value = socket_mock mock_getaddrinfo.return_value = [FAKE_ADDRINFO] bind_mock = mock.MagicMock() socket_mock.bind = bind_mock getter = heartbeat_udp.UDPStatusGetter() mock_getaddrinfo.assert_called_with(IP, PORT, 0, socket.SOCK_DGRAM) self.assertEqual((IP, PORT), getter.sockaddr) mock_socket.assert_called_with(socket.AF_INET, socket.SOCK_DGRAM) bind_mock.assert_called_once_with((IP, PORT)) self.conf.config(group="health_manager", sock_rlimit=RLIMIT) mock_getaddrinfo.return_value = [FAKE_ADDRINFO, FAKE_ADDRINFO] getter.update(KEY, IP, PORT) @mock.patch('socket.getaddrinfo') @mock.patch('socket.socket') def test_dorecv(self, mock_socket, mock_getaddrinfo): socket_mock = mock.MagicMock() mock_socket.return_value = socket_mock mock_getaddrinfo.return_value = [range(1, 6)] recvfrom = mock.MagicMock() socket_mock.recvfrom = recvfrom getter = heartbeat_udp.UDPStatusGetter() # key = 'TEST' msg = {"testkey": "TEST"} sample_msg = ('78daab562a492d2ec94ead54b252500a710d0e5' '1aa050041b506245806e5c1971e79951818394e' 'a6e71ad989ff950945f9573f4ab6f83e25db8ed7') bin_msg = binascii.unhexlify(sample_msg) recvfrom.return_value = bin_msg, ('192.0.2.1', 2) (obj, srcaddr) = getter.dorecv() self.assertEqual('192.0.2.1', srcaddr) self.assertIsNotNone(obj.pop('recv_time')) self.assertEqual({"testkey": "TEST"}, obj) @mock.patch('octavia.amphorae.backends.health_daemon.status_message.' 'unwrap_envelope') @mock.patch('socket.getaddrinfo') @mock.patch('socket.socket') def test_dorecv_bad_packet(self, mock_socket, mock_getaddrinfo, mock_unwrap): socket_mock = mock.MagicMock() mock_socket.return_value = socket_mock mock_unwrap.side_effect = Exception('boom') mock_getaddrinfo.return_value = [range(1, 6)] recvfrom = mock.MagicMock() socket_mock.recvfrom = recvfrom getter = heartbeat_udp.UDPStatusGetter() # key = 'TEST' msg = {"testkey": "TEST"} sample_msg = ('78daab562a492d2ec94ead54b252500a710d0e5' '1aa050041b506245806e5c1971e79951818394e' 'a6e71ad989ff950945f9573f4ab6f83e25db8ed7') bin_msg = binascii.unhexlify(sample_msg) recvfrom.return_value = bin_msg, 2 self.assertRaises(exceptions.InvalidHMACException, getter.dorecv) @mock.patch('socket.getaddrinfo') @mock.patch('socket.socket') def test_check(self, mock_socket, mock_getaddrinfo): socket_mock = mock.MagicMock() mock_socket.return_value = socket_mock mock_getaddrinfo.return_value = [range(1, 6)] mock_dorecv = mock.Mock() mock_health_executor = mock.Mock() mock_stats_executor = mock.Mock() getter = heartbeat_udp.UDPStatusGetter() getter.dorecv = mock_dorecv mock_dorecv.side_effect = [(dict(id=FAKE_ID), 2)] getter.health_executor = mock_health_executor getter.stats_executor = mock_stats_executor getter.check() getter.health_executor.shutdown() getter.stats_executor.shutdown() mock_health_executor.submit.assert_has_calls( [mock.call(heartbeat_udp.update_health, {'id': 1}, 2)]) mock_stats_executor.submit.assert_has_calls( [mock.call(heartbeat_udp.update_stats, {'id': 1}, 2)]) @mock.patch('socket.getaddrinfo') @mock.patch('socket.socket') def test_socket_except(self, mock_socket, mock_getaddrinfo): self.assertRaises(exceptions.NetworkConfig, heartbeat_udp.UDPStatusGetter) @mock.patch('concurrent.futures.ThreadPoolExecutor.submit') @mock.patch('socket.getaddrinfo') @mock.patch('socket.socket') def test_check_exception(self, mock_socket, mock_getaddrinfo, mock_submit): self.mock_socket = mock_socket self.mock_getaddrinfo = mock_getaddrinfo self.mock_getaddrinfo.return_value = [range(1, 6)] mock_dorecv = mock.Mock() getter = heartbeat_udp.UDPStatusGetter() getter.dorecv = mock_dorecv mock_dorecv.side_effect = exceptions.InvalidHMACException getter.check() self.assertFalse(mock_submit.called)