diff --git a/bindings/postgres/metadata.yaml b/bindings/postgres/metadata.yaml index e702a82c64..aa226a309c 100644 --- a/bindings/postgres/metadata.yaml +++ b/bindings/postgres/metadata.yaml @@ -124,3 +124,38 @@ metadata: - "simple_protocol" example: "cache_describe" default: "" + - name: host + required: false + description: The host of the PostgreSQL database + example: "localhost" + type: string + - name: hostaddr + required: false + description: The host address of the PostgreSQL database + example: "127.0.0.1" + type: string + - name: port + required: false + description: The port of the PostgreSQL database + example: "5432" + type: string + - name: database + required: false + description: The database of the PostgreSQL database + example: "postgres" + type: string + - name: user + required: false + description: The user of the PostgreSQL database + example: "postgres" + type: string + - name: password + required: false + description: The password of the PostgreSQL database + example: "password" + type: string + - name: sslRootCert + required: false + description: The path to the SSL root certificate file + example: "/path/to/ssl/root/cert.pem" + type: string diff --git a/bindings/postgres/metadata_test.go b/bindings/postgres/metadata_test.go index ece5e433ed..4ac6faaf67 100644 --- a/bindings/postgres/metadata_test.go +++ b/bindings/postgres/metadata_test.go @@ -34,7 +34,7 @@ func TestMetadata(t *testing.T) { t.Run("has connection string", func(t *testing.T) { m := psqlMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } err := m.InitWithMetadata(props) @@ -44,7 +44,7 @@ func TestMetadata(t *testing.T) { t.Run("default timeout", func(t *testing.T) { m := psqlMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } err := m.InitWithMetadata(props) @@ -55,7 +55,7 @@ func TestMetadata(t *testing.T) { t.Run("invalid timeout", func(t *testing.T) { m := psqlMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "NaN", } @@ -66,7 +66,7 @@ func TestMetadata(t *testing.T) { t.Run("positive timeout", func(t *testing.T) { m := psqlMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "42", } @@ -78,7 +78,7 @@ func TestMetadata(t *testing.T) { t.Run("zero timeout", func(t *testing.T) { m := psqlMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "0", } diff --git a/common/authentication/postgresql/metadata.go b/common/authentication/postgresql/metadata.go index 7a197dffc3..c9c24432bd 100644 --- a/common/authentication/postgresql/metadata.go +++ b/common/authentication/postgresql/metadata.go @@ -17,6 +17,8 @@ import ( "context" "errors" "fmt" + "net/url" + "strings" "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" @@ -32,6 +34,13 @@ import ( // PostgresAuthMetadata contains authentication metadata for PostgreSQL components. type PostgresAuthMetadata struct { ConnectionString string `mapstructure:"connectionString" mapstructurealiases:"url"` + Host string `mapstructure:"host"` + HostAddr string `mapstructure:"hostaddr"` + Port string `mapstructure:"port"` + Database string `mapstructure:"database"` + User string `mapstructure:"user"` + Password string `mapstructure:"password"` + SslRootCert string `mapstructure:"sslRootCert"` ConnectionMaxIdleTime time.Duration `mapstructure:"connectionMaxIdleTime"` MaxConns int `mapstructure:"maxConns"` UseAzureAD bool `mapstructure:"useAzureAD"` @@ -45,6 +54,13 @@ type PostgresAuthMetadata struct { // Reset the object. func (m *PostgresAuthMetadata) Reset() { m.ConnectionString = "" + m.Host = "" + m.HostAddr = "" + m.Port = "" + m.Database = "" + m.User = "" + m.Password = "" + m.SslRootCert = "" m.ConnectionMaxIdleTime = 0 m.MaxConns = 0 m.UseAzureAD = false @@ -62,8 +78,9 @@ type InitWithMetadataOpts struct { // This is different from the "useAzureAD" property from the user, which is provided by the user and instructs the component to authenticate using Azure AD. func (m *PostgresAuthMetadata) InitWithMetadata(meta map[string]string, opts InitWithMetadataOpts) (err error) { // Validate input - if m.ConnectionString == "" { - return errors.New("missing connection string") + _, err = m.buildConnectionString() + if err != nil { + return err } switch { case opts.AzureADEnabled && m.UseAzureAD: @@ -87,6 +104,118 @@ func (m *PostgresAuthMetadata) InitWithMetadata(meta map[string]string, opts Ini return nil } +// buildConnectionString builds the connection string from the metadata. +// It supports both DSN-style and URL-style connection strings. +// Metadata fields override existing values in the connection string. +func (m *PostgresAuthMetadata) buildConnectionString() (string, error) { + metadata := m.getConnectionStringMetadata() + if strings.HasPrefix(m.ConnectionString, "postgres://") || strings.HasPrefix(m.ConnectionString, "postgresql://") { + return m.buildURLConnectionString(metadata) + } + return m.buildDSNConnectionString(metadata) +} + +func (m *PostgresAuthMetadata) buildDSNConnectionString(metadata map[string]string) (string, error) { + connectionString := "" + parts := strings.Split(m.ConnectionString, " ") + for _, part := range parts { + kv := strings.SplitN(part, "=", 2) + if len(kv) == 2 { + key := kv[0] + if value, ok := metadata[key]; ok { + connectionString += fmt.Sprintf("%s=%s ", key, value) + delete(metadata, key) + } else { + connectionString += fmt.Sprintf("%s=%s ", key, kv[1]) + } + } + } + for k, v := range metadata { + connectionString += fmt.Sprintf("%s=%s ", k, v) + } + + if connectionString == "" { + return "", errors.New("failed to build connection string") + } + + return strings.TrimSpace(connectionString), nil +} + +func (m *PostgresAuthMetadata) getConnectionStringMetadata() map[string]string { + metadata := make(map[string]string) + if m.User != "" { + metadata["user"] = m.User + } + if m.Host != "" { + metadata["host"] = m.Host + } + if m.HostAddr != "" { + metadata["hostaddr"] = m.HostAddr + } + if m.Port != "" { + metadata["port"] = m.Port + } + if m.Database != "" { + metadata["database"] = m.Database + } + if m.Password != "" { + metadata["password"] = m.Password + } + if m.SslRootCert != "" { + metadata["sslrootcert"] = m.SslRootCert + } + return metadata +} + +func (m *PostgresAuthMetadata) buildURLConnectionString(metadata map[string]string) (string, error) { + u, err := url.Parse(m.ConnectionString) + if err != nil { + return "", fmt.Errorf("invalid URL connection string: %w", err) + } + + var username string + var password string + if u.User != nil { + username = u.User.Username() + pw, set := u.User.Password() + if set { + password = pw + } + } + + if val, ok := metadata["user"]; ok { + username = val + } + if val, ok := metadata["password"]; ok { + password = val + } + if username != "" { + u.User = url.UserPassword(username, password) + } + + if val, ok := metadata["host"]; ok { + u.Host = val + } + if val, ok := metadata["hostaddr"]; ok { + u.Host = val + } + if m.Port != "" { + u.Host = fmt.Sprintf("%s:%s", u.Host, m.Port) + } + + if val, ok := metadata["database"]; ok { + u.Path = "/" + strings.TrimPrefix(val, "/") + } + + q := u.Query() + if val, ok := metadata["sslrootcert"]; ok { + q.Set("sslrootcert", val) + } + u.RawQuery = q.Encode() + + return u.String(), nil +} + func (m *PostgresAuthMetadata) BuildAwsIamOptions(logger logger.Logger, properties map[string]string) (*aws.Options, error) { awsRegion, _ := metadata.GetMetadataProperty(m.awsEnv.Metadata, "AWSRegion") region, _ := metadata.GetMetadataProperty(m.awsEnv.Metadata, "region") @@ -132,8 +261,11 @@ func (m *PostgresAuthMetadata) BuildAwsIamOptions(logger logger.Logger, properti // GetPgxPoolConfig returns the pgxpool.Config object that contains the credentials for connecting to PostgreSQL. func (m *PostgresAuthMetadata) GetPgxPoolConfig() (*pgxpool.Config, error) { - // Get the config from the connection string - config, err := pgxpool.ParseConfig(m.ConnectionString) + connectionString, err := m.buildConnectionString() + if err != nil { + return nil, err + } + config, err := pgxpool.ParseConfig(connectionString) if err != nil { return nil, fmt.Errorf("failed to parse connection string: %w", err) } diff --git a/common/authentication/postgresql/metadata_test.go b/common/authentication/postgresql/metadata_test.go new file mode 100644 index 0000000000..77b7849389 --- /dev/null +++ b/common/authentication/postgresql/metadata_test.go @@ -0,0 +1,174 @@ +package postgresql + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestBuildConnectionString(t *testing.T) { + tc := []struct { + name string + metadata PostgresAuthMetadata + expected string + expectError bool + }{ + { + name: "empty metadata", + metadata: PostgresAuthMetadata{}, + expected: "", + expectError: true, + }, + { + name: "valid DSN connection string", + metadata: PostgresAuthMetadata{ + ConnectionString: "host=localhost user=postgres password=example port=5432 connect_timeout=10 database=my_db", + }, + expected: "host=localhost user=postgres password=example port=5432 connect_timeout=10 database=my_db", + expectError: false, + }, + { + name: "invalid DSN string with metadata", + metadata: PostgresAuthMetadata{ + ConnectionString: "this is not a valid connection string", + }, + expected: "", + expectError: true, + }, + { + name: "DSN string overridden by metadata", + metadata: PostgresAuthMetadata{ + ConnectionString: "host=localhost user=postgres password=example", + User: "overrideUser", + Password: "overridePass", + }, + expected: "host=localhost user=overrideUser password=overridePass", + expectError: false, + }, + { + name: "DSN missing user, added by metadata", + metadata: PostgresAuthMetadata{ + ConnectionString: "host=localhost port=5432", + User: "fromMetadata", + }, + expected: "host=localhost port=5432 user=fromMetadata", + expectError: false, + }, + { + name: "URL connection string no metadata", + metadata: PostgresAuthMetadata{ + ConnectionString: "postgres://user:pass@localhost:5432/mydb?sslmode=disable", + }, + expected: "postgres://user:pass@localhost:5432/mydb?sslmode=disable", + expectError: false, + }, + { + name: "URL connection string overridden by metadata", + metadata: PostgresAuthMetadata{ + ConnectionString: "postgres://original:secret@localhost:5432/mydb?sslmode=disable", + User: "newuser", + Password: "newpass", + Host: "newhost", + Port: "5433", + Database: "newdb", + SslRootCert: "/certs/root.pem", + }, + expected: "postgres://newuser:newpass@newhost:5433/newdb?sslmode=disable&sslrootcert=%2Fcerts%2Froot.pem", + expectError: false, + }, + { + name: "URL connection string overridden by metadata with hostaddr", + metadata: PostgresAuthMetadata{ + ConnectionString: "postgres://original:secret@localhost:5432/mydb?sslmode=disable", + User: "newuser", + Password: "newpass", + Host: "newhost", + HostAddr: "127.0.0.1", + Port: "5433", + Database: "newdb", + SslRootCert: "/certs/root.pem", + }, + expected: "postgres://newuser:newpass@127.0.0.1:5433/newdb?sslmode=disable&sslrootcert=%2Fcerts%2Froot.pem", + expectError: false, + }, + { + name: "URL connection string adds sslrootcert via metadata", + metadata: PostgresAuthMetadata{ + ConnectionString: "postgres://user:pass@localhost:5432/mydb?sslmode=verify-full", + SslRootCert: "/certs/root.pem", + }, + expected: "postgres://user:pass@localhost:5432/mydb?sslmode=verify-full&sslrootcert=%2Fcerts%2Froot.pem", + expectError: false, + }, + { + name: "URL connection string adds sslrootcert via metadata with hostaddr", + metadata: PostgresAuthMetadata{ + ConnectionString: "postgres://user:pass@localhost:5432/mydb?sslmode=verify-full", + SslRootCert: "/certs/root.pem", + HostAddr: "127.0.0.1", + Port: "5433", + }, + expected: "postgres://user:pass@127.0.0.1:5433/mydb?sslmode=verify-full&sslrootcert=%2Fcerts%2Froot.pem", + expectError: false, + }, + } + for _, tt := range tc { + t.Run(tt.name, func(t *testing.T) { + actual, err := tt.metadata.buildConnectionString() + if tt.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expected, actual) + } + }) + } +} + +func TestURLBuildConnectionStringOnlyWithMetadata(t *testing.T) { + metadata := PostgresAuthMetadata{ + ConnectionString: "postgres://original:secret@localhost:5432/mydb?sslmode=disable", + User: "postgres", + Password: "example", + Host: "localhost", + Port: "5432", + Database: "my_db", + SslRootCert: "/certs/root.pem", + } + actual, err := metadata.buildConnectionString() + require.NoError(t, err) + require.Equal(t, "postgres://postgres:example@localhost:5432/my_db?sslmode=disable&sslrootcert=%2Fcerts%2Froot.pem", actual) +} + +func TestDSNBuildConnectionStringOnlyWithMetadata(t *testing.T) { + metadata := PostgresAuthMetadata{ + User: "postgres", + Password: "example", + Host: "localhost", + Port: "5432", + Database: "my_db", + SslRootCert: "/certs/root.pem", + } + actual, err := metadata.buildConnectionString() + require.NoError(t, err) + parts := strings.Split(actual, " ") + for _, part := range parts { + kv := strings.Split(part, "=") + require.Len(t, kv, 2) + switch kv[0] { + case "host": + require.Equal(t, "localhost", kv[1]) + case "user": + require.Equal(t, "postgres", kv[1]) + case "password": + require.Equal(t, "example", kv[1]) + case "port": + require.Equal(t, "5432", kv[1]) + case "database": + require.Equal(t, "my_db", kv[1]) + case "sslrootcert": + require.Equal(t, "/certs/root.pem", kv[1]) + } + } +} diff --git a/common/component/postgresql/v1/metadata_test.go b/common/component/postgresql/v1/metadata_test.go index e714bf2e09..d68cdffdef 100644 --- a/common/component/postgresql/v1/metadata_test.go +++ b/common/component/postgresql/v1/metadata_test.go @@ -39,7 +39,7 @@ func TestMetadata(t *testing.T) { t.Run("has connection string", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -50,7 +50,7 @@ func TestMetadata(t *testing.T) { t.Run("default table name", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -62,7 +62,7 @@ func TestMetadata(t *testing.T) { t.Run("custom table name", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "tableName": "mytable", } @@ -75,7 +75,7 @@ func TestMetadata(t *testing.T) { t.Run("default timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -87,7 +87,7 @@ func TestMetadata(t *testing.T) { t.Run("invalid timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "NaN", } @@ -99,7 +99,7 @@ func TestMetadata(t *testing.T) { t.Run("positive timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "42", } @@ -112,7 +112,7 @@ func TestMetadata(t *testing.T) { t.Run("zero timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "0", } @@ -124,7 +124,7 @@ func TestMetadata(t *testing.T) { t.Run("default cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -137,7 +137,7 @@ func TestMetadata(t *testing.T) { t.Run("invalid cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "NaN", } @@ -149,7 +149,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "42", } @@ -163,7 +163,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupIntervalInSeconds", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInSeconds": "42", } @@ -177,7 +177,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupInterval as duration", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "42m", } @@ -191,7 +191,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupIntervalInseconds as duration", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInseconds": "42m", } @@ -205,7 +205,7 @@ func TestMetadata(t *testing.T) { t.Run("zero cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "0", } @@ -218,7 +218,7 @@ func TestMetadata(t *testing.T) { t.Run("zero cleanupIntervalInSeconds", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInSeconds": "0", } @@ -231,7 +231,7 @@ func TestMetadata(t *testing.T) { t.Run("empty cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "", } @@ -245,7 +245,7 @@ func TestMetadata(t *testing.T) { t.Run("empty cleanupIntervalInSeconds", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInSeconds": "", } diff --git a/configuration/postgres/metadata.yaml b/configuration/postgres/metadata.yaml index 16db28f2ee..198791d51d 100644 --- a/configuration/postgres/metadata.yaml +++ b/configuration/postgres/metadata.yaml @@ -122,3 +122,38 @@ metadata: - "simple_protocol" example: "cache_describe" default: "" + - name: host + required: false + description: The host of the PostgreSQL database + example: "localhost" + type: string + - name: hostaddr + required: false + description: The host address of the PostgreSQL database + example: "127.0.0.1" + type: string + - name: port + required: false + description: The port of the PostgreSQL database + example: "5432" + type: string + - name: database + required: false + description: The database of the PostgreSQL database + example: "postgres" + type: string + - name: user + required: false + description: The user of the PostgreSQL database + example: "postgres" + type: string + - name: password + required: false + description: The password of the PostgreSQL database + example: "password" + type: string + - name: sslRootCert + required: false + description: The path to the SSL root certificate file + example: "/path/to/ssl/root/cert.pem" + type: string diff --git a/state/postgresql/v1/metadata.yaml b/state/postgresql/v1/metadata.yaml index 03387519ae..597bd0259a 100644 --- a/state/postgresql/v1/metadata.yaml +++ b/state/postgresql/v1/metadata.yaml @@ -141,3 +141,38 @@ metadata: - "simple_protocol" example: "cache_describe" default: "" + - name: host + required: false + description: The host of the PostgreSQL database + example: "localhost" + type: string + - name: hostaddr + required: false + description: The host address of the PostgreSQL database + example: "127.0.0.1" + type: string + - name: port + required: false + description: The port of the PostgreSQL database + example: "5432" + type: string + - name: database + required: false + description: The database of the PostgreSQL database + example: "postgres" + type: string + - name: user + required: false + description: The user of the PostgreSQL database + example: "postgres" + type: string + - name: password + required: false + description: The password of the PostgreSQL database + example: "password" + type: string + - name: sslRootCert + required: false + description: The path to the SSL root certificate file + example: "/path/to/ssl/root/cert.pem" + type: string \ No newline at end of file diff --git a/state/postgresql/v2/metadata.yaml b/state/postgresql/v2/metadata.yaml index de6103918d..cf894d195c 100644 --- a/state/postgresql/v2/metadata.yaml +++ b/state/postgresql/v2/metadata.yaml @@ -140,3 +140,38 @@ metadata: - "simple_protocol" example: "cache_describe" default: "" + - name: host + required: false + description: The host of the PostgreSQL database + example: "localhost" + type: string + - name: hostaddr + required: false + description: The host address of the PostgreSQL database + example: "127.0.0.1" + type: string + - name: port + required: false + description: The port of the PostgreSQL database + example: "5432" + type: string + - name: database + required: false + description: The database of the PostgreSQL database + example: "postgres" + type: string + - name: user + required: false + description: The user of the PostgreSQL database + example: "postgres" + type: string + - name: password + required: false + description: The password of the PostgreSQL database + example: "password" + type: string + - name: sslRootCert + required: false + description: The path to the SSL root certificate file + example: "/path/to/ssl/root/cert.pem" + type: string diff --git a/state/postgresql/v2/metadata_test.go b/state/postgresql/v2/metadata_test.go index a645f20e25..4aa6019a0c 100644 --- a/state/postgresql/v2/metadata_test.go +++ b/state/postgresql/v2/metadata_test.go @@ -39,7 +39,7 @@ func TestMetadata(t *testing.T) { t.Run("has connection string", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -50,7 +50,7 @@ func TestMetadata(t *testing.T) { t.Run("default table prefix", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -62,7 +62,7 @@ func TestMetadata(t *testing.T) { t.Run("custom table prefix", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "tablePrefix": "my_", } @@ -75,7 +75,7 @@ func TestMetadata(t *testing.T) { t.Run("default timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -87,7 +87,7 @@ func TestMetadata(t *testing.T) { t.Run("invalid timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "NaN", } @@ -100,7 +100,7 @@ func TestMetadata(t *testing.T) { t.Run("positive timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "42", } @@ -113,7 +113,7 @@ func TestMetadata(t *testing.T) { t.Run("zero timeout", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "timeout": "0", } @@ -125,7 +125,7 @@ func TestMetadata(t *testing.T) { t.Run("default cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", } opts := postgresql.InitWithMetadataOpts{} @@ -139,7 +139,7 @@ func TestMetadata(t *testing.T) { t.Run("invalid cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "NaN", } @@ -151,7 +151,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "42", } @@ -165,7 +165,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupIntervalInSeconds", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInSeconds": "42", } @@ -179,7 +179,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupInterval as duration", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "42m", } @@ -193,7 +193,7 @@ func TestMetadata(t *testing.T) { t.Run("positive cleanupIntervalInseconds as duration", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInseconds": "42m", } @@ -207,7 +207,7 @@ func TestMetadata(t *testing.T) { t.Run("zero cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "0", } @@ -220,7 +220,7 @@ func TestMetadata(t *testing.T) { t.Run("zero cleanupIntervalInSeconds", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInSeconds": "0", } @@ -233,7 +233,7 @@ func TestMetadata(t *testing.T) { t.Run("empty cleanupInterval", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupInterval": "", } @@ -247,7 +247,7 @@ func TestMetadata(t *testing.T) { t.Run("empty cleanupIntervalInSeconds", func(t *testing.T) { m := pgMetadata{} props := map[string]string{ - "connectionString": "foo", + "connectionString": "foo=bar", "cleanupIntervalInSeconds": "", }