File: test_examples.py

package info (click to toggle)
pymodbus 3.8.6-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,720 kB
  • sloc: python: 14,867; makefile: 27; sh: 17
file content (234 lines) | stat: -rwxr-xr-x 8,767 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
"""Test example server/client async.

This is a thorough test of the clientexamples.

"""
import asyncio
from threading import Thread
from time import sleep
from unittest import mock

import pytest

from examples.client_async import run_a_few_calls, run_async_client, setup_async_client
from examples.client_async_calls import async_template_call
from examples.client_async_calls import main as main_client_async_calls
from examples.client_calls import main as main_client_calls
from examples.client_calls import template_call
from examples.client_payload import main as main_payload_calls
from examples.custom_msg import main as main_custom_client
from examples.datastore_simulator_share import main as main_datastore_simulator_share3
from examples.message_parser import main as main_parse_messages
from examples.server_async import setup_server
from examples.server_callback import run_callback_server
from examples.server_payload import main as main_payload_server
from examples.server_sync import run_sync_server
from examples.server_updating import main as main_updating_server
from examples.simple_async_client import run_async_simple_client
from examples.simple_sync_client import run_sync_simple_client
from examples.simulator import run_simulator as run_simulator3
from examples.simulator_datamodel import main as run_main_simulator_datamodel
from pymodbus.exceptions import ModbusException
from pymodbus.pdu import ExceptionResponse
from pymodbus.server import ServerAsyncStop, ServerStop


class TestExamples:
    """Test examples."""

    @staticmethod
    @pytest.fixture(name="use_port")
    def get_port_in_class(base_ports):
        """Return next port."""
        base_ports[__class__.__name__] += 1
        return base_ports[__class__.__name__]

    @pytest.mark.parametrize("framer", ["socket", "rtu", "ascii"])
    def test_message_parser(self, framer):
        """Test message parser."""
        main_parse_messages(["--framer", framer, "-m", "000100000006010100200001"])
        main_parse_messages(["--framer", framer, "-m", "00010000000401010101"])

    async def test_server_callback(self, use_port, use_host):
        """Test server/client with payload."""
        cmdargs = ["--port", str(use_port), "--host", use_host]
        task = asyncio.create_task(run_callback_server(cmdline=cmdargs))
        task.set_name("run callback_server")
        await asyncio.sleep(0.1)
        testclient = setup_async_client(cmdline=cmdargs)
        await run_async_client(testclient, modbus_calls=run_a_few_calls)
        await asyncio.sleep(0.1)
        await ServerAsyncStop()
        await asyncio.sleep(0.1)
        task.cancel()
        await task

    async def test_updating_server(self, use_port, use_host):
        """Test server server updating."""
        cmdargs = ["--port", str(use_port), "--host", use_host]
        task = asyncio.create_task(main_updating_server(cmdline=cmdargs))
        task.set_name("run main_updating_server")
        await asyncio.sleep(0.1)
        client = setup_async_client(cmdline=cmdargs)
        await run_async_client(client, modbus_calls=run_a_few_calls)
        await asyncio.sleep(0.1)
        await ServerAsyncStop()
        await asyncio.sleep(0.1)
        task.cancel()
        await task

    async def test_datastore_simulator_share(self, use_port, use_host):
        """Test server simulator."""
        cmdargs = ["--port", str(use_port), "--host", use_host]
        task = asyncio.create_task(main_datastore_simulator_share3(cmdline=cmdargs))
        task.set_name("run main_datastore_simulator3")
        await asyncio.sleep(0.1)
        testclient = setup_async_client(cmdline=cmdargs)
        await run_async_client(testclient, modbus_calls=run_a_few_calls)
        await asyncio.sleep(0.1)
        await ServerAsyncStop()
        await asyncio.sleep(0.1)
        task.cancel()
        await task

    async def test_simulator3(self):
        """Run simulator3 server/client."""
        # Awaiting fix, missing stop of task.
        await run_simulator3()

    def test_simulator_datamodel(self):
        """Run different simulator configurations."""
        run_main_simulator_datamodel()

    async def test_modbus_forwarder(self):
        """Test modbus forwarder."""
        print("waiting for fix")


