You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							374 lines
						
					
					
						
							12 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							374 lines
						
					
					
						
							12 KiB
						
					
					
				| #!/usr/bin/env python3 | |
| """ | |
| Test client for SeaweedFS PostgreSQL protocol support. | |
|  | |
| This script demonstrates how to connect to SeaweedFS using standard PostgreSQL | |
| libraries and execute various types of queries. | |
|  | |
| Requirements: | |
|     pip install psycopg2-binary | |
|  | |
| Usage: | |
|     python test_client.py | |
|     python test_client.py --host localhost --port 5432 --user seaweedfs --database default | |
| """ | |
| 
 | |
| import sys | |
| import argparse | |
| import time | |
| import traceback | |
| 
 | |
| try: | |
|     import psycopg2 | |
|     import psycopg2.extras | |
| except ImportError: | |
|     print("Error: psycopg2 not found. Install with: pip install psycopg2-binary") | |
|     sys.exit(1) | |
| 
 | |
| 
 | |
| def test_connection(host, port, user, database, password=None): | |
|     """Test basic connection to SeaweedFS PostgreSQL server.""" | |
|     print(f"🔗 Testing connection to {host}:{port}/{database} as user '{user}'") | |
|      | |
|     try: | |
|         conn_params = { | |
|             'host': host, | |
|             'port': port, | |
|             'user': user, | |
|             'database': database, | |
|             'connect_timeout': 10 | |
|         } | |
|          | |
|         if password: | |
|             conn_params['password'] = password | |
|              | |
|         conn = psycopg2.connect(**conn_params) | |
|         print("✅ Connection successful!") | |
|          | |
|         # Test basic query | |
|         cursor = conn.cursor() | |
|         cursor.execute("SELECT 1 as test") | |
|         result = cursor.fetchone() | |
|         print(f"✅ Basic query successful: {result}") | |
|          | |
|         cursor.close() | |
|         conn.close() | |
|         return True | |
|          | |
|     except Exception as e: | |
|         print(f"❌ Connection failed: {e}") | |
|         return False | |
| 
 | |
| 
 | |
| def test_system_queries(host, port, user, database, password=None): | |
|     """Test PostgreSQL system queries.""" | |
|     print("\n🔧 Testing PostgreSQL system queries...") | |
|      | |
|     try: | |
|         conn_params = { | |
|             'host': host, | |
|             'port': port, | |
|             'user': user, | |
|             'database': database | |
|         } | |
|         if password: | |
|             conn_params['password'] = password | |
|              | |
|         conn = psycopg2.connect(**conn_params) | |
|         cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) | |
|          | |
|         system_queries = [ | |
|             ("Version", "SELECT version()"), | |
|             ("Current Database", "SELECT current_database()"), | |
|             ("Current User", "SELECT current_user"), | |
|             ("Server Encoding", "SELECT current_setting('server_encoding')"), | |
|             ("Client Encoding", "SELECT current_setting('client_encoding')"), | |
|         ] | |
|          | |
|         for name, query in system_queries: | |
|             try: | |
|                 cursor.execute(query) | |
|                 result = cursor.fetchone() | |
|                 print(f"  ✅ {name}: {result[0]}") | |
|             except Exception as e: | |
|                 print(f"  ❌ {name}: {e}") | |
|          | |
|         cursor.close() | |
|         conn.close() | |
|          | |
|     except Exception as e: | |
|         print(f"❌ System queries failed: {e}") | |
| 
 | |
| 
 | |
| def test_schema_queries(host, port, user, database, password=None): | |
|     """Test schema and metadata queries.""" | |
|     print("\n📊 Testing schema queries...") | |
|      | |
|     try: | |
|         conn_params = { | |
|             'host': host, | |
|             'port': port, | |
|             'user': user, | |
|             'database': database | |
|         } | |
|         if password: | |
|             conn_params['password'] = password | |
|              | |
|         conn = psycopg2.connect(**conn_params) | |
|         cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) | |
|          | |
|         schema_queries = [ | |
|             ("Show Databases", "SHOW DATABASES"), | |
|             ("Show Tables", "SHOW TABLES"), | |
|             ("List Schemas", "SELECT 'public' as schema_name"), | |
|         ] | |
|          | |
|         for name, query in schema_queries: | |
|             try: | |
|                 cursor.execute(query) | |
|                 results = cursor.fetchall() | |
|                 print(f"  ✅ {name}: Found {len(results)} items") | |
|                 for row in results[:3]:  # Show first 3 results | |
|                     print(f"    - {dict(row)}") | |
|                 if len(results) > 3: | |
|                     print(f"    ... and {len(results) - 3} more") | |
|             except Exception as e: | |
|                 print(f"  ❌ {name}: {e}") | |
|          | |
|         cursor.close() | |
|         conn.close() | |
|          | |
|     except Exception as e: | |
|         print(f"❌ Schema queries failed: {e}") | |
| 
 | |
