forked from retoor/devplacepy
Party Hardy
This commit is contained in:
@@ -27,13 +27,13 @@ def references(path):
|
||||
return any(needle in body for needle in NEEDLES)
|
||||
|
||||
|
||||
def test_only_main_imports_the_acceptance_package():
|
||||
def test_only_lifespan_imports_the_acceptance_package():
|
||||
importers = [
|
||||
path.relative_to(PACKAGE_ROOT).as_posix()
|
||||
for path in source_files({".py"})
|
||||
if references(path)
|
||||
]
|
||||
assert importers == ["main.py"]
|
||||
assert importers == ["lifespan.py"]
|
||||
|
||||
|
||||
def test_no_template_or_static_asset_mentions_the_package():
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import queue
|
||||
import threading
|
||||
|
||||
from tests.conftest import run_async
|
||||
from devplacepy.services.background import BackgroundQueue
|
||||
|
||||
|
||||
def _fill(direct_queue, count, executed):
|
||||
for _ in range(count):
|
||||
direct_queue.put_nowait((executed.append, ("x",), {}))
|
||||
|
||||
|
||||
def test_stop_without_start_returns_cleanly():
|
||||
direct = BackgroundQueue()
|
||||
run_async(direct.stop())
|
||||
assert direct.stats()["running"] is False
|
||||
|
||||
|
||||
def test_stop_full_queue_does_not_block():
|
||||
direct = BackgroundQueue(maxsize=4)
|
||||
dead = threading.Thread(target=lambda: None)
|
||||
dead.start()
|
||||
dead.join()
|
||||
direct._thread = dead
|
||||
executed = []
|
||||
_fill(direct._queue, 4, executed)
|
||||
run_async(direct.stop())
|
||||
assert executed == ["x"] * 4
|
||||
|
||||
|
||||
def test_stop_bounds_shutdown_drain_and_counts_dropped():
|
||||
from devplacepy.services.background import SHUTDOWN_DRAIN_MAX
|
||||
|
||||
direct = BackgroundQueue(maxsize=5000)
|
||||
executed = []
|
||||
_fill(direct._queue, SHUTDOWN_DRAIN_MAX + 200, executed)
|
||||
run_async(direct.stop())
|
||||
stats = direct.stats()
|
||||
assert len(executed) == SHUTDOWN_DRAIN_MAX
|
||||
assert stats["dropped"] == 200
|
||||
|
||||
|
||||
def test_start_stop_roundtrip_executes_submitted_task():
|
||||
direct = BackgroundQueue()
|
||||
run_async(direct.start())
|
||||
try:
|
||||
executed = []
|
||||
direct.submit(executed.append, "x")
|
||||
finally:
|
||||
run_async(direct.stop())
|
||||
assert executed == ["x"]
|
||||
assert direct.stats()["running"] is False
|
||||
@@ -793,3 +793,39 @@ def test_tunnel_target_is_empty_without_a_route_to_the_port():
|
||||
instance = {"ports_json": "[]", "container_gateway": "172.17.0.1"}
|
||||
assert api.tunnel_target(instance, 3000) == (None, None)
|
||||
assert api.tunnel_target({"container_ip": "172.17.0.9"}, 0) == (None, None)
|
||||
|
||||
|
||||
def test_allocate_host_port_returns_lowest_free(monkeypatch):
|
||||
monkeypatch.setattr(api, "_host_port_free", lambda port: True)
|
||||
assert api.allocate_host_port(set()) == api.HOST_PORT_MIN
|
||||
assert api.allocate_host_port({20001, 20002}) == 20003
|
||||
|
||||
|
||||
def test_allocate_host_port_skips_bound_ports(monkeypatch):
|
||||
monkeypatch.setattr(api, "_host_port_free", lambda port: port != 20001)
|
||||
assert api.allocate_host_port(set()) == 20002
|
||||
|
||||
|
||||
def test_allocate_host_port_probe_budget_exhausted(monkeypatch):
|
||||
from devplacepy.services.containers.api import ContainerError
|
||||
|
||||
calls = []
|
||||
monkeypatch.setattr(
|
||||
api, "_host_port_free", lambda port: calls.append(port) or False
|
||||
)
|
||||
with pytest.raises(ContainerError, match="probing"):
|
||||
api.allocate_host_port(set())
|
||||
assert len(calls) == api.MAX_PORT_PROBES
|
||||
|
||||
|
||||
def test_parse_ports_accepts_mapping_cap():
|
||||
value = "\n".join(str(8000 + i) for i in range(api.MAX_PORTS_PER_INSTANCE))
|
||||
assert len(api.parse_ports(value)) == api.MAX_PORTS_PER_INSTANCE
|
||||
|
||||
|
||||
def test_parse_ports_rejects_too_many_mappings():
|
||||
from devplacepy.services.containers.api import ContainerError
|
||||
|
||||
value = "\n".join(str(8000 + i) for i in range(api.MAX_PORTS_PER_INSTANCE + 1))
|
||||
with pytest.raises(ContainerError, match="at most"):
|
||||
api.parse_ports(value)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
@@ -0,0 +1,41 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
from dataclasses import replace
|
||||
|
||||
from devplacepy.services.devii.config import load_settings
|
||||
from devplacepy.services.devii.fetch.controller import MIN_FETCH_CHARS, FetchController
|
||||
|
||||
|
||||
def _controller(ceiling):
|
||||
return FetchController(replace(load_settings(), fetch_max_chars=ceiling))
|
||||
|
||||
|
||||
def test_optional_cap_defaults_to_ceiling():
|
||||
controller = _controller(2000)
|
||||
assert controller._optional_cap(None, "a" * 5000) == "a" * 2000
|
||||
|
||||
|
||||
def test_optional_cap_clamps_large_request_to_ceiling():
|
||||
controller = _controller(2000)
|
||||
assert controller._optional_cap(10**9, "b" * 5000) == "b" * 2000
|
||||
|
||||
|
||||
def test_optional_cap_honors_smaller_request():
|
||||
controller = _controller(2000)
|
||||
assert controller._optional_cap(1500, "c" * 5000) == "c" * 1500
|
||||
|
||||
|
||||
def test_optional_cap_floors_tiny_request():
|
||||
controller = _controller(2000)
|
||||
assert controller._optional_cap(10, "d" * 5000) == "d" * MIN_FETCH_CHARS
|
||||
|
||||
|
||||
def test_optional_cap_invalid_request_falls_back_to_ceiling():
|
||||
controller = _controller(2000)
|
||||
assert controller._optional_cap("many", "e" * 5000) == "e" * 2000
|
||||
|
||||
|
||||
def test_optional_cap_leaves_short_content_alone():
|
||||
controller = _controller(2000)
|
||||
assert controller._optional_cap(None, "short") == "short"
|
||||
assert controller._optional_cap(1500, "short") == "short"
|
||||
Reference in New Issue
Block a user