Spaces:
Running
Running
| """ | |
| Unit tests for database schema | |
| Tests table creation, constraints, and foreign key relationships | |
| Requirements: 23.2 | |
| """ | |
| import pytest | |
| import os | |
| from pathlib import Path | |
| class TestDatabaseSchemaStructure: | |
| """ | |
| Tests for database schema structure and SQL file validity | |
| """ | |
| def test_schema_file_exists(self): | |
| """ | |
| Test that the schema.sql file exists | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| assert schema_path.exists(), "schema.sql file should exist" | |
| assert schema_path.is_file(), "schema.sql should be a file" | |
| def test_schema_file_not_empty(self): | |
| """ | |
| Test that the schema.sql file is not empty | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert len(content) > 0, "schema.sql should not be empty" | |
| assert "CREATE TABLE" in content, "schema.sql should contain CREATE TABLE statements" | |
| def test_schema_has_required_extensions(self): | |
| """ | |
| Test that schema enables required PostgreSQL extensions | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"' in content, \ | |
| "Schema should enable uuid-ossp extension" | |
| assert 'CREATE EXTENSION IF NOT EXISTS "pgvector"' in content, \ | |
| "Schema should enable pgvector extension" | |
| class TestTableDefinitions: | |
| """ | |
| Tests for individual table definitions in the schema | |
| """ | |
| def test_users_table_definition(self): | |
| """ | |
| Test that users table has all required fields | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| # Check table creation | |
| assert "CREATE TABLE IF NOT EXISTS users" in content | |
| # Check required fields | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "email TEXT UNIQUE NOT NULL", | |
| "name TEXT", | |
| "plan TEXT NOT NULL DEFAULT 'free'", | |
| "role TEXT", | |
| "personal_api_key TEXT", | |
| "created_at TIMESTAMPTZ", | |
| "updated_at TIMESTAMPTZ", | |
| "disabled BOOLEAN" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"Users table should have {field}" | |
| # Check plan constraint | |
| assert "CHECK (plan IN ('free', 'student', 'pro', 'admin'))" in content | |
| # Check role constraint | |
| assert "CHECK (role IN ('super_admin', 'admin', 'ops', 'support', 'viewer'))" in content | |
| def test_admin_allowlist_table_definition(self): | |
| """ | |
| Test that admin_allowlist table has all required fields | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS admin_allowlist" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "email TEXT UNIQUE NOT NULL", | |
| "role TEXT NOT NULL", | |
| "added_by UUID REFERENCES users(id)", | |
| "created_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"admin_allowlist table should have {field}" | |
| def test_usage_counters_table_definition(self): | |
| """ | |
| Test that usage_counters table has all required tracking fields | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS usage_counters" in content | |
| # Check all tracking fields | |
| tracking_fields = [ | |
| "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE", | |
| "date DATE NOT NULL DEFAULT CURRENT_DATE", | |
| "tokens_used INTEGER", | |
| "requests_count INTEGER", | |
| "pdf_uploads INTEGER", | |
| "mcqs_generated INTEGER", | |
| "images_used INTEGER", | |
| "flashcards_generated INTEGER", | |
| "UNIQUE(user_id, date)" | |
| ] | |
| for field in tracking_fields: | |
| assert field in content, f"usage_counters table should have {field}" | |
| def test_api_keys_table_definition(self): | |
| """ | |
| Test that api_keys table has encryption support and priority fields | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS api_keys" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "provider TEXT NOT NULL", | |
| "feature TEXT NOT NULL", | |
| "key_value TEXT NOT NULL", # encrypted | |
| "priority INTEGER NOT NULL DEFAULT 0", | |
| "status TEXT NOT NULL DEFAULT 'active'", | |
| "failure_count INTEGER", | |
| "last_used_at TIMESTAMPTZ", | |
| "created_at TIMESTAMPTZ", | |
| "updated_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"api_keys table should have {field}" | |
| # Check status constraint | |
| assert "CHECK (status IN ('active', 'degraded', 'disabled'))" in content | |
| def test_provider_health_table_definition(self): | |
| """ | |
| Test that provider_health table exists with required fields | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS provider_health" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "api_key_id UUID NOT NULL REFERENCES api_keys(id) ON DELETE CASCADE", | |
| "checked_at TIMESTAMPTZ", | |
| "status TEXT NOT NULL", | |
| "response_time_ms INTEGER", | |
| "error_message TEXT", | |
| "quota_remaining INTEGER" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"provider_health table should have {field}" | |
| def test_system_flags_table_definition(self): | |
| """ | |
| Test that system_flags table exists for feature toggles | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS system_flags" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "flag_name TEXT UNIQUE NOT NULL", | |
| "flag_value TEXT NOT NULL", | |
| "updated_by UUID REFERENCES users(id)", | |
| "updated_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"system_flags table should have {field}" | |
| def test_documents_table_definition(self): | |
| """ | |
| Test that documents table exists for PDF/image uploads | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS documents" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE", | |
| "filename TEXT NOT NULL", | |
| "file_type TEXT NOT NULL", | |
| "file_size INTEGER NOT NULL", | |
| "storage_path TEXT NOT NULL", | |
| "processing_status TEXT NOT NULL DEFAULT 'pending'", | |
| "created_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"documents table should have {field}" | |
| def test_embeddings_table_definition(self): | |
| """ | |
| Test that embeddings table exists with pgvector support | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS embeddings" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE", | |
| "chunk_text TEXT NOT NULL", | |
| "chunk_index INTEGER NOT NULL", | |
| "embedding VECTOR(768)", | |
| "created_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"embeddings table should have {field}" | |
| # Check vector index | |
| assert "CREATE INDEX IF NOT EXISTS idx_embeddings_vector ON embeddings USING ivfflat" in content | |
| def test_chat_sessions_table_definition(self): | |
| """ | |
| Test that chat_sessions table exists | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS chat_sessions" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE", | |
| "title TEXT", | |
| "created_at TIMESTAMPTZ", | |
| "updated_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"chat_sessions table should have {field}" | |
| def test_messages_table_definition(self): | |
| """ | |
| Test that messages table exists with citations support | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS messages" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "session_id UUID NOT NULL REFERENCES chat_sessions(id) ON DELETE CASCADE", | |
| "role TEXT NOT NULL", | |
| "content TEXT NOT NULL", | |
| "tokens_used INTEGER", | |
| "citations JSONB", | |
| "created_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"messages table should have {field}" | |
| # Check role constraint | |
| assert "CHECK (role IN ('user', 'assistant', 'system'))" in content | |
| def test_subscriptions_table_definition(self): | |
| """ | |
| Test that subscriptions table exists | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS subscriptions" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE", | |
| "plan TEXT NOT NULL", | |
| "razorpay_subscription_id TEXT UNIQUE", | |
| "status TEXT NOT NULL", | |
| "current_period_start TIMESTAMPTZ", | |
| "current_period_end TIMESTAMPTZ", | |
| "created_at TIMESTAMPTZ", | |
| "updated_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"subscriptions table should have {field}" | |
| def test_payments_table_definition(self): | |
| """ | |
| Test that payments table exists | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS payments" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE", | |
| "subscription_id UUID REFERENCES subscriptions(id)", | |
| "razorpay_payment_id TEXT UNIQUE", | |
| "amount INTEGER NOT NULL", | |
| "currency TEXT NOT NULL DEFAULT 'INR'", | |
| "status TEXT NOT NULL", | |
| "created_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"payments table should have {field}" | |
| def test_audit_logs_table_definition(self): | |
| """ | |
| Test that audit_logs table exists | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TABLE IF NOT EXISTS audit_logs" in content | |
| required_fields = [ | |
| "id UUID PRIMARY KEY", | |
| "admin_id UUID REFERENCES users(id)", | |
| "action_type TEXT NOT NULL", | |
| "target_type TEXT", | |
| "target_id TEXT", | |
| "details JSONB", | |
| "created_at TIMESTAMPTZ" | |
| ] | |
| for field in required_fields: | |
| assert field in content, f"audit_logs table should have {field}" | |
| class TestForeignKeyRelationships: | |
| """ | |
| Tests for foreign key relationships between tables | |
| Requirements: 23.2 | |
| """ | |
| def test_usage_counters_user_foreign_key(self): | |
| """ | |
| Test that usage_counters has foreign key to users with CASCADE delete | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE" in content | |
| def test_admin_allowlist_user_foreign_key(self): | |
| """ | |
| Test that admin_allowlist has foreign key to users | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "added_by UUID REFERENCES users(id)" in content | |
| def test_provider_health_api_key_foreign_key(self): | |
| """ | |
| Test that provider_health has foreign key to api_keys with CASCADE delete | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "api_key_id UUID NOT NULL REFERENCES api_keys(id) ON DELETE CASCADE" in content | |
| def test_documents_user_foreign_key(self): | |
| """ | |
| Test that documents has foreign key to users with CASCADE delete | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| # Check in documents table section | |
| documents_section = content[content.find("CREATE TABLE IF NOT EXISTS documents"): | |
| content.find("CREATE TABLE IF NOT EXISTS embeddings")] | |
| assert "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE" in documents_section | |
| def test_embeddings_document_foreign_key(self): | |
| """ | |
| Test that embeddings has foreign key to documents with CASCADE delete | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE" in content | |
| def test_chat_sessions_user_foreign_key(self): | |
| """ | |
| Test that chat_sessions has foreign key to users with CASCADE delete | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| # Check in chat_sessions table section | |
| sessions_section = content[content.find("CREATE TABLE IF NOT EXISTS chat_sessions"): | |
| content.find("CREATE TABLE IF NOT EXISTS messages")] | |
| assert "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE" in sessions_section | |
| def test_messages_session_foreign_key(self): | |
| """ | |
| Test that messages has foreign key to chat_sessions with CASCADE delete | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "session_id UUID NOT NULL REFERENCES chat_sessions(id) ON DELETE CASCADE" in content | |
| def test_subscriptions_user_foreign_key(self): | |
| """ | |
| Test that subscriptions has foreign key to users with CASCADE delete | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| # Check in subscriptions table section | |
| subscriptions_section = content[content.find("CREATE TABLE IF NOT EXISTS subscriptions"): | |
| content.find("CREATE TABLE IF NOT EXISTS payments")] | |
| assert "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE" in subscriptions_section | |
| def test_payments_user_and_subscription_foreign_keys(self): | |
| """ | |
| Test that payments has foreign keys to users and subscriptions | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| # Check in payments table section | |
| payments_section = content[content.find("CREATE TABLE IF NOT EXISTS payments"): | |
| content.find("CREATE TABLE IF NOT EXISTS audit_logs")] | |
| assert "user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE" in payments_section | |
| assert "subscription_id UUID REFERENCES subscriptions(id)" in payments_section | |
| class TestIndexes: | |
| """ | |
| Tests for database indexes | |
| Requirements: 23.2 | |
| """ | |
| def test_users_indexes(self): | |
| """ | |
| Test that users table has required indexes | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)" in content | |
| assert "CREATE INDEX IF NOT EXISTS idx_users_plan ON users(plan)" in content | |
| def test_usage_counters_indexes(self): | |
| """ | |
| Test that usage_counters table has required indexes | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE INDEX IF NOT EXISTS idx_usage_counters_user_date ON usage_counters(user_id, date)" in content | |
| def test_api_keys_indexes(self): | |
| """ | |
| Test that api_keys table has required indexes | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE INDEX IF NOT EXISTS idx_api_keys_provider_feature ON api_keys(provider, feature)" in content | |
| assert "CREATE INDEX IF NOT EXISTS idx_api_keys_status_priority ON api_keys(status, priority DESC)" in content | |
| def test_embeddings_vector_index(self): | |
| """ | |
| Test that embeddings table has vector similarity index | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE INDEX IF NOT EXISTS idx_embeddings_vector ON embeddings USING ivfflat (embedding vector_cosine_ops)" in content | |
| def test_audit_logs_indexes(self): | |
| """ | |
| Test that audit_logs table has required indexes | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE INDEX IF NOT EXISTS idx_audit_logs_admin_created ON audit_logs(admin_id, created_at DESC)" in content | |
| assert "CREATE INDEX IF NOT EXISTS idx_audit_logs_action_created ON audit_logs(action_type, created_at DESC)" in content | |
| class TestConstraints: | |
| """ | |
| Tests for database constraints | |
| Requirements: 23.2 | |
| """ | |
| def test_users_plan_constraint(self): | |
| """ | |
| Test that users table has plan constraint | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CHECK (plan IN ('free', 'student', 'pro', 'admin'))" in content | |
| def test_users_role_constraint(self): | |
| """ | |
| Test that users table has role constraint | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CHECK (role IN ('super_admin', 'admin', 'ops', 'support', 'viewer'))" in content | |
| def test_api_keys_status_constraint(self): | |
| """ | |
| Test that api_keys table has status constraint | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CHECK (status IN ('active', 'degraded', 'disabled'))" in content | |
| def test_usage_counters_unique_constraint(self): | |
| """ | |
| Test that usage_counters has unique constraint on user_id and date | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "UNIQUE(user_id, date)" in content | |
| def test_unique_email_constraints(self): | |
| """ | |
| Test that email fields have unique constraints where required | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| # Users table | |
| users_section = content[content.find("CREATE TABLE IF NOT EXISTS users"): | |
| content.find("CREATE TABLE IF NOT EXISTS admin_allowlist")] | |
| assert "email TEXT UNIQUE NOT NULL" in users_section | |
| # Admin allowlist table | |
| admin_section = content[content.find("CREATE TABLE IF NOT EXISTS admin_allowlist"): | |
| content.find("CREATE TABLE IF NOT EXISTS usage_counters")] | |
| assert "email TEXT UNIQUE NOT NULL" in admin_section | |
| class TestTriggers: | |
| """ | |
| Tests for database triggers | |
| Requirements: 23.2 | |
| """ | |
| def test_updated_at_trigger_function(self): | |
| """ | |
| Test that updated_at trigger function exists | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE OR REPLACE FUNCTION update_updated_at_column()" in content | |
| assert "NEW.updated_at = NOW()" in content | |
| def test_users_updated_at_trigger(self): | |
| """ | |
| Test that users table has updated_at trigger | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users" in content | |
| def test_api_keys_updated_at_trigger(self): | |
| """ | |
| Test that api_keys table has updated_at trigger | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TRIGGER update_api_keys_updated_at BEFORE UPDATE ON api_keys" in content | |
| def test_chat_sessions_updated_at_trigger(self): | |
| """ | |
| Test that chat_sessions table has updated_at trigger | |
| Requirements: 23.2 | |
| """ | |
| schema_path = Path(__file__).parent.parent.parent / "database" / "schema.sql" | |
| content = schema_path.read_text() | |
| assert "CREATE TRIGGER update_chat_sessions_updated_at BEFORE UPDATE ON chat_sessions" in content | |