chore: initialize EverOS 1.0.0
md-first memory extraction framework for AI agents. Markdown is the single source of truth; SQLite holds state and LanceDB provides the rebuildable vector + BM25 + scalar index. The codebase follows a single-direction DDD layering (entrypoints -> service -> memory -> infra, with component / core / config cross-cutting) enforced by import-linter. Engineering surface: - Coding conventions in .claude/rules/ (path-scoped) and workflows in .claude/skills/ (/commit, /new-branch, /pr). - GitHub Actions CI runs make lint + test + integration; pre-commit mirrors the gates locally (ruff, hygiene hooks, gitlint commit-msg). - Commit messages follow Conventional Commits, enforced by gitlint. - make lint also enforces datetime two-zone discipline and OpenAPI drift.
This commit is contained in:
134
tests/unit/test_entrypoints/test_cli/test_server_command.py
Normal file
134
tests/unit/test_entrypoints/test_cli/test_server_command.py
Normal file
@ -0,0 +1,134 @@
|
||||
"""``everos server start`` — argument resolution + uvicorn handoff.
|
||||
|
||||
Uvicorn ``run`` is the external boundary and is mocked. We assert the
|
||||
host/port/log_level resolution chain (CLI flag > env > default) and the
|
||||
KeyboardInterrupt / OSError exit paths.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from everos.entrypoints.cli.commands import server as server_mod
|
||||
from everos.entrypoints.cli.main import app as root_app
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def captured(monkeypatch: pytest.MonkeyPatch) -> dict[str, object]:
|
||||
"""Mock ``uvicorn.run`` and return the kwargs it was called with."""
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def fake_run(*args: object, **kwargs: object) -> None:
|
||||
captured["args"] = args
|
||||
captured["kwargs"] = kwargs
|
||||
|
||||
monkeypatch.setattr(server_mod.uvicorn, "run", fake_run)
|
||||
# Strip env so default resolution path is deterministic.
|
||||
for k in ("EVEROS_HOST", "EVEROS_PORT", "EVEROS_LOG_LEVEL"):
|
||||
monkeypatch.delenv(k, raising=False)
|
||||
return captured
|
||||
|
||||
|
||||
# Typer lifts single-command sub-apps to root; we invoke via the real
|
||||
# ``everos server start`` path through the assembled root app.
|
||||
|
||||
|
||||
def test_start_uses_default_host_port_log_level(captured: dict[str, object]) -> None:
|
||||
result = CliRunner().invoke(
|
||||
root_app, ["server", "start", "--env-file", "/nonexistent"]
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
kwargs = captured["kwargs"]
|
||||
assert isinstance(kwargs, dict)
|
||||
assert kwargs["host"] == "127.0.0.1"
|
||||
assert kwargs["port"] == 8000
|
||||
assert kwargs["log_level"] == "info"
|
||||
assert kwargs["factory"] is True
|
||||
args = captured["args"]
|
||||
assert args == ("everos.entrypoints.api.app:create_app",)
|
||||
|
||||
|
||||
def test_start_cli_flags_override_env(
|
||||
captured: dict[str, object], monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setenv("EVEROS_API__HOST", "1.2.3.4")
|
||||
monkeypatch.setenv("EVEROS_API__PORT", "9000")
|
||||
monkeypatch.setenv("EVEROS_API__LOG_LEVEL", "debug")
|
||||
result = CliRunner().invoke(
|
||||
root_app,
|
||||
[
|
||||
"server",
|
||||
"start",
|
||||
"--env-file",
|
||||
"/nonexistent",
|
||||
"--host",
|
||||
"127.0.0.1",
|
||||
"--port",
|
||||
"8765",
|
||||
"--log-level",
|
||||
"warning",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
kwargs = captured["kwargs"]
|
||||
assert isinstance(kwargs, dict)
|
||||
assert kwargs["host"] == "127.0.0.1"
|
||||
assert kwargs["port"] == 8765
|
||||
assert kwargs["log_level"] == "warning"
|
||||
|
||||
|
||||
def test_start_falls_back_to_env_when_flags_omitted(
|
||||
captured: dict[str, object], monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setenv("EVEROS_API__HOST", "10.0.0.1")
|
||||
monkeypatch.setenv("EVEROS_API__PORT", "8765")
|
||||
result = CliRunner().invoke(
|
||||
root_app, ["server", "start", "--env-file", "/nonexistent"]
|
||||
)
|
||||
assert result.exit_code == 0, result.stdout
|
||||
kwargs = captured["kwargs"]
|
||||
assert isinstance(kwargs, dict)
|
||||
assert kwargs["host"] == "10.0.0.1"
|
||||
assert kwargs["port"] == 8765
|
||||
|
||||
|
||||
def test_start_swallows_keyboard_interrupt(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def boom(*args: object, **kwargs: object) -> None:
|
||||
raise KeyboardInterrupt
|
||||
|
||||
monkeypatch.setattr(server_mod.uvicorn, "run", boom)
|
||||
result = CliRunner().invoke(
|
||||
root_app, ["server", "start", "--env-file", "/nonexistent"]
|
||||
)
|
||||
# KeyboardInterrupt path returns normally — exit 0.
|
||||
assert result.exit_code == 0
|
||||
|
||||
|
||||
def test_start_exits_one_on_os_error(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def boom(*args: object, **kwargs: object) -> None:
|
||||
raise OSError("port in use")
|
||||
|
||||
monkeypatch.setattr(server_mod.uvicorn, "run", boom)
|
||||
result = CliRunner().invoke(
|
||||
root_app, ["server", "start", "--env-file", "/nonexistent"]
|
||||
)
|
||||
assert result.exit_code == 1
|
||||
|
||||
|
||||
def test_load_env_file_missing_path_is_noop(tmp_path) -> None: # type: ignore[no-untyped-def]
|
||||
# Function should not raise when the file does not exist.
|
||||
server_mod._load_env_file(str(tmp_path / "does-not-exist.env"))
|
||||
|
||||
|
||||
def test_load_env_file_reads_present_file(
|
||||
tmp_path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None: # type: ignore[no-untyped-def]
|
||||
monkeypatch.delenv("EVEROS_TEST_DOTENV_VAR", raising=False)
|
||||
env_file = tmp_path / ".env"
|
||||
env_file.write_text("EVEROS_TEST_DOTENV_VAR=loaded\n")
|
||||
server_mod._load_env_file(str(env_file))
|
||||
import os
|
||||
|
||||
assert os.environ.get("EVEROS_TEST_DOTENV_VAR") == "loaded"
|
||||
monkeypatch.delenv("EVEROS_TEST_DOTENV_VAR", raising=False)
|
||||
Reference in New Issue
Block a user