예제 #1
0
 def test_wrappedIdentifier(self):
     """
     If the wrapped object has an C{identifier} method then its return value
     is returned by L{MethodSuffixOutputer.identifier}.
     """
     world = AnimalWorld([])
     outputer = MethodSuffixOutputer(world)
     self.assertEqual(world.identifier(), outputer.identifier())
예제 #2
0
 def test_unicodeFallbackIdentifier(self):
     """
     If the wrapped object has no C{identifier} method then the identifier
     generated by L{MethodSuffixOutputer.identifier} is a L{unicode} string.
     """
     world = object()
     outputer = MethodSuffixOutputer(world)
     self.assertIsInstance(outputer.identifier(), unicode)
예제 #3
0
 def test_wrappedIdentifier(self):
     """
     If the wrapped object has an C{identifier} method then its return value
     is returned by L{MethodSuffixOutputer.identifier}.
     """
     world = AnimalWorld([])
     outputer = MethodSuffixOutputer(world)
     self.assertEqual(world.identifier(), outputer.identifier())
예제 #4
0
 def test_unicodeFallbackIdentifier(self):
     """
     If the wrapped object has no C{identifier} method then the identifier
     generated by L{MethodSuffixOutputer.identifier} is a L{unicode} string.
     """
     world = object()
     outputer = MethodSuffixOutputer(world)
     self.assertIsInstance(outputer.identifier(), unicode)
예제 #5
0
 def test_fallbackIdentifier(self):
     """
     If the wrapped object has no C{identifier} method then
     L{MethodSuffixOutputer.identifier} generates an identifier for the
     wrapped object and returns that.
     """
     world = object()
     outputer = MethodSuffixOutputer(world)
     self.assertEqual(repr(world), outputer.identifier())
예제 #6
0
 def test_fallbackIdentifier(self):
     """
     If the wrapped object has no C{identifier} method then
     L{MethodSuffixOutputer.identifier} generates an identifier for the
     wrapped object and returns that.
     """
     world = object()
     outputer = MethodSuffixOutputer(world)
     self.assertEqual(repr(world), outputer.identifier())
예제 #7
0
 def test_fallbackIdentifierStable(self):
     """
     If L{MethodSuffixOutputer} generates an identifier for the wrapped
     object then it generates the same identifier for all calls to
     C{identifier} regardless of changes to the wrapped object.
     """
     world = ["first state"]
     outputer = MethodSuffixOutputer(world)
     firstIdentifier = outputer.identifier()
     world.append("second state")
     secondIdentifier = outputer.identifier()
     self.assertEqual(firstIdentifier, secondIdentifier)
예제 #8
0
 def test_fallbackIdentifierStable(self):
     """
     If L{MethodSuffixOutputer} generates an identifier for the wrapped
     object then it generates the same identifier for all calls to
     C{identifier} regardless of changes to the wrapped object.
     """
     world = ["first state"]
     outputer = MethodSuffixOutputer(world)
     firstIdentifier = outputer.identifier()
     world.append("second state")
     secondIdentifier = outputer.identifier()
     self.assertEqual(firstIdentifier, secondIdentifier)
예제 #9
0
 def test_dispatch(self):
     """
     When L{MethodSuffixOutputer.output} is called with an input and the
     wrapped object has a method named like I{output_INPUT} where I{INPUT}
     is the name of the input given, that method is called with the context
     object given.
     """
     context = object()
     animals = []
     world = AnimalWorld(animals)
     outputer = MethodSuffixOutputer(world)
     outputer.output(Output.aardvark, context)
     self.assertEqual([(Output.aardvark, context)], animals)
예제 #10
0
 def test_dispatch(self):
     """
     When L{MethodSuffixOutputer.output} is called with an input and the
     wrapped object has a method named like I{output_INPUT} where I{INPUT}
     is the name of the input given, that method is called with the context
     object given.
     """
     context = object()
     animals = []
     world = AnimalWorld(animals)
     outputer = MethodSuffixOutputer(world)
     outputer.output(Output.aardvark, context)
     self.assertEqual([(Output.aardvark, context)], animals)
