TestAsyncUDPSocket: remove dead code and add test
[ganeti-local] / test / ganeti.daemon_unittest.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2010 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 # 02110-1301, USA.
20
21
22 """Script for unittesting the daemon module"""
23
24 import unittest
25 import signal
26 import os
27 import socket
28 import time
29
30 from ganeti import daemon
31 from ganeti import constants
32 from ganeti import utils
33 from ganeti import errors
34
35 import testutils
36
37
38 class TestMainloop(testutils.GanetiTestCase):
39   """Test daemon.Mainloop"""
40
41   def setUp(self):
42     testutils.GanetiTestCase.setUp(self)
43     self.mainloop = daemon.Mainloop()
44     self.sendsig_events = []
45     self.onsignal_events = []
46
47   def _CancelEvent(self, handle):
48     self.mainloop.scheduler.cancel(handle)
49
50   def _SendSig(self, sig):
51     self.sendsig_events.append(sig)
52     os.kill(os.getpid(), sig)
53
54   def OnSignal(self, signum):
55     self.onsignal_events.append(signum)
56
57   def testRunAndTermBySched(self):
58     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGTERM])
59     self.mainloop.Run() # terminates by _SendSig being scheduled
60     self.assertEquals(self.sendsig_events, [signal.SIGTERM])
61
62   def testTerminatingSignals(self):
63     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGCHLD])
64     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGINT])
65     self.mainloop.Run()
66     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGINT])
67     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGTERM])
68     self.mainloop.Run()
69     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGINT,
70                                             signal.SIGTERM])
71
72   def testSchedulerCancel(self):
73     handle = self.mainloop.scheduler.enter(0.1, 1, self._SendSig,
74                                            [signal.SIGTERM])
75     self.mainloop.scheduler.cancel(handle)
76     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGCHLD])
77     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
78     self.mainloop.Run()
79     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGTERM])
80
81   def testRegisterSignal(self):
82     self.mainloop.RegisterSignal(self)
83     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGCHLD])
84     handle = self.mainloop.scheduler.enter(0.1, 1, self._SendSig,
85                                            [signal.SIGTERM])
86     self.mainloop.scheduler.cancel(handle)
87     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGCHLD])
88     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
89     # ...not delievered because they are scheduled after TERM
90     self.mainloop.scheduler.enter(0.4, 1, self._SendSig, [signal.SIGCHLD])
91     self.mainloop.scheduler.enter(0.5, 1, self._SendSig, [signal.SIGCHLD])
92     self.mainloop.Run()
93     self.assertEquals(self.sendsig_events,
94                       [signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM])
95     self.assertEquals(self.onsignal_events, self.sendsig_events)
96
97   def testDeferredCancel(self):
98     self.mainloop.RegisterSignal(self)
99     now = time.time()
100     self.mainloop.scheduler.enterabs(now + 0.1, 1, self._SendSig,
101                                      [signal.SIGCHLD])
102     handle1 = self.mainloop.scheduler.enterabs(now + 0.3, 2, self._SendSig,
103                                                [signal.SIGCHLD])
104     handle2 = self.mainloop.scheduler.enterabs(now + 0.4, 2, self._SendSig,
105                                                [signal.SIGCHLD])
106     self.mainloop.scheduler.enterabs(now + 0.2, 1, self._CancelEvent,
107                                      [handle1])
108     self.mainloop.scheduler.enterabs(now + 0.2, 1, self._CancelEvent,
109                                      [handle2])
110     self.mainloop.scheduler.enter(0.5, 1, self._SendSig, [signal.SIGTERM])
111     self.mainloop.Run()
112     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGTERM])
113     self.assertEquals(self.onsignal_events, self.sendsig_events)
114
115   def testReRun(self):
116     self.mainloop.RegisterSignal(self)
117     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGCHLD])
118     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGCHLD])
119     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
120     self.mainloop.scheduler.enter(0.4, 1, self._SendSig, [signal.SIGCHLD])
121     self.mainloop.scheduler.enter(0.5, 1, self._SendSig, [signal.SIGCHLD])
122     self.mainloop.Run()
123     self.assertEquals(self.sendsig_events,
124                       [signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM])
125     self.assertEquals(self.onsignal_events, self.sendsig_events)
126     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
127     self.mainloop.Run()
128     self.assertEquals(self.sendsig_events,
129                       [signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM,
130                        signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM])
131     self.assertEquals(self.onsignal_events, self.sendsig_events)
132
133   def testPriority(self):
134     # for events at the same time, the highest priority one executes first
135     now = time.time()
136     self.mainloop.scheduler.enterabs(now + 0.1, 2, self._SendSig,
137                                      [signal.SIGCHLD])
138     self.mainloop.scheduler.enterabs(now + 0.1, 1, self._SendSig,
139                                      [signal.SIGTERM])
140     self.mainloop.Run()
141     self.assertEquals(self.sendsig_events, [signal.SIGTERM])
142     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGTERM])
143     self.mainloop.Run()
144     self.assertEquals(self.sendsig_events,
145                       [signal.SIGTERM, signal.SIGCHLD, signal.SIGTERM])
146
147
148 class _MyAsyncUDPSocket(daemon.AsyncUDPSocket):
149
150   def __init__(self):
151     daemon.AsyncUDPSocket.__init__(self)
152     self.received = []
153     self.error_count = 0
154
155   def handle_datagram(self, payload, ip, port):
156     self.received.append((payload))
157     if payload == "terminate":
158       os.kill(os.getpid(), signal.SIGTERM)
159     elif payload == "error":
160       raise errors.GenericError("error")
161
162   def handle_error(self):
163     self.error_count += 1
164
165
166 class TestAsyncUDPSocket(testutils.GanetiTestCase):
167   """Test daemon.AsyncUDPSocket"""
168
169   def setUp(self):
170     testutils.GanetiTestCase.setUp(self)
171     self.mainloop = daemon.Mainloop()
172     self.server = _MyAsyncUDPSocket()
173     self.client = _MyAsyncUDPSocket()
174     self.server.bind(("127.0.0.1", 0))
175     self.port = self.server.getsockname()[1]
176     # Save utils.IgnoreSignals so we can do evil things to it...
177     self.saved_utils_ignoresignals = utils.IgnoreSignals
178
179   def tearDown(self):
180     self.server.close()
181     self.client.close()
182     # ...and restore it as well
183     utils.IgnoreSignals = self.saved_utils_ignoresignals
184     testutils.GanetiTestCase.tearDown(self)
185
186   def testNoDoubleBind(self):
187     self.assertRaises(socket.error, self.client.bind, ("127.0.0.1", self.port))
188
189   def testAsyncClientServer(self):
190     self.client.enqueue_send("127.0.0.1", self.port, "p1")
191     self.client.enqueue_send("127.0.0.1", self.port, "p2")
192     self.client.enqueue_send("127.0.0.1", self.port, "terminate")
193     self.mainloop.Run()
194     self.assertEquals(self.server.received, ["p1", "p2", "terminate"])
195
196   def testSyncClientServer(self):
197     self.client.handle_write()
198     self.client.enqueue_send("127.0.0.1", self.port, "p1")
199     self.client.enqueue_send("127.0.0.1", self.port, "p2")
200     while self.client.writable():
201       self.client.handle_write()
202     self.server.process_next_packet()
203     self.assertEquals(self.server.received, ["p1"])
204     self.server.process_next_packet()
205     self.assertEquals(self.server.received, ["p1", "p2"])
206     self.client.enqueue_send("127.0.0.1", self.port, "p3")
207     while self.client.writable():
208       self.client.handle_write()
209     self.server.process_next_packet()
210     self.assertEquals(self.server.received, ["p1", "p2", "p3"])
211
212   def testErrorHandling(self):
213     self.client.enqueue_send("127.0.0.1", self.port, "p1")
214     self.client.enqueue_send("127.0.0.1", self.port, "p2")
215     self.client.enqueue_send("127.0.0.1", self.port, "error")
216     self.client.enqueue_send("127.0.0.1", self.port, "p3")
217     self.client.enqueue_send("127.0.0.1", self.port, "error")
218     self.client.enqueue_send("127.0.0.1", self.port, "terminate")
219     self.mainloop.Run()
220     self.assertEquals(self.server.received,
221                       ["p1", "p2", "error", "p3", "error", "terminate"])
222     self.assertEquals(self.server.error_count, 2)
223
224   def testSignaledWhileReceiving(self):
225     utils.IgnoreSignals = lambda fn, *args, **kwargs: None
226     self.client.enqueue_send("127.0.0.1", self.port, "p1")
227     self.client.enqueue_send("127.0.0.1", self.port, "p2")
228     self.server.handle_read()
229     self.assertEquals(self.server.received, [])
230     self.client.enqueue_send("127.0.0.1", self.port, "terminate")
231     utils.IgnoreSignals = self.saved_utils_ignoresignals
232     self.mainloop.Run()
233     self.assertEquals(self.server.received, ["p1", "p2", "terminate"])
234
235   def testOversizedDatagram(self):
236     oversized_data = (constants.MAX_UDP_DATA_SIZE + 1) * "a"
237     self.assertRaises(errors.UdpDataSizeError, self.client.enqueue_send,
238                       "127.0.0.1", self.port, oversized_data)
239
240
241 if __name__ == "__main__":
242   testutils.GanetiTestProgram()