Skip to content

Commit 9f101a6

Browse files
authored
Merge pull request #23 from bp100a/abstract-socket-for-testability
Abstract socket for testability
2 parents c1a0ab0 + bf1ff6b commit 9f101a6

File tree

10 files changed

+254
-45
lines changed

10 files changed

+254
-45
lines changed

README.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ failing USBIPD attachments, and `1-2` & `1-3` have the same VID/PID (for testing
8989
During testing, the `MockUSBIP` service acts as a stand-in for an actual USBIP server. Since the tests are run in parallel,
9090
the port on which the service listens must be unique for each unit test. This is accomplished by the `conftest.py::pytest_sessionstart` which is run
9191
when the pytest session is started and collects all tests being run into a file called `lists_of_tests.json`. The unit test's index into this array
92-
is used to determine the offset to be added to the port base (typically **3240**).
92+
is used to determine the offset to be added to the port base (typically **3240**). The `SocketWrapper` class is overridden in unit tests to inject low-level socket failures.
9393

9494

9595
Tooling
@@ -124,17 +124,9 @@ pip install -r tool_requirements.txt
124124

125125
Tooling is not needed to run the package but is required for testing & packaging.
126126

127-
Build Process
127+
Build Process (_now using Poetry!_)
128128
--------------------------------------------------------------------------
129129
___
130-
Using `pip-compile` from the [pip-tools](https://pypi.org/project/pip-tools/) package, read the docs [here](https://pip-tools.readthedocs.io/en/latest/)
131-
132-
```bash
133-
pip-compile requirements.in
134-
```
135-
136-
Release to PyPi (_now using Poetry!_)
137-
----------------------------------------------------------------------------
138130
Store the PyPi API token
139131
```bash
140132
keyring set https://upload.pypi.org/legacy/ __token__

coverage.svg

Lines changed: 2 additions & 2 deletions
Loading

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ build-backend = "poetry.core.masonry.api"
66
name = "serial-usbipclient"
77
authors = [{name = "Harry J. Collins", email="bp100a@gmail.com"}]
88
maintainers = [{name = "Harry J. Collins", email="bp100a@gmail.com"}]
9-
version = "0.0.7"
109
description = "Simple serial connectivity to CDC (serial) USB devices exposed by a USBIPD service."
1110
readme = "README.md"
1211
license = {text = "BSD License"}
@@ -47,7 +46,7 @@ Repository = "https://github.com/bp100a/serial-usbipclient"
4746
name = "serial-usbipclient"
4847
authors = ["Harry J. Collins <bp100a@gmail.com>"]
4948
maintainers = ["Harry J. Collins <bp100a@gmail.com>"]
50-
version = "0.1.2"
49+
version = "0.1.3"
5150
description = "Simple serial connectivity to CDC (serial) USB devices exposed by a USBIPD service."
5251
readme = "README.md"
5352
package-mode = true

requirements.in

Lines changed: 0 additions & 1 deletion
This file was deleted.

requirements.txt

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""wraps socket so we can abstract if for testing (dependency injection)"""
2+
from socket import AddressFamily, SocketKind, socket
3+
4+
from typing_extensions import Buffer
5+
6+
7+
class SocketWrapper:
8+
"""wraps the raw socket class, exposes appropriate methods"""
9+
SOCKET_TIMEOUT: float = 0.005
10+
SERVER_CONNECT_TIMEOUT: float = 1.0
11+
12+
def __init__(self, family: AddressFamily, kind: SocketKind):
13+
"""set up socket"""
14+
self._socket: socket = socket(family, kind)
15+
self._address: tuple[str, int] = ('', 0)
16+
17+
def raw_socket(self) -> socket:
18+
"""return the underly, raw socket"""
19+
return self._socket
20+
21+
def settimeout(self, timeout: float | None) -> None:
22+
"""set the timeout on the socket"""
23+
self._socket.settimeout(timeout)
24+
25+
def connect(self, address: tuple[str, int]) -> None:
26+
"""connect to the remote host"""
27+
self._address = address
28+
self._socket.connect(self._address)
29+
30+
def setsockopt(self, level: int, option: int, value: int | Buffer) -> None:
31+
"""set the socket's options"""
32+
self._socket.setsockopt(level, option, value)
33+
34+
def shutdown(self, how: int) -> None:
35+
"""shutdown the underlying socket"""
36+
self._socket.shutdown(how)
37+
38+
def close(self) -> None:
39+
"""close the socket"""
40+
self._socket.close()
41+
42+
def getsockname(self) -> tuple[str, int]:
43+
"""get the socket's name"""
44+
return self._socket.getsockname()[1] # always returning (address, port)
45+
46+
def sendall(self, data: bytes) -> None:
47+
"""send out to our socket"""
48+
self._socket.sendall(data)
49+
50+
def recv(self, size: int) -> bytes:
51+
"""read from our socket"""
52+
return self._socket.recv(size)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
["serial_usbipclient.tests.test_connection.py.testusbipconnection.test_connection", "serial_usbipclient.tests.test_connection.py.testusbipconnection.test_connection_shutdown", "serial_usbipclient.tests.test_connection.py.testusbipconnection.test_queue_urbs", "serial_usbipclient.tests.test_descriptors.py.testinterfacedescriptor.test_descriptors", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_mock_usbip_server_connection", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_mock_usbip_server_startup", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_mocked_response", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_reading_paths", "serial_usbipclient.tests.test_mock_usbip_server.py.testdeviceconfiguration.test_lsusb_parsing", "serial_usbipclient.tests.test_mock_usbip_server.py.testdeviceconfiguration.test_usbip_path", "serial_usbipclient.tests.test_packaging.py.testversion.test_version", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_cmd_response", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_cmd_submit", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_iso_packet_descriptor", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_metastruct_size", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_queue_urb", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_request_devlist", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_sizing", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_urb_endianness", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_configuration", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_delimited_read", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_failed_attachment", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_hardware_id_formatting", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_invalid_response", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_no_read_response", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_no_write_response", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_read_timeout", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_read_write", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_readline", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_readline_timeout", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_restore_connection", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_restore_unattachable_connection", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_restore_unknown_connection", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_timeout_error", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_unknown_device", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_write_string", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_configuration_descriptor", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_descriptor_handlers", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_endpoint_descriptor_handlers", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_generate_configuration", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_interface_association_handlers"]
1+
["serial_usbipclient.tests.test_connection.py.testusbipconnection.test_connection", "serial_usbipclient.tests.test_connection.py.testusbipconnection.test_connection_shutdown", "serial_usbipclient.tests.test_connection.py.testusbipconnection.test_queue_urbs", "serial_usbipclient.tests.test_descriptors.py.testinterfacedescriptor.test_descriptors", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_mock_usbip_server_connection", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_mock_usbip_server_startup", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_mocked_response", "serial_usbipclient.tests.test_mock_usbip_server.py.testmockusbipserver.test_reading_paths", "serial_usbipclient.tests.test_mock_usbip_server.py.testdeviceconfiguration.test_lsusb_parsing", "serial_usbipclient.tests.test_mock_usbip_server.py.testdeviceconfiguration.test_usbip_path", "serial_usbipclient.tests.test_packaging.py.testversion.test_version", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_cmd_response", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_cmd_submit", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_iso_packet_descriptor", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_metastruct_size", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_queue_urb", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_request_devlist", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_sizing", "serial_usbipclient.tests.test_packet_generation.py.testpacketgeneration.test_urb_endianness", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_configuration", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_delimited_read", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_failed_attachment", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_hardware_id_formatting", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_invalid_response", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_no_read_response", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_no_write_response", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_read_timeout", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_read_write", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_readline", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_readline_timeout", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_restore_connection", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_restore_unattachable_connection", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_restore_unknown_connection", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_timeout_error", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_unknown_device", "serial_usbipclient.tests.test_rw_device.py.testreadwrite.test_write_string", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_attachment", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_connection", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_gai_error", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_list_published", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_recv_error", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_restore_connection", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_restore_connection_no_device", "serial_usbipclient.tests.test_socket_handling.py.testsocketwrapper.test_timeout_error", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_configuration_descriptor", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_descriptor_handlers", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_endpoint_descriptor_handlers", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_generate_configuration", "serial_usbipclient.tests.test_urb_packets.py.testurbpackets.test_interface_association_handlers"]

0 commit comments

Comments
 (0)