feat(config): watch runtime configuration changes (#5026)
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import asyncio
|
||||
from contextlib import suppress
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from watchfiles import Change
|
||||
|
||||
import nanobot.config.watcher as config_watcher
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_watch_config_file_filters_directory_events(
|
||||
tmp_path: Path,
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
config_path = tmp_path / "config.json"
|
||||
other_path = tmp_path / "other.json"
|
||||
seen: dict[str, object] = {}
|
||||
|
||||
async def fake_awatch(*paths, **kwargs):
|
||||
seen["paths"] = paths
|
||||
seen["recursive"] = kwargs["recursive"]
|
||||
watch_filter = kwargs["watch_filter"]
|
||||
assert watch_filter(Change.modified, str(config_path)) is True
|
||||
assert watch_filter(Change.modified, str(other_path)) is False
|
||||
yield {(Change.modified, str(config_path))}
|
||||
|
||||
monkeypatch.setattr(config_watcher, "awatch", fake_awatch)
|
||||
changes: list[None] = []
|
||||
|
||||
await config_watcher.watch_config_file(config_path, lambda: changes.append(None))
|
||||
|
||||
assert seen == {"paths": (tmp_path,), "recursive": False}
|
||||
assert changes == [None]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_watch_config_file_observes_atomic_replace(tmp_path: Path) -> None:
|
||||
config_path = tmp_path / "config.json"
|
||||
config_path.write_text("{}", encoding="utf-8")
|
||||
changed = asyncio.Event()
|
||||
task = asyncio.create_task(
|
||||
config_watcher.watch_config_file(config_path, changed.set)
|
||||
)
|
||||
|
||||
try:
|
||||
for attempt in range(10):
|
||||
replacement = tmp_path / "config.tmp"
|
||||
replacement.write_text(f'{{"attempt": {attempt}}}', encoding="utf-8")
|
||||
replacement.replace(config_path)
|
||||
try:
|
||||
await asyncio.wait_for(changed.wait(), timeout=0.2)
|
||||
break
|
||||
except TimeoutError:
|
||||
continue
|
||||
assert changed.is_set()
|
||||
finally:
|
||||
task.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await task
|
||||
Reference in New Issue
Block a user