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  }