| 
 | |
| def test_data_queries(host, port, user, database, password=None): | |
|     """Test data queries on actual topics.""" | |
|     print("\n📝 Testing data queries...") | |
|      | |
|     try: | |
|         conn_params = { | |
|             'host': host, | |
|             'port': port, | |
|             'user': user, | |
|             'database': database | |
|         } | |
|         if password: | |
|             conn_params['password'] = password | |
|              | |
|         conn = psycopg2.connect(**conn_params) | |
|         cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) | |
|          | |
|         # First, try to get available tables/topics | |
|         cursor.execute("SHOW TABLES") | |
|         tables = cursor.fetchall() | |
|          | |
|         if not tables: | |
|             print("  ℹ️  No tables/topics found for data testing") | |
|             cursor.close() | |
|             conn.close() | |
|             return | |
|              | |
|         # Test with first available table | |
|         table_name = tables[0][0] if tables[0] else 'test_topic' | |
|         print(f"  📋 Testing with table: {table_name}") | |
|          | |
|         test_queries = [ | |
|             (f"Count records in {table_name}", f"SELECT COUNT(*) FROM \"{table_name}\""), | |
|             (f"Sample data from {table_name}", f"SELECT * FROM \"{table_name}\" LIMIT 3"), | |
|             (f"System columns from {table_name}", f"SELECT _timestamp_ns, _key, _source FROM \"{table_name}\" LIMIT 3"), | |
|             (f"Describe {table_name}", f"DESCRIBE \"{table_name}\""), | |
|         ] | |
|          | |
|         for name, query in test_queries: | |
|             try: | |
|                 cursor.execute(query) | |
|                 results = cursor.fetchall() | |
|                  | |
|                 if "COUNT" in query.upper(): | |
|                     count = results[0][0] if results else 0 | |
|                     print(f"  ✅ {name}: {count} records") | |
|                 elif "DESCRIBE" in query.upper(): | |
|                     print(f"  ✅ {name}: {len(results)} columns") | |
|                     for row in results[:5]:  # Show first 5 columns | |
|                         print(f"    - {dict(row)}") | |
|                 else: | |
|                     print(f"  ✅ {name}: {len(results)} rows") | |
|                     for row in results: | |
|                         print(f"    - {dict(row)}") | |
|                          | |
|             except Exception as e: | |
|                 print(f"  ❌ {name}: {e}") | |
|          | |
|         cursor.close() | |
|         conn.close() | |
|          | |
|     except Exception as e: | |
|         print(f"❌ Data queries failed: {e}") | |
| 
 | |
| 
 | |
| def test_prepared_statements(host, port, user, database, password=None): | |
|     """Test prepared statements.""" | |
|     print("\n📝 Testing prepared statements...") | |
|      | |
|     try: | |
|         conn_params = { | |
|             'host': host, | |
|             'port': port, | |
|             'user': user, | |
|             'database': database | |
|         } | |
|         if password: | |
|             conn_params['password'] = password | |
|              | |
|         conn = psycopg2.connect(**conn_params) | |
|         cursor = conn.cursor() | |
|          | |
|         # Test parameterized query | |
|         try: | |
|             cursor.execute("SELECT %s as param1, %s as param2", ("hello", 42)) | |
|             result = cursor.fetchone() | |
|             print(f"  ✅ Prepared statement: {result}") | |
|         except Exception as e: | |
|             print(f"  ❌ Prepared statement: {e}") | |
|          | |
|         cursor.close() | |
|         conn.close() | |
|          | |
|     except Exception as e: | |
|         print(f"❌ Prepared statements test failed: {e}") | |
| 
 | |
| 
 | |
| def test_transaction_support(host, port, user, database, password=None): | |
|     """Test transaction support (should be no-op for read-only).""" | |
|     print("\n🔄 Testing transaction support...") | |
|      | |
|     try: | |
|         conn_params = { | |
|             'host': host, | |
|             'port': port, | |
|             'user': user, | |
|             'database': database | |
|         } | |
|         if password: | |
|             conn_params['password'] = password | |
|              | |
|         conn = psycopg2.connect(**conn_params) | |
|         cursor = conn.cursor() | |
|          | |
|         transaction_commands = [ | |
|             "BEGIN", | |
|             "SELECT 1 as in_transaction",  | |
|             "COMMIT", | |
|             "SELECT 1 as after_commit", | |
|         ] | |
|          | |
|         for cmd in transaction_commands: | |
|             try: | |
|                 cursor.execute(cmd) | |
|                 if "SELECT" in cmd: | |
|                     result = cursor.fetchone() | |
|                     print(f"  ✅ {cmd}: {result}") | |
|                 else: | |
|                     print(f"  ✅ {cmd}: OK") | |
|             except Exception as e: | |
|                 print(f"  ❌ {cmd}: {e}") | |
|          | |
|         cursor.close() | |
|         conn.close() | |
|          | |
|     except Exception as e: | |
|         print(f"❌ Transaction test failed: {e}") | |
| 
 | |
