Merge branch 'devel-2.1'
[ganeti-local] / test / ganeti.confd_client_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2009 Google Inc.
5 #
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.
10 #
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.
15 #
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
19 # 0.0510-1301, USA.
20
21
22 """Script for unittesting the confd client module"""
23
24
25 import unittest
26
27 from ganeti import confd
28 from ganeti import constants
29 from ganeti import errors
30
31 import ganeti.confd.client
32
33 import testutils
34
35
36 class ResettableMock(object):
37   def __init__(self, *args, **kwargs):
38     self.Reset()
39
40   def Reset(self):
41     pass
42
43
44 class MockLogger(ResettableMock):
45   def Reset(self):
46     self.debug_count = 0
47     self.warn_count = 0
48     self.error_count = 0
49
50   def debug(string):
51     self.debug_count += 1
52
53   def warning(string):
54     self.warn_count += 1
55
56   def error(string):
57     self.error_count += 1
58
59 class MockConfdAsyncUDPClient(ResettableMock):
60   def Reset(self):
61     self.send_count = 0
62     self.last_address = ''
63     self.last_port = -1
64     self.last_sent = ''
65
66   def enqueue_send(self, address, port, payload):
67     self.send_count += 1
68     self.last_payload = payload
69     self.last_port = port
70     self.last_address = address
71
72 class MockCallback(ResettableMock):
73   def Reset(self):
74     self.call_count = 0
75     self.last_up = None
76
77   def __call__(self, up):
78     """Callback
79
80     @type up: L{ConfdUpcallPayload}
81     @param up: upper callback
82
83     """
84     self.call_count += 1
85     self.last_up = up
86
87
88 class MockTime(ResettableMock):
89   def Reset(self):
90     self.mytime  = 1254213006.5175071
91
92   def time(self):
93     return self.mytime
94
95   def increase(self, delta):
96     self.mytime += delta
97
98
99 class TestClient(unittest.TestCase):
100   """Client tests"""
101
102   def setUp(self):
103     self.mock_time = MockTime()
104     confd.client.time = self.mock_time
105     confd.client.ConfdAsyncUDPClient = MockConfdAsyncUDPClient
106     self.logger = MockLogger()
107     hmac_key = "mykeydata"
108     self.mc_list = ['10.0.0.1',
109                     '10.0.0.2',
110                     '10.0.0.3',
111                     '10.0.0.4',
112                     '10.0.0.5',
113                     '10.0.0.6',
114                     '10.0.0.7',
115                     '10.0.0.8',
116                     '10.0.0.9',
117                    ]
118     self.callback = MockCallback()
119     self.client = confd.client.ConfdClient(hmac_key, self.mc_list,
120                                            self.callback, logger=self.logger)
121
122   def testRequest(self):
123     req1 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
124     req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
125     self.assertNotEqual(req1.rsalt, req2.rsalt)
126     self.assertEqual(req1.protocol, constants.CONFD_PROTOCOL_VERSION)
127     self.assertEqual(req2.protocol, constants.CONFD_PROTOCOL_VERSION)
128     self.assertRaises(errors.ConfdClientError, confd.client.ConfdClientRequest,
129                       type=-33)
130
131   def testClientSend(self):
132     req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
133     self.client.SendRequest(req)
134     # Cannot send the same request twice
135     self.assertRaises(errors.ConfdClientError, self.client.SendRequest, req)
136     req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
137     # Coverage is too big
138     self.assertRaises(errors.ConfdClientError, self.client.SendRequest,
139                       req2, coverage=15)
140     self.assertEquals(self.client._socket.send_count,
141                       constants.CONFD_DEFAULT_REQ_COVERAGE)
142     self.assert_(self.client._socket.last_address in self.mc_list)
143
144
145   def testClientExpire(self):
146     req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
147     self.client.SendRequest(req)
148     # Make a couple of seconds pass ;)
149     self.mock_time.increase(2)
150     # Now sending the second request
151     req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
152     self.client.SendRequest(req2)
153     self.mock_time.increase(constants.CONFD_CLIENT_EXPIRE_TIMEOUT - 1)
154     # First request should be expired, second one should not
155     self.client.ExpireRequests()
156     self.assertEquals(self.callback.call_count, 1)
157     self.assertEquals(self.callback.last_up.type, confd.client.UPCALL_EXPIRE)
158     self.assertEquals(self.callback.last_up.salt, req.rsalt)
159     self.assertEquals(self.callback.last_up.orig_request, req)
160     self.mock_time.increase(3)
161     self.assertEquals(self.callback.call_count, 1)
162     self.client.ExpireRequests()
163     self.assertEquals(self.callback.call_count, 2)
164     self.assertEquals(self.callback.last_up.type, confd.client.UPCALL_EXPIRE)
165     self.assertEquals(self.callback.last_up.salt, req2.rsalt)
166     self.assertEquals(self.callback.last_up.orig_request, req2)
167
168   def testClientCascadeExpire(self):
169     req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
170     self.client.SendRequest(req)
171     self.mock_time.increase(constants.CONFD_CLIENT_EXPIRE_TIMEOUT +1)
172     req2 = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
173     self.client.SendRequest(req2)
174     self.assertEquals(self.callback.call_count, 1)
175
176   def testUpdatePeerList(self):
177     new_peers = ['1.2.3.4', '1.2.3.5']
178     self.client.UpdatePeerList(new_peers)
179     self.assertEquals(self.client._peers, new_peers)
180     req = confd.client.ConfdClientRequest(type=constants.CONFD_REQ_PING)
181     self.client.SendRequest(req)
182     self.assertEquals(self.client._socket.send_count, len(new_peers))
183     self.assert_(self.client._socket.last_address in new_peers)
184
185
186 if __name__ == '__main__':
187   testutils.GanetiTestProgram()