def test_gen_object_child_parent_waits_2nd(self): child_gen_object = self._fast_child() parent = self._parent(child_gen_object) success, result = run(parent) self.assertTrue(success) self._assert_parent_result(child_gen_object, result)
def test_child_task_spawns_and_is_destroyed(self): async def child(): window = await api.window_create(0, 0, 80, 25) args = _sleeper_process_args(42) process = await api.process_spawn(window, args) await api.message_send(None, process) _ = await api.process_wait() async def parent(): child_task = child() await api.task_spawn(child_task) _, process = await api.message_wait() # Sleep to ensure child gets to `api.process_wait`. await api.sleep(0.001) await api.task_destroy(child_task) _ = await api.task_wait() return child_task, process # Calling it ourselves such that repr(task) can be found in the log. task = parent() success, result = run(task) child_task, process = result # Task should have succeeded. self.assertTrue(success, f'non-success result: {process!r}') # Child process should have been left running, clean it up when done. self.addCleanup(lambda: process.terminate()) self._assert_process_running_and_message_logged(process, child_task)
def test_running_plain_task_raises_not_implemented(self): task = Task() success, result = run(task) self.assertFalse(success, 'should not have succeeded') self.assertIsInstance(result, NotImplementedError)
def test_put_key(self): async def first_reader_child(): byte_key = await api.key_read() await api.key_unread(byte_key) await api.sleep(42) async def second_reader_child(): byte_key = await api.key_read() return byte_key async def parent(first_reader, second_reader): all_tasks = {first_reader, second_reader} await api.task_spawn(first_reader) await api.task_spawn(second_reader) await api.sleep(1) self.input_control.feed_data(b't') completed_task, child_success, child_result = await api.task_wait() all_tasks.remove(completed_task) other_task = all_tasks.pop() await api.task_destroy(other_task) destroyed_task, _, _ = await api.task_wait() return completed_task, child_success, child_result, destroyed_task success, result = run(parent(first_reader_child, second_reader_child)) self.assertTrue(success) completed_task, child_success, child_result, destroyed_task = result self.assertIs(completed_task, second_reader_child) self.assertTrue(child_success) self.assertEqual(child_result, b't') self.assertIs(destroyed_task, first_reader_child)
def _test_spawn_child_then_destroy(self, running): async def child(): await api.sleep(42) async def parent(child_task): await api.task_spawn(child_task) await api.task_destroy(child_task) completed_task, child_success, child_result = await api.task_wait() return completed_task, child_success, child_result # Time starts at 0. self.assertEqual(self.auto_time.monotonic, 0) child_task = child() if running else child parent_task = parent(child_task) success, result = run(parent_task) self.assertTrue(success) completed_task, child_success, child_result = result self.assertIs(completed_task, child_task) self.assertFalse(child_success) self.assertIsInstance(child_result, TrapDestroyed) self.assertEqual(len(child_result.args), 1) self.assertIs(child_result.args[0], parent_task) # Time hasn't passed. self.assertEqual(self.auto_time.monotonic, 0)
def test_task_termination_forces_all_other_windows_render(self): async def child(): w = await api.window_create(40, 0, 30, 10) await api.window_render(w) await api.message_send(None, 'child-rendered') await api.message_wait() async def parent(): # setup our window w = await api.window_create(0, 0, 30, 10) w.print('parent-window-frst-line', 0, 0) w.print('parent-window-last-line', 0, 9) await api.window_render(w) # child will create a window and let parent know when it's rendered await api.task_spawn(child) await api.message_wait() # reset os written bytes and send message so that child terminates self.reset_os_written_bytes() await api.message_send(child, 'you-can-terminate') await api.task_wait() # caller will assert that os written bytes include our window return self.get_os_written_bytes() success, written_bytes = run(parent) self.assertTrue(success) self.assertIn(b'parent-window-frst-line', written_bytes) self.assertIn(b'parent-window-last-line', written_bytes)
def test_gen_function_child_parent_waits_2nd(self): child_gen_function = self._fast_child parent = self._parent(child_gen_function) success, result = run(parent) self.assertTrue(success) self._assert_parent_result(child_gen_function, result)
def test_sleep(self): for sleep_time in (0, 0.5, 1, 10, -1): with self.subTest(sleep_time=sleep_time): task = self._sleeper(sleep_time) success, result = run(task) self.assertTrue(success) self.assertIsNone(result)
def test_spawn_sigusr1_wait(self): task = self._signal_test_task(lambda p: p.signal(signal.SIGUSR1)) success, completed_process = run(task) self.assertTrue(success, f'non-success result: {completed_process!r}') self.assertEqual(completed_process.exit_signal, signal.SIGUSR1) self.assertEqual(completed_process.exit_code, 0)
def test_wait_child_success(self): task = tasks.spawn_wait(tasks.sleep_zero_return_42_idiv_arg(42)) parent_sucess, parent_result = run(task) self.assertTrue(parent_sucess) _completed_child, child_success, child_result = parent_result self.assertTrue(child_success) self.assertEqual(child_result, 1)
def test_spawn_terminate_wait(self): task = self._signal_test_task(lambda p: p.terminate()) success, completed_process = run(task) self.assertTrue(success, f'non-success result: {completed_process!r}') self.assertEqual(completed_process.exit_signal, signal.SIGTERM) self.assertEqual(completed_process.exit_code, 0)
def test_wait_child_exception(self): task = tasks.spawn_wait(tasks.sleep_zero_return_42_idiv_arg(0)) parent_success, parent_result = run(task) self.assertTrue(parent_success) _completed_child, child_success, child_result = parent_result self.assertFalse(child_success) self.assertIsInstance(child_result, ZeroDivisionError)
def test_parent_spawn_message_wait_child_message_send(self): # child_sleeps_first: child message-send AFTER parent message-wait parent_task = self._parent(child_sleeps_first=True) success, result = run(parent_task) self.assertTrue(success) self._assert_child_to_parent_message_result(result, parent_task)
def test_spawn_wait_process_ends(self): success, result = run(self._spawn_sleep_wait(0, 0.1)) self.assertTrue(success) spawned_process, completed_process = result self.assertIs(spawned_process, completed_process) self.assertEqual(completed_process.exit_code, 42) self.assertEqual(completed_process.exit_signal, 0)
def test_window_create_and_destroy(self): async def task(): w = await api.window_create(0, 0, 40, 20) await api.window_destroy(w) success, result = run(task) self.assertTrue(success) self.assertIsNone(result)
def test_spawn_wait_gen_object_child_completes_2nd(self): generator_object = tasks.sleep_zero() task = tasks.spawn_wait(generator_object, sleep_before_wait=True) success, result = run(task) self.assertTrue(success) completed_child, child_success, child_result = result self.assertIs(completed_child, generator_object) self.assertTrue(child_success) self.assertIsNone(child_result)
def parent_spawn_wait_child_exception(self, child_task, expected_exc_class): success, result = run(tasks.spawn_wait(child_task)) self.assertTrue(success) completed_child, child_task_success, child_task_result = result self.assertIs(completed_child, child_task) self.assertFalse(child_task_success) self.assertIsInstance(child_task_result, expected_exc_class) return child_task_result
def test_task_catches_non_existing_trap_exception(self): def task(): try: yield ('this-trap-does-not-exist', ) except TrapDoesNotExist: pass success, result = run(task) self.assertTrue(success) self.assertIsNone(result)
def test_task_catches_wrong_trap_arg_count_exception(self): def task(): try: yield (api.Trap.SLEEP, 1, 2, 3) except TrapArgCountWrong: pass success, result = run(task) self.assertTrue(success) self.assertIsNone(result)
def test_spawn_wait_gen_function_child_completes_1st(self): generator_function = tasks.sleep_zero task = tasks.spawn_wait(generator_function) success, result = run(task) self.assertTrue(success) completed_child, child_success, child_result = result self.assertIs(completed_child, generator_function) self.assertTrue(child_success) self.assertIsNone(child_result)
def test_kernel_run_stops_with_ctrl_f_dot_input(self): async def task(): self.input_control.feed_data(b'\x06.') while True: await api.sleep(42) success, result = run(task) self.assertIsNone(success) self.assertIsInstance(result, loop._ForcedStop)
def test_tasks_are_runnable(self): class SleepZero(Task): async def run(self): await api.sleep(0) task = SleepZero() success, result = run(task) self.assertTrue(success, 'should have succeeded') self.assertEqual(result, None)
def test_window_create_returns_a_window(self): async def task(): w = await api.window_create(0, 0, 40, 20) is_window_instance = isinstance(w, window.Window) return is_window_instance success, result = run(task) self.assertTrue(success) self.assertTrue(result, 'window-create returned non-Window object')
def test_non_existing_trap_raises_exception(self): def task(): yield ('no-such-trap', ) success, result = run(task) self.assertFalse(success) self.assertIsInstance(result, TrapDoesNotExist) exception_args = result.args self.assertEqual(len(exception_args), 1) # Exception "message" should include the trap name. self.assertIn('no-such-trap', exception_args[0])
def test_top_task_message_parent_fails(self): async def top_task(): await api.message_send(None, 'goes-nowhere') success, result = run(top_task) self.assertFalse(success) self.assertIsInstance(result, TrapException) self.assertGreaterEqual(len(result.args), 1) self.assertIn('parent', result.args[0])
def test_window_render_raises_with_bad_argument(self): async def task(): non_window_object = 42 await api.window_render(non_window_object) success, result = run(task) self.assertFalse(success) self.assertIsInstance(result, TrapException) # "window" somewhere inside the exceptions "message" self.assertIn('window', result.args[0])
def test_read_key(self): async def task(): result = await api.key_read() return result self.input_control.feed_data(b'x') success, result = run(task) self.assertTrue(success) self.assertEqual(result, b'x')
def test_wrong_trap_arg_count_raises_exception(self): def task(): yield (api.Trap.SLEEP, ) success, result = run(task) self.assertFalse(success) self.assertIsInstance(result, TrapArgCountWrong) exception_args = result.args self.assertEqual(len(exception_args), 1) # Exception "message" should include 'argument', somehow. self.assertIn('argument', exception_args[0])
def test_kernel_run_does_not_stop_with_ctrl_f_and_something_else(self): async def task(): await api.sleep(42) return 'confirming-regular-completion' self.input_control.feed_data(b'\x06x') success, result = run(task) self.assertTrue(success) self.assertNotIsInstance(result, loop._ForcedStop) self.assertEqual(result, 'confirming-regular-completion')
def test_parent_spawn_crash_no_child_wait_parent_completes_1st(self): async def child(): await api.sleep(0) return 42 async def parent(): child_task = child() await api.task_spawn(child_task) raise RuntimeError('parent crashing before child task-wait') success, result = run(parent) self.assertFalse(success) self.assertIsInstance(result, RuntimeError)