Skip to main content
Glama
test_integration.py8.67 kB
""" Integration tests for postgresql-mcp. These tests require a running PostgreSQL instance. Run with: docker-compose up -d && uv run pytest tests/test_integration.py -v Skip these tests if no database is available by running: uv run pytest tests/ -v --ignore=tests/test_integration.py """ import os import pytest # Skip all tests in this module if POSTGRES_PASSWORD is not set pytestmark = pytest.mark.skipif( not os.environ.get("POSTGRES_PASSWORD"), reason="Integration tests require POSTGRES_PASSWORD environment variable" ) class TestDatabaseConnection: """Test basic database connectivity.""" def test_can_connect(self): """Verify we can connect to the database.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() # get_connection() is a context manager with client.get_connection() as conn: assert conn is not None assert not conn.closed def test_list_schemas(self): """Test listing schemas.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() schemas = client.list_schemas() assert isinstance(schemas, list) schema_names = [s["schema_name"] for s in schemas] assert "public" in schema_names def test_list_tables(self): """Test listing tables in public schema.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() tables = client.list_tables("public") assert isinstance(tables, list) # Should have our sample tables table_names = [t["table_name"] for t in tables] assert "customers" in table_names assert "products" in table_names assert "orders" in table_names def test_describe_table(self): """Test describing a table.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() result = client.describe_table("customers", "public") assert isinstance(result, dict) assert "columns" in result assert len(result["columns"]) > 0 column_names = [c["column_name"] for c in result["columns"]] assert "id" in column_names assert "email" in column_names assert "name" in column_names # Check primary keys assert "id" in result["primary_keys"] def test_execute_query_select(self): """Test executing a SELECT query.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() result = client.execute_query("SELECT COUNT(*) as count FROM customers") assert result["success"] is True assert isinstance(result["rows"], list) assert len(result["rows"]) == 1 assert result["rows"][0]["count"] >= 0 def test_execute_query_with_limit(self): """Test query respects max_rows parameter.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() result = client.execute_query("SELECT * FROM products", max_rows=2) assert result["success"] is True assert isinstance(result["rows"], list) assert len(result["rows"]) <= 2 def test_get_table_stats(self): """Test getting table statistics.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() stats = client.get_table_stats("customers", "public") assert isinstance(stats, dict) assert "table_name" in stats assert "row_count" in stats assert "total_size" in stats def test_list_indexes(self): """Test listing indexes.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() indexes = client.list_indexes("orders", "public") assert isinstance(indexes, list) # orders table should have indexes index_names = [i["index_name"] for i in indexes] assert "orders_pkey" in index_names def test_list_views(self): """Test listing views.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() views = client.list_views("public") assert isinstance(views, list) view_names = [v["table_name"] for v in views] assert "customer_order_summary" in view_names def test_explain_query(self): """Test EXPLAIN.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() result = client.explain_query("SELECT * FROM customers WHERE id = 1") assert result["success"] is True assert "plan" in result def test_search_columns(self): """Test searching for columns by name pattern.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() columns = client.search_columns("email") assert isinstance(columns, list) assert len(columns) > 0 # Should find email column in customers table found = any( c["table_name"] == "customers" and c["column_name"] == "email" for c in columns ) assert found def test_get_database_info(self): """Test getting database information.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() info = client.get_database_info() assert isinstance(info, dict) assert "database" in info assert "version" in info def test_list_constraints(self): """Test listing constraints.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() constraints = client.list_constraints("orders", "public") assert isinstance(constraints, list) # orders table should have foreign key constraints constraint_types = [c["constraint_type"] for c in constraints] assert "PRIMARY KEY" in constraint_types assert "FOREIGN KEY" in constraint_types class TestSecurityIntegration: """Test security features with real database.""" def test_write_blocked_by_default(self): """Verify write operations are blocked in execute_query().""" from postgres_mcp.postgres_client import PostgresClient from postgres_mcp.security import SQLValidationError client = PostgresClient() with pytest.raises(SQLValidationError, match="not allowed"): client.execute_query("INSERT INTO customers (email, name) VALUES ('test@test.com', 'Test')") def test_drop_blocked(self): """Verify DROP is blocked.""" from postgres_mcp.postgres_client import PostgresClient from postgres_mcp.security import SQLValidationError client = PostgresClient() with pytest.raises(SQLValidationError, match="not allowed"): client.execute_query("DROP TABLE customers") def test_sql_injection_blocked(self): """Test SQL injection attempts are blocked.""" from postgres_mcp.postgres_client import PostgresClient from postgres_mcp.security import SQLValidationError client = PostgresClient() # Multiple statements blocked with pytest.raises(SQLValidationError, match="[Mm]ultiple"): client.execute_query("SELECT 1; DROP TABLE customers;") # DROP keyword blocked (regardless of multiple statements) with pytest.raises(SQLValidationError, match="not allowed"): client.execute_query("DROP TABLE customers") def test_write_allowed_when_enabled(self): """Verify write operations work with allow_write=True.""" from postgres_mcp.postgres_client import PostgresClient client = PostgresClient() # This should not raise when allow_write is True # We'll test with a harmless INSERT that we can rollback result = client.execute_query( "INSERT INTO customers (email, name) VALUES ('integration_test@test.com', 'Integration Test')", allow_write=True ) assert result["success"] is True # Clean up client.execute_query( "DELETE FROM customers WHERE email = 'integration_test@test.com'", allow_write=True )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JaviMaligno/postgres-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server