예제 #11
0
 def test_FiniteStateInterpreterRepr(self):
     """
     The result of L{_FiniteStateInterpreter.__repr__} is a string that
     includes the L{IOutputExecutor} provider that
     L{_FiniteStateInterpreter} can drive.
     """
     fsm = constructFiniteStateMachine(Input, Output, MoreState,
                                       TRANSITIONS, self.initial,
                                       [Gravenstein],
                                       {Output.aardvark: IFood},
                                       MethodSuffixOutputer(self.world),
                                       None)
     self.assertEqual(repr(fsm),
                      "<FSM / %s>" % (MethodSuffixOutputer(self.world), ))
예제 #12
0
파일: _loop.py 프로젝트: jaggerliu/flocker
def build_convergence_loop_fsm(reactor, deployer):
    """
    Create a convergence loop FSM.

    :param IReactorTime reactor: Used to schedule delays in the loop.

    :param IDeployer deployer: Used to discover local state and calcualte
        necessary changes to match desired configuration.
    """
    I = ConvergenceLoopInputs
    O = ConvergenceLoopOutputs
    S = ConvergenceLoopStates

    table = TransitionTable()
    table = table.addTransition(
        S.STOPPED, I.STATUS_UPDATE, [O.STORE_INFO, O.CONVERGE], S.CONVERGING)
    table = table.addTransitions(
        S.CONVERGING, {
            I.STATUS_UPDATE: ([O.STORE_INFO], S.CONVERGING),
            I.STOP: ([], S.CONVERGING_STOPPING),
            I.ITERATION_DONE: ([O.CONVERGE], S.CONVERGING),
        })
    table = table.addTransitions(
        S.CONVERGING_STOPPING, {
            I.STATUS_UPDATE: ([O.STORE_INFO], S.CONVERGING),
            I.ITERATION_DONE: ([], S.STOPPED),
        })

    loop = ConvergenceLoop(reactor, deployer)
    fsm = constructFiniteStateMachine(
        inputs=I, outputs=O, states=S, initial=S.STOPPED, table=table,
        richInputs=[_ClientStatusUpdate], inputContext={},
        world=MethodSuffixOutputer(loop))
    loop.fsm = fsm
    return fsm
예제 #13
0
 def __init__(self):
     self._fsm = constructFiniteStateMachine(
         inputs=Input, outputs=Output, states=State, table=table,
         initial=State.IDLE,
         richInputs=[RequestStart, InstanceStarted, StartFailed,
                     RequestStop, InstanceStopped, StopFailed],
         inputContext={}, world=MethodSuffixOutputer(self))
예제 #14
0
def setup_driver():
    """
    Instantiate all of the driver components

    includes the following objects:
    trace, dbus, radio, state machine actions, finite state machine.

    Returns list of [fsm, radio, dbus] object references.
    """
    trace = si446xtrace.Trace(1000)
    dbus = Si446xDbus(OBJECT_PATH, trace=trace)
    radio = Si446xRadio(device=0, callback=dbus.async_interrupt, trace=trace)
    print('init radio done')
    actions = Si446xFsmActionHandlers(radio, dbus)
    machine = constructFiniteStateMachine(
        inputs=Events,
        outputs=Actions,
        states=States,
        table=table,
        initial=States.S_SDN,
        richInputs=[],
        inputContext={},
        world=MethodSuffixOutputer(actions),
    )
    fsm = {'actions': actions, 'machine': machine, 'trace': trace}
    dbus.marry(fsm, radio)
    return [fsm, radio, dbus]
예제 #15
0
    def test_noRepeatedTerminalLogging(self, logger):
        """
        When the L{IFiniteStateMachine} receives an input in a terminal state
        (and does not generate an output or change to a different state, as is
        required in terminal states) it does not re-log the completion of its
        initialization event.
        """
        # Accept this input in MoreState.blue but remain a terminal state (no
        # output, no state change).
        transitions = TRANSITIONS.addTransition(MoreState.blue, Input.apple,
                                                [], MoreState.blue)

        fsm = constructFiniteStateMachine(
            Input, Output, MoreState, transitions, MoreState.amber,
            [Gravenstein], {Output.aardvark: IFood},
            MethodSuffixOutputer(AnimalWorld([])), logger)

        fsm.receive(Gravenstein())
        howMany = len(logger.messages)

        fsm.receive(Gravenstein())

        # No additional initialization messages please!
        self.assertEqual([], [
            msg for msg in logger.messages[howMany:]
            if msg[u"action_type"] == u"fsm:initialize"
        ])
예제 #16
0
def main():
    hardware = TurnstileController(digitalPin=0x13)
    turnstileFSM = constructFiniteStateMachine(
        inputs=TurnstileInput,
        outputs=TurnstileOutput,
        states=TurnstileState,
        table=table,
        initial=TurnstileState.LOCKED,
        richInputs={},
        inputContext={},
        world=MethodSuffixOutputer(Turnstile(hardware)),
    )
    while True:
        if hardware.paymentMade():
            hardware.resetNotification()
            turnstileFSM.receive(TurnstileInput.FARE_PAID)
        elif hardware.armTurned():
            hardware.resetNotification()
            turnstileFSM.receive(TurnstileInput.ARM_TURNED)
        elif hardware.finishedLocking():
            hardware.resetNotification()
            turnstileFSM.receive(TurnstileInput.ARM_LOCKED)
        elif hardware.finishedUnlocking():
            hardware.resetNotification()
            turnstileFSM.receive(TurnstileInput.ARM_UNLOCKED)
        else:
            time.sleep(0.1)
예제 #17
0
    def test_prefix(self):
        """
        If a value is given for the optional second L{MethodSuffixOutputer}
        initializer argument then it is used instead of C{"output_"} as the
        method dispatch prefix.
        """
        animals = []

        class AlternatePrefixWorld(object):
            def foobar_AARDVARK(self, context):
                animals.append(context)

        context = object()
        world = AlternatePrefixWorld()
        outputer = MethodSuffixOutputer(world, "foobar_")
        outputer.output(Output.aardvark, context)
        self.assertEqual([context], animals)
예제 #18
0
 def test_repr(self):
     """
     The result of L{MethodSuffixOutputer.__repr__} is a string that
     mentions the wrapped object.
     """
     world = object()
     self.assertEqual("<Output / %s>" % (world, ),
                      repr(MethodSuffixOutputer(world)))
예제 #19
0
    def test_prefix(self):
        """
        If a value is given for the optional second L{MethodSuffixOutputer}
        initializer argument then it is used instead of C{"output_"} as the
        method dispatch prefix.
        """
        animals = []

        class AlternatePrefixWorld(object):
            def foobar_AARDVARK(self, context):
                animals.append(context)

        context = object()
        world = AlternatePrefixWorld()
        outputer = MethodSuffixOutputer(world, "foobar_")
        outputer.output(Output.aardvark, context)
        self.assertEqual([context], animals)
예제 #20
0
    def setUp(self):
        self.animals = []
        self.initial = MoreState.amber

        self.world = AnimalWorld(self.animals)
        self.fsm = constructFiniteStateMachine(
            Input, Output, MoreState, TRANSITIONS, self.initial, [Gravenstein],
            {Output.aardvark: IFood}, MethodSuffixOutputer(self.world))
