This is a testing repo for OpenDataHub and OpenShift AI, which are MLOps platforms for OpenShift. The tests are high-level integration tests at the Kubernetes API level.
You are an expert QE engineer writing maintainable pytest tests that other engineers can understand without deep domain knowledge.
# Run all pre-commit checks
pre-commit run --all-files
# Run tox (CI validation)
tox# Collect tests without running (verify structure)
uv run pytest --collect-only
# Run specific marker
uv run pytest -m smoke
uv run pytest -m "model_serving and tier1"
# Run with setup plan (debug fixtures)
uv run pytest --setup-plan tests/model_serving/tests/ # Test modules by component
├── conftest.py # All shared fixtures
├── <component>/ # Component test directories
│ ├── conftest.py # Component-scoped fixtures
│ └── test_*.py # Test files
| └── utils.py # Component-specific utility functions
utilities/ # Shared utility functions
└── <topic>_utils.py # Topic-specific utility functions
- Every test MUST have a docstring explaining what it tests (see
tests/cluster_health/test_cluster_health.py) - Apply relevant markers from
pytest.ini: tier (smoke,sanity,tier1,tier2), component (model_serving,model_registry,llama_stack), infrastructure (gpu,parallel,slow) - Use Given-When-Then format in docstrings for behavioral clarity
- Fixture names MUST be nouns:
storage_secretnotcreate_secret - Use context managers for resource lifecycle (see
tests/conftest.py:544-550for pattern) - Fixtures do one thing only—compose them rather than nesting
- Use narrowest scope that meets the need: function > class > module > session
- Use openshift-python-wrapper for all K8s API calls
- Resource lifecycle MUST use context managers to ensure cleanup
- Use
ocCLI only when wrapper is not relevant (e.g., must-gather)
- ERROR vs FAILED: Pytest reports fixture failures as ERROR, test failures as FAILED
- Heavy imports: Don't import heavy resources at module level; defer to fixture scope
- Flaky tests: Use
pytest.skip()with@pytest.mark.jira("PROJ-123"), never delete - Fixture scope: Session fixtures in
tests/conftest.pyrun once for entire suite—modify carefully
- Follow existing patterns before introducing new approaches
- Add type annotations (mypy strict enforced)
- Write Google-format docstrings for tests and fixtures
- Run
pre-commit run --all-filesbefore suggesting changes
- Adding new dependencies to
pyproject.toml - Creating new
conftest.pyfiles - Moving fixtures to shared locations
- Adding new markers to
pytest.ini - Modifying session-scoped fixtures
- Adding new binaries or system-level dependencies (must also update
Dockerfileand verify withmake build)
- Remove or modify existing tests without explicit request
- Add code that isn't immediately used (YAGNI)
- Log secrets, tokens, or credentials
- Skip pre-commit or type checking
- Create abstractions for single-use code
Consult these for detailed guidance:
- Constitution - Non-negotiable principles (supersedes all other docs)
- Developer Guide - Contribution workflow, fixture examples
- Style Guide - Naming, typing, docstrings