268
268
def test_child_connection_timeout(self):
269
269
self.assertEqual(self.service.CHILD_CONNECT_TIMEOUT,
270
270
self.service._child_connect_timeout)
271
response = self.send_message_to_service('child_connect_timeout 1.0\n')
271
response = self.send_message_to_service('child_connect_timeout 1\n')
272
272
self.assertEqual('ok\n', response)
273
self.assertEqual(1.0, self.service._child_connect_timeout)
273
self.assertEqual(1, self.service._child_connect_timeout)
275
def test_child_connection_timeout_bad_float(self):
276
self.assertEqual(self.service.CHILD_CONNECT_TIMEOUT,
277
self.service._child_connect_timeout)
278
response = self.send_message_to_service('child_connect_timeout 1.2\n')
279
self.assertStartsWith(response, 'FAILURE:')
275
281
def test_child_connection_timeout_no_val(self):
276
282
response = self.send_message_to_service('child_connect_timeout \n')
281
287
self.assertStartsWith(response, 'FAILURE:')
283
289
def test__open_handles_will_timeout(self):
284
self.service._child_connect_timeout = 0.1
290
# signal.alarm() has only 1-second granularity. :(
291
self.service._child_connect_timeout = 1
285
292
tempdir = tempfile.mkdtemp(prefix='testlpserve-')
286
293
self.addCleanup(shutil.rmtree, tempdir, ignore_errors=True)
287
294
os.mkfifo(os.path.join(tempdir, 'stdin'))
288
295
os.mkfifo(os.path.join(tempdir, 'stdout'))
289
296
os.mkfifo(os.path.join(tempdir, 'stderr'))
297
def noop_on_alarm(signal, frame):
299
signal.signal(signal.SIGALRM, noop_on_alarm)
300
self.addCleanup(signal.signal, signal.SIGALRM, signal.SIG_DFL)
290
301
e = self.assertRaises(errors.BzrError,
291
302
self.service._open_handles, tempdir)
292
303
self.assertContainsRe(str(e), r'After \d+.\d+s we failed to open.*')
593
604
# We won't ever bind to the socket the child wants, and after some
594
605
# time, the child should exit cleanly.
595
606
# First, tell the subprocess that we want children to exit quickly.
596
response = self.send_message_to_service('child_connect_timeout 0.05\n')
607
# *sigh* signal.alarm only has 1s resolution, so this test is slow.
608
response = self.send_message_to_service('child_connect_timeout 1\n')
597
609
self.assertEqual('ok\n', response)
598
610
# Now request a fork
599
611
path, pid, sock = self.send_fork_request('rocks')
602
614
stdout_path = os.path.join(path, 'stdout')
603
615
stderr_path = os.path.join(path, 'stderr')
604
616
child_stdin = open(stdin_path, 'wb')
605
# # I hate adding time.sleep here, but I don't see a better way, yet
607
if not os.path.exists(path):
611
self.fail('Child process failed to cleanup after timeout.')
617
# We started opening the child, but stop before we get all handles
618
# open. After 1 second, the child should get signaled and die.
619
# The master process should notice, and tell us the status of the
621
val = sock.recv(4096)
622
self.assertEqual('exited\n%s\n' % (signal.SIGALRM,), val)
623
# The master process should clean up after the now deceased child.
624
self.failIfExists(path)
614
627
class TestCaseWithLPForkingServiceDaemon(
733
746
# We're done, shut it down
734
747
self.stop_service()
735
748
self.failIf(os.path.isfile(self.service_pid_filename))
738
class Test_WakeUp(tests.TestCaseInTempDir):
740
def test_wakeup_interrupts_fifo_open(self):
741
os.mkfifo('test-fifo')
742
self.addCleanup(os.remove, 'test-fifo')
743
cancel, t = lpserve._wake_me_up_in_a_few(0.01)
744
e = self.assertRaises(OSError, os.open, 'test-fifo', os.O_RDONLY)
745
self.assertEqual(errno.EINTR, e.errno)
748
def test_custom_callback_called(self):
750
def _sigusr1_called(sig, frame):
752
signal.signal(signal.SIGUSR1, signal.SIG_DFL)
753
cancel, t = lpserve._wake_me_up_in_a_few(0.01, _sigusr1_called)
755
self.assertEqual([signal.SIGUSR1], called)
758
def test_cancel_aborts_interrupt(self):
760
def _sigusr1_called(sig, frame):
761
called.append(sig, frame)
762
cancel, t = lpserve._wake_me_up_in_a_few(0.01)
765
# The signal should not have been fired, and we should have reset the
767
self.assertEqual([], called)
768
self.assertEqual(signal.SIG_DFL,
769
signal.signal(signal.SIGUSR1, signal.SIG_DFL))
770
# Should have already been joined in cancel()