3 changed files with 366 additions and 70 deletions
@ -0,0 +1,242 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"database/sql" |
||||
|
"fmt" |
||||
|
"log" |
||||
|
"testing" |
||||
|
"time" |
||||
|
|
||||
|
_ "github.com/lib/pq" |
||||
|
) |
||||
|
|
||||
|
// TestSHOWTablesRecovery tests that SHOW TABLES doesn't crash with nil pointer dereference
|
||||
|
func TestSHOWTablesRecovery(t *testing.T) { |
||||
|
db := setupTestDB(t) |
||||
|
defer db.Close() |
||||
|
|
||||
|
// Test SHOW TABLES (this was causing panics before the fix)
|
||||
|
rows, err := db.Query("SHOW TABLES") |
||||
|
if err != nil { |
||||
|
t.Fatalf("SHOW TABLES failed: %v", err) |
||||
|
} |
||||
|
defer rows.Close() |
||||
|
|
||||
|
tableCount := 0 |
||||
|
for rows.Next() { |
||||
|
var tableName string |
||||
|
if err := rows.Scan(&tableName); err != nil { |
||||
|
t.Errorf("Error scanning table name: %v", err) |
||||
|
continue |
||||
|
} |
||||
|
tableCount++ |
||||
|
log.Printf("Found table: %s", tableName) |
||||
|
} |
||||
|
|
||||
|
if tableCount == 0 { |
||||
|
t.Error("Expected at least one table, got 0") |
||||
|
} |
||||
|
log.Printf("✓ SHOW TABLES recovery test passed - found %d tables", tableCount) |
||||
|
} |
||||
|
|
||||
|
// TestSHOWTablesFromDatabase tests SHOW TABLES FROM database syntax
|
||||
|
func TestSHOWTablesFromDatabase(t *testing.T) { |
||||
|
db := setupTestDB(t) |
||||
|
defer db.Close() |
||||
|
|
||||
|
// Test SHOW TABLES FROM specific database
|
||||
|
rows, err := db.Query(`SHOW TABLES FROM "logs"`) |
||||
|
if err != nil { |
||||
|
t.Fatalf("SHOW TABLES FROM logs failed: %v", err) |
||||
|
} |
||||
|
defer rows.Close() |
||||
|
|
||||
|
found := false |
||||
|
for rows.Next() { |
||||
|
var tableName string |
||||
|
if err := rows.Scan(&tableName); err != nil { |
||||
|
t.Errorf("Error scanning table name: %v", err) |
||||
|
continue |
||||
|
} |
||||
|
found = true |
||||
|
log.Printf("Found table in logs database: %s", tableName) |
||||
|
} |
||||
|
|
||||
|
if !found { |
||||
|
t.Error("Expected tables in logs database, found none") |
||||
|
} |
||||
|
log.Printf("✓ SHOW TABLES FROM database test passed") |
||||
|
} |
||||
|
|
||||
|
// TestSystemQueriesIndividualConnections tests system queries with fresh connections
|
||||
|
func TestSystemQueriesIndividualConnections(t *testing.T) { |
||||
|
queries := []struct { |
||||
|
name string |
||||
|
query string |
||||
|
}{ |
||||
|
{"Version", "SELECT version()"}, |
||||
|
{"Current User", "SELECT current_user"}, |
||||
|
{"Current Database", "SELECT current_database()"}, |
||||
|
{"Server Encoding", "SELECT current_setting('server_encoding')"}, |
||||
|
} |
||||
|
|
||||
|
connStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable", |
||||
|
getEnv("POSTGRES_HOST", "postgres-server"), |
||||
|
getEnv("POSTGRES_PORT", "5432"), |
||||
|
getEnv("POSTGRES_USER", "seaweedfs"), |
||||
|
getEnv("POSTGRES_DB", "logs")) |
||||
|
|
||||
|
for _, q := range queries { |
||||
|
t.Run(q.name, func(t *testing.T) { |
||||
|
// Create fresh connection for each system query (this was the fix)
|
||||
|
db, err := sql.Open("postgres", connStr) |
||||
|
if err != nil { |
||||
|
t.Fatalf("Failed to create connection for %s: %v", q.name, err) |
||||
|
} |
||||
|
defer db.Close() |
||||
|
|
||||
|
var result string |
||||
|
err = db.QueryRow(q.query).Scan(&result) |
||||
|
if err != nil { |
||||
|
t.Errorf("System query %s failed: %v", q.name, err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if result == "" { |
||||
|
t.Errorf("System query %s returned empty result", q.name) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
log.Printf("✓ %s: %s", q.name, result) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// TestDatabaseConnectionSwitching tests connecting to different databases
|
||||
|
func TestDatabaseConnectionSwitching(t *testing.T) { |
||||
|
databases := []string{"analytics", "ecommerce", "logs"} |
||||
|
|
||||
|
host := getEnv("POSTGRES_HOST", "postgres-server") |
||||
|
port := getEnv("POSTGRES_PORT", "5432") |
||||
|
user := getEnv("POSTGRES_USER", "seaweedfs") |
||||
|
|
||||
|
for _, dbName := range databases { |
||||
|
t.Run(fmt.Sprintf("Connect to %s", dbName), func(t *testing.T) { |
||||
|
// Create fresh connection to specific database (this was the fix instead of USE commands)
|
||||
|
connStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable", |
||||
|
host, port, user, dbName) |
||||
|
|
||||
|
db, err := sql.Open("postgres", connStr) |
||||
|
if err != nil { |
||||
|
t.Fatalf("Failed to connect to database %s: %v", dbName, err) |
||||
|
} |
||||
|
defer db.Close() |
||||
|
|
||||
|
var currentDB string |
||||
|
err = db.QueryRow("SELECT current_database()").Scan(¤tDB) |
||||
|
if err != nil { |
||||
|
t.Errorf("Failed to verify database connection to %s: %v", dbName, err) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
log.Printf("✓ Successfully connected to database: %s", currentDB) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// TestCOUNTFunctionParsing tests COUNT(*) parsing that was fixed
|
||||
|
func TestCOUNTFunctionParsing(t *testing.T) { |
||||
|
db := setupTestDB(t) |
||||
|
defer db.Close() |
||||
|
|
||||
|
// Test COUNT(*) on known table (this was fixed in the parser)
|
||||
|
var count int |
||||
|
err := db.QueryRow("SELECT COUNT(*) FROM application_logs").Scan(&count) |
||||
|
if err != nil { |
||||
|
t.Fatalf("COUNT(*) query failed: %v", err) |
||||
|
} |
||||
|
|
||||
|
if count <= 0 { |
||||
|
t.Error("Expected COUNT(*) to return positive number") |
||||
|
} |
||||
|
|
||||
|
log.Printf("✓ COUNT(*) parsing test passed - found %d records", count) |
||||
|
} |
||||
|
|
||||
|
// TestParquetLogicalTypesDisplay tests that Parquet logical types are displayed correctly
|
||||
|
func TestParquetLogicalTypesDisplay(t *testing.T) { |
||||
|
db := setupTestDB(t) |
||||
|
defer db.Close() |
||||
|
|
||||
|
// Test that timestamp logical types are visible in query results
|
||||
|
rows, err := db.Query("SELECT timestamp, id FROM application_logs LIMIT 2") |
||||
|
if err != nil { |
||||
|
t.Fatalf("Failed to query logical types: %v", err) |
||||
|
} |
||||
|
defer rows.Close() |
||||
|
|
||||
|
count := 0 |
||||
|
for rows.Next() { |
||||
|
var timestamp, id string |
||||
|
if err := rows.Scan(×tamp, &id); err != nil { |
||||
|
t.Errorf("Error scanning logical type data: %v", err) |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
// Check that timestamp contains the logical type structure
|
||||
|
if !containsAny(timestamp, []string{"timestamp_value", "timestamp_mic"}) { |
||||
|
t.Errorf("Expected timestamp to contain logical type structure, got: %s", timestamp) |
||||
|
} |
||||
|
|
||||
|
count++ |
||||
|
log.Printf("Row %d - Timestamp: %s, ID: %s", count, timestamp, id) |
||||
|
} |
||||
|
|
||||
|
if count == 0 { |
||||
|
t.Error("Expected to retrieve logical type data, got none") |
||||
|
} |
||||
|
|
||||
|
log.Printf("✓ Parquet logical types display test passed - %d rows", count) |
||||
|
} |
||||
|
|
||||
|
// Helper functions
|
||||
|
|
||||
|
func setupTestDB(t *testing.T) *sql.DB { |
||||
|
connStr := fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable", |
||||
|
getEnv("POSTGRES_HOST", "postgres-server"), |
||||
|
getEnv("POSTGRES_PORT", "5432"), |
||||
|
getEnv("POSTGRES_USER", "seaweedfs"), |
||||
|
getEnv("POSTGRES_DB", "logs")) |
||||
|
|
||||
|
db, err := sql.Open("postgres", connStr) |
||||
|
if err != nil { |
||||
|
t.Fatalf("Failed to connect to database: %v", err) |
||||
|
} |
||||
|
|
||||
|
// Wait for server to be ready
|
||||
|
for i := 0; i < 30; i++ { |
||||
|
if err = db.Ping(); err == nil { |
||||
|
break |
||||
|
} |
||||
|
time.Sleep(500 * time.Millisecond) |
||||
|
} |
||||
|
|
||||
|
if err != nil { |
||||
|
t.Fatalf("Database not ready after 15 seconds: %v", err) |
||||
|
} |
||||
|
|
||||
|
return db |
||||
|
} |
||||
|
|
||||
|
func containsAny(str string, substrings []string) bool { |
||||
|
for _, sub := range substrings { |
||||
|
if len(str) >= len(sub) { |
||||
|
for i := 0; i <= len(str)-len(sub); i++ { |
||||
|
if str[i:i+len(sub)] == sub { |
||||
|
return true |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return false |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue