def testTcpServerCloseActiveConnection(self): ''' Test server_close() while there are active TCP connections ''' data = b"\x01\x00\x00\x00\x00\x06\x01\x01\x00\x00\x00\x01" server = yield from StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving random_port = server.server.sockets[0].getsockname()[1] # get the random server port step1 = self.loop.create_future() done = self.loop.create_future() received_value = None class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): self.transport = transport step1.set_result(True) transport, protocol = yield from self.loop.create_connection(BasicClient, host='127.0.0.1',port=random_port) yield from step1 # On Windows we seem to need to give this an extra chance to finish, # otherwise there ends up being an active connection at the assert. yield from asyncio.sleep(0.0) server.server_close() # close isn't synchronous and there's no notification that it's done # so we have to wait a bit yield from asyncio.sleep(0.0) self.assertTrue( len(server.active_connections) == 0 )
def testTcpServerNoSlave(self): ''' Test unknown slave unit exception ''' context = ModbusServerContext(slaves={0x01: self.store, 0x02: self.store }, single=False) data = b"\x01\x00\x00\x00\x00\x06\x05\x03\x00\x00\x00\x01" # get slave 5 function 3 (holding register) server = yield from StartTcpServer(context=context,address=("127.0.0.1", 0),loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving connect, receive, eof = self.loop.create_future(),self.loop.create_future(),self.loop.create_future() received_data = None random_port = server.server.sockets[0].getsockname()[1] # get the random server port class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): _logger.debug("Client connected") self.transport = transport transport.write(data) connect.set_result(True) def data_received(self, data): _logger.debug("Client received data") receive.set_result(True) received_data = data def eof_received(self): _logger.debug("Client stream eof") eof.set_result(True) transport, protocol = yield from self.loop.create_connection(BasicClient, host='127.0.0.1',port=random_port) yield from asyncio.wait_for(connect, timeout=0.1) self.assertFalse(eof.done()) server.server_close()
def testTcpServerReceiveData(self): ''' Test data sent on socket is received by internals - doesn't not process data ''' data = b'\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x19' server = yield from StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving with patch('pymodbus.transaction.ModbusSocketFramer.processIncomingPacket', new_callable=Mock) as process: # process = server.framer.processIncomingPacket = Mock() connected = self.loop.create_future() random_port = server.server.sockets[0].getsockname()[1] # get the random server port class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): self.transport = transport self.transport.write(data) connected.set_result(True) def eof_received(self): pass transport, protocol = yield from self.loop.create_connection(BasicClient, host='127.0.0.1',port=random_port) yield from asyncio.sleep(0.1) # this may be better done by making an internal hook in the actual implementation # if this unit test fails on a machine, see if increasing the sleep time makes a difference, if it does # blame author for a fix if PYTHON_VERSION >= (3, 6): process.assert_called_once() self.assertTrue( process.call_args[1]["data"] == data ) server.server_close()
def testStartTcpServer(self): ''' Test that the modbus tcp asyncio server starts correctly ''' identity = ModbusDeviceIdentification(info={0x00: 'VendorName'}) self.loop = asynctest.Mock(self.loop) server = yield from StartTcpServer(context=self.context,loop=self.loop,identity=identity) self.assertEqual(server.control.Identity.VendorName, 'VendorName') if PYTHON_VERSION >= (3, 6): self.loop.create_server.assert_called_once()
def testTcpServerServeNoDefer(self): ''' Test StartTcpServer without deferred start (immediate execution of server) ''' with patch('asyncio.base_events.Server.serve_forever', new_callable=asynctest.CoroutineMock) as serve: server = yield from StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop, defer_start=False) serve.assert_awaited()
def testUdpServerServeForeverStart(self): ''' Test StartUdpServer serve_forever() method ''' with patch('asyncio.base_events.Server.serve_forever', new_callable=asynctest.CoroutineMock) as serve: server = yield from StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop) yield from server.serve_forever() serve.assert_awaited()
def testTcpServerServeForeverTwice(self): ''' Call on serve_forever() twice should result in a runtime error ''' server = yield from StartTcpServer(context=self.context,address=("127.0.0.1", 0), loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving with self.assertRaises(RuntimeError): yield from server.serve_forever() server.server_close()
def testTcpServerConnectionLost(self): ''' Test tcp stream interruption ''' data = b"\x01\x00\x00\x00\x00\x06\x01\x01\x00\x00\x00\x01" server = yield from StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving random_port = server.server.sockets[0].getsockname()[1] # get the random server port step1 = self.loop.create_future() # done = self.loop.create_future() # received_value = None time.sleep(1) class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): self.transport = transport step1.set_result(True) transport, protocol = yield from self.loop.create_connection(BasicClient, host='127.0.0.1', port=random_port) yield from step1 # On Windows we seem to need to give this an extra chance to finish, # otherwise there ends up being an active connection at the assert. yield from asyncio.sleep(0.0) self.assertTrue(len(server.active_connections) == 1) protocol.transport.close() # close isn't synchronous and there's no notification that it's done # so we have to wait a bit allowed_delay = 1 deadline = time.monotonic() + allowed_delay while time.monotonic() <= deadline: yield from asyncio.sleep(0.1) if len(server.active_connections) == 0: break else: self.assertTrue( len(server.active_connections) == 0, msg="connections not closed within {} seconds".format(allowed_delay), ) server.server_close()
def testTcpServerInternalException(self): ''' Test sending garbage data on a TCP socket should drop the connection ''' data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01" # get slave 5 function 3 (holding register) server = yield from StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving with patch( "pymodbus.register_read_message.ReadHoldingRegistersRequest.execute", side_effect=Exception): connect, receive, eof = self.loop.create_future( ), self.loop.create_future(), self.loop.create_future() received_data = None random_port = server.server.sockets[0].getsockname()[ 1] # get the random server port class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): _logger.debug("Client connected") self.transport = transport transport.write(data) connect.set_result(True) def data_received(self, data): _logger.debug("Client received data") receive.set_result(True) received_data = data def eof_received(self): _logger.debug("Client stream eof") eof.set_result(True) transport, protocol = yield from self.loop.create_connection( BasicClient, host='127.0.0.1', port=random_port) yield from asyncio.wait_for(connect, timeout=0.1) yield from asyncio.wait_for(receive, timeout=0.1) self.assertFalse(eof.done()) transport.close() server.server_close()
def testTcpServerException(self): ''' Sending garbage data on a TCP socket should drop the connection ''' garbage = b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' server = yield from StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving with patch( 'pymodbus.transaction.ModbusSocketFramer.processIncomingPacket', new_callable=lambda: Mock(side_effect=Exception)) as process: connect, receive, eof = self.loop.create_future( ), self.loop.create_future(), self.loop.create_future() received_data = None random_port = server.server.sockets[0].getsockname()[ 1] # get the random server port class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): _logger.debug("Client connected") self.transport = transport transport.write(garbage) connect.set_result(True) def data_received(self, data): _logger.debug("Client received data") receive.set_result(True) received_data = data def eof_received(self): _logger.debug("Client stream eof") eof.set_result(True) transport, protocol = yield from self.loop.create_connection( BasicClient, host='127.0.0.1', port=random_port) yield from asyncio.wait_for(connect, timeout=0.1) yield from asyncio.wait_for(eof, timeout=0.1) # neither of these should timeout if the test is successful server.server_close()
def testTcpServerRoundtrip(self): ''' Test sending and receiving data on tcp socket ''' data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01" # unit 1, read register expected_response = b'\x01\x00\x00\x00\x00\x05\x01\x03\x02\x00\x11' # value of 17 as per context server = yield from StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving random_port = server.server.sockets[0].getsockname()[ 1] # get the random server port connected, done = self.loop.create_future(), self.loop.create_future() received_value = None class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): self.transport = transport self.transport.write(data) connected.set_result(True) def data_received(self, data): nonlocal received_value, done received_value = data done.set_result(True) def eof_received(self): pass transport, protocol = yield from self.loop.create_connection( BasicClient, host='127.0.0.1', port=random_port) yield from asyncio.wait_for(done, timeout=0.1) self.assertEqual(received_value, expected_response) transport.close() yield from asyncio.sleep(0) server.server_close()
def testTcpServerConnectionLost(self): ''' Test tcp stream interruption ''' data = b"\x01\x00\x00\x00\x00\x06\x01\x01\x00\x00\x00\x01" server = yield from StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop) if PYTHON_VERSION >= (3, 7): server_task = asyncio.create_task(server.serve_forever()) else: server_task = asyncio.ensure_future(server.serve_forever()) yield from server.serving random_port = server.server.sockets[0].getsockname()[ 1] # get the random server port step1 = self.loop.create_future() # done = self.loop.create_future() # received_value = None time.sleep(1) class BasicClient(asyncio.BaseProtocol): def connection_made(self, transport): self.transport = transport step1.set_result(True) transport, protocol = yield from self.loop.create_connection( BasicClient, host='127.0.0.1', port=random_port) yield from step1 # await asyncio.sleep(1) self.assertTrue(len(server.active_connections) == 1) protocol.transport.close( ) # close isn't synchronous and there's no notification that it's done # so we have to wait a bit yield from asyncio.sleep(0.1) self.assertTrue(len(server.active_connections) == 0) server.server_close()