| 
 | |
| def test_performance(host, port, user, database, password=None, iterations=10): | |
|     """Test query performance.""" | |
|     print(f"\n⚡ Testing performance ({iterations} iterations)...") | |
|      | |
|     try: | |
|         conn_params = { | |
|             'host': host, | |
|             'port': port, | |
|             'user': user, | |
|             'database': database | |
|         } | |
|         if password: | |
|             conn_params['password'] = password | |
|              | |
|         times = [] | |
|          | |
|         for i in range(iterations): | |
|             start_time = time.time() | |
|              | |
|             conn = psycopg2.connect(**conn_params) | |
|             cursor = conn.cursor() | |
|             cursor.execute("SELECT 1") | |
|             result = cursor.fetchone() | |
|             cursor.close() | |
|             conn.close() | |
|              | |
|             elapsed = time.time() - start_time | |
|             times.append(elapsed) | |
|              | |
|             if i < 3:  # Show first 3 iterations | |
|                 print(f"  Iteration {i+1}: {elapsed:.3f}s") | |
|          | |
|         avg_time = sum(times) / len(times) | |
|         min_time = min(times) | |
|         max_time = max(times) | |
|          | |
|         print(f"  ✅ Performance results:") | |
|         print(f"    - Average: {avg_time:.3f}s") | |
|         print(f"    - Min: {min_time:.3f}s")  | |
|         print(f"    - Max: {max_time:.3f}s") | |
|          | |
|     except Exception as e: | |
|         print(f"❌ Performance test failed: {e}") | |
| 
 | |
| 
 | |
| def main(): | |
|     parser = argparse.ArgumentParser(description="Test SeaweedFS PostgreSQL Protocol") | |
|     parser.add_argument("--host", default="localhost", help="PostgreSQL server host") | |
|     parser.add_argument("--port", type=int, default=5432, help="PostgreSQL server port") | |
|     parser.add_argument("--user", default="seaweedfs", help="PostgreSQL username") | |
|     parser.add_argument("--password", help="PostgreSQL password") | |
|     parser.add_argument("--database", default="default", help="PostgreSQL database") | |
|     parser.add_argument("--skip-performance", action="store_true", help="Skip performance tests") | |
|      | |
|     args = parser.parse_args() | |
|      | |
|     print("🧪 SeaweedFS PostgreSQL Protocol Test Client") | |
|     print("=" * 50) | |
|      | |
|     # Test basic connection first | |
|     if not test_connection(args.host, args.port, args.user, args.database, args.password): | |
|         print("\n❌ Basic connection failed. Cannot continue with other tests.") | |
|         sys.exit(1) | |
|      | |
|     # Run all tests | |
|     try: | |
|         test_system_queries(args.host, args.port, args.user, args.database, args.password) | |
|         test_schema_queries(args.host, args.port, args.user, args.database, args.password) | |
|         test_data_queries(args.host, args.port, args.user, args.database, args.password) | |
|         test_prepared_statements(args.host, args.port, args.user, args.database, args.password) | |
|         test_transaction_support(args.host, args.port, args.user, args.database, args.password) | |
|          | |
|         if not args.skip_performance: | |
|             test_performance(args.host, args.port, args.user, args.database, args.password) | |
|              | |
|     except KeyboardInterrupt: | |
|         print("\n\n⚠️  Tests interrupted by user") | |
|         sys.exit(0) | |
|     except Exception as e: | |
|         print(f"\n❌ Unexpected error during testing: {e}") | |
|         traceback.print_exc() | |
|         sys.exit(1) | |
|      | |
|     print("\n🎉 All tests completed!") | |
|     print("\nTo use SeaweedFS with PostgreSQL tools:") | |
|     print(f"  psql -h {args.host} -p {args.port} -U {args.user} -d {args.database}") | |
|     print(f"  Connection string: postgresql://{args.user}@{args.host}:{args.port}/{args.database}") | |
| 
 | |
| 
 | |
| if __name__ == "__main__": | |
|     main()
 |