예제 #21
0
파일: _loop.py 프로젝트: jongiddy/flocker
def build_cluster_status_fsm(convergence_loop_fsm):
    """
    Create a new cluster status FSM.

    The automatic reconnection logic is handled by the
    ``AgentLoopService``; the world object here just gets notified of
    disconnects, it need schedule the reconnect itself.

    :param convergence_loop_fsm: A convergence loop FSM as output by
    ``build_convergence_loop_fsm``.
    """
    S = ClusterStatusStates
    I = ClusterStatusInputs
    O = ClusterStatusOutputs
    table = TransitionTable()
    # We may be shut down in any state, in which case we disconnect if
    # necessary.
    table = table.addTransitions(
        S.DISCONNECTED,
        {
            # Store the client, then wait for cluster status to be sent
            # over AMP:
            I.CONNECTED_TO_CONTROL_SERVICE: ([O.STORE_CLIENT], S.IGNORANT),
            I.SHUTDOWN: ([], S.SHUTDOWN),
        })
    table = table.addTransitions(
        S.IGNORANT,
        {
            # We never told agent to start, so no need to tell it to stop:
            I.DISCONNECTED_FROM_CONTROL_SERVICE: ([], S.DISCONNECTED),
            # Tell agent latest cluster status, implicitly starting it:
            I.STATUS_UPDATE: ([O.UPDATE_STATUS], S.KNOWLEDGEABLE),
            I.SHUTDOWN: ([O.DISCONNECT], S.SHUTDOWN),
        })
    table = table.addTransitions(
        S.KNOWLEDGEABLE,
        {
            # Tell agent latest cluster status:
            I.STATUS_UPDATE: ([O.UPDATE_STATUS], S.KNOWLEDGEABLE),
            I.DISCONNECTED_FROM_CONTROL_SERVICE: ([O.STOP], S.DISCONNECTED),
            I.SHUTDOWN: ([O.STOP, O.DISCONNECT], S.SHUTDOWN),
        })
    table = table.addTransitions(
        S.SHUTDOWN, {
            I.DISCONNECTED_FROM_CONTROL_SERVICE: ([], S.SHUTDOWN),
            I.STATUS_UPDATE: ([], S.SHUTDOWN),
        })

    return constructFiniteStateMachine(
        inputs=I,
        outputs=O,
        states=S,
        initial=S.DISCONNECTED,
        table=table,
        richInputs=[_ConnectedToControlService, _StatusUpdate],
        inputContext={},
        world=MethodSuffixOutputer(ClusterStatus(convergence_loop_fsm)))
예제 #22
0
 def test_logger(self):
     """
     L{constructFiniteStateMachine} returns a FSM that also has a C{logger}
     attribute that is an L{eliot.Logger} instance.
     """
     fsm = constructFiniteStateMachine(
         Input, Output, MoreState, TRANSITIONS, MoreState.amber,
         [Gravenstein], {Output.aardvark: IFood},
         MethodSuffixOutputer(AnimalWorld([])))
     self.assertIsInstance(fsm.logger, Logger)
예제 #23
0
 def test_empty(self):
     """
     L{_FiniteStateMachine._isTerminal} returns C{True} if a state that
     defines handling of no input symbols.
     """
     fsm = constructFiniteStateMachine(
         Input, Output, MoreState, TRANSITIONS, MoreState.amber,
         [Gravenstein], {Output.aardvark: IFood},
         MethodSuffixOutputer(AnimalWorld([])))
     self.assertTrue(fsm._isTerminal(MoreState.blue))
예제 #24
0
 def test_loggerOverride(self, logger):
     """
     If an argument is given for the C{logger} argument to
     L{constructFiniteStateMachine} then that object is used as the logger
     of the resulting finite state machine.
     """
     fsm = constructFiniteStateMachine(
         Input, Output, MoreState, TRANSITIONS, MoreState.amber,
         [Gravenstein], {Output.aardvark: IFood},
         MethodSuffixOutputer(AnimalWorld([])), logger)
     self.assertIs(logger, fsm.logger)
예제 #25
0
 def test_nextStateGivenSymbolInput(self, logger):
     """
     L{IFiniteStateMachine.receive} changes L{IFiniteStateMachine.state} to
     the next state defined for the given symbolic input in the machine's
     current state.
     """
     self.fsm = constructFiniteStateMachine(
         Input, Output, MoreState, TRANSITIONS, MoreState.amber,
         [Gravenstein], {}, MethodSuffixOutputer(AnimalWorld([])), logger)
     self.fsm.logger = logger
     self.fsm.receive(Input.apple)
     self.assertEqual(MoreState.blue, self.fsm.state)
