reraise exceptions in async tests' error handlers
[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 errors
32
33 import testutils
34
35
36 class TestMainloop(testutils.GanetiTestCase):
37   """Test daemon.Mainloop"""
38
39   def setUp(self):
40     testutils.GanetiTestCase.setUp(self)
41     self.mainloop = daemon.Mainloop()
42     self.sendsig_events = []
43     self.onsignal_events = []
44
45   def _CancelEvent(self, handle):
46     self.mainloop.scheduler.cancel(handle)
47
48   def _SendSig(self, sig):
49     self.sendsig_events.append(sig)
50     os.kill(os.getpid(), sig)
51
52   def OnSignal(self, signum):
53     self.onsignal_events.append(signum)
54
55   def testRunAndTermBySched(self):
56     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGTERM])
57     self.mainloop.Run() # terminates by _SendSig being scheduled
58     self.assertEquals(self.sendsig_events, [signal.SIGTERM])
59
60   def testTerminatingSignals(self):
61     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGCHLD])
62     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGINT])
63     self.mainloop.Run()
64     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGINT])
65     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGTERM])
66     self.mainloop.Run()
67     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGINT,
68                                             signal.SIGTERM])
69
70   def testSchedulerCancel(self):
71     handle = self.mainloop.scheduler.enter(0.1, 1, self._SendSig,
72                                            [signal.SIGTERM])
73     self.mainloop.scheduler.cancel(handle)
74     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGCHLD])
75     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
76     self.mainloop.Run()
77     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGTERM])
78
79   def testRegisterSignal(self):
80     self.mainloop.RegisterSignal(self)
81     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGCHLD])
82     handle = self.mainloop.scheduler.enter(0.1, 1, self._SendSig,
83                                            [signal.SIGTERM])
84     self.mainloop.scheduler.cancel(handle)
85     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGCHLD])
86     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
87     # ...not delievered because they are scheduled after TERM
88     self.mainloop.scheduler.enter(0.4, 1, self._SendSig, [signal.SIGCHLD])
89     self.mainloop.scheduler.enter(0.5, 1, self._SendSig, [signal.SIGCHLD])
90     self.mainloop.Run()
91     self.assertEquals(self.sendsig_events,
92                       [signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM])
93     self.assertEquals(self.onsignal_events, self.sendsig_events)
94
95   def testDeferredCancel(self):
96     self.mainloop.RegisterSignal(self)
97     now = time.time()
98     self.mainloop.scheduler.enterabs(now + 0.1, 1, self._SendSig,
99                                      [signal.SIGCHLD])
100     handle1 = self.mainloop.scheduler.enterabs(now + 0.3, 2, self._SendSig,
101                                                [signal.SIGCHLD])
102     handle2 = self.mainloop.scheduler.enterabs(now + 0.4, 2, self._SendSig,
103                                                [signal.SIGCHLD])
104     self.mainloop.scheduler.enterabs(now + 0.2, 1, self._CancelEvent,
105                                      [handle1])
106     self.mainloop.scheduler.enterabs(now + 0.2, 1, self._CancelEvent,
107                                      [handle2])
108     self.mainloop.scheduler.enter(0.5, 1, self._SendSig, [signal.SIGTERM])
109     self.mainloop.Run()
110     self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGTERM])
111     self.assertEquals(self.onsignal_events, self.sendsig_events)
112
113   def testReRun(self):
114     self.mainloop.RegisterSignal(self)
115     self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGCHLD])
116     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGCHLD])
117     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
118     self.mainloop.scheduler.enter(0.4, 1, self._SendSig, [signal.SIGCHLD])
119     self.mainloop.scheduler.enter(0.5, 1, self._SendSig, [signal.SIGCHLD])
120     self.mainloop.Run()
121     self.assertEquals(self.sendsig_events,
122                       [signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM])
123     self.assertEquals(self.onsignal_events, self.sendsig_events)
124     self.mainloop.scheduler.enter(0.3, 1, self._SendSig, [signal.SIGTERM])
125     self.mainloop.Run()
126     self.assertEquals(self.sendsig_events,
127                       [signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM,
128                        signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM])
129     self.assertEquals(self.onsignal_events, self.sendsig_events)
130
131   def testPriority(self):
132     # for events at the same time, the highest priority one executes first
133     now = time.time()
134     self.mainloop.scheduler.enterabs(now + 0.1, 2, self._SendSig,
135                                      [signal.SIGCHLD])
136     self.mainloop.scheduler.enterabs(now + 0.1, 1, self._SendSig,
137                                      [signal.SIGTERM])
138     self.mainloop.Run()
139     self.assertEquals(self.sendsig_events, [signal.SIGTERM])
140     self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGTERM])
141     self.mainloop.Run()
142     self.assertEquals(self.sendsig_events,
143                       [signal.SIGTERM, signal.SIGCHLD, signal.SIGTERM])
144
145
146 class _MyAsyncUDPSocket(daemon.AsyncUDPSocket):
147
148   def __init__(self):
149     daemon.AsyncUDPSocket.__init__(self)
150     self.received = []
151     self.error_count = 0
152
153   def handle_datagram(self, payload, ip, port):
154     self.received.append((payload))
155     if payload == "terminate":
156       os.kill(os.getpid(), signal.SIGTERM)
157     elif payload == "error":
158       raise errors.GenericError("error")
159
160   def handle_error(self):
161     self.error_count += 1
162     raise
163
164
165 class TestAsyncUDPSocket(testutils.GanetiTestCase):
166   """Test daemon.AsyncUDPSocket"""
167
168   def setUp(self):
169     testutils.GanetiTestCase.setUp(self)
170     self.mainloop = daemon.Mainloop()
171     self.server = _MyAsyncUDPSocket()
172     self.client = _MyAsyncUDPSocket()
173     self.server.bind(("127.0.0.1", 0))
174     self.port = self.server.getsockname()[1]
175
176   def tearDown(self):
177     self.server.close()
178     self.client.close()
179     testutils.GanetiTestCase.tearDown(self)
180
181   def testNoDoubleBind(self):
182     self.assertRaises(socket.error, self.client.bind, ("127.0.0.1", self.port))
183
184   def _ThreadedClient(self, payload):
185     self.client.enqueue_send("127.0.0.1", self.port, payload)
186     print "sending %s" % payload
187     while self.client.writable():
188       self.client.handle_write()
189
190   def testAsyncClientServer(self):
191     self.client.enqueue_send("127.0.0.1", self.port, "p1")
192     self.client.enqueue_send("127.0.0.1", self.port, "p2")
193     self.client.enqueue_send("127.0.0.1", self.port, "terminate")
194     self.mainloop.Run()
195     self.assertEquals(self.server.received, ["p1", "p2", "terminate"])
196
197   def testSyncClientServer(self):
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.assertRaises(errors.GenericError, self.mainloop.Run)
220     self.assertEquals(self.server.received,
221                       ["p1", "p2", "error"])
222     self.assertEquals(self.server.error_count, 1)
223     self.assertRaises(errors.GenericError, self.mainloop.Run)
224     self.assertEquals(self.server.received,
225                       ["p1", "p2", "error", "p3", "error"])
226     self.assertEquals(self.server.error_count, 2)
227     self.mainloop.Run()
228     self.assertEquals(self.server.received,
229                       ["p1", "p2", "error", "p3", "error", "terminate"])
230     self.assertEquals(self.server.error_count, 2)
231
232
233 if __name__ == "__main__":
234   testutils.GanetiTestProgram()