github.com/blend/go-sdk@v1.20220411.3/db/config_test.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package db 9 10 import ( 11 "fmt" 12 "testing" 13 "time" 14 15 "github.com/blend/go-sdk/assert" 16 "github.com/blend/go-sdk/configutil" 17 ) 18 19 var ( 20 _ configutil.Resolver = (*Config)(nil) 21 ) 22 23 func TestConfigCreateDSN(t *testing.T) { 24 assert := assert.New(t) 25 26 cfg := &Config{ 27 Host: "bar", 28 Port: "1234", 29 Username: "example-string", 30 Password: "dog", 31 Database: "blend", 32 Schema: "primary_schema", 33 ApplicationName: "this-pod-7897744df9-v4bbx", 34 SSLMode: SSLModeVerifyCA, 35 LockTimeout: 1704 * time.Millisecond, 36 StatementTimeout: 2704 * time.Millisecond, 37 ConnectTimeout: 7 * time.Second, 38 } 39 40 assert.Equal("postgres://example-string:dog@bar:1234/blend?application_name=this-pod-7897744df9-v4bbx&connect_timeout=7&lock_timeout=1704ms&search_path=primary_schema&sslmode=verify-ca&statement_timeout=2704ms", cfg.CreateDSN()) 41 42 cfg = &Config{ 43 DSN: "foo", 44 Host: "bar", 45 Username: "example-string", 46 Password: "dog", 47 Database: "blend", 48 Schema: "primary_schema", 49 ApplicationName: "this-pod-7897744df9-v4bbx", 50 SSLMode: SSLModeVerifyCA, 51 } 52 53 assert.Equal("foo", cfg.CreateDSN()) 54 55 cfg = &Config{ 56 Host: "bar", 57 Port: "1234", 58 Username: "example-string", 59 Password: "dog", 60 Database: "blend", 61 Schema: "primary_schema", 62 ApplicationName: "this-pod-7897744df9-v4bbx", 63 SSLMode: SSLModeVerifyCA, 64 } 65 66 assert.Equal("postgres://example-string:dog@bar:1234/blend?application_name=this-pod-7897744df9-v4bbx&search_path=primary_schema&sslmode=verify-ca", cfg.CreateDSN()) 67 68 cfg = &Config{ 69 Host: "bar", 70 Port: "1234", 71 Username: "example-string", 72 Password: "dog", 73 Database: "blend", 74 Schema: "primary_schema", 75 ApplicationName: "this-pod-7897744df9-v4bbx", 76 } 77 78 assert.Equal("postgres://example-string:dog@bar:1234/blend?application_name=this-pod-7897744df9-v4bbx&search_path=primary_schema", cfg.CreateDSN()) 79 80 cfg = &Config{ 81 Host: "bar", 82 Port: "1234", 83 Username: "example-string", 84 Password: "dog", 85 Database: "blend", 86 } 87 88 assert.Equal("postgres://example-string:dog@bar:1234/blend", cfg.CreateDSN()) 89 90 cfg = &Config{ 91 Host: "bar", 92 Port: "1234", 93 Username: "example-string", 94 Password: "dog", 95 } 96 97 assert.Equal("postgres://example-string:dog@bar:1234/postgres", cfg.CreateDSN()) 98 99 cfg = &Config{ 100 Host: "bar", 101 Port: "1234", 102 Username: "example-string", 103 } 104 105 assert.Equal("postgres://example-string@bar:1234/postgres", cfg.CreateDSN()) 106 107 cfg = &Config{ 108 Host: "bar", 109 Port: "1234", 110 } 111 112 assert.Equal("postgres://bar:1234/postgres", cfg.CreateDSN()) 113 114 cfg = &Config{ 115 Host: "bar", 116 } 117 118 assert.Equal("postgres://bar:5432/postgres", cfg.CreateDSN()) 119 120 cfg = &Config{} 121 assert.Equal("postgres://localhost:5432/postgres", cfg.CreateDSN()) 122 } 123 124 func TestNewConfigFromDSN(t *testing.T) { 125 assert := assert.New(t) 126 127 // Fails to parse URL 128 dsn := "a://b" 129 parsed, err := NewConfigFromDSN(dsn) 130 assert.Equal(Config{}, parsed) 131 assert.Equal("invalid connection protocol: a", fmt.Sprintf("%v", err)) 132 133 // Success, coverage for lots of fields 134 dsn = "postgres://example-string:dog@bar:1234/blend?connect_timeout=5&lock_timeout=4500ms&statement_timeout=5500ms&sslmode=verify-ca" 135 parsed, err = NewConfigFromDSN(dsn) 136 assert.Nil(err) 137 expected := Config{ 138 Host: "bar", 139 Port: "1234", 140 Database: "blend", 141 Username: "example-string", 142 Password: "dog", 143 ConnectTimeout: 5 * time.Second, 144 LockTimeout: 4500 * time.Millisecond, 145 StatementTimeout: 5500 * time.Millisecond, 146 SSLMode: SSLModeVerifyCA, 147 } 148 assert.Equal(expected, parsed) 149 150 // Failure to parse lock timeout 151 dsn = "postgres://bar:1234/blend?lock_timeout=1000" 152 parsed, err = NewConfigFromDSN(dsn) 153 partial := Config{ 154 Host: "bar", 155 Database: "blend", 156 } 157 assert.Equal(partial, parsed) 158 assert.Matches(`(?m)time: missing unit in duration (")?1000(")?; field: lock_timeout$`, fmt.Sprint(err)) 159 160 // Failure to parse statement timeout 161 dsn = "postgres://bar:1234/blend?statement_timeout=2000" 162 parsed, err = NewConfigFromDSN(dsn) 163 partial = Config{ 164 Host: "bar", 165 Port: "1234", 166 Database: "blend", 167 } 168 assert.Equal(partial, parsed) 169 assert.Matches(`(?m)time: missing unit in duration (")?2000(")?; field: statement_timeout$`, fmt.Sprint(err)) 170 } 171 172 func TestNewConfigFromDSNWithSchema(t *testing.T) { 173 assert := assert.New(t) 174 175 dsn := "postgres://example-string:dog@bar:1234/blend?connect_timeout=5&sslmode=verify-ca&search_path=primary_schema&application_name=this-pod-7897744df9-v4bbx" 176 177 parsed, err := NewConfigFromDSN(dsn) 178 assert.Nil(err) 179 180 expected := Config{ 181 Host: "bar", 182 Port: "1234", 183 Database: "blend", 184 Schema: "primary_schema", 185 ApplicationName: "this-pod-7897744df9-v4bbx", 186 Username: "example-string", 187 Password: "dog", 188 ConnectTimeout: 5 * time.Second, 189 SSLMode: SSLModeVerifyCA, 190 } 191 assert.Equal(expected, parsed) 192 } 193 194 func TestNewConfigFromDSNConnectTimeoutParseError(t *testing.T) { 195 assert := assert.New(t) 196 197 dsn := "postgres://example-string:dog@bar:1234/blend?connect_timeout=abcd&sslmode=verify-ca" 198 199 _, err := NewConfigFromDSN(dsn) 200 assert.NotNil(err) 201 } 202 203 func TestConfigValidateProduction(t *testing.T) { 204 assert := assert.New(t) 205 206 assert.True(IsUsernameUnset(Config{}.ValidateProduction())) 207 assert.True(IsPasswordUnset(Config{Username: "foo"}.ValidateProduction())) 208 assert.True(IsUnsafeSSLMode(Config{Username: "foo", Password: "bar", SSLMode: SSLModeDisable}.ValidateProduction())) 209 assert.True(IsUnsafeSSLMode(Config{Username: "foo", Password: "bar", SSLMode: SSLModeAllow}.ValidateProduction())) 210 assert.True(IsUnsafeSSLMode(Config{Username: "foo", Password: "bar", SSLMode: SSLModePrefer}.ValidateProduction())) 211 assert.True(IsUnsafeSSLMode(Config{Username: "foo", Password: "bar", SSLMode: "NOT A REAL MODE"}.ValidateProduction())) 212 assert.Nil(Config{Username: "foo", Password: "bar", SSLMode: SSLModeVerifyFull}.ValidateProduction()) 213 assert.True(IsDurationConversion(Config{Username: "foo", Password: "bar", SSLMode: SSLModeVerifyFull, LockTimeout: time.Nanosecond}.ValidateProduction())) 214 assert.True(IsDurationConversion(Config{Username: "foo", Password: "bar", SSLMode: SSLModeVerifyFull, StatementTimeout: time.Nanosecond}.ValidateProduction())) 215 } 216 217 func TestConfigReparse(t *testing.T) { 218 assert := assert.New(t) 219 220 cfg := &Config{ 221 Host: "bar", 222 Username: "example-string", 223 Password: "dog", 224 Database: "blend", 225 Schema: "primary_schema", 226 SSLMode: SSLModeVerifyCA, 227 BufferPoolSize: 10, 228 MaxConnections: 10, 229 IdleConnections: 5, 230 MaxLifetime: 100, 231 } 232 233 resolved, err := cfg.Reparse() 234 assert.Nil(err) 235 assert.NotNil(resolved) 236 assert.Equal("bar", resolved.Host) 237 238 assert.Equal(resolved.BufferPoolSize, 10) 239 assert.Equal(resolved.MaxConnections, 10) 240 assert.Equal(resolved.IdleConnections, 5) 241 assert.Equal(resolved.MaxLifetime, 100) 242 }