4 # Copyright (C) 2010 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 daemon module"""
30 from ganeti import daemon
31 from ganeti import constants
32 from ganeti import utils
33 from ganeti import errors
38 class TestMainloop(testutils.GanetiTestCase):
39 """Test daemon.Mainloop"""
42 testutils.GanetiTestCase.setUp(self)
43 self.mainloop = daemon.Mainloop()
44 self.sendsig_events = []
45 self.onsignal_events = []
47 def _CancelEvent(self, handle):
48 self.mainloop.scheduler.cancel(handle)
50 def _SendSig(self, sig):
51 self.sendsig_events.append(sig)
52 os.kill(os.getpid(), sig)
54 def OnSignal(self, signum):
55 self.onsignal_events.append(signum)
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])
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])
66 self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGINT])
67 self.mainloop.scheduler.enter(0.1, 1, self._SendSig, [signal.SIGTERM])
69 self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGINT,
72 def testSchedulerCancel(self):
73 handle = self.mainloop.scheduler.enter(0.1, 1, self._SendSig,
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])
79 self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGTERM])
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,
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])
93 self.assertEquals(self.sendsig_events,
94 [signal.SIGCHLD, signal.SIGCHLD, signal.SIGTERM])
95 self.assertEquals(self.onsignal_events, self.sendsig_events)
97 def testDeferredCancel(self):
98 self.mainloop.RegisterSignal(self)
100 self.mainloop.scheduler.enterabs(now + 0.1, 1, self._SendSig,
102 handle1 = self.mainloop.scheduler.enterabs(now + 0.3, 2, self._SendSig,
104 handle2 = self.mainloop.scheduler.enterabs(now + 0.4, 2, self._SendSig,
106 self.mainloop.scheduler.enterabs(now + 0.2, 1, self._CancelEvent,
108 self.mainloop.scheduler.enterabs(now + 0.2, 1, self._CancelEvent,
110 self.mainloop.scheduler.enter(0.5, 1, self._SendSig, [signal.SIGTERM])
112 self.assertEquals(self.sendsig_events, [signal.SIGCHLD, signal.SIGTERM])
113 self.assertEquals(self.onsignal_events, self.sendsig_events)
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])
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])
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)
133 def testPriority(self):
134 # for events at the same time, the highest priority one executes first
136 self.mainloop.scheduler.enterabs(now + 0.1, 2, self._SendSig,
138 self.mainloop.scheduler.enterabs(now + 0.1, 1, self._SendSig,
141 self.assertEquals(self.sendsig_events, [signal.SIGTERM])
142 self.mainloop.scheduler.enter(0.2, 1, self._SendSig, [signal.SIGTERM])
144 self.assertEquals(self.sendsig_events,
145 [signal.SIGTERM, signal.SIGCHLD, signal.SIGTERM])
148 class _MyAsyncUDPSocket(daemon.AsyncUDPSocket):
151 daemon.AsyncUDPSocket.__init__(self)
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")
162 def handle_error(self):
163 self.error_count += 1
166 class TestAsyncUDPSocket(testutils.GanetiTestCase):
167 """Test daemon.AsyncUDPSocket"""
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
182 # ...and restore it as well
183 utils.IgnoreSignals = self.saved_utils_ignoresignals
184 testutils.GanetiTestCase.tearDown(self)
186 def testNoDoubleBind(self):
187 self.assertRaises(socket.error, self.client.bind, ("127.0.0.1", self.port))
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")
194 self.assertEquals(self.server.received, ["p1", "p2", "terminate"])
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"])
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")
220 self.assertEquals(self.server.received,
221 ["p1", "p2", "error", "p3", "error", "terminate"])
222 self.assertEquals(self.server.error_count, 2)
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
233 self.assertEquals(self.server.received, ["p1", "p2", "terminate"])
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)
241 if __name__ == "__main__":
242 testutils.GanetiTestProgram()