UDS: implicitly create `Address.bindspace: Path`
Since it's merely a local-file-sys subdirectory and there should be no reason file creation conflicts with other bind spaces. Also add 2 test suites to match, - `tests/ipc/test_each_tpt::test_uds_bindspace_created_implicitly` to verify the dir creation when DNE. - `..test_uds_double_listen_raises_connerr` to ensure a double bind raises a `ConnectionError` from the src `OSError`.to_asyncio_eoc_signal
parent
c2acc4f55c
commit
d079675dd4
|
@ -0,0 +1,113 @@
|
||||||
|
'''
|
||||||
|
Unit-ish tests for specific IPC transport protocol backends.
|
||||||
|
|
||||||
|
'''
|
||||||
|
from __future__ import annotations
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import trio
|
||||||
|
import tractor
|
||||||
|
from tractor import (
|
||||||
|
Actor,
|
||||||
|
_state,
|
||||||
|
_addr,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def bindspace_dir_str() -> str:
|
||||||
|
|
||||||
|
bs_dir_str: str = '/run/user/1000/doggy'
|
||||||
|
bs_dir = Path(bs_dir_str)
|
||||||
|
assert not bs_dir.is_dir()
|
||||||
|
|
||||||
|
yield bs_dir_str
|
||||||
|
|
||||||
|
# delete it on suite teardown.
|
||||||
|
# ?TODO? should we support this internally
|
||||||
|
# or is leaking it ok?
|
||||||
|
if bs_dir.is_dir():
|
||||||
|
bs_dir.rmdir()
|
||||||
|
|
||||||
|
|
||||||
|
def test_uds_bindspace_created_implicitly(
|
||||||
|
debug_mode: bool,
|
||||||
|
bindspace_dir_str: str,
|
||||||
|
):
|
||||||
|
registry_addr: tuple = (
|
||||||
|
f'{bindspace_dir_str}',
|
||||||
|
'registry@doggy.sock',
|
||||||
|
)
|
||||||
|
bs_dir_str: str = registry_addr[0]
|
||||||
|
|
||||||
|
# XXX, ensure bindspace-dir DNE beforehand!
|
||||||
|
assert not Path(bs_dir_str).is_dir()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with tractor.open_nursery(
|
||||||
|
enable_transports=['uds'],
|
||||||
|
registry_addrs=[registry_addr],
|
||||||
|
debug_mode=debug_mode,
|
||||||
|
) as _an:
|
||||||
|
|
||||||
|
# XXX MUST be created implicitly by
|
||||||
|
# `.ipc._uds.start_listener()`!
|
||||||
|
assert Path(bs_dir_str).is_dir()
|
||||||
|
|
||||||
|
root: Actor = tractor.current_actor()
|
||||||
|
assert root.is_registrar
|
||||||
|
|
||||||
|
assert registry_addr in root.reg_addrs
|
||||||
|
assert (
|
||||||
|
registry_addr
|
||||||
|
in
|
||||||
|
_state._runtime_vars['_registry_addrs']
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
_addr.wrap_address(registry_addr)
|
||||||
|
in
|
||||||
|
root.registry_addrs
|
||||||
|
)
|
||||||
|
|
||||||
|
trio.run(main)
|
||||||
|
|
||||||
|
|
||||||
|
def test_uds_double_listen_raises_connerr(
|
||||||
|
debug_mode: bool,
|
||||||
|
bindspace_dir_str: str,
|
||||||
|
):
|
||||||
|
registry_addr: tuple = (
|
||||||
|
f'{bindspace_dir_str}',
|
||||||
|
'registry@doggy.sock',
|
||||||
|
)
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with tractor.open_nursery(
|
||||||
|
enable_transports=['uds'],
|
||||||
|
registry_addrs=[registry_addr],
|
||||||
|
debug_mode=debug_mode,
|
||||||
|
) as _an:
|
||||||
|
|
||||||
|
# runtime up
|
||||||
|
root: Actor = tractor.current_actor()
|
||||||
|
|
||||||
|
from tractor.ipc._uds import (
|
||||||
|
start_listener,
|
||||||
|
UDSAddress,
|
||||||
|
)
|
||||||
|
ya_bound_addr: UDSAddress = root.registry_addrs[0]
|
||||||
|
try:
|
||||||
|
await start_listener(
|
||||||
|
addr=ya_bound_addr,
|
||||||
|
)
|
||||||
|
except ConnectionError as connerr:
|
||||||
|
assert type(src_exc := connerr.__context__) is OSError
|
||||||
|
assert 'Address already in use' in src_exc.args
|
||||||
|
# complete, exit test.
|
||||||
|
|
||||||
|
else:
|
||||||
|
pytest.fail('It dint raise a connerr !?')
|
||||||
|
|
||||||
|
|
||||||
|
trio.run(main)
|
|
@ -103,8 +103,6 @@ class UDSAddress(
|
||||||
self.filedir
|
self.filedir
|
||||||
or
|
or
|
||||||
self.def_bindspace
|
self.def_bindspace
|
||||||
# or
|
|
||||||
# get_rt_dir()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -230,7 +228,14 @@ async def start_listener(
|
||||||
addr: UDSAddress,
|
addr: UDSAddress,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> SocketListener:
|
) -> SocketListener:
|
||||||
# sock = addr._sock = socket.socket(
|
'''
|
||||||
|
Start listening for inbound connections via
|
||||||
|
a `trio.SocketListener` (task) which `socket.bind()`s on `addr`.
|
||||||
|
|
||||||
|
Note, if the `UDSAddress.bindspace: Path` directory dne it is
|
||||||
|
implicitly created.
|
||||||
|
|
||||||
|
'''
|
||||||
sock = socket.socket(
|
sock = socket.socket(
|
||||||
socket.AF_UNIX,
|
socket.AF_UNIX,
|
||||||
socket.SOCK_STREAM
|
socket.SOCK_STREAM
|
||||||
|
@ -241,7 +246,17 @@ async def start_listener(
|
||||||
f'|_{addr}\n'
|
f'|_{addr}\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ?TODO? should we use the `actor.lifetime_stack`
|
||||||
|
# to rm on shutdown?
|
||||||
bindpath: Path = addr.sockpath
|
bindpath: Path = addr.sockpath
|
||||||
|
if not (bs := addr.bindspace).is_dir():
|
||||||
|
log.info(
|
||||||
|
'Creating bindspace dir in file-sys\n'
|
||||||
|
f'>{{\n'
|
||||||
|
f'|_{bs!r}\n'
|
||||||
|
)
|
||||||
|
bs.mkdir()
|
||||||
|
|
||||||
with _reraise_as_connerr(
|
with _reraise_as_connerr(
|
||||||
src_excs=(
|
src_excs=(
|
||||||
FileNotFoundError,
|
FileNotFoundError,
|
||||||
|
|
Loading…
Reference in New Issue