Пример #1
0
class Datatype(Enum):
    u1 = uniq()
    u2 = uniq()
    # fixed size-string, 40 bytes
    s40 = uniq()
    # fixed size-string, 100 bytes
    s100 = uniq()
    # variable string (u2 tells payload length, then payload)
    vs = uniq()
Пример #2
0
 def init_cog(self, fn):
     if type(fn) != types.FunctionType:
         raise Exception("install_cog takes a function only.")
     cog = fn(cog_h='cog_%s_%s' % (uniq(), fn.__name__),
              orb=self,
              engine=self.engine)
     self.add_cog(cog=cog)
     return cog
Пример #3
0
class ServerCustomsState(Enum):
    #
    # we sit on this state when we have a clear slate
    awaiting_login = uniq()
    authorised = uniq()
    #
    # when we decide to kick someone, the first thing we do is to sleep
    # on it for a bit, so that they can't sit there and spam us with
    # reconnects. this state handles that
    reject_stage_a = uniq()
    #
    # after a bit, we send them a message telling them why we're booting them
    # and then we sleep for a little bit more
    reject_stage_b = uniq()
    #
    # this is for after we've booted them.
    rejected = uniq()
Пример #4
0
def should_return_to_dormant_on_failed_connection():
    addr = '127.0.0.1'
    port = 4098
    #
    engine = engine_fake()
    gruel_schema = gruel_schema_new()
    gruel_press = gruel_press_new(gruel_schema=gruel_schema, mtu=MTU)
    gruel_puff = gruel_puff_new(gruel_schema=gruel_schema, mtu=MTU)
    prop_gruel_client = prop_gruel_client_new(engine=engine,
                                              gruel_press=gruel_press,
                                              gruel_puff=gruel_puff)
    #
    connection_info = ConnectionInfo()
    doc_receiver = DocReceiver()
    #
    # connection attempt
    assert 0 == len(engine.events)
    prop_gruel_client.attempt_connection(
        addr=addr,
        port=port,
        password='******',
        cb_connect=connection_info.on_tcp_connect,
        cb_condrop=connection_info.on_tcp_condrop,
        cb_doc=doc_receiver.on_doc)
    #
    # confirm effects
    assert prop_gruel_client.get_status() == 'attempting_tcp_connection'
    #
    # simulate the engine rejecting the connection
    cs_tcp_condrop = cs.CsTcpCondrop()
    cs_tcp_condrop.engine = engine
    cs_tcp_condrop.sid = uniq()
    cs_tcp_condrop.message = 'test123'
    prop_gruel_client._engine_on_tcp_condrop(cs_tcp_condrop=cs_tcp_condrop)
    #
    # confirm effects
    assert 0 == connection_info.calls_to_on_connect
    assert 1 == connection_info.calls_to_on_condrop
    assert prop_gruel_client.get_status() == 'dormant'
    #
    return True
Пример #5
0
def should_handle_successful_tcp_connection():
    addr = '127.0.0.1'
    port = 4098
    #
    engine = engine_fake()
    gruel_schema = gruel_schema_new()
    gruel_press = gruel_press_new(gruel_schema=gruel_schema, mtu=MTU)
    gruel_puff = gruel_puff_new(gruel_schema=gruel_schema, mtu=MTU)
    prop_gruel_client = prop_gruel_client_new(engine=engine,
                                              gruel_press=gruel_press,
                                              gruel_puff=gruel_puff)
    #
    connection_info = ConnectionInfo()
    doc_receiver = DocReceiver()
    #
    # connection attempt
    assert 0 == len(engine.events)
    prop_gruel_client.attempt_connection(
        addr=addr,
        port=port,
        password='******',
        cb_connect=connection_info.on_tcp_connect,
        cb_condrop=connection_info.on_tcp_condrop,
        cb_doc=doc_receiver.on_doc)
    #
    # have engine indicate connection success
    cs_tcp_connect = cs.CsTcpConnect()
    cs_tcp_connect.engine = engine
    cs_tcp_connect.sid = uniq()
    cs_tcp_connect.message = 'test123'
    prop_gruel_client._engine_on_tcp_connect(cs_tcp_connect=cs_tcp_connect)
    #
    # confirm effects
    assert 1 == connection_info.calls_to_on_connect
    assert 0 == connection_info.calls_to_on_condrop
    assert prop_gruel_client.get_status() == 'ready_to_attempt_login'
    #
    return True