예제 #26
0
 def test_stateChange(self):
     """
     L{_FiniteStateMachine._isTerminal} returns C{False} if a state defines
     handling of inputs that cause a state change.
     """
     transitions = TRANSITIONS.addTransition(MoreState.blue, Input.apple,
                                             [], MoreState.amber)
     fsm = constructFiniteStateMachine(
         Input, Output, MoreState, transitions, MoreState.amber,
         [Gravenstein], {Output.aardvark: IFood},
         MethodSuffixOutputer(AnimalWorld([])))
     self.assertFalse(fsm._isTerminal(MoreState.blue))
예제 #27
0
 def test_selfTransition(self):
     """
     L{_FiniteStateMachine._isTerminal} returns C{True} if a state defines
     handling of inputs that generate no outputs and do not change the state
     of the machine.
     """
     transitions = TRANSITIONS.addTransition(MoreState.blue, Input.apple,
                                             [], MoreState.blue)
     fsm = constructFiniteStateMachine(
         Input, Output, MoreState, transitions, MoreState.amber,
         [Gravenstein], {Output.aardvark: IFood},
         MethodSuffixOutputer(AnimalWorld([])))
     self.assertTrue(fsm._isTerminal(MoreState.blue))
예제 #28
0
    def test_outputFromSymbolInput(self, logger):
        """
        L{IFiniteStateMachine.receive} finds the transition for the symbol
        input in the machine's current state and returns the corresponding
        output.
        """
        self.fsm = constructFiniteStateMachine(
            Input, Output, MoreState, TRANSITIONS, self.initial, [Gravenstein],
            {}, MethodSuffixOutputer(self.world))

        self.fsm.logger = logger
        self.world.logger = logger
        self.assertEqual([Output.aardvark], self.fsm.receive(Input.apple))
예제 #29
0
 def test_initializationLogging(self, logger):
     """
     The initialization of the L{IFiniteStateMachine} created by
     L{constructFiniteStateMachine} is logged.
     """
     constructFiniteStateMachine(Input, Output, MoreState, TRANSITIONS,
                                 MoreState.amber, [Gravenstein],
                                 {Output.aardvark: IFood},
                                 MethodSuffixOutputer(AnimalWorld([])),
                                 logger)
     self.assertTrue(
         issuperset(
             logger.messages[0], {
                 u"fsm_identifier": u"<AnimalWorld>",
                 u"fsm_state": u"<MoreState=amber>",
                 u"action_status": u"started",
                 u"action_type": u"fsm:initialize",
             }))
예제 #30
0
def build_convergence_loop_fsm(reactor, deployer):
    """
    Create a convergence loop FSM.

    Once cluster config+cluster state updates from control service are
    received the basic loop is:

    1. Discover local state.
    2. Calculate ``IStateChanges`` based on local state and cluster
       configuration and cluster state we received from control service.
    3. Execute the change.
    4. Sleep.

    However, if an update is received during sleep then we calculate based
    on that updated config+state whether a ``IStateChange`` needs to
    happen. If it does that means this change will have impact on what we
    do, so we interrupt the sleep. If calculation suggests a no-op then we
    keep sleeping. Notably we do **not** do a discovery of local state
    when an update is received while sleeping, since that is an expensive
    operation that can involve talking to external resources. Moreover an
    external update only implies external state/config changed, so we're
    not interested in the latest local state in trying to decide if this
    update requires us to do something; a recently cached version should
    suffice.

    :param IReactorTime reactor: Used to schedule delays in the loop.

    :param IDeployer deployer: Used to discover local state and calcualte
        necessary changes to match desired configuration.
    """
    loop = ConvergenceLoop(reactor, deployer)
    fsm = constructFiniteStateMachine(
        inputs=ConvergenceLoopInputs,
        outputs=ConvergenceLoopOutputs,
        states=ConvergenceLoopStates,
        initial=ConvergenceLoopStates.STOPPED,
        table=_CONVERGENCE_LOOP_FSM_TABLE,
        richInputs=[_ClientStatusUpdate, _Sleep],
        inputContext={},
        world=MethodSuffixOutputer(loop))
    loop.fsm = fsm
    return fsm
