- 76 new tests covering CLI commands, API routes, auth, runner, load modules — coverage 99% (169 remaining lines are infrastructure) - Enhanced /health endpoint with DuckDB, bib, pipeline service checks - Added `stack health` CLI command with graceful degradation - SnapshotManager for DuckDB data versioning and rollback - .woodpecker.yml CI pipeline: lint, test (99% gate), marimo check - Error handling audit: no bare except clauses, all exceptions logged Closes #31, #32, #33, #34, #35.
153 lines
4.8 KiB
Python
153 lines
4.8 KiB
Python
"""Tests for CLI skeleton — all subcommands are reachable and print stubs."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
from cli import app
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
class TestTopLevel:
|
|
def test_help(self) -> None:
|
|
result = runner.invoke(app, ["--help"])
|
|
assert result.exit_code == 0
|
|
assert "Healthcare data platform CLI" in result.output
|
|
|
|
def test_no_args_shows_help(self) -> None:
|
|
result = runner.invoke(app, [])
|
|
assert "Commands" in result.output
|
|
|
|
|
|
class TestRun:
|
|
def test_run_help(self) -> None:
|
|
result = runner.invoke(app, ["run", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "target" in result.output
|
|
|
|
def test_run_unknown_pipeline(self) -> None:
|
|
result = runner.invoke(app, ["run", "nonexistent"])
|
|
assert result.exit_code != 0
|
|
assert "Unknown pipeline" in result.output
|
|
|
|
def test_run_lists_available(self) -> None:
|
|
result = runner.invoke(app, ["run", "nonexistent"])
|
|
assert "readmissions" in result.output
|
|
|
|
|
|
class TestLoad:
|
|
def test_load_help(self) -> None:
|
|
result = runner.invoke(app, ["load", "--help"])
|
|
assert result.exit_code == 0
|
|
for cmd in ("cclf", "bcda", "seed"):
|
|
assert cmd in result.output
|
|
|
|
def test_load_cclf_requires_path(self) -> None:
|
|
result = runner.invoke(app, ["load", "cclf"])
|
|
assert result.exit_code != 0
|
|
|
|
def test_load_bcda_help(self) -> None:
|
|
result = runner.invoke(app, ["load", "bcda", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "ndjson" in result.output
|
|
|
|
def test_load_seed_help(self) -> None:
|
|
result = runner.invoke(app, ["load", "seed", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "seed" in result.output.lower()
|
|
|
|
|
|
class TestGenerate:
|
|
def test_generate_models_help(self) -> None:
|
|
result = runner.invoke(app, ["generate", "models", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "sync" in result.output
|
|
|
|
|
|
class TestBib:
|
|
def test_bib_sync_help(self) -> None:
|
|
result = runner.invoke(app, ["bib", "sync", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "dry-run" in result.output
|
|
|
|
def test_bib_tag(self) -> None:
|
|
result = runner.invoke(app, ["bib", "tag"])
|
|
assert result.exit_code == 0
|
|
assert "tags found" in result.output
|
|
|
|
def test_bib_query(self) -> None:
|
|
result = runner.invoke(app, ["bib", "query", "pfs"])
|
|
assert result.exit_code == 0
|
|
assert "items found" in result.output
|
|
|
|
|
|
class TestLake:
|
|
def test_lake_deploy_help(self) -> None:
|
|
result = runner.invoke(app, ["lake", "deploy", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "catalog-type" in result.output
|
|
assert "dry-run" in result.output
|
|
|
|
def test_lake_load_help(self) -> None:
|
|
result = runner.invoke(app, ["lake", "load", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "catalog-type" in result.output
|
|
assert "mode" in result.output
|
|
|
|
def test_lake_validate_help(self) -> None:
|
|
result = runner.invoke(app, ["lake", "validate", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "catalog-type" in result.output
|
|
|
|
def test_lake_parity_help(self) -> None:
|
|
result = runner.invoke(app, ["lake", "parity", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "schema" in result.output
|
|
|
|
|
|
class TestDb:
|
|
def test_db_comment(self) -> None:
|
|
result = runner.invoke(app, ["db", "comment"])
|
|
assert result.exit_code == 0
|
|
assert "db comment" in result.output
|
|
|
|
def test_db_inspect(self) -> None:
|
|
result = runner.invoke(app, ["db", "inspect"])
|
|
assert result.exit_code == 0
|
|
assert "db inspect" in result.output
|
|
|
|
|
|
class TestValidate:
|
|
def test_validate_single(self) -> None:
|
|
result = runner.invoke(app, ["validate", "readmissions"])
|
|
assert "readmissions" in result.output.lower()
|
|
|
|
def test_validate_unknown(self) -> None:
|
|
result = runner.invoke(app, ["validate", "nonexistent"])
|
|
assert result.exit_code != 0
|
|
|
|
|
|
class TestHealth:
|
|
def test_health(self) -> None:
|
|
result = runner.invoke(app, ["health"])
|
|
assert "duckdb" in result.output
|
|
assert "pipelines" in result.output
|
|
|
|
|
|
class TestDocs:
|
|
def test_docs_build_help(self) -> None:
|
|
result = runner.invoke(app, ["docs", "build", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "skip-generate" in result.output
|
|
|
|
def test_docs_serve_help(self) -> None:
|
|
result = runner.invoke(app, ["docs", "serve", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "port" in result.output
|
|
|
|
def test_docs_generate_help(self) -> None:
|
|
result = runner.invoke(app, ["docs", "generate", "--help"])
|
|
assert result.exit_code == 0
|
|
assert "Generate" in result.output
|