4 # Copyright (C) 2009 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for unittesting the confd client module"""
28 from ganeti import confd
29 from ganeti import constants
30 from ganeti import errors
32 import ganeti.confd.client
37 class ResettableMock(object):
38 def __init__(self, *args, **kwargs):
45 class MockLogger(ResettableMock):
60 class MockConfdAsyncUDPClient(ResettableMock):
63 self.last_address = ''
67 def enqueue_send(self, address, port, payload):
69 self.last_payload = payload
71 self.last_address = address
73 class MockCallback(ResettableMock):
78 def __call__(self, up):
81 @type up: L{ConfdUpcallPayload}
82 @param up: upper callback
89 class MockTime(ResettableMock):
91 self.mytime = 1254213006.5175071
96 def increase(self, delta):
100 class _BaseClientTest:
101 """Base class for client tests"""
107 self.mock_time = MockTime()
108 confd.client.time = self.mock_time
109 confd.client.ConfdAsyncUDPClient = MockConfdAsyncUDPClient
110 self.logger = MockLogger()
111 hmac_key = "mykeydata"
112 self.callback = MockCallback()
113 self.client = confd.client.ConfdClient(hmac_key, self.mc_list,
114 self.callback, logger=self.logger)
116 def testRequest(self):
117 req1 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
118 req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
119 self.assertNotEqual(req1.rsalt, req2.rsalt)
120 self.assertEqual(req1.protocol, constants.CONFD_PROTOCOL_VERSION)
121 self.assertEqual(req2.protocol, constants.CONFD_PROTOCOL_VERSION)
122 self.assertRaises(errors.ConfdClientError, confd.client.ConfdClientRequest,
125 def testClientSend(self):
126 req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
127 self.client.SendRequest(req)
128 # Cannot send the same request twice
129 self.assertRaises(errors.ConfdClientError, self.client.SendRequest, req)
130 req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
131 # Coverage is too big
132 self.assertRaises(errors.ConfdClientError, self.client.SendRequest,
134 self.assertEquals(self.client._socket.send_count,
135 constants.CONFD_DEFAULT_REQ_COVERAGE)
136 # Send with max coverage
137 self.client.SendRequest(req2, coverage=-1)
138 self.assertEquals(self.client._socket.send_count,
139 constants.CONFD_DEFAULT_REQ_COVERAGE + len(self.mc_list))
140 self.assert_(self.client._socket.last_address in self.mc_list)
143 def testClientExpire(self):
144 req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
145 self.client.SendRequest(req)
146 # Make a couple of seconds pass ;)
147 self.mock_time.increase(2)
148 # Now sending the second request
149 req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
150 self.client.SendRequest(req2)
151 self.mock_time.increase(constants.CONFD_CLIENT_EXPIRE_TIMEOUT - 1)
152 # First request should be expired, second one should not
153 self.client.ExpireRequests()
154 self.assertEquals(self.callback.call_count, 1)
155 self.assertEquals(self.callback.last_up.type, confd.client.UPCALL_EXPIRE)
156 self.assertEquals(self.callback.last_up.salt, req.rsalt)
157 self.assertEquals(self.callback.last_up.orig_request, req)
158 self.mock_time.increase(3)
159 self.assertEquals(self.callback.call_count, 1)
160 self.client.ExpireRequests()
161 self.assertEquals(self.callback.call_count, 2)
162 self.assertEquals(self.callback.last_up.type, confd.client.UPCALL_EXPIRE)
163 self.assertEquals(self.callback.last_up.salt, req2.rsalt)
164 self.assertEquals(self.callback.last_up.orig_request, req2)
166 def testClientCascadeExpire(self):
167 req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
168 self.client.SendRequest(req)
169 self.mock_time.increase(constants.CONFD_CLIENT_EXPIRE_TIMEOUT +1)
170 req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
171 self.client.SendRequest(req2)
172 self.assertEquals(self.callback.call_count, 1)
174 def testUpdatePeerList(self):
175 self.client.UpdatePeerList(self.new_peers)
176 self.assertEquals(self.client._peers, self.new_peers)
177 req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
178 self.client.SendRequest(req)
179 self.assertEquals(self.client._socket.send_count, len(self.new_peers))
180 self.assert_(self.client._socket.last_address in self.new_peers)
182 def testSetPeersFamily(self):
183 self.client._SetPeersAddressFamily()
184 self.assertEquals(self.client._family, self.family)
185 mixed_peers = ["192.0.2.99", "2001:db8:beef::13"]
186 self.client.UpdatePeerList(mixed_peers)
187 self.assertRaises(errors.ConfdClientError,
188 self.client._SetPeersAddressFamily)
191 class TestIP4Client(unittest.TestCase, _BaseClientTest):
193 mc_list = ["192.0.2.1",
203 new_peers = ["198.51.100.1", "198.51.100.2"]
204 family = socket.AF_INET
207 unittest.TestCase.setUp(self)
208 _BaseClientTest.setUp(self)
211 class TestIP6Client(unittest.TestCase, _BaseClientTest):
213 mc_list = ["2001:db8::1",
223 new_peers = ["2001:db8:beef::11", "2001:db8:beef::12"]
224 family = socket.AF_INET6
227 unittest.TestCase.setUp(self)
228 _BaseClientTest.setUp(self)
231 if __name__ == '__main__':
232 testutils.GanetiTestProgram()