Пример #1
0
 def test_dotty(self):
     idle = State("I")
     fsm = FSM([idle])
     self.assertTrue(idle.dotty() in fsm.dotty())
     self.assertTrue("digraph" in fsm.dotty())
     fname = tempfile.mktemp() + '.dot'
     try:
         f = open(fname, 'w')
         f.write(fsm.dotty())
         f.close()
         try:
             proc = subprocess.Popen(('dot', fname),
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
         except OSError:
             # Graphviz probably not available; skip
             return
         else:
             _, stderr = proc.communicate()
             retcode = proc.poll()
             if retcode:
                 self.fail('Calling dot returned %i (%s)' %
                           (retcode, stderr))
     finally:
         os.unlink(fname)
Пример #2
0
 def test_no_init_ctor(self):
     fsm = FSM([])
     idle = State("I")
     str(idle)
     fsm.add_state(idle)
     self.assertWarns(RuntimeWarning, "No next state",
                      txtorcon.spaghetti.__file__, fsm.process, "")
Пример #3
0
 def test_dotty(self):
     idle = State("I")
     fsm = FSM([idle])
     self.assertTrue(idle.dotty() in fsm.dotty())
     self.assertTrue("digraph" in fsm.dotty())
     fname = tempfile.mktemp() + '.dot'
     try:
         f = open(fname, 'w')
         f.write(fsm.dotty())
         f.close()
         try:
             proc = subprocess.Popen(('dot', fname),
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
         except OSError:
             # Graphviz probably not available; skip
             return
         else:
             _, stderr = proc.communicate()
             retcode = proc.poll()
             if retcode:
                 self.fail('Calling dot returned %i (%s)' % (retcode,
                                                             stderr))
     finally:
         os.unlink(fname)
Пример #4
0
    def test_no_matcher(self):
        idle = State("I")
        other = State("O")
        fsm = FSM([idle, other])

        idle.add_transition(Transition(other, None, None))
        fsm.process("")
Пример #5
0
 def test_no_init_ctor(self):
     fsm = FSM([])
     idle = State("I")
     str(idle)
     fsm.add_state(idle)
     self.assertWarns(RuntimeWarning, "No next state",
                      txtorcon.spaghetti.__file__, fsm.process, "")
Пример #6
0
    def test_no_matcher(self):
        idle = State("I")
        other = State("O")
        fsm = FSM([idle, other])

        idle.add_transition(Transition(other, None, None))
        fsm.process("")
Пример #7
0
    def test_simple_machine(self):
        idle = State("I")
        cmd = State("C")

        idle.add_transitions([Transition(cmd, self.match, None)])

        fsm = FSM([idle, cmd])
        self.commands = []
        self.assertEqual(fsm.state, idle)
        fsm.process("250 OK\n")
        self.assertEqual(fsm.state, cmd)
Пример #8
0
    def test_handler_state(self):
        idle = State("I")
        cmd = State("C")

        idle.add_transitions([Transition(cmd, self.match, lambda x: idle)])

        fsm = FSM([idle, cmd])
        self.commands = []
        self.assertEqual(fsm.state, idle)
        fsm.process("250 OK\n")
        self.assertEqual(fsm.state, idle)
Пример #9
0
    def test_handler_state(self):
        idle = State("I")
        cmd = State("C")

        idle.add_transitions([Transition(cmd,
                                         self.match,
                                         lambda x: idle)])

        fsm = FSM([idle, cmd])
        self.commands = []
        self.assertEqual(fsm.state, idle)
        fsm.process("250 OK\n")
        self.assertEqual(fsm.state, idle)
Пример #10
0
    def test_simple_machine(self):
        idle = State("I")
        cmd = State("C")

        idle.add_transitions([Transition(cmd,
                                         self.match,
                                         None)])

        fsm = FSM([idle, cmd])
        self.commands = []
        self.assertEqual(fsm.state, idle)
        fsm.process("250 OK\n")
        self.assertEqual(fsm.state, cmd)
Пример #11
0
    def test_reprs(self):
        """
        not really 'testing' here, going for code-coverage to simply
        call the __str__ methods to ensure they don't explode
        """

        a = State("A")
        b = State("B")
        tran = Transition(b, lambda x: None, lambda x: None)
        a.add_transition(tran)
        fsm = FSM([a, b])
        str(fsm)
        str(a)
        str(tran)
        tran.start_state = None
        str(tran)
        fsm.dotty()
Пример #12
0
    def test_reprs(self):
        """
        not really 'testing' here, going for code-coverage to simply
        call the __str__ methods to ensure they don't explode
        """

        a = State("A")
        b = State("B")
        tran = Transition(b, lambda x: None, lambda x: None)
        a.add_transition(tran)
        fsm = FSM([a, b])
        str(fsm)
        str(a)
        str(tran)
        tran.start_state = None
        str(tran)
        fsm.dotty()
Пример #13
0
def parse_client_keys(stream):
    '''
    This parses a hidden-service "client_keys" file, either stealth or
    basic (they're the same, except "stealth" includes a
    "client-key"). Returns a list of HiddenServiceClientAuth() instances.

    Note that the key does NOT include the "----BEGIN ---" markers,
    nor *any* embedded whitespace. It is *just* the key blob.

    '''

    def parse_error(data):
        raise RuntimeError("Parse error at: " + data)

    class ParserState(object):
        def __init__(self):
            self.keys = []
            self.reset()

        def reset(self):
            self.name = None
            self.cookie = None
            self.key = []

        def create_key(self):
            if self.name is not None:
                self.keys.append(HiddenServiceClientAuth(self.name, self.cookie, self.key))
            self.reset()

        def set_name(self, name):
            self.create_key()
            self.name = name.split()[1]

        def set_cookie(self, cookie):
            self.cookie = cookie.split()[1]
            if self.cookie.endswith('=='):
                self.cookie = self.cookie[:-2]

        def add_key_line(self, line):
            self.key.append(line)

    from txtorcon.spaghetti import FSM, State, Transition
    init = State('init')
    got_name = State('got_name')
    got_cookie = State('got_cookie')
    reading_key = State('got_key')

    parser_state = ParserState()

    # initial state; we want "client-name" or it's an error
    init.add_transitions([
        Transition(got_name, lambda line: line.startswith('client-name '), parser_state.set_name),
        Transition(init, lambda line: not line.startswith('client-name '), parse_error),
    ])

    # next up is "descriptor-cookie" or it's an error
    got_name.add_transitions([
        Transition(got_cookie, lambda line: line.startswith('descriptor-cookie '), parser_state.set_cookie),
        Transition(init, lambda line: not line.startswith('descriptor-cookie '), parse_error),
    ])

    # the "interesting bit": there's either a client-name if we're a
    # "basic" file, or an RSA key (with "client-key" before it)
    got_cookie.add_transitions([
        Transition(reading_key, lambda line: line.startswith('client-key'), None),
        Transition(got_name, lambda line: line.startswith('client-name '), parser_state.set_name),
    ])

    # if we're reading an RSA key, we accumulate it in current_key.key
    # until we hit a line starting with "client-name"
    reading_key.add_transitions([
        Transition(reading_key, lambda line: not line.startswith('client-name'), parser_state.add_key_line),
        Transition(got_name, lambda line: line.startswith('client-name '), parser_state.set_name),
    ])

    # create our FSM and parse the data
    fsm = FSM([init, got_name, got_cookie, reading_key])
    for line in stream.readlines():
        fsm.process(line.strip())

    parser_state.create_key()  # make sure we get the "last" one
    return parser_state.keys
Пример #14
0
def parse_client_keys(stream):
    '''
    This parses a hidden-service "client_keys" file, either stealth or
    basic (they're the same, except "stealth" includes a
    "client-key"). Returns a list of HiddenServiceClientAuth() instances.

    Note that the key does NOT include the "----BEGIN ---" markers,
    nor *any* embedded whitespace. It is *just* the key blob.

    '''

    def parse_error(data):
        raise RuntimeError("Parse error at: " + data)

    class ParserState(object):
        def __init__(self):
            self.keys = []
            self.reset()

        def reset(self):
            self.name = None
            self.cookie = None
            self.key = []

        def create_key(self):
            if self.name is not None:
                self.keys.append(HiddenServiceClientAuth(self.name, self.cookie, self.key))
            self.reset()

        def set_name(self, name):
            self.create_key()
            self.name = name.split()[1]

        def set_cookie(self, cookie):
            self.cookie = cookie.split()[1]
            if self.cookie.endswith('=='):
                self.cookie = self.cookie[:-2]

        def add_key_line(self, line):
            self.key.append(line)

    from txtorcon.spaghetti import FSM, State, Transition
    init = State('init')
    got_name = State('got_name')
    got_cookie = State('got_cookie')
    reading_key = State('got_key')

    parser_state = ParserState()

    # initial state; we want "client-name" or it's an error
    init.add_transitions([
        Transition(got_name, lambda line: line.startswith('client-name '), parser_state.set_name),
        Transition(init, lambda line: not line.startswith('client-name '), parse_error),
    ])

    # next up is "descriptor-cookie" or it's an error
    got_name.add_transitions([
        Transition(got_cookie, lambda line: line.startswith('descriptor-cookie '), parser_state.set_cookie),
        Transition(init, lambda line: not line.startswith('descriptor-cookie '), parse_error),
    ])

    # the "interesting bit": there's either a client-name if we're a
    # "basic" file, or an RSA key (with "client-key" before it)
    got_cookie.add_transitions([
        Transition(reading_key, lambda line: line.startswith('client-key'), None),
        Transition(got_name, lambda line: line.startswith('client-name '), parser_state.set_name),
    ])

    # if we're reading an RSA key, we accumulate it in current_key.key
    # until we hit a line starting with "client-name"
    reading_key.add_transitions([
        Transition(reading_key, lambda line: not line.startswith('client-name'), parser_state.add_key_line),
        Transition(got_name, lambda line: line.startswith('client-name '), parser_state.set_name),
    ])

    # create our FSM and parse the data
    fsm = FSM([init, got_name, got_cookie, reading_key])
    for line in stream.readlines():
        fsm.process(line.strip())

    parser_state.create_key()  # make sure we get the "last" one
    return parser_state.keys
Пример #15
0
 def test_no_init(self):
     fsm = FSM([])
     self.assertRaises(Exception, fsm.process, "")
Пример #16
0
 def test_two_states(self):
     fsm = FSM([])
     idle = State("I")
     notidle = State("N")
     fsm.add_state(idle)
     fsm.add_state(notidle)
Пример #17
0
 def test_two_states(self):
     fsm = FSM([])
     idle = State("I")
     notidle = State("N")
     fsm.add_state(idle)
     fsm.add_state(notidle)