"""Tests for migration 040_inference_registry.sql. Validates: - SQL is syntactically valid (parseable) - Required tables are created (inference_endpoints, model_deployments, agent_stage_bindings) - Required constraints exist (protocol CHECK, UNIQUE composites) - Lineage columns added to agent_performance_log - Migration is idempotent (uses IF NOT EXISTS / IF NOT EXISTS patterns) """ import re from pathlib import Path import pytest MIGRATION_PATH = Path(__file__).resolve().parent.parent / "infra" / "migrations" / "040_inference_registry.sql" @pytest.fixture def migration_sql() -> str: """Load the migration SQL content.""" assert MIGRATION_PATH.exists(), f"Migration file not found: {MIGRATION_PATH}" return MIGRATION_PATH.read_text() class TestMigrationFileExists: def test_file_exists(self): assert MIGRATION_PATH.exists() def test_file_not_empty(self): content = MIGRATION_PATH.read_text() assert len(content.strip()) > 100 class TestSQLSyntax: """Basic syntax validation via regex pattern checks.""" def test_no_unclosed_parentheses(self, migration_sql: str): """Every CREATE TABLE block has balanced parentheses.""" # Remove comments sql = re.sub(r"--[^\n]*", "", migration_sql) # Remove string literals sql = re.sub(r"'[^']*'", "''", sql) open_count = sql.count("(") close_count = sql.count(")") assert open_count == close_count, ( f"Unbalanced parentheses: {open_count} open vs {close_count} close" ) def test_no_trailing_commas_before_close_paren(self, migration_sql: str): """No trailing comma before closing paren in CREATE TABLE.""" # Pattern: comma followed by optional whitespace/newline then ) # This is a common SQL syntax error sql = re.sub(r"--[^\n]*", "", migration_sql) matches = re.findall(r",\s*\)", sql) assert len(matches) == 0, f"Trailing commas before ')': {matches}" def test_all_statements_terminated(self, migration_sql: str): """Every SQL statement ends with a semicolon.""" # Remove comments and empty lines sql = re.sub(r"--[^\n]*", "", migration_sql) # Remove function bodies (between $$ markers) sql = re.sub(r"\$\$.*?\$\$", "$$BODY$$", sql, flags=re.DOTALL) # Find significant lines that look like statements but don't end with ; lines = [ln.strip() for ln in sql.split("\n") if ln.strip()] # We just check that the overall content has properly terminated statements # by checking that we have multiple semicolons semicolons = migration_sql.count(";") assert semicolons >= 10, f"Expected at least 10 semicolons, got {semicolons}" class TestTableCreation: """Verify all required tables are defined.""" def test_inference_endpoints_table(self, migration_sql: str): assert "CREATE TABLE IF NOT EXISTS inference_endpoints" in migration_sql def test_model_deployments_table(self, migration_sql: str): assert "CREATE TABLE IF NOT EXISTS model_deployments" in migration_sql def test_agent_stage_bindings_table(self, migration_sql: str): assert "CREATE TABLE IF NOT EXISTS agent_stage_bindings" in migration_sql class TestInferenceEndpointsColumns: """Verify inference_endpoints has required columns.""" def test_has_id_primary_key(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "id UUID PRIMARY KEY" in block def test_has_name_unique(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "name TEXT NOT NULL UNIQUE" in block def test_has_protocol_check(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "CHECK" in block assert "ollama_native" in block assert "openai_chat" in block assert "specialist_http" in block def test_has_base_url(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "base_url TEXT NOT NULL" in block def test_has_auth_secret_ref(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "auth_secret_ref TEXT" in block def test_has_auth_scheme_default(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "auth_scheme" in block assert "'bearer'" in block def test_has_enabled_default_true(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "enabled BOOLEAN NOT NULL DEFAULT TRUE" in block def test_has_revision(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "revision INTEGER NOT NULL DEFAULT 1" in block def test_has_timestamps(self, migration_sql: str): block = _extract_create_block(migration_sql, "inference_endpoints") assert "created_at TIMESTAMPTZ" in block assert "updated_at TIMESTAMPTZ" in block class TestModelDeploymentsColumns: """Verify model_deployments has required columns and FK.""" def test_has_endpoint_fk(self, migration_sql: str): block = _extract_create_block(migration_sql, "model_deployments") assert "REFERENCES inference_endpoints(id)" in block def test_has_served_model_name(self, migration_sql: str): block = _extract_create_block(migration_sql, "model_deployments") assert "served_model_name TEXT NOT NULL" in block def test_has_capabilities_jsonb(self, migration_sql: str): block = _extract_create_block(migration_sql, "model_deployments") assert "capabilities JSONB NOT NULL" in block def test_has_context_window(self, migration_sql: str): block = _extract_create_block(migration_sql, "model_deployments") assert "context_window INTEGER" in block def test_has_unique_endpoint_model(self, migration_sql: str): block = _extract_create_block(migration_sql, "model_deployments") assert "UNIQUE(endpoint_id, served_model_name)" in block def test_has_timestamps(self, migration_sql: str): block = _extract_create_block(migration_sql, "model_deployments") assert "created_at TIMESTAMPTZ" in block assert "updated_at TIMESTAMPTZ" in block class TestAgentStageBindingsColumns: """Verify agent_stage_bindings has required columns and FKs.""" def test_has_agent_fk(self, migration_sql: str): block = _extract_create_block(migration_sql, "agent_stage_bindings") assert "REFERENCES ai_agents(id)" in block def test_has_model_deployment_fk(self, migration_sql: str): block = _extract_create_block(migration_sql, "agent_stage_bindings") assert "REFERENCES model_deployments(id)" in block def test_has_stage_column(self, migration_sql: str): block = _extract_create_block(migration_sql, "agent_stage_bindings") assert "stage TEXT NOT NULL" in block def test_has_route_order(self, migration_sql: str): block = _extract_create_block(migration_sql, "agent_stage_bindings") assert "route_order INTEGER NOT NULL DEFAULT 0" in block def test_has_unique_agent_stage_order(self, migration_sql: str): block = _extract_create_block(migration_sql, "agent_stage_bindings") assert "UNIQUE(agent_id, stage, route_order)" in block def test_has_is_active(self, migration_sql: str): block = _extract_create_block(migration_sql, "agent_stage_bindings") assert "is_active BOOLEAN NOT NULL DEFAULT TRUE" in block def test_has_timestamps(self, migration_sql: str): block = _extract_create_block(migration_sql, "agent_stage_bindings") assert "created_at TIMESTAMPTZ" in block assert "updated_at TIMESTAMPTZ" in block class TestIndexes: """Verify required indexes are created.""" def test_endpoint_protocol_index(self, migration_sql: str): assert "idx_inference_endpoints_protocol" in migration_sql assert "ON inference_endpoints(protocol)" in migration_sql def test_deployment_endpoint_index(self, migration_sql: str): assert "idx_model_deployments_endpoint" in migration_sql assert "ON model_deployments(endpoint_id)" in migration_sql def test_binding_agent_index(self, migration_sql: str): assert "idx_agent_stage_bindings_agent" in migration_sql assert "ON agent_stage_bindings(agent_id)" in migration_sql def test_binding_deployment_index(self, migration_sql: str): assert "idx_agent_stage_bindings_deployment" in migration_sql assert "ON agent_stage_bindings(model_deployment_id)" in migration_sql class TestUpdatedAtTrigger: """Verify the updated_at trigger function and triggers exist.""" def test_trigger_function_defined(self, migration_sql: str): assert "CREATE OR REPLACE FUNCTION update_updated_at_column()" in migration_sql def test_trigger_on_inference_endpoints(self, migration_sql: str): assert "trg_inference_endpoints_updated_at" in migration_sql def test_trigger_on_model_deployments(self, migration_sql: str): assert "trg_model_deployments_updated_at" in migration_sql def test_trigger_on_agent_stage_bindings(self, migration_sql: str): assert "trg_agent_stage_bindings_updated_at" in migration_sql class TestLineageColumns: """Verify additive lineage columns on agent_performance_log.""" def test_endpoint_id_column(self, migration_sql: str): assert "ADD COLUMN IF NOT EXISTS endpoint_id UUID" in migration_sql assert "REFERENCES inference_endpoints(id)" in migration_sql def test_deployment_id_column(self, migration_sql: str): assert "ADD COLUMN IF NOT EXISTS deployment_id UUID" in migration_sql assert "REFERENCES model_deployments(id)" in migration_sql def test_binding_revision_column(self, migration_sql: str): assert "ADD COLUMN IF NOT EXISTS binding_revision INTEGER" in migration_sql def test_structured_mode_column(self, migration_sql: str): assert "ADD COLUMN IF NOT EXISTS structured_mode TEXT" in migration_sql class TestIdempotency: """Verify the migration uses idempotent patterns.""" def test_create_table_if_not_exists(self, migration_sql: str): creates = re.findall(r"CREATE TABLE\b", migration_sql) creates_idempotent = re.findall(r"CREATE TABLE IF NOT EXISTS", migration_sql) assert len(creates) == len(creates_idempotent), ( "All CREATE TABLE should use IF NOT EXISTS" ) def test_create_index_if_not_exists(self, migration_sql: str): indexes = re.findall(r"CREATE INDEX\b", migration_sql) indexes_idempotent = re.findall(r"CREATE INDEX IF NOT EXISTS", migration_sql) assert len(indexes) == len(indexes_idempotent), ( "All CREATE INDEX should use IF NOT EXISTS" ) def test_alter_table_if_not_exists(self, migration_sql: str): alters = re.findall(r"ADD COLUMN\b", migration_sql) alters_idempotent = re.findall(r"ADD COLUMN IF NOT EXISTS", migration_sql) assert len(alters) == len(alters_idempotent), ( "All ADD COLUMN should use IF NOT EXISTS" ) def test_trigger_uses_drop_if_exists(self, migration_sql: str): """Triggers use DROP IF EXISTS before CREATE for idempotency.""" drops = re.findall(r"DROP TRIGGER IF EXISTS", migration_sql) creates = re.findall(r"CREATE TRIGGER", migration_sql) assert len(drops) == len(creates), ( "Each CREATE TRIGGER should be preceded by DROP TRIGGER IF EXISTS" ) # ─── Helpers ─────────────────────────────────────────────────────────────────── def _extract_create_block(sql: str, table_name: str) -> str: """Extract the CREATE TABLE block for a given table name.""" pattern = rf"CREATE TABLE IF NOT EXISTS {table_name}\s*\((.*?)\);" match = re.search(pattern, sql, re.DOTALL) assert match is not None, f"Could not find CREATE TABLE block for {table_name}" return match.group(1)