Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions pymodbus/transaction/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from ..framer import FramerAscii, FramerBase, FramerRTU
from ..logging import Log
from ..pdu import ModbusPDU
from ..transport import CommParams, ModbusProtocol
from ..transport import CommParams, CommType, ModbusProtocol


class TransactionManager(ModbusProtocol):
Expand Down Expand Up @@ -169,7 +169,8 @@ def sync_execute(self, no_response_expected: bool, request: ModbusPDU) -> Modbus
except asyncio.exceptions.TimeoutError:
count_retries += 1
if self.count_until_disconnect < 0:
self.connection_lost(asyncio.TimeoutError("Server not responding"))
if self.comm_params.comm_type != CommType.SERIAL:
self.connection_lost(asyncio.TimeoutError("Server not responding"))
raise self._io_exception_from_request(
"ERROR: No response received of the last requests (default: retries+3), CLOSING CONNECTION.",
request,
Expand Down Expand Up @@ -225,7 +226,8 @@ async def execute(
except asyncio.exceptions.TimeoutError:
count_retries += 1
if self.count_until_disconnect < 0:
self.connection_lost(asyncio.TimeoutError("Server not responding"))
if self.comm_params.comm_type != CommType.SERIAL:
self.connection_lost(asyncio.TimeoutError("Server not responding"))
raise self._io_exception_from_request(
"ERROR: No response received of the last requests (default: retries+3), CLOSING CONNECTION.",
request,
Expand Down
46 changes: 32 additions & 14 deletions test/transaction/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from pymodbus.pdu import DecodePDU, ExceptionResponse
from pymodbus.pdu.bit_message import ReadCoilsRequest, ReadCoilsResponse
from pymodbus.transaction import TransactionManager
from pymodbus.transport import CommType


@pytest.mark.parametrize("use_port", [5098])
Expand Down Expand Up @@ -186,8 +187,8 @@ async def test_transaction_data_2(self, use_clc, test):
transact.response_future.set_result((1, pdu))
transact.callback_data(packet)

@pytest.mark.parametrize("scenario", range(10))
async def test_transaction_execute(self, use_clc, scenario):
@pytest.mark.parametrize("scenario", range(11))
async def test_transaction_execute(self, use_clc, scenario): # noqa: C901
"""Test tracers in disconnect."""
transact = TransactionManager(
use_clc,
Expand Down Expand Up @@ -236,12 +237,21 @@ async def test_transaction_execute(self, use_clc, scenario):
await transact.execute(False, request)
assert exc_info.value.fcode == request.function_code
assert exc_info.value.transaction_id == request.transaction_id
elif scenario == 5: # wait receive,timeout, no_responses pass
elif scenario == 5: # wait receive,timeout, disconnect
transact.comm_params.timeout_connect = 0.1
transact.comm_params.comm_type = CommType.SERIAL
transact.count_until_disconnect = -1
transact.connection_lost = mock.Mock() # type: ignore[method-assign]
with pytest.raises(ModbusIOException) as exc_info:
await transact.execute(False, request)
assert exc_info.value.fcode == request.function_code
assert exc_info.value.transaction_id == request.transaction_id
elif scenario == 6: # wait receive,timeout, no_responses pass
transact.comm_params.timeout_connect = 0.1
transact.connection_lost = mock.Mock() # type: ignore[method-assign]
with pytest.raises(ModbusIOException):
await transact.execute(False, request)
elif scenario == 6: # wait receive, cancel
elif scenario == 7: # wait receive, cancel
transact.comm_params.timeout_connect = 0.2
resp = asyncio.create_task(transact.execute(False, request))
await asyncio.sleep(0.1)
Expand All @@ -250,14 +260,14 @@ async def test_transaction_execute(self, use_clc, scenario):
with pytest.raises(asyncio.CancelledError):
await resp
assert resp.cancelled()
elif scenario == 7: # response
elif scenario == 8: # response
transact.comm_params.timeout_connect = 0.2
resp = asyncio.create_task(transact.execute(False, request))
await asyncio.sleep(0.1)
transact.response_future.set_result(response)
await asyncio.sleep(0.1)
assert response == await resp
elif scenario == 8: # response wrong dev_id
elif scenario == 9: # response wrong dev_id
transact.comm_params.timeout_connect = 0.2
resp = asyncio.create_task(transact.execute(False, request))
await asyncio.sleep(0.1)
Expand All @@ -270,7 +280,7 @@ async def test_transaction_execute(self, use_clc, scenario):
assert exc_info.value.fcode == request.function_code
assert exc_info.value.dev_id == request.dev_id
assert exc_info.value.transaction_id == request.transaction_id
else: # if scenario == 9: # response wrong tid
else: # if scenario == 10: # response wrong tid
transact.comm_params.timeout_connect = 0.2
resp = asyncio.create_task(transact.execute(False, request))
await asyncio.sleep(0.1)
Expand Down Expand Up @@ -421,8 +431,8 @@ def test_sync_transaction_instance(self, use_clc):
sync_client=client,
)

@pytest.mark.parametrize("scenario", range(10))
async def test_sync_transaction_execute(self, use_clc, scenario):
@pytest.mark.parametrize("scenario", range(11))
async def test_sync_transaction_execute(self, use_clc, scenario): # noqa: C901
"""Test tracers in disconnect."""
client = self.dummy_client(use_clc)
transact = TransactionManager(
Expand Down Expand Up @@ -473,19 +483,27 @@ async def test_sync_transaction_execute(self, use_clc, scenario):
transact.sync_execute(False, request)
assert exc_info.value.fcode == request.function_code
assert exc_info.value.transaction_id == request.transaction_id
elif scenario == 5: # wait receive,timeout, no_responses pass
elif scenario == 5: # wait receive,timeout, disconnect
transact.comm_params.timeout_connect = 0.1
transact.comm_params.comm_type = CommType.SERIAL
transact.count_until_disconnect = -1
with pytest.raises(ModbusIOException) as exc_info:
transact.sync_execute(False, request)
assert exc_info.value.fcode == request.function_code
assert exc_info.value.transaction_id == request.transaction_id
elif scenario == 6: # wait receive,timeout, no_responses pass
transact.comm_params.timeout_connect = 0.1
with pytest.raises(ModbusIOException):
transact.sync_execute(False, request)
elif scenario == 6: # response
elif scenario == 7: # response
transact.transport = 1 # type: ignore[assignment]
resp_bytes = transact.framer.buildFrame(response)
transact.sync_client.recv = mock.Mock(return_value=resp_bytes)
transact.sync_client.send = mock.Mock()
transact.comm_params.timeout_connect = 0.2
resp = transact.sync_execute(False, request)
assert response.bits == resp.bits
elif scenario == 7: # response wrong dev_id
elif scenario == 8: # response wrong dev_id
transact.transport = 1 # type: ignore[assignment]
pdu = copy.deepcopy(response)
pdu.dev_id = 17
Expand All @@ -497,7 +515,7 @@ async def test_sync_transaction_execute(self, use_clc, scenario):
assert exc_info.value.fcode == request.function_code
assert exc_info.value.dev_id == request.dev_id
assert exc_info.value.transaction_id == request.transaction_id
elif scenario == 8: # response wrong tid
elif scenario == 9: # response wrong tid
transact.transport = 1 # type: ignore[assignment]
pdu = copy.deepcopy(response)
pdu.transaction_id = 17
Expand All @@ -509,7 +527,7 @@ async def test_sync_transaction_execute(self, use_clc, scenario):
assert exc_info.value.fcode == request.function_code
assert exc_info.value.dev_id == request.dev_id
assert exc_info.value.transaction_id == request.transaction_id
else: # if scenario == 9 # pdu_send from client
else: # if scenario == 10 # pdu_send from client
transact.transport = 1 # type: ignore[assignment]
transact.is_server = True
resp_bytes = transact.framer.buildFrame(response)
Expand Down