예제 #31
0
파일: _loop.py 프로젝트: AlexRRR/flocker
def build_cluster_status_fsm(convergence_loop_fsm):
    """
    Create a new cluster status FSM.

    The automatic reconnection logic is handled by the
    ``AgentLoopService``; the world object here just gets notified of
    disconnects, it need schedule the reconnect itself.

    :param convergence_loop_fsm: A convergence loop FSM as output by
    ``build_convergence_loop_fsm``.
    """
    return constructFiniteStateMachine(
        inputs=ClusterStatusInputs,
        outputs=ClusterStatusOutputs,
        states=ClusterStatusStates,
        initial=ClusterStatusStates.DISCONNECTED,
        table=_CLUSTER_STATUS_FSM_TABLE,
        richInputs=[_ConnectedToControlService, _StatusUpdate],
        inputContext={},
        world=MethodSuffixOutputer(ClusterStatus(convergence_loop_fsm)))
예제 #32
0
    def test_terminalLogging(self, logger):
        """
        When the L{IFiniteStateMachine} enters a terminal state the
        initialization action is finished successfully.
        """
        fsm = constructFiniteStateMachine(
            Input, Output, MoreState, TRANSITIONS, MoreState.amber,
            [Gravenstein], {Output.aardvark: IFood},
            MethodSuffixOutputer(AnimalWorld([])), logger)

        fsm.receive(Gravenstein())

        (initialize, ) = LoggedAction.of_type(logger.messages,
                                              LOG_FSM_INITIALIZE)

        assertContainsFields(
            self, initialize.end_message, {
                u"fsm_terminal_state": u"<MoreState=blue>",
                u"action_status": u"succeeded",
            })
예제 #33
0
    def test_terminalLogging(self, logger):
        """
        When the L{IFiniteStateMachine} enters a terminal state the
        initialization action is finished successfully.
        """
        fsm = constructFiniteStateMachine(
            Input, Output, MoreState, TRANSITIONS, MoreState.amber,
            [Gravenstein], {Output.aardvark: IFood},
            MethodSuffixOutputer(AnimalWorld([])), logger)

        fsm.receive(Gravenstein())

        self.assertTrue(
            issuperset(
                logger.messages[3],
                {
                    u"fsm_terminal_state": u"<MoreState=blue>",
                    # Prove it associates with the initialization action.
                    u"action_type": u"fsm:initialize",
                    u"action_status": u"succeeded",
                    u"task_uuid": logger.messages[0][u"task_uuid"],
                    u"task_level": u"/",
                }))
예제 #34
0

class State(Names):
    amber = NamedConstant()


class MoreState(Names):
    amber = NamedConstant()
    blue = NamedConstant()


class IRequiredByAardvark(Interface):
    pass


NULL_WORLD = MethodSuffixOutputer(None)


class TransitionTests(TestCase):
    """
    Tests for L{Transition}.
    """
    def test_str(self):
        """
        The string representation of a L{Transition} includes the output and
        next state it represents.
        """
        self.assertEqual("<Transition output='a' nextState='b'>",
                         str(Transition("a", "b")))

    def test_repr(self):
예제 #35
0
    })
# end last transitions

# begin outputer
from machinist import MethodSuffixOutputer


class Outputer(object):
    def output_ENGAGE_LOCK(self, engage):
        print("Engaging the lock.")

    def output_DISENGAGE_LOCK(self, disengage):
        print("Disengaging the lock.")


outputer = MethodSuffixOutputer(Outputer())
# end outputer

# begin construct
from machinist import constructFiniteStateMachine

turnstile = constructFiniteStateMachine(
    inputs=Input,
    outputs=Output,
    states=State,
    table=table,
    initial=State.LOCKED,
    richInputs=[],
    inputContext={},
    world=outputer,
)