@pytest.mark.parametrize(
    ("use_comm", "use_framer"),
    [
        ("tcp", "socket"),
        ("tcp", "rtu"),
        ("tls", "tls"),
        ("udp", "socket"),
        ("udp", "rtu"),
        ("serial", "rtu"),
    ],
)
class TestAsyncExamples:
    """Test examples."""

    @staticmethod
    @pytest.fixture(name="use_port")
    def get_port_in_class(base_ports):
        """Return next port."""
        base_ports[__class__.__name__] += 1
        return base_ports[__class__.__name__]

    async def test_client_async_calls(self, mock_server):
        """Test client_async_calls."""
        await main_client_async_calls(cmdline=mock_server)

    async def test_client_async_calls_errors(self, mock_server):
        """Test client_async_calls."""
        client = setup_async_client(cmdline=mock_server)
        client.read_coils = mock.AsyncMock(side_effect=ModbusException("test"))
        with pytest.raises(ModbusException):
            await run_async_client(client, modbus_calls=async_template_call)
        client.close()
        client.read_coils = mock.AsyncMock(return_value=ExceptionResponse(0x05, 0x10))
        with pytest.raises(ModbusException):
            await run_async_client(client, modbus_calls=async_template_call)
        client.close()

    async def test_client_calls_errors(self, mock_server):
        """Test client_calls."""
        client = setup_async_client(cmdline=mock_server)
        client.read_coils = mock.Mock(side_effect=ModbusException("test"))
        with pytest.raises(ModbusException):
            await run_async_client(client, modbus_calls=async_template_call)
        client.close()
        client.read_coils = mock.Mock(return_value=ExceptionResponse(0x05, 0x10))
        with pytest.raises(ModbusException):
            await run_async_client(client, modbus_calls=template_call)
        client.close()

    async def test_custom_msg(self, use_comm, use_port, use_framer, use_host):
        """Test client with custom message."""
        _ = use_framer
        if use_comm != "tcp":
            return
        await main_custom_client(port=use_port, host=use_host)

    async def test_payload(self, mock_clc, mock_cls):
        """Test server/client with payload."""
        task = asyncio.create_task(main_payload_server(cmdline=mock_cls))
        task.set_name("run main_payload_server")
        await asyncio.sleep(0.1)
        await main_payload_calls(cmdline=mock_clc)
        await asyncio.sleep(0.1)
        await ServerAsyncStop()
        await asyncio.sleep(0.1)
        task.cancel()
        await task

    async def test_async_simple_client(
        self, use_comm, use_port, use_framer, mock_server, use_host
    ):
        """Run simple async client."""
        _cmdline = mock_server
        if use_comm == "tls":
            return
        if use_comm == "udp" and use_framer == "rtu":
            return
        if use_comm == "serial":
            use_port = f"socket://{use_host}:{use_port}"
        await run_async_simple_client(use_comm, use_host, use_port, framer=use_framer)


@pytest.mark.parametrize("use_host", ["localhost"])
@pytest.mark.parametrize(
    ("use_comm", "use_framer"),
    [
        ("tcp", "socket"),
        ("tcp", "rtu"),
        # awaiting fix: ("tls", "tls"),
        ("udp", "socket"),
        ("udp", "rtu"),
        ("serial", "rtu"),
    ],
)
class TestSyncExamples:
    """Test examples."""

    @staticmethod
    @pytest.fixture(name="use_port")
    def get_port_in_class(base_ports):
        """Return next port."""
        base_ports[__class__.__name__] += 1
        return base_ports[__class__.__name__]

    def test_client_calls(self, mock_clc, mock_cls):
        """Test client_calls."""
        server_args = setup_server(cmdline=mock_cls)
        thread = Thread(target=run_sync_server, args=(server_args,))
        thread.daemon = True
        thread.start()
        sleep(1)
        main_client_calls(cmdline=mock_clc)
        ServerStop()

    def test_sync_simple_client(
        self, use_framer, use_comm, use_host, use_port, mock_cls
    ):
        """Run simple async client."""
        server_args = setup_server(cmdline=mock_cls)
        thread = Thread(target=run_sync_server, args=(server_args,))
        thread.daemon = True
        thread.start()
        sleep(1)
        if use_comm == "serial":
            use_port = f"socket://{use_host}:{use_port}"
        run_sync_simple_client(use_comm, use_host, use_port, framer=use_framer)
        ServerStop()