This document is the high-level guide for everything under tests/ in ocelle-py.
It explains test structure, execution flow, CI behavior, and security expectations.
The test suite verifies:
- Public SDK API behavior and backward compatibility.
- Internal behavior that must remain stable (env mapping, attribute renaming, vendored import boundaries).
- Provider instrumentation behavior with two layers:
- Mocked unit tests (fast, deterministic, no network).
- VCR-backed integration tests (record once, replay by default).
Current layout:
-
tests/conftest.py- Shared fixtures and test-state reset.
- Resets relevant env vars and OTel/FortifyRoot singleton state between tests.
- Provides
init_openai_sdk,span_exporter, and VCR config fixtures.
-
tests/test_init.py- Public
init()/version/API surface sanity checks.
- Public
-
tests/test_decorators.py- Decorator wrappers (
task,workflow,agent,tool) andInstrumentsenum behavior.
- Decorator wrappers (
-
tests/test_env_mapping.pyFORTIFYROOT_*->TRACELOOP_*env var mapping behavior.
-
tests/test_attribute_renaming.py- Span attribute remapping from
traceloop.*tofortifyroot.*.
- Span attribute remapping from
-
tests/test_vendored_imports.py- Vendor boundary checks and public API branding checks.
-
tests/openai/- Provider-specific OpenAI tests and cassettes.
- See
tests/openai/README.mdfor provider-specific details.
tests/conftest.py is the shared stability layer for this suite.
- It resets SDK and OpenTelemetry global state around each test.
- It isolates env vars used by FortifyRoot and test runs.
- Provider tests should prefer shared fixtures (for example
init_openai_sdk) instead of custom ad-hoc init logic.
Use these layers intentionally:
-
Core tests (
tests/test_*.py)- No provider network.
- Verify FortifyRoot Ocelle SDK contract and internal behavior.
-
Provider mocked tests (
tests/openai/test_instrumentation.py)- Patch provider SDK calls.
- Validate telemetry/span behavior deterministically.
-
Provider VCR tests (
tests/openai/test_vcr.py)- Validate real request/response shape.
- Replay cassettes in normal runs.
- Record only when intentionally refreshing cassettes.
# from the ocelle-py repo root
poetry install --with test- Run full test suite:
poetry run pytest tests -q- Run only core SDK tests:
poetry run pytest tests/test_*.py -q- Run only OpenAI tests:
poetry run pytest tests/openai -q- Run OpenAI VCR in replay mode (CI-like):
poetry run pytest tests/openai/test_vcr.py -q --record-mode=none- Record or refresh OpenAI cassettes intentionally:
OPENAI_API_KEY="<provider-key>" \
OPENAI_BASE_URL="https://api.openai.com/v1" \
OPENAI_TEST_MODEL="gpt-4.1" \
poetry run pytest tests/openai/test_vcr.py -q --record-mode=rewrite -rsFor OpenRouter or another OpenAI-compatible endpoint, override OPENAI_BASE_URL and OPENAI_TEST_MODEL accordingly.
Configured in pyproject.toml:
-
vcr- Marks tests using cassette record/replay via
pytest-recording.
- Marks tests using cassette record/replay via
-
default_cassette(name)- Pins a VCR test to a specific cassette file stem.
VCR matching is strict (method, scheme, host, port, path, query), so replay must use the same request shape as recording.
CI workflow: .github/workflows/tests-ci.yml
On every pull request:
-
Secret Policy Check- Fails if provider key patterns are hardcoded in tracked files.
-
Run Test Suite- Installs dependencies and runs
poetry run pytest tests -q. - Uses OpenAI-compatible defaults for VCR replay envs:
OPENAI_BASE_URL=https://api.openai.com/v1OPENAI_TEST_MODEL=gpt-4.1
- Installs dependencies and runs
Rules for all tests, docs, scripts, and workflows:
- Never commit real API keys or bearer tokens.
- Use placeholder values in examples.
- Keep cassette sanitization enabled for auth headers/query params.
- Store runtime credentials only in local env or GitHub Actions secrets.
- If a key leak is suspected, rotate immediately and invalidate the old key.
- Generate a new provider key.
- Update the corresponding GitHub repository secret.
- Re-run CI and any recording flows that require live credentials.
- Revoke the old key.
- Confirm no leaked values remain in history or open diffs.
When introducing another provider (for example Anthropic), use this contract checklist:
- Create
tests/<provider>/test_instrumentation.pyfor mocked behavior tests. - Create
tests/<provider>/test_vcr.pyfor integration record/replay tests. - Create
tests/<provider>/cassettes/and commit sanitized cassette fixtures. - Add
tests/<provider>/README.mdwith local run, replay, record, and troubleshooting instructions. - Reuse shared fixtures from
tests/conftest.pyfor state reset and exporter wiring. - Keep replay-first behavior for CI stability (
--record-mode=none). - Register and use explicit pytest markers/cassette naming where required.
- Ensure secret filtering covers auth headers and API key query params before any cassette commit.
-
OPENAI_API_KEY is required when recording VCR cassettes- You used record mode (
onceorrewrite) without a key.
- You used record mode (
-
CannotOverwriteExistingCassetteException- Replay request does not match recorded cassette host/path/query/method.
- Re-run with matching base URL/model or intentionally re-record.
-
Unexpected cross-test state leakage
- Usually means state reset fixtures were bypassed.
- Use shared fixtures and avoid direct one-off global setup in tests.
- OpenAI-specific details:
tests/openai/README.md