""" Unit tests for the DataAnalyst Agent project. Covers: security utils, rate limiting, cleanup, profiler, models, and API endpoints. """ import os import sys import time import json import uuid import tempfile import pytest import pandas as pd from unittest.mock import patch, MagicMock # Force tests to use a temporary file-based database so that connections across the test client share the data _test_db_fd, _test_db_path = tempfile.mkstemp(suffix=".db") os.environ["DATABASE_URL"] = f"sqlite:///{_test_db_path}" from datetime import datetime, timezone # ============================================================================ # SECURITY UTILS TESTS # ============================================================================ class TestRedactSensitiveData: """Tests for app.utils.security.redact_sensitive_data""" def test_redacts_api_key(self): from app.utils.security import redact_sensitive_data text = "api_key=sk-abc123secret" result = redact_sensitive_data(text) assert "sk-abc123secret" not in result assert "[REDACTED]" in result def test_redacts_bearer_token(self): from app.utils.security import redact_sensitive_data text = "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.longtoken" result = redact_sensitive_data(text) assert "eyJhbGciOiJIUzI1NiJ9" not in result def test_redacts_database_url(self): from app.utils.security import redact_sensitive_data text = "connecting to postgres://user:pass@host:5432/db" result = redact_sensitive_data(text) assert "user:pass" not in result assert "[DATABASE_URL_REDACTED]" in result def test_redacts_password_field(self): from app.utils.security import redact_sensitive_data text = "password: mysecretpassword123" result = redact_sensitive_data(text) assert "mysecretpassword123" not in result def test_preserves_normal_text(self): from app.utils.security import redact_sensitive_data text = "This is a normal log message with no secrets." result = redact_sensitive_data(text) assert result == text class TestValidateTableName: """Tests for app.utils.security.validate_table_name""" def test_valid_simple_name(self): from app.utils.security import validate_table_name assert validate_table_name("users") is True def test_valid_with_underscore(self): from app.utils.security import validate_table_name assert validate_table_name("user_profiles") is True def test_valid_starts_with_underscore(self): from app.utils.security import validate_table_name assert validate_table_name("_temp_table") is True def test_invalid_starts_with_number(self): from app.utils.security import validate_table_name assert validate_table_name("123table") is False def test_invalid_contains_dash(self): from app.utils.security import validate_table_name assert validate_table_name("user-table") is False def test_invalid_contains_space(self): from app.utils.security import validate_table_name assert validate_table_name("user table") is False def test_invalid_empty_string(self): from app.utils.security import validate_table_name assert validate_table_name("") is False def test_invalid_too_long(self): from app.utils.security import validate_table_name assert validate_table_name("a" * 64) is False def test_valid_at_max_length(self): from app.utils.security import validate_table_name assert validate_table_name("a" * 63) is True def test_invalid_sql_injection_attempt(self): from app.utils.security import validate_table_name assert validate_table_name("users; DROP TABLE users;--") is False class TestSanitizeHtml: """Tests for app.utils.security.sanitize_html""" def test_allows_safe_tags(self): from app.utils.security import sanitize_html html = "

Hello world

" result = sanitize_html(html) assert "

" in result assert "" in result def test_removes_script_tags(self): from app.utils.security import sanitize_html html = "

Hello

" result = sanitize_html(html) assert "\nHello" result = sanitize_markdown_output(md) assert "