Merge pull request 'tests: rewrite port allocation function' (#194) from Mic92-main into main

This commit is contained in:
clan-bot
2023-08-27 07:47:23 +00:00
5 changed files with 55 additions and 39 deletions

View File

@@ -9,6 +9,7 @@
, pytest , pytest
, pytest-cov , pytest-cov
, pytest-subprocess , pytest-subprocess
, pytest-parallel
, python3 , python3
, runCommand , runCommand
, self , self
@@ -36,6 +37,7 @@ let
pytest pytest
pytest-cov pytest-cov
pytest-subprocess pytest-subprocess
pytest-parallel
openssh openssh
stdenv.cc stdenv.cc
]; ];

View File

@@ -15,7 +15,7 @@ exclude = ["clan_cli.nixpkgs*"]
clan_cli = [ "config/jsonschema/*", "webui/assets/**/*"] clan_cli = [ "config/jsonschema/*", "webui/assets/**/*"]
[tool.pytest.ini_options] [tool.pytest.ini_options]
addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail" addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail --workers auto"
norecursedirs = "tests/helpers" norecursedirs = "tests/helpers"
[tool.mypy] [tool.mypy]

View File

@@ -1,46 +1,55 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import contextlib
import socket import socket
from typing import Callable
import pytest import pytest
NEXT_PORT = 10000
def _unused_port(socket_type: int) -> int:
"""Find an unused localhost port from 1024-65535 and return it."""
with contextlib.closing(socket.socket(type=socket_type)) as sock:
sock.bind(("127.0.0.1", 0))
return sock.getsockname()[1]
def check_port(port: int) -> bool: PortFunction = Callable[[], int]
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
with tcp, udp:
try:
tcp.bind(("127.0.0.1", port))
udp.bind(("127.0.0.1", port))
return True
except socket.error:
return False
def check_port_range(port_range: range) -> bool: @pytest.fixture(scope="session")
for port in port_range: def unused_tcp_port() -> PortFunction:
if not check_port(port): """A function, producing different unused TCP ports."""
return False produced = set()
return True
def factory() -> int:
"""Return an unused port."""
port = _unused_port(socket.SOCK_STREAM)
while port in produced:
port = _unused_port(socket.SOCK_STREAM)
produced.add(port)
return port
return factory
class Ports: @pytest.fixture(scope="session")
def allocate(self, num: int) -> int: def unused_udp_port() -> PortFunction:
""" """A function, producing different unused UDP ports."""
Allocates produced = set()
"""
global NEXT_PORT
while NEXT_PORT + num <= 65535:
start = NEXT_PORT
NEXT_PORT += num
if not check_port_range(range(start, NEXT_PORT)):
continue
return start
raise Exception("cannot find enough free port")
def factory() -> int:
"""Return an unused port."""
port = _unused_port(socket.SOCK_DGRAM)
@pytest.fixture while port in produced:
def ports() -> Ports: port = _unused_port(socket.SOCK_DGRAM)
return Ports()
produced.add(port)
return port
return factory

View File

@@ -11,7 +11,7 @@ import pytest
if TYPE_CHECKING: if TYPE_CHECKING:
from command import Command from command import Command
from ports import Ports from ports import PortFunction
class Sshd: class Sshd:
@@ -104,8 +104,13 @@ exec {bash} -l "${{@}}"
@pytest.fixture @pytest.fixture
def sshd(sshd_config: SshdConfig, command: "Command", ports: "Ports") -> Iterator[Sshd]: def sshd(
port = ports.allocate(1) sshd_config: SshdConfig, command: "Command", unused_tcp_port: "PortFunction"
) -> Iterator[Sshd]:
import subprocess
subprocess.run(["echo", "hello"], check=True)
port = unused_tcp_port()
sshd = shutil.which("sshd") sshd = shutil.which("sshd")
assert sshd is not None, "no sshd binary found" assert sshd is not None, "no sshd binary found"
env = {} env = {}

View File

@@ -5,11 +5,11 @@ import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
from ports import Ports from ports import PortFunction
def test_start_server(ports: Ports, temporary_dir: Path) -> None: def test_start_server(unused_tcp_port: PortFunction, temporary_dir: Path) -> None:
port = ports.allocate(1) port = unused_tcp_port()
fifo = temporary_dir / "fifo" fifo = temporary_dir / "fifo"
os.mkfifo(fifo) os.mkfifo(fifo)