diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..6545b4d --- /dev/null +++ b/conftest.py @@ -0,0 +1,7 @@ +import sys +from pathlib import Path + +# Ensure src/ package takes precedence over the legacy root-level governs_ai/ directory +_src = str(Path(__file__).parent / "src") +if _src not in sys.path: + sys.path.insert(0, _src) diff --git a/governs_ai/exceptions/precheck.py b/governs_ai/exceptions/precheck.py index 37e4843..4b6eb34 100644 --- a/governs_ai/exceptions/precheck.py +++ b/governs_ai/exceptions/precheck.py @@ -4,6 +4,8 @@ Precheck-specific exceptions. """ +from typing import Any, Dict, Optional + from .base import GovernsAIError diff --git a/pyproject.toml b/pyproject.toml index ed2884d..baefc8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,14 @@ dev = [ "mypy>=1.0.0", ] +[tool.setuptools.packages.find] +where = ["src"] + [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"] +pythonpath = ["src"] +addopts = "--import-mode=importlib" +markers = [ + "integration: requires running local services (deselect with '-m not integration')", +] diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/test_precheck_integration.py b/tests/integration/test_precheck_integration.py new file mode 100644 index 0000000..a19345d --- /dev/null +++ b/tests/integration/test_precheck_integration.py @@ -0,0 +1,36 @@ +"""Integration tests for precheck() — require local precheck service on localhost:8000.""" + +import os + +import pytest + +from governs_ai.client import GovernsAIClient + + +@pytest.fixture +def client(): + return GovernsAIClient( + api_key=os.getenv("GOVERNS_API_KEY", "dev-key"), + base_url=os.getenv("GOVERNS_BASE_URL", "http://localhost:8000"), + org_id=os.getenv("GOVERNS_ORG_ID", "org-dev"), + ) + + +@pytest.mark.integration +def test_precheck_returns_real_decision(client): + """precheck() against local service returns a valid decision.""" + result = client.precheck(content="Hello from integration test", tool="model.chat") + assert result.decision in ("allow", "deny", "transform", "confirm") + assert isinstance(result.redacted_content, str) + assert isinstance(result.reasons, list) + assert result.latency_ms > 0 + + +@pytest.mark.integration +async def test_async_precheck_returns_real_decision(client): + """async_precheck() against local service returns a valid decision.""" + result = await client.async_precheck( + content="Hello from async integration test", tool="model.chat" + ) + assert result.decision in ("allow", "deny", "transform", "confirm") + assert result.latency_ms > 0