9 """Base class for errors from this module."""
13 """Raised if there are not free ports for worker"""
16@pytest.fixture(scope='session')
18 _get_free_port_sock_storing,
19 _get_free_port_range_based,
20) -> typing.Callable[[], int]:
22 Returns an ephemeral TCP port that is free for IPv4 and for IPv6.
24 @ingroup userver_testsuite_fixtures
25 Part of the [yandex-taxi-testsuite](https://github.com/yandex/yandex-taxi-testsuite/blob/develop/testsuite/plugins/network.py#L17)
27 if platform.system() == 'Linux':
28 return _get_free_port_sock_storing
29 return _get_free_port_range_based
32@pytest.fixture(scope='session')
33def _get_free_port_sock_storing(
34 _testsuite_default_af,
35 _testsuite_socket_cleanup,
36) -> typing.Callable[[], int]:
37 family, address = _testsuite_default_af
39 # Relies on https://github.com/torvalds/linux/commit/aacd9289af8b82f5fb01b
41 sock = socket.socket(family, socket.SOCK_STREAM)
43 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
44 sock.bind((address, 0))
45 _testsuite_socket_cleanup(sock) # shared variable
46 return sock.getsockname()[1]
48 raise NoEnabledPorts()
53@pytest.fixture(scope='session')
54def _get_free_port_range_based(
55 _testsuite_default_af,
56) -> typing.Callable[[], int]:
57 family, address = _testsuite_default_af
58 port_seq = iter(range(61000, 2048, -1))
62 if _is_port_free(port, family, address):
64 raise NoEnabledPorts()
69@pytest.fixture(scope='session')
70def _testsuite_socket_cleanup():
71 sock_list: list[socket.socket] = []
73 yield sock_list.append
75 for sock in sock_list:
79@pytest.fixture(scope='session')
80def _testsuite_default_af():
81 for family, address in _get_inet_families():
82 return family, address
83 raise RuntimeError('No suitable address families available')
86def _is_port_free(port_num: int, family: int, address: str) -> bool:
88 with socket.socket(family, socket.SOCK_STREAM) as sock:
89 sock.bind((address, port_num))
96def _is_af_available(family: int, address: str):
97 return _is_port_free(0, family, address)
100def _get_inet_families():
101 for family_str, address in (('AF_INET6', '::'), ('AF_INET', '127.0.0.1')):
102 family = getattr(socket, family_str, None)
103 if family and _is_af_available(family, address):
104 yield family, address