Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[run]
branch = True
relative_files = True
source =
config_manager
discovery
services
setup_utils
status
updates
wizard

[report]
precision = 1
show_missing = True
skip_empty = True

[xml]
output = coverage-reports/coverage.xml

[html]
directory = coverage-reports/html
15 changes: 8 additions & 7 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ Documentation for CI/CD workflows and test automation.

Chronicle uses **three separate test workflows** to balance fast PR feedback with comprehensive testing:

| Workflow | Trigger | Test Coverage | API Keys | Purpose |
| Workflow | Trigger | Test selection | API Keys | Purpose |
|----------|---------|---------------|----------|---------|
| `robot-tests.yml` | All PRs | ~70% (no-API tests) | ❌ Not required | Fast PR validation |
| `full-tests-with-api.yml` | Push to dev/main | 100% (full suite) | ✅ Required | Comprehensive validation |
| `pr-tests-with-api.yml` | PR label trigger | 100% (full suite) | ✅ Required | Pre-merge API testing |
| `python-tests.yml` | Relevant PRs, dev/main | Root, backend, and ASR pytest lanes | Not required | Unit tests and branch coverage reports |
| `robot-tests.yml` | All PRs | No-API Robot subset | Not required | Fast PR validation |
| `full-tests-with-api.yml` | Push to dev/main | Full Robot selection | Required | Comprehensive validation |
| `pr-tests-with-api.yml` | PR label trigger | Full Robot selection | Required | Pre-merge API testing |

## Workflow Details

Expand All @@ -35,7 +36,7 @@ on:
- **Makefile Target**: `make test-no-api OUTPUTDIR=results-no-api`
- **Results**: `results-no-api/`
- **Time**: ~10-15 minutes
- **Coverage**: ~70% of test suite
- **Selection**: Robot cases that do not require secrets, GPUs, or excluded slow/SDK environments

**Benefits**:
- Fast feedback on PRs
Expand Down Expand Up @@ -134,15 +135,15 @@ if: contains(github.event.pull_request.labels.*.name, 'test-with-api-keys')
**Normal PR Workflow**:
1. Push your branch
2. Create PR
3. `robot-tests.yml` runs automatically (~70% coverage)
3. `robot-tests.yml` runs the no-API Robot selection automatically
4. Fix any failures
5. Merge when tests pass

**Testing API Integrations**:
1. Push your branch
2. Create PR
3. Ask maintainer to add `test-with-api-keys` label
4. `pr-tests-with-api.yml` runs (100% coverage)
4. `pr-tests-with-api.yml` runs the full Robot selection
5. Fix any failures
6. Merge when tests pass

Expand Down
156 changes: 156 additions & 0 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
name: Python Tests

on:
pull_request:
paths:
- "*.py"
- "setup-requirements.txt"
- ".coveragerc"
- "tests/unit/**"
- "backends/advanced/src/**"
- "backends/advanced/tests/**"
- "backends/advanced/pyproject.toml"
- "backends/advanced/uv.lock"
- "extras/asr-services/common/**"
- "extras/asr-services/providers/**"
- "extras/asr-services/tests/**"
- "extras/asr-services/pyproject.toml"
- "extras/asr-services/uv.lock"
- ".github/workflows/python-tests.yml"
push:
branches: [dev, main]
workflow_dispatch:

permissions:
contents: read

jobs:
root-unit:
name: Root tooling unit tests
runs-on: ubuntu-latest
timeout-minutes: 10
env:
PYTHONPATH: ${{ github.workspace }}/backends/advanced/src

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Run unit tests with coverage
run: >-
uv run
--with-requirements setup-requirements.txt
--with pytest
--with pytest-cov
pytest tests/unit
--cov
--cov-config=.coveragerc
--cov-report=term-missing
--cov-report=xml
--cov-report=html

- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: root-unit-coverage
path: coverage-reports/
if-no-files-found: warn
retention-days: 14

advanced-backend-unit:
name: Advanced backend unit tests
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: backends/advanced

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Install test dependencies
run: uv sync --locked --group test

- name: Run unit tests with coverage
run: >-
uv run --group test pytest
--ignore=tests/test_audio_persistence_mongodb.py
--cov=advanced_omi_backend
--cov-report=term-missing
--cov-report=xml
--cov-report=html

- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: advanced-backend-unit-coverage
path: backends/advanced/coverage-reports/
if-no-files-found: warn
retention-days: 14

asr-unit:
name: ASR unit tests
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
working-directory: extras/asr-services

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Install test dependencies
run: uv sync --locked --group test

- name: Run unit tests with coverage
run: >-
uv run --group test pytest
--ignore=tests/test_parakeet_service.py
--cov=common
--cov=providers
--cov-report=term-missing
--cov-report=xml
--cov-report=html

- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: asr-unit-coverage
path: extras/asr-services/coverage-reports/
if-no-files-found: warn
retention-days: 14
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
**/__pycache__
.coverage
.coverage.*
**/coverage-reports/
**/htmlcov/
*.wav
# Wake-word notification tones are bundled assets, not user audio — keep them tracked
# so they're baked into the wakeword-service image (and served to all clients).
Expand Down Expand Up @@ -34,6 +38,7 @@ plugins/*/config.yml.backup
example/*
**/node_modules/*
**/ollama-data/*
**/model_cache
**/model_cache/*
.vscode/*
**/audio_chunks/*
Expand Down Expand Up @@ -108,6 +113,8 @@ backends/advanced-backend/data/speaker_model_cache/
*.bin
*.sqlite3
*checkpoints
# Experimental provider-local model fine-tuning workspaces
extras/asr-services/providers/*/finetune/


