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 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 testTcpServerServeForever(self): ''' Test StartTcpServer 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 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 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 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 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 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 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 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()