async def test_terminate_jobs(callback, mocker): ui = TUI() ui._jobs = { 'a': SimpleNamespace(job=Mock(is_started=False, is_finished=False, is_enabled=False, wait=AsyncMock())), 'b': SimpleNamespace(job=Mock(is_started=False, is_finished=False, is_enabled=True, wait=AsyncMock())), 'c': SimpleNamespace(job=Mock(is_started=False, is_finished=True, is_enabled=False, wait=AsyncMock())), 'd': SimpleNamespace(job=Mock(is_started=False, is_finished=True, is_enabled=True, wait=AsyncMock())), 'e': SimpleNamespace(job=Mock(is_started=True, is_finished=False, is_enabled=False, wait=AsyncMock())), 'f': SimpleNamespace(job=Mock(is_started=True, is_finished=False, is_enabled=True, wait=AsyncMock())), 'g': SimpleNamespace(job=Mock(is_started=True, is_finished=True, is_enabled=False, wait=AsyncMock())), 'h': SimpleNamespace(job=Mock(is_started=True, is_finished=True, is_enabled=True, wait=AsyncMock())), } mocker.patch.object(ui, '_finish_jobs', Mock()) await ui._terminate_jobs(callback=callback) assert ui._finish_jobs.call_args_list == [call()] assert ui._jobs['a'].job.wait.call_args_list == [] assert ui._jobs['b'].job.wait.call_args_list == [] assert ui._jobs['c'].job.wait.call_args_list == [] assert ui._jobs['d'].job.wait.call_args_list == [] assert ui._jobs['e'].job.wait.call_args_list == [] assert ui._jobs['f'].job.wait.call_args_list == [call()] assert ui._jobs['g'].job.wait.call_args_list == [] assert ui._jobs['h'].job.wait.call_args_list == [] if callback: assert callback.call_args_list == [call()]
async def test_get_exception_returns_None_if_no_exception_raised(): ui = TUI() ui._exception = None ui._jobs = { 'a': SimpleNamespace(job=Mock(raised=None, is_enabled=False)), 'b': SimpleNamespace(job=Mock(raised=None, is_enabled=False)), 'c': SimpleNamespace(job=Mock(raised=None, is_enabled=True)), 'd': SimpleNamespace(job=Mock(raised=None, is_enabled=True)), } assert ui._get_exception() is None
async def test_update_jobs_container_adds_all_jobs_it_if_one_job_has_errors( failed_job_name): ui = TUI() ui._jobs = { 'ai': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='aw')), 'bn': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=False), container=Mock(name='bw')), 'ci': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='cw')), 'dn': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=False), container=Mock(name='dw')), 'ei': SimpleNamespace(job=Mock(is_enabled=False, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='ew')), 'fn': SimpleNamespace(job=Mock(is_enabled=False, is_finished=False, errors=()), widget=Mock(is_interactive=False), container=Mock(name='fw')), 'gi': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='gw')), } ui._jobs[failed_job_name].job.errors = ('Some error message', ) ui._layout = Mock() jobs_container_id = id(ui._jobs_container) def assert_jobs_container(*keys, focused): ui._update_jobs_container() assert id(ui._jobs_container) == jobs_container_id containers = [ui._jobs[k].container for k in keys] assert ui._jobs_container.children == containers assert_jobs_container('ai', 'ci', 'gi', 'bn', 'dn', focused='ai')
async def test_finish_jobs(): ui = TUI() ui._jobs = { 'a': SimpleNamespace(job=Mock(is_finished=False, is_enabled=False)), 'b': SimpleNamespace(job=Mock(is_finished=True, is_enabled=False)), 'c': SimpleNamespace(job=Mock(is_finished=False, is_enabled=True)), 'd': SimpleNamespace(job=Mock(is_finished=True, is_enabled=True)), } ui._finish_jobs() assert ui._jobs['a'].job.finish.call_args_list == [] assert ui._jobs['b'].job.finish.call_args_list == [] assert ui._jobs['c'].job.finish.call_args_list == [call()] assert ui._jobs['d'].job.finish.call_args_list == []
async def test_run_returns_zero_if_all_jobs_finished_successfully(mocker): ui = TUI() ui._jobs = { 'a': SimpleNamespace(job=Mock(exit_code=0)), 'b': SimpleNamespace(job=Mock(exit_code=0)), 'c': SimpleNamespace(job=Mock(exit_code=0)), 'd': SimpleNamespace(job=Mock(exit_code=0)), } mocker.patch.object(ui, 'add_jobs') mocker.patch.object(ui._app, 'run') mocker.patch.object(ui, '_get_exception', Mock(return_value=None)) exit_code = ui.run(('a', 'b', 'c')) assert exit_code == 0
async def test_run_returns_first_nonzero_job_exit_code(mocker): ui = TUI() ui._jobs = { 'a': SimpleNamespace(job=Mock(exit_code=0)), 'b': SimpleNamespace(job=Mock(exit_code=1)), 'c': SimpleNamespace(job=Mock(exit_code=2)), 'd': SimpleNamespace(job=Mock(exit_code=3)), } mocker.patch.object(ui, 'add_jobs') mocker.patch.object(ui._app, 'run') mocker.patch.object(ui, '_get_exception', Mock(return_value=None)) exit_code = ui.run(('a', 'b', 'c')) assert exit_code == 1
async def test_get_exception_from_first_failed_enabled_job(): ui = TUI() ui._exception = None ui._jobs = { 'a': SimpleNamespace(job=Mock(raised=ValueError('foo'), is_enabled=False)), 'b': SimpleNamespace(job=Mock(raised=None, is_enabled=False)), 'c': SimpleNamespace(job=Mock(raised=ValueError('bar'), is_enabled=True)), 'd': SimpleNamespace(job=Mock(raised=None, is_enabled=True)), } exc = ui._get_exception() assert isinstance(exc, ValueError) assert str(exc) == 'bar'
async def test_exit_if_all_jobs_finished(mocker): ui = TUI() ui._jobs = { 'a': SimpleNamespace(job=Mock(is_finished=False)), 'b': SimpleNamespace(job=Mock(is_finished=False)), 'c': SimpleNamespace(job=Mock(is_finished=False)), 'd': SimpleNamespace(job=Mock(is_finished=False)), } mocker.patch.object(ui, '_exit') for job_name in ('a', 'b', 'c', 'd'): ui._exit_if_all_jobs_finished() assert ui._exit.call_args_list == [] ui._exit_if_all_jobs_finished('mock job instance') assert ui._exit.call_args_list == [] ui._jobs[job_name].job.is_finished = True ui._exit_if_all_jobs_finished() assert ui._exit.call_args_list == [call()]
async def test_update_jobs_container_sorts_interactive_jobs_above_background_jobs( ): ui = TUI() ui._jobs = { 'a': SimpleNamespace(job=Mock(is_enabled=True), widget=Mock(is_interactive=True), container=Mock()), 'b': SimpleNamespace(job=Mock(is_enabled=True), widget=Mock(is_interactive=False), container=Mock()), 'c': SimpleNamespace(job=Mock(is_enabled=True), widget=Mock(is_interactive=True), container=Mock()), 'd': SimpleNamespace(job=Mock(is_enabled=True), widget=Mock(is_interactive=False), container=Mock()), 'e': SimpleNamespace(job=Mock(is_enabled=False), widget=Mock(is_interactive=True), container=Mock()), 'f': SimpleNamespace(job=Mock(is_enabled=False), widget=Mock(is_interactive=False), container=Mock()), } ui._update_jobs_container() assert ui._jobs_container.children == [ ui._jobs['a'].container, ui._jobs['c'].container, ui._jobs['b'].container, ui._jobs['d'].container, ]
async def test_update_jobs_container_only_adds_first_unfinished_job_and_focuses_it_if_no_job_has_errors( ): ui = TUI() ui._jobs = { 'ai': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='aw')), 'bn': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=False), container=Mock(name='bw')), 'ci': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='cw')), 'dn': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=False), container=Mock(name='dw')), 'ei': SimpleNamespace(job=Mock(is_enabled=False, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='ew')), 'fn': SimpleNamespace(job=Mock(is_enabled=False, is_finished=False, errors=()), widget=Mock(is_interactive=False), container=Mock(name='fw')), 'gi': SimpleNamespace(job=Mock(is_enabled=True, is_finished=False, errors=()), widget=Mock(is_interactive=True), container=Mock(name='gw')), } ui._layout = Mock() jobs_container_id = id(ui._jobs_container) def assert_jobs_container(*keys, focused): ui._update_jobs_container() assert id(ui._jobs_container) == jobs_container_id containers = [ui._jobs[k].container for k in keys] assert ui._jobs_container.children == containers assert ui._layout.focus.call_args_list[-1] == call( ui._jobs[focused].container) assert_jobs_container('ai', 'bn', 'dn', focused='ai') ui._jobs['ai'].job.is_finished = True assert_jobs_container('ai', 'ci', 'bn', 'dn', focused='ci') ui._jobs['bn'].job.is_finished = True assert_jobs_container('ai', 'ci', 'bn', 'dn', focused='ci') ui._jobs['dn'].job.is_finished = True assert_jobs_container('ai', 'ci', 'bn', 'dn', focused='ci') ui._jobs['ci'].job.is_finished = True assert_jobs_container('ai', 'ci', 'gi', 'bn', 'dn', focused='gi')