Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test case for UDP issue #1470

Merged
merged 4 commits into from
Apr 8, 2023
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
56 changes: 30 additions & 26 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Configure pytest."""
import functools
import platform
from collections import deque

import pytest

Expand Down Expand Up @@ -80,53 +81,56 @@ class mockSocket: # pylint: disable=invalid-name

timeout = 2

def __init__(self):
def __init__(self, copy_send=True):
"""Initialize."""
self.data = None
self.packets = deque()
self.buffer = None
self.in_waiting = 0
self.copy_send = copy_send

def mock_store(self, msg):
def mock_prepare_receive(self, msg):
"""Store message."""
self.data = msg
self.in_waiting = len(self.data)

def mock_retrieve(self, size):
"""Get message."""
if not self.data or not size:
return b""
if size >= len(self.data):
retval = self.data
else:
retval = self.data[0:size]
self.data = None
self.in_waiting = 0
return retval
self.packets.append(msg)
self.in_waiting += len(msg)

def close(self):
"""Close."""
return True

def recv(self, size):
"""Receive."""
return self.mock_retrieve(size)
if not self.packets or not size:
return b""
if not self.buffer:
self.buffer = self.packets.popleft()
if size >= len(self.buffer):
retval = self.buffer
self.buffer = None
else:
retval = self.buffer[0:size]
self.buffer = self.buffer[size]
self.in_waiting -= len(retval)
return retval

def read(self, size):
"""Read."""
return self.mock_retrieve(size)
return self.recv(size)

def recvfrom(self, size):
"""Receive from."""
return [self.recv(size)]

def send(self, msg):
"""Send."""
self.mock_store(msg)
if not self.copy_send:
return len(msg)
self.packets.append(msg)
self.in_waiting += len(msg)
return len(msg)

def recvfrom(self, size):
"""Receive from."""
return [self.mock_retrieve(size)]

def sendto(self, msg, *_args):
"""Send to."""
self.mock_store(msg)
return len(msg)
return self.send(msg)

def setblocking(self, _flag):
"""Set blocking."""
Expand Down
52 changes: 45 additions & 7 deletions test/test_client_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,48 @@ def test_udp_client_recv(self):
with pytest.raises(ConnectionException):
client.recv(1024)
client.socket = mockSocket()
client.socket.mock_store(b"\x00" * 4)
client.socket.mock_prepare_receive(b"\x00" * 4)
assert client.recv(0) == b""
assert client.recv(4) == b"\x00" * 4

def test_udp_client_recv_duplicate(self):
"""Test the udp client receive method"""
test_msg = b"\x00\x01\x00\x00\x00\x05\x01\x04\x02\x00\x03"
client = ModbusUdpClient("127.0.0.1")
client.socket = mockSocket(copy_send=False)

# test normal receive
client.socket.mock_prepare_receive(test_msg)
reply_ok = client.read_input_registers(0x820, 1, 1)
assert not reply_ok.isError()
reply_timeout = client.read_input_registers(0x820, 1, 1)
assert reply_timeout.isError()
client.close()

# test duplicate receive
client = ModbusUdpClient("127.0.0.1")
client.socket = mockSocket(copy_send=False)
client.socket.mock_prepare_receive(test_msg)
client.socket.mock_prepare_receive(test_msg)
reply_ok = client.read_input_registers(0x820, 1, 1)
assert not reply_ok.isError()
# ERROR hanging transaction --> reply_timeout = client.read_input_registers(0x820, 1, 1)
# ERROR hanging transaction --> assert reply_timeout.isError()
client.close()

# test duplicate receive with garbage
client = ModbusUdpClient("127.0.0.1")
client.socket = mockSocket(copy_send=False)
client.socket.mock_prepare_receive(test_msg)
client.socket.mock_prepare_receive(test_msg + b"\xf6\x3e")
reply_ok = client.read_input_registers(0x820, 1, 1)
assert not reply_ok.isError()
# ERROR hanging transaction --> reply_timeout = client.read_input_registers(0x820, 1, 1)
# ERROR hanging transaction --> assert reply_timeout.isError()
# ERROR hanging transaction --> reply_timeout = client.read_input_registers(0x820, 1, 1)
# ERROR hanging transaction --> assert reply_timeout.isError()
client.close()

def test_udp_client_repr(self):
"""Test udp client representation."""
client = ModbusUdpClient("127.0.0.1")
Expand Down Expand Up @@ -143,7 +181,7 @@ def test_tcp_client_recv(self, mock_select, mock_time):
client.recv(1024)
client.socket = mockSocket()
assert client.recv(0) == b""
client.socket.mock_store(b"\x00" * 4)
client.socket.mock_prepare_receive(b"\x00" * 4)
assert client.recv(4) == b"\x00" * 4

mock_socket = mock.MagicMock()
Expand All @@ -156,7 +194,7 @@ def test_tcp_client_recv(self, mock_select, mock_time):
mock_select.select.return_value = [False]
assert client.recv(2) == b""
client.socket = mockSocket()
client.socket.mock_store(b"\x00")
client.socket.mock_prepare_receive(b"\x00")
mock_select.select.return_value = [True]
assert client.recv(None) in b"\x00"

Expand Down Expand Up @@ -271,12 +309,12 @@ def test_tls_client_recv(self, mock_select, mock_time):
mock_time.time.side_effect = count()

client.socket = mockSocket()
client.socket.mock_store(b"\x00" * 4)
client.socket.mock_prepare_receive(b"\x00" * 4)
assert client.recv(0) == b""
assert client.recv(4) == b"\x00" * 4

client.params.timeout = 2
client.socket.mock_store(b"\x00")
client.socket.mock_prepare_receive(b"\x00")
assert b"\x00" in client.recv(None)

def test_tls_client_repr(self):
Expand Down Expand Up @@ -422,10 +460,10 @@ def test_serial_client_recv(self):
client.recv(1024)
client.socket = mockSocket()
assert client.recv(0) == b""
client.socket.mock_store(b"\x00" * 4)
client.socket.mock_prepare_receive(b"\x00" * 4)
assert client.recv(4) == b"\x00" * 4
client.socket = mockSocket()
client.socket.mock_store(b"")
client.socket.mock_prepare_receive(b"")
assert client.recv(None) == b""
client.socket.timeout = 0
assert client.recv(0) == b""
Expand Down
14 changes: 7 additions & 7 deletions test/test_client_sync_diag.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,28 +65,28 @@ def test_tcp_diag_client_recv(self, mock_select, mock_diag_time, mock_time):
client.recv(1024)
client.socket = mockSocket()
# Test logging of non-delayed responses
client.socket.mock_store(b"\x00")
client.socket.mock_prepare_receive(b"\x00")
assert b"\x00" in client.recv(None)
client.socket = mockSocket()
client.socket.mock_store(b"\x00")
client.socket.mock_prepare_receive(b"\x00")
assert client.recv(1) == b"\x00"

# Fool diagnostic logger into thinking we"re running late,
# test logging of delayed responses
mock_diag_time.time.side_effect = count(step=3)
client.socket.mock_store(b"\x00" * 4)
client.socket.mock_prepare_receive(b"\x00" * 4)
assert client.recv(4) == b"\x00" * 4
assert client.recv(0) == b""

client.socket.mock_store(b"\x00\x01\x02")
client.socket.mock_prepare_receive(b"\x00\x01\x02")
client.timeout = 3
assert client.recv(3) == b"\x00\x01\x02"
client.socket.mock_store(b"\x00\x01\x02")
client.socket.mock_prepare_receive(b"\x00\x01\x02")
assert client.recv(2) == b"\x00\x01"
mock_select.select.return_value = [False]
assert client.recv(2) == b""
client.socket = mockSocket()
client.socket.mock_store(b"\x00")
client.socket.mock_prepare_receive(b"\x00")
mock_select.select.return_value = [True]
assert b"\x00" in client.recv(None)

Expand All @@ -96,7 +96,7 @@ def test_tcp_diag_client_recv(self, mock_select, mock_diag_time, mock_time):
with pytest.raises(ConnectionException):
client.recv(1024)
client.socket = mockSocket()
client.socket.mock_store(b"\x00\x01\x02")
client.socket.mock_prepare_receive(b"\x00\x01\x02")
assert client.recv(1024) == b"\x00\x01\x02"

def test_tcp_diag_client_repr(self):
Expand Down