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()
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
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()
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
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
class ClientStatus(Enum): dormant = uniq() attempting_tcp_connection = uniq() ready_to_attempt_login = uniq() login_message_in_flight = uniq() streaming = uniq()
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
def create_sid(): return 'fake_sid_%s' % (uniq())
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()