#!/usr/bin/python # # Copyright (C) 2009 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 0.0510-1301, USA. """Script for unittesting the confd client module""" import socket import unittest from ganeti import confd from ganeti import constants from ganeti import errors import ganeti.confd.client import testutils class ResettableMock(object): def __init__(self, *args, **kwargs): self.Reset() def Reset(self): pass class MockLogger(ResettableMock): def Reset(self): self.debug_count = 0 self.warn_count = 0 self.error_count = 0 def debug(string): self.debug_count += 1 def warning(string): self.warn_count += 1 def error(string): self.error_count += 1 class MockConfdAsyncUDPClient(ResettableMock): def Reset(self): self.send_count = 0 self.last_address = '' self.last_port = -1 self.last_sent = '' def enqueue_send(self, address, port, payload): self.send_count += 1 self.last_payload = payload self.last_port = port self.last_address = address class MockCallback(ResettableMock): def Reset(self): self.call_count = 0 self.last_up = None def __call__(self, up): """Callback @type up: L{ConfdUpcallPayload} @param up: upper callback """ self.call_count += 1 self.last_up = up class MockTime(ResettableMock): def Reset(self): self.mytime = 1254213006.5175071 def time(self): return self.mytime def increase(self, delta): self.mytime += delta class _BaseClientTest: """Base class for client tests""" mc_list = None new_peers = None family = None def setUp(self): self.mock_time = MockTime() confd.client.time = self.mock_time confd.client.ConfdAsyncUDPClient = MockConfdAsyncUDPClient self.logger = MockLogger() hmac_key = "mykeydata" self.callback = MockCallback() self.client = confd.client.ConfdClient(hmac_key, self.mc_list, self.callback, logger=self.logger) def testRequest(self): req1 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) self.assertNotEqual(req1.rsalt, req2.rsalt) self.assertEqual(req1.protocol, constants.CONFD_PROTOCOL_VERSION) self.assertEqual(req2.protocol, constants.CONFD_PROTOCOL_VERSION) self.assertRaises(errors.ConfdClientError, confd.client.ConfdClientRequest, type=-33) def testClientSend(self): req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) self.client.SendRequest(req) # Cannot send the same request twice self.assertRaises(errors.ConfdClientError, self.client.SendRequest, req) req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) # Coverage is too big self.assertRaises(errors.ConfdClientError, self.client.SendRequest, req2, coverage=15) self.assertEquals(self.client._socket.send_count, constants.CONFD_DEFAULT_REQ_COVERAGE) # Send with max coverage self.client.SendRequest(req2, coverage=-1) self.assertEquals(self.client._socket.send_count, constants.CONFD_DEFAULT_REQ_COVERAGE + len(self.mc_list)) self.assert_(self.client._socket.last_address in self.mc_list) def testClientExpire(self): req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) self.client.SendRequest(req) # Make a couple of seconds pass ;) self.mock_time.increase(2) # Now sending the second request req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) self.client.SendRequest(req2) self.mock_time.increase(constants.CONFD_CLIENT_EXPIRE_TIMEOUT - 1) # First request should be expired, second one should not self.client.ExpireRequests() self.assertEquals(self.callback.call_count, 1) self.assertEquals(self.callback.last_up.type, confd.client.UPCALL_EXPIRE) self.assertEquals(self.callback.last_up.salt, req.rsalt) self.assertEquals(self.callback.last_up.orig_request, req) self.mock_time.increase(3) self.assertEquals(self.callback.call_count, 1) self.client.ExpireRequests() self.assertEquals(self.callback.call_count, 2) self.assertEquals(self.callback.last_up.type, confd.client.UPCALL_EXPIRE) self.assertEquals(self.callback.last_up.salt, req2.rsalt) self.assertEquals(self.callback.last_up.orig_request, req2) def testClientCascadeExpire(self): req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) self.client.SendRequest(req) self.mock_time.increase(constants.CONFD_CLIENT_EXPIRE_TIMEOUT +1) req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) self.client.SendRequest(req2) self.assertEquals(self.callback.call_count, 1) def testUpdatePeerList(self): self.client.UpdatePeerList(self.new_peers) self.assertEquals(self.client._peers, self.new_peers) req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING) self.client.SendRequest(req) self.assertEquals(self.client._socket.send_count, len(self.new_peers)) self.assert_(self.client._socket.last_address in self.new_peers) def testSetPeersFamily(self): self.client._SetPeersAddressFamily() self.assertEquals(self.client._family, self.family) mixed_peers = ["192.0.2.99", "2001:db8:beef::13"] self.client.UpdatePeerList(mixed_peers) self.assertRaises(errors.ConfdClientError, self.client._SetPeersAddressFamily) class TestIP4Client(unittest.TestCase, _BaseClientTest): """Client tests""" mc_list = ["192.0.2.1", "192.0.2.2", "192.0.2.3", "192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7", "192.0.2.8", "192.0.2.9", ] new_peers = ["198.51.100.1", "198.51.100.2"] family = socket.AF_INET def setUp(self): unittest.TestCase.setUp(self) _BaseClientTest.setUp(self) class TestIP6Client(unittest.TestCase, _BaseClientTest): """Client tests""" mc_list = ["2001:db8::1", "2001:db8::2", "2001:db8::3", "2001:db8::4", "2001:db8::5", "2001:db8::6", "2001:db8::7", "2001:db8::8", "2001:db8::9", ] new_peers = ["2001:db8:beef::11", "2001:db8:beef::12"] family = socket.AF_INET6 def setUp(self): unittest.TestCase.setUp(self) _BaseClientTest.setUp(self) if __name__ == '__main__': testutils.GanetiTestProgram()