postgres_exporter/config/dsn_test.go

229 lines
5.8 KiB
Go

// Copyright 2022 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package config
import (
"net/url"
"reflect"
"testing"
)
// Test_dsn_String is designed to test different dsn combinations for their string representation.
// dsn.String() is designed to be safe to print, redacting any password information and these test
// cases are intended to cover known cases.
func Test_dsn_String(t *testing.T) {
type fields struct {
scheme string
username string
password string
host string
path string
query url.Values
}
tests := []struct {
name string
fields fields
want string
}{
{
name: "Without Password",
fields: fields{
scheme: "postgresql",
username: "test",
host: "localhost:5432",
query: url.Values{},
},
want: "postgresql://test@localhost:5432?",
},
{
name: "With Password",
fields: fields{
scheme: "postgresql",
username: "test",
password: "supersecret",
host: "localhost:5432",
query: url.Values{},
},
want: "postgresql://test:******@localhost:5432?",
},
{
name: "With Password and Query String",
fields: fields{
scheme: "postgresql",
username: "test",
password: "supersecret",
host: "localhost:5432",
query: url.Values{
"ssldisable": []string{"true"},
},
},
want: "postgresql://test:******@localhost:5432?ssldisable=true",
},
{
name: "With Password, Path, and Query String",
fields: fields{
scheme: "postgresql",
username: "test",
password: "supersecret",
host: "localhost:5432",
path: "/somevalue",
query: url.Values{
"ssldisable": []string{"true"},
},
},
want: "postgresql://test:******@localhost:5432/somevalue?ssldisable=true",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := DSN{
scheme: tt.fields.scheme,
username: tt.fields.username,
password: tt.fields.password,
host: tt.fields.host,
path: tt.fields.path,
query: tt.fields.query,
}
if got := d.String(); got != tt.want {
t.Errorf("dsn.String() = %v, want %v", got, tt.want)
}
})
}
}
// Test_dsnFromString tests the dsnFromString function with known variations
// of connection string inputs to ensure that it properly parses the input into
// a dsn.
func Test_dsnFromString(t *testing.T) {
tests := []struct {
name string
input string
want DSN
wantErr bool
}{
{
name: "Key value with password",
input: "host=host.example.com user=postgres port=5432 password=s3cr3t",
want: DSN{
scheme: "postgresql",
host: "host.example.com:5432",
username: "postgres",
password: "s3cr3t",
query: url.Values{},
},
wantErr: false,
},
{
name: "Key value with quoted password and space",
input: "host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"",
want: DSN{
scheme: "postgresql",
host: "host.example.com:5432",
username: "postgres",
password: "s3cr 3t",
query: url.Values{},
},
wantErr: false,
},
{
name: "Key value with different order",
input: "password=abcde host=host.example.com user=postgres port=5432",
want: DSN{
scheme: "postgresql",
host: "host.example.com:5432",
username: "postgres",
password: "abcde",
query: url.Values{},
},
wantErr: false,
},
{
name: "Key value with different order, quoted password, duplicate password",
input: "password=abcde host=host.example.com user=postgres port=5432 password=\"s3cr 3t\"",
want: DSN{
scheme: "postgresql",
host: "host.example.com:5432",
username: "postgres",
password: "s3cr 3t",
query: url.Values{},
},
wantErr: false,
},
{
name: "URL with user in query string",
input: "postgresql://host.example.com:5432/tsdb?user=postgres",
want: DSN{
scheme: "postgresql",
host: "host.example.com:5432",
path: "/tsdb",
query: url.Values{},
username: "postgres",
},
wantErr: false,
},
{
name: "URL with user and password",
input: "postgresql://user:s3cret@host.example.com:5432/tsdb?user=postgres",
want: DSN{
scheme: "postgresql",
host: "host.example.com:5432",
path: "/tsdb",
query: url.Values{},
username: "user",
password: "s3cret",
},
wantErr: false,
},
{
name: "Alternative URL prefix",
input: "postgres://user:s3cret@host.example.com:5432/tsdb?user=postgres",
want: DSN{
scheme: "postgres",
host: "host.example.com:5432",
path: "/tsdb",
query: url.Values{},
username: "user",
password: "s3cret",
},
wantErr: false,
},
{
name: "URL with user and password in query string",
input: "postgresql://host.example.com:5432/tsdb?user=postgres&password=s3cr3t",
want: DSN{
scheme: "postgresql",
host: "host.example.com:5432",
path: "/tsdb",
query: url.Values{},
username: "postgres",
password: "s3cr3t",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := dsnFromString(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("dsnFromString() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("dsnFromString() = %+v, want %+v", got, tt.want)
}
})
}
}