Пример #6
0
class ClientStatus(Enum):
    dormant = uniq()
    attempting_tcp_connection = uniq()
    ready_to_attempt_login = uniq()
    login_message_in_flight = uniq()
    streaming = uniq()
Пример #7
0
def should_simulate_common_behaviour():
    MAX_PACKET_LEN = 800
    #
    # get our engine going
    engine = engine_fake()
    clock = engine.get_clock()
    #
    gruel_schema = gruel_schema_new()
    gruel_press = gruel_press_new(gruel_schema=gruel_schema, mtu=MTU)
    gruel_puff = gruel_puff_new(gruel_schema=gruel_schema, mtu=MTU)
    prop_gruel_client = prop_gruel_client_new(engine=engine,
                                              gruel_press=gruel_press,
                                              gruel_puff=gruel_puff)
    assert prop_gruel_client.heartbeat_interval == 1
    #
    # other bits we'll need
    activity = activity_new()
    connection_info = ConnectionInfo()
    doc_receiver = DocReceiver()
    #
    # scenario: connection attempt
    assert 0 == len(engine.events)
    addr = '127.0.0.1'
    port = 4098
    password = '******'
    prop_gruel_client.attempt_connection(
        addr=addr,
        port=port,
        password=password,
        cb_connect=connection_info.on_tcp_connect,
        cb_condrop=connection_info.on_tcp_condrop,
        cb_doc=doc_receiver.on_doc)
    #
    # scenario: successful connection
    # (here we simulate the engine calling back to the client to say
    # that there connection was successful)
    clock.set(5)
    cs_tcp_connect = cs.CsTcpConnect()
    cs_tcp_connect.engine = engine
    cs_tcp_connect.sid = uniq()
    cs_tcp_connect.message = 'test123'
    prop_gruel_client._engine_on_tcp_connect(cs_tcp_connect=cs_tcp_connect)
    #
    # confirm effects
    assert prop_gruel_client.get_status() == 'ready_to_attempt_login'
    assert prop_gruel_client.last_heartbeat_recv == 5
    assert prop_gruel_client.last_heartbeat_sent == 5
    #
    # give the client a turn so it can move to logging in.
    prop_gruel_client.at_turn(activity=activity)
    #
    # confirm effects
    assert activity.get()[-1] == 'PropGruelClient/sending login'
    assert prop_gruel_client.get_status() == 'login_message_in_flight'
    #
    # do we see the login message in-flight?
    assert 1 == len(engine.sent_data)
    latest_payload = engine.sent_data[-1]
    d_client_login = gruel_puff.unpack(payload=latest_payload)
    assert d_client_login['message_h'] == 'client_login'
    assert d_client_login['password'] == password
    assert d_client_login['heartbeat_interval'] == 1

    #
    # simulate server sending back a successful login. (first, we create
    # the kind of payload that the server would have created in this
    # circumstance. Then we call back to the client in the same way that
    # a real engine would call back to it.)
    def server_sends_greet_payload():
        server_greet_payload = gruel_press.create_server_greet_payload(
            max_packet_size=MAX_PACKET_LEN)
        cs_tcp_recv = cs.CsTcpRecv()
        cs_tcp_recv.engine = engine
        cs_tcp_recv.client_sid = 'fake_sid'
        cs_tcp_recv.data = server_greet_payload
        prop_gruel_client._engine_on_tcp_recv(cs_tcp_recv=cs_tcp_recv)

    server_sends_greet_payload()
    #
    # confirm effects
    assert prop_gruel_client.get_status() == 'streaming'
    #
    # scenario: server sends a heartbeat
    clock.set(10)

    def server_sends_heartbeat():
        server_heartbeat = gruel_press.create_heartbeat_payload()
        cs_tcp_recv = cs.CsTcpRecv()
        cs_tcp_recv.engine = engine
        cs_tcp_recv.client_sid = 'fake_sid'
        cs_tcp_recv.data = server_heartbeat
        prop_gruel_client._engine_on_tcp_recv(cs_tcp_recv=cs_tcp_recv)

    server_sends_heartbeat()
    #
    # confirm effects
    assert prop_gruel_client.get_status() == 'streaming'
    assert prop_gruel_client.last_heartbeat_recv == 10
    #
    # scenario: client should send a heartbeat
    clock.set(11)
    prop_gruel_client.at_turn(activity=activity)
    #
    # confirm effects
    assert 2 == len(engine.sent_data)
    payload = engine.sent_data[-1]
    d_payload = gruel_puff.unpack(payload=payload)
    assert d_payload['message_h'] == 'heartbeat'
    #
    # confirm that it now does not send another one
    prop_gruel_client.at_turn(activity=activity)
    assert 2 == len(engine.sent_data)
    #
    # scenario: client sends a small payload
    small_doc = '''
        i greet message
        greet "hello, world!"
    '''
    mcount_before = len(engine.sent_data)
    prop_gruel_client.send_document(doc=small_doc)
    prop_gruel_client.at_turn(activity=activity)
    #
    # confirm effects
    assert len(engine.sent_data) == (mcount_before + 1)
    payload = engine.sent_data[-1]
    d_payload = gruel_puff.unpack(payload=payload)
    assert d_payload['message_h'] == 'docdata'
    assert d_payload['b_complete'] == 1
    assert d_payload['data'] == small_doc
    #
    # scenario: client sends a payload that must span several
    # packets
    large_doc = 'w/%s/y' % ('x' * (2 * MAX_PACKET_LEN))
    mcount_before = len(engine.sent_data)
    prop_gruel_client.send_document(doc=large_doc)
    # give it several turns to allow doc to be dispatched
    prop_gruel_client.at_turn(activity)
    prop_gruel_client.at_turn(activity)
    prop_gruel_client.at_turn(activity)
    #
    # confirm effects
    assert len(engine.sent_data) > mcount_before
    #   (inspect first packet)
    d_payload = gruel_puff.unpack(payload=engine.sent_data[mcount_before])
    assert d_payload['message_h'] == 'docdata'
    assert d_payload['b_complete'] == 0
    assert d_payload['data'][0] == 'w'
    #   (inspect next-to-last packet)
    d_payload = gruel_puff.unpack(payload=engine.sent_data[-2])
    assert d_payload['message_h'] == 'docdata'
    assert d_payload['b_complete'] == 0
    assert d_payload['data'][-1] == 'x'
    #   (inspect last packet)
    d_payload = gruel_puff.unpack(payload=engine.sent_data[-1])
    assert d_payload['message_h'] == 'docdata'
    assert d_payload['b_complete'] == 1
    assert d_payload['data'][-1] == 'y'
    #
    # scenario: client receives a single-packet payload from server
    docs_received = len(doc_receiver.docs)
    small_doc = '''
        i arbitrary message
        arbitrary "message content"
    '''

    def server_sends_small_payload():
        payload = gruel_press.create_docdata_payload(b_complete=1,
                                                     data=small_doc)
        cs_tcp_recv = cs.CsTcpRecv()
        cs_tcp_recv.engine = engine
        cs_tcp_recv.client_sid = 'fake_sid'
        cs_tcp_recv.data = payload
        prop_gruel_client._engine_on_tcp_recv(cs_tcp_recv=cs_tcp_recv)

    server_sends_small_payload()
    #
    # confirm effects
    assert len(doc_receiver.docs) == docs_received + 1
    assert doc_receiver.docs[-1] == small_doc
    #
    # scenario: client receives a multi-packet doc that requires
    # buffering on the client side
    docs_received = len(doc_receiver.docs)
    large_doc_segments = 'h/%s/j' % ('i' * (2 * MAX_PACKET_LEN))
    large_doc = ''.join(large_doc_segments)

    def server_sends_large_doc():
        remaining = large_doc_segments
        to_send = deque()
        while remaining != '':
            doc = remaining[:50]
            remaining = remaining[50:]
            to_send.append(doc)
        while to_send:
            docpart = to_send.popleft()
            b_complete = 0
            if not to_send:
                b_complete = 1
            #
            payload = gruel_press.create_docdata_payload(b_complete=b_complete,
                                                         data=docpart)
            #
            cs_tcp_recv = cs.CsTcpRecv()
            cs_tcp_recv.engine = engine
            cs_tcp_recv.client_sid = 'fake_sid'
            cs_tcp_recv.data = payload
            prop_gruel_client._engine_on_tcp_recv(cs_tcp_recv=cs_tcp_recv)

    server_sends_large_doc()
    #
    # confirm effects
    assert len(doc_receiver.docs) > docs_received
    assert doc_receiver.docs[-1] == large_doc
    #
    return True
Пример #8
0
def create_sid():
    return 'fake_sid_%s' % (uniq())
Пример #9
0
 def open_tcp_server(self, addr, port, cb_tcp_connect, cb_tcp_condrop,
                     cb_tcp_recv):
     self.events.append(('open_tcp_server', addr, port))
     return 'fake_sid_%s' % uniq()