package postgres import ( "context" "testing" "time" ) func TestDSN(t *testing.T) { c := &Config{ Host: "db.example.com", Port: "5433", User: "alice", Password: "s3cret", DBName: "mydb", SSLMode: "require", } want := "host=db.example.com port=5433 user=alice password=s3cret dbname=mydb sslmode=require" if got := c.DSN(); got != want { t.Errorf("DSN() = %q, want %q", got, want) } } func TestNewConfig_defaults(t *testing.T) { // Clear all env vars that NewConfig reads so we get pure defaults. for _, key := range []string{"DB_HOST", "DB_PORT", "DB_USER", "DB_PASSWORD", "DB_NAME", "DB_SSL_MODE"} { t.Setenv(key, "") } c := NewConfig() if c.Host != "localhost" { t.Errorf("Host = %q, want %q", c.Host, "localhost") } if c.Port != "5432" { t.Errorf("Port = %q, want %q", c.Port, "5432") } if c.User != "postgres" { t.Errorf("User = %q, want %q", c.User, "postgres") } if c.Password != "postgres" { t.Errorf("Password = %q, want %q", c.Password, "postgres") } if c.DBName != "" { t.Errorf("DBName = %q, want empty", c.DBName) } if c.SSLMode != "disable" { t.Errorf("SSLMode = %q, want %q", c.SSLMode, "disable") } } func TestNewConfig_envOverrides(t *testing.T) { t.Setenv("DB_HOST", "remotehost") t.Setenv("DB_PORT", "9999") t.Setenv("DB_USER", "bob") t.Setenv("DB_PASSWORD", "hunter2") t.Setenv("DB_NAME", "testdb") t.Setenv("DB_SSL_MODE", "verify-full") c := NewConfig() if c.Host != "remotehost" { t.Errorf("Host = %q, want %q", c.Host, "remotehost") } if c.Port != "9999" { t.Errorf("Port = %q, want %q", c.Port, "9999") } if c.User != "bob" { t.Errorf("User = %q, want %q", c.User, "bob") } if c.Password != "hunter2" { t.Errorf("Password = %q, want %q", c.Password, "hunter2") } if c.DBName != "testdb" { t.Errorf("DBName = %q, want %q", c.DBName, "testdb") } if c.SSLMode != "verify-full" { t.Errorf("SSLMode = %q, want %q", c.SSLMode, "verify-full") } } func TestNewConfig_withContext(t *testing.T) { ctx := context.WithValue(context.Background(), struct{}{}, "test") c := NewConfig(WithContext(ctx)) if c.Context() != ctx { t.Error("WithContext option did not set the context") } } func TestContext_default(t *testing.T) { c := &Config{} ctx := c.Context() if ctx == nil { t.Fatal("Context() returned nil") } // Should return background context. if ctx != context.Background() { t.Error("Context() should return context.Background() when none set") } } func TestContext_set(t *testing.T) { ctx := t.Context() c := &Config{ctx: ctx} if c.Context() != ctx { t.Error("Context() did not return the set context") } } func TestDialect_Placeholder(t *testing.T) { d := Dialect{} tests := []struct { n int want string }{ {1, "$1"}, {2, "$2"}, {10, "$10"}, {100, "$100"}, } for _, tt := range tests { if got := d.Placeholder(tt.n); got != tt.want { t.Errorf("Placeholder(%d) = %q, want %q", tt.n, got, tt.want) } } } func TestDialect_TableExistsQuery(t *testing.T) { q := Dialect{}.TableExistsQuery() if q == "" { t.Fatal("TableExistsQuery() returned empty string") } // Should reference information_schema and use $1 placeholder. if got := q; got != "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $1)" { t.Errorf("TableExistsQuery() = %q", got) } } func TestDefaultPoolConfig(t *testing.T) { pc := DefaultPoolConfig() if pc.MaxConns != 10 { t.Errorf("MaxConns = %d, want 10", pc.MaxConns) } if pc.MinConns != 2 { t.Errorf("MinConns = %d, want 2", pc.MinConns) } if pc.MaxConnLifetime != time.Hour { t.Errorf("MaxConnLifetime = %v, want %v", pc.MaxConnLifetime, time.Hour) } if pc.MaxConnIdleTime != 30*time.Minute { t.Errorf("MaxConnIdleTime = %v, want %v", pc.MaxConnIdleTime, 30*time.Minute) } if pc.HealthCheckPeriod != time.Minute { t.Errorf("HealthCheckPeriod = %v, want %v", pc.HealthCheckPeriod, time.Minute) } } func TestClosePool_nil(t *testing.T) { // Should not panic. ClosePool(nil) }