Skip to content

Commit 0b595ea

Browse files
authored
test(infra): cleanup mocked integration tests + register 'release' pytest marker (closes #166) (#170)
* test: clean mocked integration tests and add release marker - Delete tests/integration/test_chat_completion.py and test_embedding.py (both used MagicMock on the method under test — tested nothing real) - Move to_langchain() coverage for OpenRouter, xAI, and Google into their provider test files; drop already-covered OpenAI/Anthropic variants - Delete tests/integration/test_langchain_integration.py - Register `release` pytest marker in pyproject.toml and exclude it from the default addopts with -m 'not release' - Decorate all 11 test classes in test_tool_calling_real.py with @pytest.mark.release so they are only collected when explicitly requested task=t1 validator: DIFF: 8 files changed, 93 insertions(+), 532 deletions(-) — matches expected scope (3 integration files deleted, 3 provider files updated, test_tool_calling_real.py updated, pyproject.toml updated); AC1: tests/integration/ contains only conftest.py and test_tool_calling_real.py — the three deleted files (test_chat_completion.py, test_embedding.py, test_langchain_integration.py) are confirmed absent. conftest.py pre-existed and was not in scope of deletion.; AC2: tests/providers/llm/test_openrouter_provider.py line 344 asserts `langchain_model.openai_api_base == 'https://openrouter.ai/api/v1'` in a test that calls to_langchain().; AC3: tests/providers/llm/test_xai_provider.py line 349 asserts `langchain_model.openai_api_base == 'https://api.x.ai/v1'` in a test that calls to_langchain().; AC4: tests/providers/llm/test_google_provider.py line 781 asserts `isinstance(langchain_model, ChatGoogleGenerativeAI)` in a test that calls to_langchain().; AC5: pyproject.toml [tool.pytest.ini_options] has markers = ['release: real-API tests run before each release (costs money, requires keys)'] and addopts ends with "-m 'not release'".; AC6: 11 @pytest.mark.release decorators confirmed at lines 77, 172, 264, 356, 448, 535, 622, 710, 797, 900, 996 in test_tool_calling_real.py — covering all 11 classes.; AC7: `uv run pytest tests/providers tests/unit tests/common_types tests/test_deprecation_warnings.py -q --no-cov` exited 0 with 996 passed, 1 skipped in 64.59s.; AC8: `uv run pytest -m release --collect-only` lists exactly 11 classes (TestOpenAIToolCalling through TestGoogleToolCalling) all from test_tool_calling_real.py — 22 tests collected.; AC9: `uv run pytest --collect-only` shows no paths containing 'integration/' — default run excludes all integration tests via -m 'not release'.; AC10: `uv run ruff check .` exited 0 — all checks passed.; AC11: `uv run mypy src/esperanto` exited 0 — success: no issues found in 73 source files. * docs: document release pytest marker in CLAUDE.md, CONTRIBUTING.md, and CHANGELOG Add Release Tests section explaining that tests/integration/ real-API tests are gated by the `release` marker, excluded from default pytest runs and CI, cost money, and require provider keys in .env. Reference #166 and #141. task=t2 validator: DIFF: 3 files changed, 27 insertions(+), 0 deletions(-) — CHANGELOG.md +1, CLAUDE.md +10, CONTRIBUTING.md +16; AC1: pass — CLAUDE.md lines 274-282 contain a '### Release tests' sub-section under 'For Automated Agents' with all required phrases: 'uv run pytest -m release', 'cost real money', 'require provider keys set in a .env file at the repo root', and 'CI does not run them'; AC2: pass — CONTRIBUTING.md exists (174 lines) with a '## Release Tests' section (lines 102-116) in human-readable prose covering: uv run pytest -m release, costs real money, requires provider API keys in .env, and deliberately excluded from CI; AC3: pass — CHANGELOG.md [Unreleased] ### Changed line 19 contains a new bullet '**Test-infrastructure cleanup**' describing: mocked integration tests removed from tests/integration/, release pytest marker introduced, uv run pytest -m release invocation, to_langchain() coverage moved to per-provider test files, and references (#166, #141)
1 parent d2dcddd commit 0b595ea

11 files changed

Lines changed: 120 additions & 532 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
### Changed
1818

19+
- **Test-infrastructure cleanup** — mocked integration tests removed from `tests/integration/` (moved to per-provider test files under `tests/providers/`). A `release` pytest marker introduced: real-API tests are now tagged `@pytest.mark.release`, excluded from the default `uv run pytest` run, and invoked explicitly with `uv run pytest -m release` before each release. Unique `to_langchain()` coverage previously in `tests/integration/` moved to the corresponding per-provider test files. (#166, #141)
1920
- **Ollama `num_ctx` default lowered from 128,000 to 8,192.** The previous 128K default caused out-of-memory errors on consumer GPUs with 8 GB VRAM. 8,192 tokens works reliably on common hardware while still being large enough for typical chat workloads. Override with `config={"num_ctx": N}` when you need a larger context window. (#107)
2021
- **Lint and type-check the codebase clean.** Ruff (`ruff check .`) and mypy (`mypy src/esperanto`) now report zero errors. Most fixes are type-only and do not change runtime behavior. Notable structural changes:
2122
- `HttpConnectionMixin` now declares `client: httpx.Client` and `async_client: httpx.AsyncClient` as non-Optional. The `Optional[Client] = None` dataclass fields previously redeclared on every provider base class have been removed; clients are still assigned by `_create_http_clients()` during `__post_init__`, so the runtime contract is unchanged.

CLAUDE.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,16 @@ Both are clean on `main` and gated on every PR by `.github/workflows/lint.yml`.
272272

273273
`tests/integration/` requires real provider API keys and external network. Always exclude from automated runs unless the user has explicitly set up credentials and asked for it.
274274

275+
### Release tests
276+
277+
Real-API tests live in `tests/integration/` and are gated by the `release` pytest marker. Run them with:
278+
279+
```bash
280+
uv run pytest -m release
281+
```
282+
283+
These tests cost real money (they make actual API calls to provider endpoints) and require provider keys set in a `.env` file at the repo root. CI does not run them — they are a local-only ritual intended to be executed by a maintainer before publishing a release. Never include them in automated agent validation runs.
284+
275285
### Other notes
276286

277287
- The `notebooks/` directory is local-only (gitignored). If you see modifications there, leave them alone — they aren't part of the project.

CONTRIBUTING.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ The project's ruff configuration is in `pyproject.toml` and enforces:
9999
- Standard Python style rules (E, F)
100100
- Import sorting (I)
101101

102+
## Release Tests
103+
104+
The `tests/integration/` directory contains tests that call real provider APIs. These are marked with the `release` pytest marker and are excluded from the default `uv run pytest` run to avoid accidental API charges.
105+
106+
To run release tests:
107+
108+
```bash
109+
uv run pytest -m release
110+
```
111+
112+
**Important:**
113+
- These tests cost real money — they make live API calls to provider endpoints.
114+
- They require provider API keys to be set in a `.env` file at the repo root.
115+
- They are deliberately excluded from CI. Running them is a local-only ritual, intended for maintainers to verify everything works end-to-end before publishing a release.
116+
- Do not add release tests to the default test scope, and do not run them in automated pipelines.
117+
102118
## Adding a New Provider
103119

104120
This is the most common type of contribution. To keep Esperanto maintainable, we have clear criteria for what we accept.

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ package-dir = {"esperanto" = "src/esperanto"}
4848
asyncio_mode = "auto"
4949
testpaths = ["tests"]
5050
python_files = ["test_*.py"]
51-
addopts = "-v --cov=esperanto --cov-report=term-missing"
51+
addopts = "-v --cov=esperanto --cov-report=term-missing -m 'not release'"
52+
markers = [
53+
"release: real-API tests run before each release (costs money, requires keys)",
54+
]
5255

5356
[tool.ruff]
5457
line-length = 88

tests/integration/test_chat_completion.py

Lines changed: 0 additions & 138 deletions
This file was deleted.

0 commit comments

Comments
 (0)