def test_workflow_get_transitions(self): workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) self.assertRaises(InvalidStateError, workflow.get_transitions, "magic") self.assertEqual(workflow.get_transitions("initialized"), [workflow.get_transition("start")])
def test_state_get_available_transitions(self): workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) workflow_state = AttributeWorkflowState(workflow) transitions = yield workflow_state.get_available_transitions() yield self.assertEqual(transitions, [workflow.get_transition("init_workflow")])
def test_state_get_available_transitions(self): workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) workflow_state = AttributeWorkflowState(workflow) transitions = yield workflow_state.get_available_transitions() yield self.assertEqual( transitions, [workflow.get_transition("init_workflow")])
def test_workflow_get_transition(self): transition = Transition("init_workflow", "", None, "initialized") workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) self.assertRaises(KeyError, workflow.get_transition, "rabid") self.assertEqual( workflow.get_transition("init_workflow").transition_id, transition.transition_id)
def test_workflow_get_transitions(self): workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) self.assertRaises(InvalidStateError, workflow.get_transitions, "magic") self.assertEqual( workflow.get_transitions("initialized"), [workflow.get_transition("start")])
def test_fire_transition_alias_none(self): workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) workflow_state = AttributeWorkflowState(workflow) return self.assertFailure(workflow_state.fire_transition_alias("dog"), InvalidTransitionError)
def test_transition_action_unknown_error(self): """If an unknown error is raised by a transition action, it is raised from the fire transition method. """ workflow = Workflow(Transition("error_unknown", "", None, "next-state")) workflow_state = AttributeWorkflowState(workflow) return self.assertFailure( workflow_state.fire_transition("error_unknown"), AttributeError)
def test_state_transition_callback(self): """If the workflow state, defines an action callback for a transition, its invoked when the transition is fired. """ workflow = Workflow(Transition("jump_puddle", "", None, "dry")) workflow_state = AttributeWorkflowState(workflow) yield workflow_state.fire_transition("jump_puddle") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "dry") self.assertEqual(getattr(workflow_state, "_jumped", None), True)
def test_state_get_set(self): workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) workflow_state = AttributeWorkflowState(workflow) current_state = yield workflow_state.get_state() self.assertEqual(current_state, None) yield workflow_state.set_state("started") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "started")
def test_transition_success_transition(self): """If a transition specifies a success transition, and its action handler completes successfully, the success transistion and associated action handler are executed. """ workflow = Workflow( Transition("initialized", "", None, "next-state", success_transition_id="markup"), Transition("markup", "", "next-state", "final-state"), ) workflow_state = AttributeWorkflowState(workflow) yield workflow_state.fire_transition("initialized") self.assertEqual((yield workflow_state.get_state()), "final-state") self.assertIn("initiating success transition: markup", self.log_stream.getvalue())
def test_state_machine_observer(self): """A state machine observer can be registered for tests visibility of async state transitions.""" results = [] def observer(state, variables): results.append((state, variables)) workflow = Workflow( Transition("begin", "", None, "next-state"), Transition("continue", "", "next-state", "final-state")) workflow_state = AttributeWorkflowState(workflow) workflow_state.set_observer(observer) yield workflow_state.fire_transition("begin") yield workflow_state.fire_transition("continue") self.assertEqual(results, [("next-state", {}), ("final-state", {})])
def test_transition_error_transition(self): """If a transition specifies an error transition, and its action handler raises a transition error, the error transition and associated hooks are executed. """ workflow = Workflow( Transition("raises_transition_error", "", None, "next-state", error_transition_id="error_transition"), Transition("error_transition", "", None, "error-state")) workflow_state = AttributeWorkflowState(workflow) yield workflow_state.fire_transition("raises_transition_error") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "error-state") state_variables = yield workflow_state.get_state_variables() self.assertEqual(state_variables, {"error": True})
def test_transition_action_workflow_error(self): """If a transition action callback raises a transitionerror, the transition does not complete, and the state remains the same. The fire_transition method in this cae returns False. """ workflow = Workflow( Transition("raises_transition_error", "", None, "next-state")) workflow_state = AttributeWorkflowState(workflow) result = yield workflow_state.fire_transition( "raises_transition_error") self.assertEqual(result, False) current_state = yield workflow_state.get_state() self.assertEqual(current_state, None) name = "attributeworkflowstate" output = ( "%s: transition raises_transition_error (None -> next-state) {}", "%s: execute action do_raises_transition_error", "%s: transition raises_transition_error failed eek\n") self.assertEqual(self.log_stream.getvalue(), "\n".join([line % name for line in output]))
def test_transition_state(self): """Transitions can be specified by the desired state. """ workflow = Workflow(Transition("begin", "", None, "trail"), Transition("to_cabin", "", "trail", "cabin"), Transition("to_house", "", "trail", "house")) workflow_state = AttributeWorkflowState(workflow) result = yield workflow_state.transition_state("trail") self.assertEqual(result, True) current_state = yield workflow_state.get_state() self.assertEqual(current_state, "trail") result = yield workflow_state.transition_state("cabin") self.assertEqual(result, True) result = yield workflow_state.transition_state("house") self.assertEqual(result, False) self.assertFailure(workflow_state.transition_state("unknown"), InvalidStateError)
def test_state_fire_transition(self): workflow = Workflow( Transition("init_workflow", "", None, "initialized"), Transition("start", "", "initialized", "started")) workflow_state = AttributeWorkflowState(workflow) yield workflow_state.fire_transition("init_workflow") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "initialized") yield workflow_state.fire_transition("start") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "started") yield self.assertFailure(workflow_state.fire_transition("stop"), InvalidTransitionError) name = "attributeworkflowstate" output = ( "%s: transition init_workflow (None -> initialized) {}", "%s: transition complete init_workflow (state initialized) {}", "%s: transition start (initialized -> started) {}", "%s: transition complete start (state started) {}\n") self.assertEqual(self.log_stream.getvalue(), "\n".join([line % name for line in output]))
def test_state_variables_via_transition(self): """Per state variables can be passed into the transition. """ workflow = Workflow( Transition("begin", "", None, "next-state"), Transition("continue", "", "next-state", "final-state")) workflow_state = AttributeWorkflowState(workflow) yield workflow_state.fire_transition("begin", rabbit="moon", hello=True) current_state = yield workflow_state.get_state() self.assertEqual(current_state, "next-state") variables = yield workflow_state.get_state_variables() self.assertEqual({"rabbit": "moon", "hello": True}, variables) yield workflow_state.fire_transition("continue") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "final-state") variables = yield workflow_state.get_state_variables() self.assertEqual({}, variables)
def test_transition_resets_state_variables(self): """State variables are only stored, while the associated state is current. """ workflow = Workflow( Transition("transition_variables", "", None, "next-state"), Transition("some_transition", "", "next-state", "final-state")) workflow_state = AttributeWorkflowState(workflow) state_variables = yield workflow_state.get_state_variables() self.assertEqual(state_variables, {}) yield workflow_state.fire_transition("transition_variables") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "next-state") state_variables = yield workflow_state.get_state_variables() self.assertEqual(state_variables, {"hello": "world"}) yield workflow_state.fire_transition("some_transition") current_state = yield workflow_state.get_state() self.assertEqual(current_state, "final-state") state_variables = yield workflow_state.get_state_variables() self.assertEqual(state_variables, {})
def test_fire_transition_alias(self): workflow = Workflow( Transition("init_magic", "", None, "initialized", alias="init")) workflow_state = AttributeWorkflowState(workflow) value = yield workflow_state.fire_transition_alias("init") self.assertEqual(value, True)
UnitWorkflow = Workflow( # Install transitions Transition("install", "Install", None, "installed", error_transition_id="error_install"), Transition("error_install", "Install error", None, "install_error"), Transition("retry_install", "Retry install", "install_error", "installed", alias="retry", success_transition_id="start"), Transition("retry_install_hook", "Retry install with hook", "install_error", "installed", alias="retry_hook", success_transition_id="start"), # Start transitions Transition("start", "Start", "installed", "started", error_transition_id="error_start"), Transition("error_start", "Start error", "installed", "start_error"), Transition("retry_start", "Retry start", "start_error", "started", alias="retry"), Transition("retry_start_hook", "Retry start with hook", "start_error", "started", alias="retry_hook"), # Stop transitions Transition("stop", "Stop", "started", "stopped", error_transition_id="error_stop"), Transition("error_stop", "Stop error", "started", "stop_error"), Transition("retry_stop", "Retry stop", "stop_error", "stopped", alias="retry"), Transition("retry_stop_hook", "Retry stop with hook", "stop_error", "stopped", alias="retry_hook"), # Restart transitions Transition("restart", "Restart", "stop", "start", error_transition_id="error_start", alias="retry"), Transition("restart_with_hook", "Restart with hook", "stop", "start", alias="retry_hook", error_transition_id="error_start"), # Upgrade transitions Transition( "upgrade_charm", "Upgrade", "started", "started", error_transition_id="upgrade_charm_error"), Transition( "upgrade_charm_error", "Upgrade from stop error", "started", "charm_upgrade_error"), Transition( "retry_upgrade_charm", "Upgrade from stop error", "charm_upgrade_error", "started", alias="retry"), Transition( "retry_upgrade_charm_hook", "Upgrade from stop error with hook", "charm_upgrade_error", "started", alias="retry_hook"), # Configuration Transitions Transition( "reconfigure", "Reconfigure", "started", "started", error_transition_id="error_configure"), Transition( "error_configure", "On configure error", "started", "configure_error"), Transition( "retry_error", "On retry configure error", "configure_error", "configure_error"), Transition( "retry_configure", "Retry configure", "configure_error", "started", alias="retry", error_transition_id="retry_error"), Transition( "retry_configure_hook", "Retry configure with hooks", "configure_error", "started", alias="retry_hook", error_transition_id="retry_error") )