class TestActionRun(TestCase): @setup def setup_action_run(self): self.output_path = filehandler.OutputPath(tempfile.mkdtemp()) self.action_runner = actioncommand.NoActionRunnerFactory() self.command = "do command {actionname}" self.rendered_command = "do command action_name" self.action_run = ActionRun( job_run_id="ns.id.0", name="action_name", node=mock.create_autospec(node.Node), bare_command=self.command, output_path=self.output_path, action_runner=self.action_runner, ) # These should be implemented in subclasses, we don't care here self.action_run.submit_command = mock.Mock() self.action_run.stop = mock.Mock() self.action_run.kill = mock.Mock() def test_init_state(self): assert_equal(self.action_run.state, ActionRun.SCHEDULED) def test_start(self): self.action_run.machine.transition('ready') assert self.action_run.start() assert_equal(self.action_run.submit_command.call_count, 1) assert self.action_run.is_starting assert self.action_run.start_time def test_start_bad_state(self): self.action_run.fail() assert not self.action_run.start() @mock.patch('tron.core.actionrun.log', autospec=True) def test_start_invalid_command(self, _log): self.action_run.bare_command = "{notfound}" self.action_run.machine.transition('ready') assert not self.action_run.start() assert self.action_run.is_failed assert_equal(self.action_run.exit_status, -1) def test_success(self): assert self.action_run.ready() self.action_run.machine.transition('start') self.action_run.machine.transition('started') assert self.action_run.is_running assert self.action_run.success() assert not self.action_run.is_running assert self.action_run.is_done assert self.action_run.end_time assert_equal(self.action_run.exit_status, 0) def test_success_emits_not(self): self.action_run.machine.transition('start') self.action_run.machine.transition('started') self.action_run.trigger_downstreams = None self.action_run.emit_triggers = mock.Mock() assert self.action_run.success() assert self.action_run.emit_triggers.call_count == 0 def test_success_emits_on_true(self): self.action_run.machine.transition('start') self.action_run.machine.transition('started') self.action_run.trigger_downstreams = True self.action_run.emit_triggers = mock.Mock() assert self.action_run.success() assert self.action_run.emit_triggers.call_count == 1 def test_success_emits_on_dict(self): self.action_run.machine.transition('start') self.action_run.machine.transition('started') self.action_run.trigger_downstreams = dict(foo="bar") self.action_run.emit_triggers = mock.Mock() assert self.action_run.success() assert self.action_run.emit_triggers.call_count == 1 @mock.patch('tron.core.actionrun.EventBus') def test_emit_triggers(self, eventbus): self.action_run.context = {'shortdate': 'foo'} self.action_run.trigger_downstreams = True self.action_run.emit_triggers() self.action_run.trigger_downstreams = dict(foo="bar") self.action_run.emit_triggers() assert eventbus.publish.mock_calls == [ mock.call(f"ns.id.action_name.shortdate.foo"), mock.call(f"ns.id.action_name.foo.bar"), ] def test_success_bad_state(self): self.action_run.cancel() assert not self.action_run.success() def test_failure(self): self.action_run._exit_unsuccessful(1) assert not self.action_run.is_running assert self.action_run.is_done assert self.action_run.end_time assert_equal(self.action_run.exit_status, 1) def test_failure_bad_state(self): self.action_run.fail(444) assert not self.action_run.fail(123) assert_equal(self.action_run.exit_status, 444) def test_skip(self): assert not self.action_run.is_running self.action_run.ready() assert self.action_run.start() assert self.action_run.fail(-1) assert self.action_run.skip() assert self.action_run.is_skipped def test_skip_bad_state(self): assert not self.action_run.skip() def test_state_data(self): state_data = self.action_run.state_data assert_equal(state_data['command'], self.action_run.bare_command) assert not self.action_run.rendered_command assert not state_data['rendered_command'] def test_state_data_after_rendered(self): command = self.action_run.command state_data = self.action_run.state_data assert_equal(state_data['command'], command) assert_equal(state_data['rendered_command'], command) def test_render_command(self): self.action_run.context = {'stars': 'bright'} self.action_run.bare_command = "{stars}" assert_equal(self.action_run.render_command(), 'bright') def test_command_not_yet_rendered(self): assert_equal(self.action_run.command, self.rendered_command) def test_command_already_rendered(self): assert self.action_run.command self.action_run.bare_command = "new command" assert_equal(self.action_run.command, self.rendered_command) @mock.patch('tron.core.actionrun.log', autospec=True) def test_command_failed_render(self, _log): self.action_run.bare_command = "{this_is_missing}" assert_equal(self.action_run.command, ActionRun.FAILED_RENDER) def test_is_complete(self): self.action_run.machine.state = ActionRun.SUCCEEDED assert self.action_run.is_complete self.action_run.machine.state = ActionRun.SKIPPED assert self.action_run.is_complete self.action_run.machine.state = ActionRun.RUNNING assert not self.action_run.is_complete def test_is_broken(self): self.action_run.machine.state = ActionRun.UNKNOWN assert self.action_run.is_broken self.action_run.machine.state = ActionRun.FAILED assert self.action_run.is_broken self.action_run.machine.state = ActionRun.QUEUED assert not self.action_run.is_broken def test__getattr__(self): assert not self.action_run.is_succeeded assert not self.action_run.is_failed assert not self.action_run.is_queued assert self.action_run.is_scheduled assert self.action_run.cancel() assert self.action_run.is_cancelled def test__getattr__missing_attribute(self): assert_raises( AttributeError, self.action_run.__getattr__, 'is_not_a_real_state', )
class ActionRunTestCase(TestCase): @setup def setup_action_run(self): self.output_path = filehandler.OutputPath(tempfile.mkdtemp()) self.action_runner = mock.create_autospec( actioncommand.NoActionRunnerFactory) self.command = "do command %(actionname)s" self.rendered_command = "do command action_name" self.action_run = ActionRun( "id", "action_name", mock.create_autospec(node.Node), self.command, output_path=self.output_path, action_runner=self.action_runner) @teardown def teardown_action_run(self): shutil.rmtree(self.output_path.base, ignore_errors=True) def test_init_state(self): assert_equal(self.action_run.state, ActionRun.STATE_SCHEDULED) def test_start(self): self.action_run.machine.transition('ready') assert self.action_run.start() assert self.action_run.is_starting assert self.action_run.start_time def test_start_bad_state(self): self.action_run.fail() assert not self.action_run.start() def test_start_invalid_command(self): self.action_run.bare_command = "%(notfound)s" self.action_run.machine.transition('ready') assert not self.action_run.start() assert self.action_run.is_failed assert_equal(self.action_run.exit_status, -1) def test_start_node_error(self): def raise_error(c): raise node.Error("The error") self.action_run.node = turtle.Turtle(submit_command=raise_error) self.action_run.machine.transition('ready') assert not self.action_run.start() assert_equal(self.action_run.exit_status, -2) assert self.action_run.is_failed @mock.patch('tron.core.actionrun.filehandler', autospec=True) def test_build_action_command(self, mock_filehandler): autospec_method(self.action_run.watch) serializer = mock_filehandler.OutputStreamSerializer.return_value action_command = self.action_run.build_action_command() assert_equal(action_command, self.action_run.action_command) assert_equal(action_command, self.action_runner.create.return_value) self.action_runner.create.assert_called_with( self.action_run.id, self.action_run.command, serializer) mock_filehandler.OutputStreamSerializer.assert_called_with( self.action_run.output_path) self.action_run.watch.assert_called_with(action_command) def test_handler_running(self): self.action_run.build_action_command() self.action_run.machine.transition('start') assert self.action_run.handler( self.action_run.action_command, ActionCommand.RUNNING) assert self.action_run.is_running def test_handler_failstart(self): self.action_run.build_action_command() assert self.action_run.handler( self.action_run.action_command, ActionCommand.FAILSTART) assert self.action_run.is_failed def test_handler_exiting_fail(self): self.action_run.build_action_command() self.action_run.action_command.exit_status = -1 self.action_run.machine.transition('start') assert self.action_run.handler( self.action_run.action_command, ActionCommand.EXITING) assert self.action_run.is_failed assert_equal(self.action_run.exit_status, -1) def test_handler_exiting_success(self): self.action_run.build_action_command() self.action_run.action_command.exit_status = 0 self.action_run.machine.transition('start') self.action_run.machine.transition('started') assert self.action_run.handler( self.action_run.action_command, ActionCommand.EXITING) assert self.action_run.is_succeeded assert_equal(self.action_run.exit_status, 0) def test_handler_exiting_failunknown(self): self.action_run.action_command = mock.create_autospec( actioncommand.ActionCommand, exit_status=None) self.action_run.machine.transition('start') self.action_run.machine.transition('started') assert self.action_run.handler( self.action_run.action_command, ActionCommand.EXITING) assert self.action_run.is_unknown assert_equal(self.action_run.exit_status, None) def test_handler_unhandled(self): self.action_run.build_action_command() assert self.action_run.handler( self.action_run.action_command, ActionCommand.PENDING) is None assert self.action_run.is_scheduled def test_success(self): assert self.action_run.ready() self.action_run.machine.transition('start') self.action_run.machine.transition('started') assert self.action_run.is_running assert self.action_run.success() assert not self.action_run.is_running assert self.action_run.is_done assert self.action_run.end_time assert_equal(self.action_run.exit_status, 0) def test_success_bad_state(self): self.action_run.cancel() assert not self.action_run.success() def test_failure(self): self.action_run.fail(1) assert not self.action_run.is_running assert self.action_run.is_done assert self.action_run.end_time assert_equal(self.action_run.exit_status, 1) def test_failure_bad_state(self): self.action_run.fail(444) assert not self.action_run.fail(123) assert_equal(self.action_run.exit_status, 444) def test_skip(self): assert not self.action_run.is_running self.action_run.ready() assert self.action_run.start() assert self.action_run.fail(-1) assert self.action_run.skip() assert self.action_run.is_skipped def test_skip_bad_state(self): assert not self.action_run.skip() def test_state_data(self): state_data = self.action_run.state_data assert_equal(state_data['command'], self.action_run.bare_command) assert not self.action_run.rendered_command assert not state_data['rendered_command'] def test_state_data_after_rendered(self): command = self.action_run.command state_data = self.action_run.state_data assert_equal(state_data['command'], command) assert_equal(state_data['rendered_command'], command) def test_render_command(self): self.action_run.context = {'stars': 'bright'} self.action_run.bare_command = "%(stars)s" assert_equal(self.action_run.render_command(), 'bright') def test_command_not_yet_rendered(self): assert_equal(self.action_run.command, self.rendered_command) def test_command_already_rendered(self): assert self.action_run.command self.action_run.bare_command = "new command" assert_equal(self.action_run.command, self.rendered_command) def test_command_failed_render(self): self.action_run.bare_command = "%(this_is_missing)s" assert_equal(self.action_run.command, ActionRun.FAILED_RENDER) def test_is_complete(self): self.action_run.machine.state = ActionRun.STATE_SUCCEEDED assert self.action_run.is_complete self.action_run.machine.state = ActionRun.STATE_SKIPPED assert self.action_run.is_complete self.action_run.machine.state = ActionRun.STATE_RUNNING assert not self.action_run.is_complete def test_is_broken(self): self.action_run.machine.state = ActionRun.STATE_UNKNOWN assert self.action_run.is_broken self.action_run.machine.state = ActionRun.STATE_FAILED assert self.action_run.is_broken self.action_run.machine.state = ActionRun.STATE_QUEUED assert not self.action_run.is_broken def test__getattr__(self): assert not self.action_run.is_succeeded assert not self.action_run.is_failed assert not self.action_run.is_queued assert self.action_run.is_scheduled assert self.action_run.cancel() assert self.action_run.is_cancelled def test__getattr__missing_attribute(self): assert_raises(AttributeError, self.action_run.__getattr__, 'is_not_a_real_state')
class ActionRunTestCase(TestCase): @setup def setup_action_run(self): self.output_path = filehandler.OutputPath(tempfile.mkdtemp()) self.action_runner = mock.create_autospec( actioncommand.NoActionRunnerFactory) self.command = "do command %(actionname)s" self.rendered_command = "do command action_name" self.action_run = ActionRun("id", "action_name", mock.create_autospec(node.Node), self.command, output_path=self.output_path, action_runner=self.action_runner) @teardown def teardown_action_run(self): shutil.rmtree(self.output_path.base, ignore_errors=True) def test_init_state(self): assert_equal(self.action_run.state, ActionRun.STATE_SCHEDULED) def test_start(self): self.action_run.machine.transition('ready') assert self.action_run.start() assert self.action_run.is_starting assert self.action_run.start_time def test_start_bad_state(self): self.action_run.fail() assert not self.action_run.start() def test_start_invalid_command(self): self.action_run.bare_command = "%(notfound)s" self.action_run.machine.transition('ready') assert not self.action_run.start() assert self.action_run.is_failed assert_equal(self.action_run.exit_status, -1) def test_start_node_error(self): def raise_error(c): raise node.Error("The error") self.action_run.node = turtle.Turtle(submit_command=raise_error) self.action_run.machine.transition('ready') assert not self.action_run.start() assert_equal(self.action_run.exit_status, -2) assert self.action_run.is_failed @mock.patch('tron.core.actionrun.filehandler', autospec=True) def test_build_action_command(self, mock_filehandler): autospec_method(self.action_run.watch) serializer = mock_filehandler.OutputStreamSerializer.return_value action_command = self.action_run.build_action_command() assert_equal(action_command, self.action_run.action_command) assert_equal(action_command, self.action_runner.create.return_value) self.action_runner.create.assert_called_with(self.action_run.id, self.action_run.command, serializer) mock_filehandler.OutputStreamSerializer.assert_called_with( self.action_run.output_path) self.action_run.watch.assert_called_with(action_command) def test_handler_running(self): self.action_run.build_action_command() self.action_run.machine.transition('start') assert self.action_run.handler(self.action_run.action_command, ActionCommand.RUNNING) assert self.action_run.is_running def test_handler_failstart(self): self.action_run.build_action_command() assert self.action_run.handler(self.action_run.action_command, ActionCommand.FAILSTART) assert self.action_run.is_failed def test_handler_exiting_fail(self): self.action_run.build_action_command() self.action_run.action_command.exit_status = -1 self.action_run.machine.transition('start') assert self.action_run.handler(self.action_run.action_command, ActionCommand.EXITING) assert self.action_run.is_failed assert_equal(self.action_run.exit_status, -1) def test_handler_exiting_success(self): self.action_run.build_action_command() self.action_run.action_command.exit_status = 0 self.action_run.machine.transition('start') self.action_run.machine.transition('started') assert self.action_run.handler(self.action_run.action_command, ActionCommand.EXITING) assert self.action_run.is_succeeded assert_equal(self.action_run.exit_status, 0) def test_handler_exiting_failunknown(self): self.action_run.action_command = mock.create_autospec( actioncommand.ActionCommand, exit_status=None) self.action_run.machine.transition('start') self.action_run.machine.transition('started') assert self.action_run.handler(self.action_run.action_command, ActionCommand.EXITING) assert self.action_run.is_unknown assert_equal(self.action_run.exit_status, None) def test_handler_unhandled(self): self.action_run.build_action_command() assert self.action_run.handler(self.action_run.action_command, ActionCommand.PENDING) is None assert self.action_run.is_scheduled def test_success(self): assert self.action_run.ready() self.action_run.machine.transition('start') self.action_run.machine.transition('started') assert self.action_run.is_running assert self.action_run.success() assert not self.action_run.is_running assert self.action_run.is_done assert self.action_run.end_time assert_equal(self.action_run.exit_status, 0) def test_success_bad_state(self): self.action_run.cancel() assert not self.action_run.success() def test_failure(self): self.action_run.fail(1) assert not self.action_run.is_running assert self.action_run.is_done assert self.action_run.end_time assert_equal(self.action_run.exit_status, 1) def test_failure_bad_state(self): self.action_run.fail(444) assert not self.action_run.fail(123) assert_equal(self.action_run.exit_status, 444) def test_skip(self): assert not self.action_run.is_running self.action_run.ready() assert self.action_run.start() assert self.action_run.fail(-1) assert self.action_run.skip() assert self.action_run.is_skipped def test_skip_bad_state(self): assert not self.action_run.skip() def test_state_data(self): state_data = self.action_run.state_data assert_equal(state_data['command'], self.action_run.bare_command) assert not self.action_run.rendered_command assert not state_data['rendered_command'] def test_state_data_after_rendered(self): command = self.action_run.command state_data = self.action_run.state_data assert_equal(state_data['command'], command) assert_equal(state_data['rendered_command'], command) def test_render_command(self): self.action_run.context = {'stars': 'bright'} self.action_run.bare_command = "%(stars)s" assert_equal(self.action_run.render_command(), 'bright') def test_command_not_yet_rendered(self): assert_equal(self.action_run.command, self.rendered_command) def test_command_already_rendered(self): assert self.action_run.command self.action_run.bare_command = "new command" assert_equal(self.action_run.command, self.rendered_command) def test_command_failed_render(self): self.action_run.bare_command = "%(this_is_missing)s" assert_equal(self.action_run.command, ActionRun.FAILED_RENDER) def test_is_complete(self): self.action_run.machine.state = ActionRun.STATE_SUCCEEDED assert self.action_run.is_complete self.action_run.machine.state = ActionRun.STATE_SKIPPED assert self.action_run.is_complete self.action_run.machine.state = ActionRun.STATE_RUNNING assert not self.action_run.is_complete def test_is_broken(self): self.action_run.machine.state = ActionRun.STATE_UNKNOWN assert self.action_run.is_broken self.action_run.machine.state = ActionRun.STATE_FAILED assert self.action_run.is_broken self.action_run.machine.state = ActionRun.STATE_QUEUED assert not self.action_run.is_broken def test__getattr__(self): assert not self.action_run.is_succeeded assert not self.action_run.is_failed assert not self.action_run.is_queued assert self.action_run.is_scheduled assert self.action_run.cancel() assert self.action_run.is_cancelled def test__getattr__missing_attribute(self): assert_raises(AttributeError, self.action_run.__getattr__, 'is_not_a_real_state')