def test_chunked_protocol(self): """Ensure that different protocol runs produce different traces. This is done by creating two client server pairs and testing that they receive messages in different chunks. """ class TestProtocol(Protocol): """Simple protocol that stores any data received.""" def __init__(self): self.data = [] def dataReceived(self, data): """Store received data for later inspection.""" self.data.append(data) def connectionMade(self): """Write some data and drop the connection.""" self.transport.write("Hello there!") self.transport.write("This is my second message.") self.transport.write("Goodbye, it was nice talking to you.") self.transport.loseConnection() def check(_, server_a, client_a, server_b, client_b): """Test that the data sequence is different each time. The four parties record the data received, and these traces must be pair-wise different due to the simulated asynchronous behavior of the network. The first argument is from the DeferredList and is ignored. """ self.failIfEqual(server_a.data, server_b.data) self.failIfEqual(client_a.data, client_b.data) server_a = TestProtocol() client_a = TestProtocol() closed_a = loopbackAsync(server_a, client_a) server_b = TestProtocol() client_b = TestProtocol() closed_b = loopbackAsync(server_b, client_b) closed = DeferredList([closed_a, closed_b]) closed.addCallback(check, server_a, client_a, server_b, client_b) return closed
def test_interleaving(self): """Ensure that protocol runs are interleaved differently each time.""" class TestProtocol(Protocol): """Simple protocol that stores a trace of its invocations.""" def __init__(self, name, trace): self.name = name self.trace = trace def connectionMade(self): """Begin conversation.""" self.transport.write("Hello there, I'm happy to meet you! 1") def dataReceived(self, data): """Record in the trace that data was received.""" self.trace.append(self.name) if "1" in data: self.transport.write("I am pleased to meet you too! 2") if "2" in data: self.transport.write("Okay, but I gotta go now... 3") if "3" in data: self.transport.write("Goodbye! 4") if "4" in data: self.transport.loseConnection() trace_a = [] server_a = TestProtocol("Server", trace_a) client_a = TestProtocol("Client", trace_a) closed_a = loopbackAsync(server_a, client_a) trace_b = [] server_b = TestProtocol("Server", trace_b) client_b = TestProtocol("Client", trace_b) closed_b = loopbackAsync(server_b, client_b) closed = DeferredList([closed_a, closed_b]) closed.addCallback(lambda _: self.failIfEqual(trace_a, trace_b)) return closed
def create_loopback_runtime(self, id, players): """Create a L{Runtime} connected with a loopback. This is used to connect Runtime instances without involving real network traffic -- this is transparent to the Runtime. @param id: ID of the player owning this Runtime. @param players: player configuration. """ # This will yield a Runtime when all protocols are connected. result = Deferred() # Create a runtime that knows about no other players than itself. # It will eventually be returned in result when the factory has # determined that all needed protocols are ready. runtime = self.runtime_class(players[id], self.threshold) factory = ShareExchangerFactory(runtime, players, result) # We add the Deferred passed to ShareExchangerFactory and not # the Runtime, since we want everybody to wait until all # runtimes are ready. self.runtimes.append(result) for peer_id in players: if peer_id != id: protocol = ShareExchanger() protocol.factory = factory # Keys for when we are the client and when we are the server. client_key = (id, peer_id) server_key = (peer_id, id) # Store a protocol used when we are the server. self.protocols[server_key] = protocol if peer_id > id: # Make a "connection" to the other player. We are # the client (because we initiate the connection) # and the other player is the server. client = self.protocols[client_key] server = self.protocols[server_key] # The loopback connection pumps data back and # forth, and when both sides has closed the # connection, then the returned Deferred will # fire. sentinel = loopbackAsync(server, client) self.close_sentinels.append(sentinel) else: protocol = SelfShareExchanger(id, SelfShareExchangerFactory(runtime)) protocol.transport = FakeTransport() # Keys for when we are the client and when we are the server. server_key = (id, id) # Store a protocol used when we are the server. self.protocols[server_key] = protocol