def test_cleanup(self): runner = ProcRunner(TEST_CMD) runner.start() rospy.sleep(GRACE_DELAY) runner_ref = weakref.ref(runner) proc_ref = weakref.ref(runner.proc) runner.shutdown() rospy.sleep(GRACE_DELAY) gc.collect() self.assertIsNone(proc_ref(), 'proc must be freed on shutdown') runner = None gc.collect() self.assertIsNone(runner_ref(), 'runner must be freed post-delete')
class TestProcRunner(unittest.TestCase): def setUp(self): self.runner = ProcRunner(TEST_CMD) def tearDown(self): self.runner.shutdown() if self.runner.is_alive(): self.runner.join() def test_startup(self): self.runner.start() self.assertTrue(self.runner.is_alive(), 'Runner must be alive after start()') def test_shutdown(self): self.runner.start() rospy.sleep(GRACE_DELAY) pid = self.runner.proc.pid self.assertIsNotNone(pid, 'Must get a pid after start()') self.runner.shutdown() self.runner.join() self.assertFalse(check_pid(pid), 'Process must not respond to sig0 after shutdown()') def test_kill_proc(self): self.runner.start() rospy.sleep(GRACE_DELAY) pid = self.runner.proc.pid self.assertTrue(check_pid(pid), 'Must have a pid to start with') self.runner._kill_proc() self.assertFalse(check_pid(pid), 'Process must be dead') def test_respawn(self): self.runner.start() rospy.sleep(GRACE_DELAY) first_pid = self.runner.proc.pid self.runner._kill_proc() rospy.sleep(self.runner.respawn_delay + GRACE_DELAY) second_pid = self.runner.proc.pid self.assertNotEqual(first_pid, second_pid, 'Must have a different pid after respawn') self.assertTrue(check_pid(second_pid), 'Must be alive after respawn') def test_not_respawn(self): """ Test the respawn flag. respawn is True by default, this test cases aims at not respawning the managed process. """ self.runner = ProcRunner(TEST_CMD, respawn=False) self.runner.start() rospy.sleep(GRACE_DELAY) pid = self.runner.proc.pid self.runner._kill_proc() rospy.sleep(self.runner.respawn_delay + GRACE_DELAY) # we want, after the kill, there be no process self.assertFalse(check_pid(pid), 'Must be dead, was killed.') # can't do more tests the subprocess instance, it's been set None self.assertEqual(self.runner.proc, None) def test_spawn_handler(self): """ Spawn handlers must be run on each spawn. """ mock_handler = MockSpawnHandler() self.runner.add_spawn_hook(mock_handler) self.runner.start() rospy.sleep(GRACE_DELAY) self.assertEqual(mock_handler.spawns, 1, 'Invalid number of spawn handler calls so far') self.runner._kill_proc() rospy.sleep(self.runner.respawn_delay + GRACE_DELAY) self.assertEqual(mock_handler.spawns, 2, 'Invalid number of spawn handler calls so far') def test_broken_spawn_handler(self): """ Broken spawn handlers must not wreck the thread. """ mock_handler = MockBrokenSpawnHandler() self.runner.add_spawn_hook(mock_handler) self.test_spawn_handler() def test_invalid_spawn_handler(self): """ Invalid spawn handlers must raise a TypeError when added. """ invalid_hook = MockInvalidSpawnHandler() with self.assertRaises(TypeError): self.runner.add_spawn_hook(invalid_hook)