def test_send_non_binary_message(self): """ A non-binary WebSocket message is an error """ ws_factory = WebSocketServerFactory("ws://localhost:4002") ws_factory.protocol = WebSocketTransitConnection ws_protocol = ws_factory.buildProtocol(('127.0.0.1', 0)) with self.assertRaises(ValueError): ws_protocol.onMessage(u"foo", isBinary=False)
def _new_protocol_ws(transit_server, log_requests): """ Internal helper for test-suites that need to provide WebSocket client/server pairs. :returns: a 2-tuple: (iosim.IOPump, protocol) """ ws_factory = WebSocketServerFactory("ws://localhost:4002") ws_factory.protocol = WebSocketTransitConnection ws_factory.transit = transit_server ws_factory.log_requests = log_requests ws_protocol = ws_factory.buildProtocol(('127.0.0.1', 0)) @implementer(IRelayTestClient) class TransitWebSocketClientProtocol(WebSocketClientProtocol): _received = b"" connected = False def connectionMade(self): self.connected = True return super(TransitWebSocketClientProtocol, self).connectionMade() def connectionLost(self, reason): self.connected = False return super(TransitWebSocketClientProtocol, self).connectionLost(reason) def onMessage(self, data, isBinary): self._received = self._received + data def send(self, data): self.sendMessage(data, True) def get_received_data(self): return self._received def reset_received_data(self): self._received = b"" def disconnect(self): self.sendClose(1000, True) client_factory = WebSocketClientFactory() client_factory.protocol = TransitWebSocketClientProtocol client_protocol = client_factory.buildProtocol(('127.0.0.1', 31337)) client_protocol.disconnect = client_protocol.dropConnection pump = iosim.connect( ws_protocol, iosim.makeFakeServer(ws_protocol), client_protocol, iosim.makeFakeClient(client_protocol), ) return pump, client_protocol
class TestPing(unittest.TestCase): def setUp(self): if False: # debug leftover reactor events import twisted.internet.base twisted.internet.base.DelayedCall.debug = True self.factory = WebSocketServerFactory(protocols=['wamp.2.json']) self.factory.protocol = WebSocketServerProtocol self.factory.doStart() self.proto = self.factory.buildProtocol(IPv4Address('TCP', '127.0.0.1', 65534)) self.transport = MagicMock() self.proto.transport = self.transport self.proto.connectionMade() def tearDown(self): self.factory.doStop() # not really necessary, but ... del self.factory del self.proto def test_unclean_timeout(self): """ make a delayed call to drop the connection """ # first we have to drive the protocol to STATE_CLOSING # ... which we achieve by sendCloseFrame after we're in # STATE_OPEN # XXX double-check this is the correct code-path to get here # "normally"? if False: self.proto.debug = True self.proto.factory._log = print # get to STATE_OPEN self.proto.data = mock_handshake_client self.proto.processHandshake() self.assertTrue(self.proto.state == WebSocketServerProtocol.STATE_OPEN) with replace_loop(Clock()) as reactor: # now 'do the test' and transition to CLOSING self.proto.sendCloseFrame() # check we scheduled a call self.assertEqual(len(reactor.calls), 1) self.assertEqual(reactor.calls[0].func, self.proto.onCloseHandshakeTimeout) self.assertEqual(reactor.calls[0].getTime(), self.proto.closeHandshakeTimeout) # now, advance the clock past the call (and thereby # execute it) reactor.advance(self.proto.closeHandshakeTimeout + 1) # we should have called abortConnection self.assertEqual("call.abortConnection()", str(self.proto.transport.method_calls[-1])) self.assertTrue(self.proto.transport.abortConnection.called) # ...too "internal" for an assert? self.assertEqual(self.proto.state, WebSocketServerProtocol.STATE_CLOSED) def test_auto_pingpong_timeout(self): """ autoping and autoping-timeout timing """ if False: self.proto.debug = True self.proto.factory._log = print self.proto.debugCodePaths = True # options are evaluated in succeedHandshake, called below self.proto.autoPingInterval = 5 self.proto.autoPingTimeout = 2 with replace_loop(Clock()) as reactor: # get to STATE_OPEN self.proto.data = mock_handshake_client self.proto.processHandshake() self.assertTrue(self.proto.state == WebSocketServerProtocol.STATE_OPEN) # we should have scheduled an autoPing self.assertEqual(1, len(reactor.calls)) self.assertEqual(self.proto._sendAutoPing, reactor.calls[0].func) # ^^ un-unit-testy to assert on internal method? # advance past first auto-ping timeout reactor.advance(5) # first element from args tuple from transport.write() # call is our data self.assertTrue(self.transport.write.called) data = self.transport.write.call_args[0][0] # the opcode is the lower 7 bits of the first byte. (opcode,) = struct.unpack("B", data[0]) opcode = opcode & (~0x80) # ... and should be "9" for ping self.assertEqual(9, opcode) # Because we have autoPingTimeout there should be # another delayed-called created now self.assertEqual(1, len(reactor.calls)) self.assertEqual(self.proto.onAutoPingTimeout, reactor.calls[0].func) self.assertNotEqual(self.proto.state, self.proto.STATE_CLOSED) # ...which we'll now cause to trigger, aborting the connection reactor.advance(3) self.assertEqual(self.proto.state, self.proto.STATE_CLOSED) def test_auto_ping_got_pong(self): """ auto-ping with correct reply cancels timeout """ if False: self.proto.debug = True self.proto.factory._log = print self.proto.debugCodePaths = True # options are evaluated in succeedHandshake, called below self.proto.autoPingInterval = 5 self.proto.autoPingTimeout = 2 with replace_loop(Clock()) as reactor: # get to STATE_OPEN self.proto.data = mock_handshake_client self.proto.processHandshake() self.assertTrue(self.proto.state == WebSocketServerProtocol.STATE_OPEN) # we should have scheduled an autoPing self.assertEqual(1, len(reactor.calls)) self.assertEqual(self.proto._sendAutoPing, reactor.calls[0].func) # ^^ un-unit-testy to assert on internal method? # advance past first auto-ping timeout reactor.advance(5) # should have an auto-ping timeout scheduled, and we # save it for later (to check it got cancelled) self.assertEqual(1, len(reactor.calls)) self.assertEqual(self.proto.onAutoPingTimeout, reactor.calls[0].func) timeout_call = reactor.calls[0] # elsewhere we check that we actually send an opcode-9 # message; now we just blindly inject our own reply # with a PONG frame frame = create_client_frame(opcode=10, payload=self.proto.autoPingPending) self.proto.data = frame # really needed twice; does header first, then rest self.proto.processData() self.proto.processData() # which should have cancelled the call self.assertTrue(timeout_call.cancelled)
class TestPing(unittest.TestCase): def setUp(self): self.factory = WebSocketServerFactory(protocols=['wamp.2.json']) self.factory.protocol = WebSocketServerProtocol self.factory.doStart() self.proto = self.factory.buildProtocol( IPv4Address('TCP', '127.0.0.1', 65534)) self.transport = MagicMock() self.proto.transport = self.transport self.proto.connectionMade() def tearDown(self): if self.proto.openHandshakeTimeoutCall: self.proto.openHandshakeTimeoutCall.cancel() self.factory.doStop() # not really necessary, but ... del self.factory del self.proto def test_unclean_timeout(self): """ make a delayed call to drop the connection """ # first we have to drive the protocol to STATE_CLOSING # ... which we achieve by sendCloseFrame after we're in # STATE_OPEN # XXX double-check this is the correct code-path to get here # "normally"? # get to STATE_OPEN self.proto.data = mock_handshake_client self.proto.processHandshake() self.assertTrue( self.proto.state == WebSocketServerProtocol.STATE_OPEN) with replace_loop(Clock()) as reactor: # now 'do the test' and transition to CLOSING self.proto.sendCloseFrame() # check we scheduled a call self.assertEqual(len(reactor.calls), 1) # now, advance the clock past the call (and thereby # execute it) reactor.advance(self.proto.closeHandshakeTimeout + 1) # we should have called abortConnection self.assertEqual("call.abortConnection()", str(self.proto.transport.method_calls[-1])) self.assertTrue(self.proto.transport.abortConnection.called) # ...too "internal" for an assert? self.assertEqual(self.proto.state, WebSocketServerProtocol.STATE_CLOSED) def test_auto_pingpong_timeout(self): """ autoping and autoping-timeout timing """ # options are evaluated in succeedHandshake, called below self.proto.autoPingInterval = 5 self.proto.autoPingTimeout = 2 with replace_loop(Clock()) as reactor: # get to STATE_OPEN self.proto.data = mock_handshake_client self.proto.processHandshake() self.assertTrue( self.proto.state == WebSocketServerProtocol.STATE_OPEN) # we should have scheduled an autoPing self.assertEqual(1, len(reactor.calls)) # advance past first auto-ping timeout reactor.advance(5) # first element from args tuple from transport.write() # call is our data self.assertTrue(self.transport.write.called) data = self.transport.write.call_args[0][0] if PY3: _data = bytes([data[0]]) else: _data = data[0] # the opcode is the lower 7 bits of the first byte. (opcode, ) = struct.unpack("B", _data) opcode = opcode & (~0x80) # ... and should be "9" for ping self.assertEqual(9, opcode) # Because we have autoPingTimeout there should be # another delayed-called created now self.assertEqual(1, len(reactor.calls)) self.assertNotEqual(self.proto.state, self.proto.STATE_CLOSED) # ...which we'll now cause to trigger, aborting the connection reactor.advance(3) self.assertEqual(self.proto.state, self.proto.STATE_CLOSED) def test_auto_ping_got_pong(self): """ auto-ping with correct reply cancels timeout """ # options are evaluated in succeedHandshake, called below self.proto.autoPingInterval = 5 self.proto.autoPingTimeout = 2 with replace_loop(Clock()) as reactor: # get to STATE_OPEN self.proto.data = mock_handshake_client self.proto.processHandshake() self.assertTrue( self.proto.state == WebSocketServerProtocol.STATE_OPEN) # we should have scheduled an autoPing self.assertEqual(1, len(reactor.calls)) # advance past first auto-ping timeout reactor.advance(5) # should have an auto-ping timeout scheduled, and we # save it for later (to check it got cancelled) self.assertEqual(1, len(reactor.calls)) timeout_call = reactor.calls[0] # elsewhere we check that we actually send an opcode-9 # message; now we just blindly inject our own reply # with a PONG frame frame = create_client_frame(opcode=10, payload=self.proto.autoPingPending) self.proto.data = frame # really needed twice; does header first, then rest self.proto.processData() self.proto.processData() # which should have cancelled the call self.assertTrue(timeout_call.cancelled)
def buildProtocol(self, addr): # make a new socket protocol and tell the resource about it proto = WebSocketServerFactory.buildProtocol(self, addr) self.wsresource.add_client_proto(proto) return proto
def buildProtocol(self, addr): # make a new socket protocol and tell the resource about it proto = WebSocketServerFactory.buildProtocol(self, addr) self.wsresource.add_client_proto(proto) return proto