# k8s config
Expand Down
22 changes: 15 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ uv run --with-requirements setup-requirements.txt python wizard.py

**Note on Convenience Scripts**: Chronicle provides wrapper scripts (`./wizard.sh`, `./start.sh`, `./restart.sh`, `./stop.sh`, `./status.sh`) that simplify the longer `uv run --with-requirements setup-requirements.txt python` commands. Use these for everyday operations.

**Temporary Tooling Rule**: When a Python tool or dependency is needed only for a one-off task, run it ephemerally with `uv run --with <package> ...`; do not install it into a project environment or add it to project dependencies. For a package-owned CLI, use `uvx --from <package> <entrypoint>`. This applies to browser automation, screenshots, data inspection, and other temporary utilities.

### Setup Documentation
For detailed setup instructions and troubleshooting, see:
- **[@quickstart.md](quickstart.md)**: Beginner-friendly step-by-step setup guide
Expand Down Expand Up @@ -99,13 +101,13 @@ make test # Start containers + run all tests

# Or step by step
make start # Start test containers (with health checks)
make test-all # Run all test suites
make all # Run all test suites
make stop # Stop containers (preserves volumes)

# Run specific test suites
make test-endpoints # API endpoint tests (~40 tests, fast)
make test-integration # End-to-end workflows (~15 tests, slower)
make test-infra # Infrastructure resilience (~5 tests)
make endpoints # API endpoint tests
make integration # End-to-end workflows
make infra # Infrastructure resilience

# Quick iteration (reuse existing containers)
make test-quick # Run tests without restarting containers
Expand Down Expand Up @@ -611,21 +613,21 @@ For detailed technical documentation, see:

Before writing any Robot Framework test:
1. **Read [@tests/TESTING_GUIDELINES.md](tests/TESTING_GUIDELINES.md)** for comprehensive testing patterns and standards
2. **Check [@tests/tags.md](tests/tags.md)** for approved tags - ONLY 11 tags are permitted
2. **Check [@tests/tags.md](tests/tags.md)** for approved tags - only the 11 business tags and 4 execution tags are permitted
3. **SCAN existing resource files** for keywords - NEVER write code that duplicates existing keywords
4. **Follow the Arrange-Act-Assert pattern** with inline verifications (not abstracted to keywords)

Key Testing Rules:
- **Check Existing Keywords FIRST**: Before writing ANY test code, scan relevant resource files (`websocket_keywords.robot`, `queue_keywords.robot`, `conversation_keywords.robot`, etc.) for existing keywords
- **Tags**: ONLY use the 11 approved tags from tags.md, tab-separated (e.g., `[Tags] infra audio-streaming`)
- **Tags**: ONLY use the 15 approved tags from tags.md, tab-separated (e.g., `[Tags] infra audio-streaming`)
- **Verifications**: Write assertions directly in tests, not in resource keywords
- **Keywords**: Only create keywords for reusable setup/action operations AFTER confirming no existing keyword exists
- **Resources**: Always check existing resource files before creating new keywords or duplicating logic
- **Naming**: Use descriptive names that explain business purpose, not technical implementation

**DO NOT:**
- Write inline code without checking if a keyword already exists for that operation
- Create custom tags (use only the 11 approved tags)
- Create custom tags (use only the 15 approved tags)
- Abstract verifications into keywords (keep them inline in tests)
- Use space-separated tags (must be tab-separated)
- Skip reading the guidelines before writing tests
Expand All @@ -635,6 +637,12 @@ Check if the src/ is volume mounted. If not, do compose build so that code chang
Check `docs/backend/` for up-to-date information on the advanced backend.
All docker projects have .dockerignore following the exclude pattern. That means files need to be included for them to be visible to docker.
The uv package manager is used for all python projects. Wherever you'd call `python3 main.py` you'd call `uv run python main.py`
For temporary Python-backed tooling that is not part of the repo dependencies, prefer `uv run --with <package> python ...` instead of installing packages into the project. Use `uvx --from <package> <entrypoint>` when invoking a package's own CLI. For browser scripts/screenshots, use `uv run --with playwright python - <<'PY'` and import `playwright.sync_api`; for the Playwright CLI use `uvx --from playwright playwright ...`. Do not add transient Playwright/npm packages to `package.json` just to drive a one-off check.

**Compute-Intensive Workloads:**
- Chronicle is designed for heavy data and AI processing. Re-encoding or recomputation is acceptable when it improves correctness or output quality.
- Avoid wasteful repeated work: cache reusable artifacts, fingerprint model and configuration inputs, and reuse valid intermediate results.
- Prefer GPU acceleration whenever the workload and deployed service support it.

**Container Engine (Docker or Podman):**
- The project supports **both Docker and Podman**. The active engine is set by `container_engine` in `config/config.yml` (default `docker`); prefer the lifecycle scripts (`./start.sh`/`./stop.sh`/`./restart.sh`) which route through the selected engine. For one-off manual commands under Podman use `podman-compose` (not `docker compose`). See **[@docs/podman.md](docs/podman.md)**.
Expand Down
Loading
Loading