diff --git a/cmd/vela-server/database.go b/cmd/vela-server/database.go deleted file mode 100644 index e4db992ec..000000000 --- a/cmd/vela-server/database.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package main - -import ( - "github.com/go-vela/server/database" - - "github.com/sirupsen/logrus" - - "github.com/urfave/cli/v2" -) - -// helper function to setup the database from the CLI arguments. -func setupDatabase(c *cli.Context) (database.Interface, error) { - logrus.Debug("Creating database client from CLI configuration") - - // database configuration - _setup := &database.Setup{ - Driver: c.String("database.driver"), - Address: c.String("database.addr"), - CompressionLevel: c.Int("database.compression.level"), - ConnectionLife: c.Duration("database.connection.life"), - ConnectionIdle: c.Int("database.connection.idle"), - ConnectionOpen: c.Int("database.connection.open"), - EncryptionKey: c.String("database.encryption.key"), - SkipCreation: c.Bool("database.skip_creation"), - } - - // setup the database - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#New - return database.New(_setup) -} diff --git a/cmd/vela-server/server.go b/cmd/vela-server/server.go index 80508e4b0..0d95e88e5 100644 --- a/cmd/vela-server/server.go +++ b/cmd/vela-server/server.go @@ -15,6 +15,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/go-vela/server/database" "github.com/go-vela/server/router" "github.com/go-vela/server/router/middleware" "github.com/sirupsen/logrus" @@ -61,7 +62,7 @@ func server(c *cli.Context) error { return err } - database, err := setupDatabase(c) + database, err := database.FromCLIContext(c) if err != nil { return err } diff --git a/database/context.go b/database/context.go index f3a872602..d27d73550 100644 --- a/database/context.go +++ b/database/context.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. @@ -6,6 +6,9 @@ package database import ( "context" + + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" ) const key = "database" @@ -35,3 +38,19 @@ func FromContext(c context.Context) Interface { func ToContext(c Setter, d Interface) { c.Set(key, d) } + +// FromCLIContext creates and returns a database engine from the urfave/cli context. +func FromCLIContext(c *cli.Context) (Interface, error) { + logrus.Debug("creating database engine from CLI configuration") + + return New(&Config{ + Address: c.String("database.addr"), + CompressionLevel: c.Int("database.compression.level"), + ConnectionLife: c.Duration("database.connection.life"), + ConnectionIdle: c.Int("database.connection.idle"), + ConnectionOpen: c.Int("database.connection.open"), + Driver: c.String("database.driver"), + EncryptionKey: c.String("database.encryption.key"), + SkipCreation: c.Bool("database.skip_creation"), + }) +} diff --git a/database/context_test.go b/database/context_test.go index 382567a43..4037b26c0 100644 --- a/database/context_test.go +++ b/database/context_test.go @@ -1,91 +1,152 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. package database import ( + "flag" + "reflect" "testing" + "time" "github.com/gin-gonic/gin" - "github.com/go-vela/server/database/sqlite" + "github.com/urfave/cli/v2" ) func TestDatabase_FromContext(t *testing.T) { - // setup types - want, _ := sqlite.NewTest() + _postgres, _ := testPostgres(t) + defer _postgres.Close() - defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() - - // setup context gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - context.Set(key, want) - - // run test - got := FromContext(context) - - if got != want { - t.Errorf("FromContext is %v, want %v", got, want) + ctx, _ := gin.CreateTestContext(nil) + ctx.Set(key, _postgres) + + typeCtx, _ := gin.CreateTestContext(nil) + typeCtx.Set(key, nil) + + nilCtx, _ := gin.CreateTestContext(nil) + nilCtx.Set(key, nil) + + // setup tests + tests := []struct { + name string + context *gin.Context + want Interface + }{ + { + name: "success", + context: ctx, + want: _postgres, + }, + { + name: "failure with nil", + context: nilCtx, + want: nil, + }, + { + name: "failure with wrong type", + context: typeCtx, + want: nil, + }, } -} -func TestDatabase_FromContext_Bad(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - context.Set(key, nil) - - // run test - got := FromContext(context) - - if got != nil { - t.Errorf("FromContext is %v, want nil", got) + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := FromContext(test.context) + if !reflect.DeepEqual(got, test.want) { + t.Errorf("FromContext for %s is %v, want %v", test.name, got, test.want) + } + }) } } -func TestDatabase_FromContext_WrongType(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) +func TestDatabase_ToContext(t *testing.T) { context, _ := gin.CreateTestContext(nil) - context.Set(key, 1) - - // run test - got := FromContext(context) - if got != nil { - t.Errorf("FromContext is %v, want nil", got) + _postgres, _ := testPostgres(t) + defer _postgres.Close() + + _sqlite := testSqlite(t) + defer _sqlite.Close() + + // setup tests + tests := []struct { + name string + database *engine + want *engine + }{ + { + name: "success with postgres", + database: _postgres, + want: _postgres, + }, + { + name: "success with sqlite3", + database: _sqlite, + want: _sqlite, + }, } -} - -func TestDatabase_FromContext_Empty(t *testing.T) { - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - // run test - got := FromContext(context) + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ToContext(context, test.want) - if got != nil { - t.Errorf("FromContext is %v, want nil", got) + got := context.Value(key) + if !reflect.DeepEqual(got, test.want) { + t.Errorf("ToContext for %s is %v, want %v", test.name, got, test.want) + } + }) } } -func TestDatabase_ToContext(t *testing.T) { - // setup types - want, _ := sqlite.NewTest() +func TestDatabase_FromCLIContext(t *testing.T) { + flags := flag.NewFlagSet("test", 0) + flags.String("database.driver", "sqlite3", "doc") + flags.String("database.addr", "file::memory:?cache=shared", "doc") + flags.Int("database.compression.level", 3, "doc") + flags.Duration("database.connection.life", 10*time.Second, "doc") + flags.Int("database.connection.idle", 5, "doc") + flags.Int("database.connection.open", 20, "doc") + flags.String("database.encryption.key", "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", "doc") + flags.Bool("database.skip_creation", true, "doc") + + // setup tests + tests := []struct { + name string + failure bool + context *cli.Context + }{ + { + name: "success", + failure: false, + context: cli.NewContext(&cli.App{Name: "vela"}, flags, nil), + }, + { + name: "failure", + failure: true, + context: cli.NewContext(&cli.App{Name: "vela"}, flag.NewFlagSet("test", 0), nil), + }, + } - defer func() { _sql, _ := want.Sqlite.DB(); _sql.Close() }() + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + _, err := FromCLIContext(test.context) - // setup context - gin.SetMode(gin.TestMode) - context, _ := gin.CreateTestContext(nil) - ToContext(context, want) + if test.failure { + if err == nil { + t.Errorf("FromCLIContext for %s should have returned err", test.name) + } - // run test - got := context.Value(key) + return + } - if got != want { - t.Errorf("ToContext is %v, want %v", got, want) + if err != nil { + t.Errorf("FromCLIContext for %s returned err: %v", test.name, err) + } + }) } } diff --git a/database/database.go b/database/database.go index bf0ca2724..5fe3de951 100644 --- a/database/database.go +++ b/database/database.go @@ -22,6 +22,8 @@ import ( "github.com/go-vela/types/constants" "github.com/sirupsen/logrus" + "gorm.io/driver/postgres" + "gorm.io/driver/sqlite" "gorm.io/gorm" ) @@ -32,10 +34,10 @@ type ( Address string // specifies the level of compression to use for the database engine CompressionLevel int - // specifies the maximum idle connections for the database engine - ConnectionIdle int // specifies the connection duration to use for the database engine ConnectionLife time.Duration + // specifies the maximum idle connections for the database engine + ConnectionIdle int // specifies the maximum open connections for the database engine ConnectionOpen int // specifies the driver to use for the database engine @@ -66,38 +68,86 @@ type ( } ) -// New creates and returns a Vela service capable of -// integrating with the configured database provider. +// New creates and returns an engine capable of integrating with the configured database provider. // -// Currently the following database providers are supported: +// Currently, the following database providers are supported: // -// * Postgres -// * Sqlite -// . -func New(s *Setup) (Interface, error) { - // validate the setup being provided - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#Setup.Validate - err := s.Validate() +// * postgres +// * sqlite3 +func New(c *Config) (Interface, error) { + // validate the configuration being provided + err := c.Validate() if err != nil { return nil, err } - logrus.Debug("creating database service from setup") + // create new database engine + e := &engine{ + Config: c, + Database: new(gorm.DB), + Logger: logrus.NewEntry(logrus.StandardLogger()).WithField("database", c.Driver), + } + + e.Logger.Trace("creating database engine from configuration") // process the database driver being provided - switch s.Driver { + switch c.Driver { case constants.DriverPostgres: - // handle the Postgres database driver being provided - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#Setup.Postgres - return s.Postgres() + // create the new Postgres database client + e.Database, err = gorm.Open(postgres.Open(e.Config.Address), &gorm.Config{}) + if err != nil { + return nil, err + } case constants.DriverSqlite: - // handle the Sqlite database driver being provided - // - // https://pkg.go.dev/github.com/go-vela/server/database?tab=doc#Setup.Sqlite - return s.Sqlite() + // create the new Sqlite database client + e.Database, err = gorm.Open(sqlite.Open(e.Config.Address), &gorm.Config{}) + if err != nil { + return nil, err + } default: // handle an invalid database driver being provided - return nil, fmt.Errorf("invalid database driver provided: %s", s.Driver) + return nil, fmt.Errorf("invalid database driver provided: %s", c.Driver) } + + // capture database/sql database from gorm.io/gorm database + db, err := e.Database.DB() + if err != nil { + return nil, err + } + + // set the maximum amount of time a connection may be reused + db.SetConnMaxLifetime(e.Config.ConnectionLife) + // set the maximum number of connections in the idle connection pool + db.SetMaxIdleConns(e.Config.ConnectionIdle) + // set the maximum number of open connections to the database + db.SetMaxOpenConns(e.Config.ConnectionOpen) + + // verify connection to the database + err = e.Ping() + if err != nil { + return nil, err + } + + // create database agnostic engines for resources + err = e.NewResources() + if err != nil { + return nil, err + } + + return e, nil +} + +// NewTest creates and returns an engine that integrates with an in-memory database provider. +// +// This function is ONLY intended to be used for testing purposes. +func NewTest() (Interface, error) { + return New(&Config{ + Address: "file::memory:?cache=shared", + CompressionLevel: 3, + ConnectionLife: 30 * time.Minute, + ConnectionIdle: 2, + ConnectionOpen: 0, + Driver: "sqlite3", + EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", + SkipCreation: false, + }) } diff --git a/database/database_test.go b/database/database_test.go index 77de76d5b..6d18421bc 100644 --- a/database/database_test.go +++ b/database/database_test.go @@ -20,11 +20,13 @@ func TestDatabase_New(t *testing.T) { // setup tests tests := []struct { failure bool - setup *Setup + name string + config *Config }{ { + name: "failure with postgres", failure: true, - setup: &Setup{ + config: &Config{ Driver: "postgres", Address: "postgres://foo:bar@localhost:5432/vela", CompressionLevel: 3, @@ -36,8 +38,9 @@ func TestDatabase_New(t *testing.T) { }, }, { + name: "success with sqlite3", failure: false, - setup: &Setup{ + config: &Config{ Driver: "sqlite3", Address: "file::memory:?cache=shared", CompressionLevel: 3, @@ -49,10 +52,11 @@ func TestDatabase_New(t *testing.T) { }, }, { + name: "failure with invalid config", failure: true, - setup: &Setup{ - Driver: "mysql", - Address: "foo:bar@tcp(localhost:3306)/vela?charset=utf8mb4&parseTime=True&loc=Local", + config: &Config{ + Driver: "postgres", + Address: "", CompressionLevel: 3, ConnectionLife: 10 * time.Second, ConnectionIdle: 5, @@ -62,10 +66,11 @@ func TestDatabase_New(t *testing.T) { }, }, { + name: "failure with invalid driver", failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "", + config: &Config{ + Driver: "mysql", + Address: "foo:bar@tcp(localhost:3306)/vela?charset=utf8mb4&parseTime=True&loc=Local", CompressionLevel: 3, ConnectionLife: 10 * time.Second, ConnectionIdle: 5, @@ -78,19 +83,21 @@ func TestDatabase_New(t *testing.T) { // run tests for _, test := range tests { - _, err := New(test.setup) + t.Run(test.name, func(t *testing.T) { + _, err := New(test.config) - if test.failure { - if err == nil { - t.Errorf("New should have returned err") - } + if test.failure { + if err == nil { + t.Errorf("New for %s should have returned err", test.name) + } - continue - } + return + } - if err != nil { - t.Errorf("New returned err: %v", err) - } + if err != nil { + t.Errorf("New for %s returned err: %v", test.name, err) + } + }) } } diff --git a/database/flags.go b/database/flags.go index 75d3c109b..f8d4fd36e 100644 --- a/database/flags.go +++ b/database/flags.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. @@ -11,13 +11,8 @@ import ( "github.com/urfave/cli/v2" ) -// Flags represents all supported command line -// interface (CLI) flags for the database. -// -// https://pkg.go.dev/github.com/urfave/cli?tab=doc#Flag +// Flags represents all supported command line interface (CLI) flags for the database. var Flags = []cli.Flag{ - // Database Flags - &cli.StringFlag{ EnvVars: []string{"VELA_DATABASE_DRIVER", "DATABASE_DRIVER"}, FilePath: "/vela/database/driver", diff --git a/database/interface.go b/database/interface.go index 975206c93..eed4b27c8 100644 --- a/database/interface.go +++ b/database/interface.go @@ -18,15 +18,23 @@ import ( "github.com/go-vela/server/database/worker" ) -// Interface represents the interface for Vela integrating -// with the different supported Database backends. +// Interface represents the interface for integrating with the supported database providers. type Interface interface { - // Database Interface Functions + // Generic Interface Functions - // Driver defines a function that outputs - // the configured database driver. + // TODO: Add this function to the interface once other code has been updated to use the agnostic engine. + // + // Close defines a function that stops and terminates the connection to the database. + // Close() error + + // Driver defines a function that outputs the configured database driver. Driver() string + // Ping defines a function that sends a "ping" request to the configured database. + Ping() error + + // Resource Interface Functions + // BuildInterface defines the interface for builds stored in the database. build.BuildInterface diff --git a/database/setup.go b/database/setup.go deleted file mode 100644 index a4b553d4d..000000000 --- a/database/setup.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package database - -import ( - "fmt" - "strings" - "time" - - "github.com/go-vela/server/database/postgres" - "github.com/go-vela/server/database/sqlite" - "github.com/go-vela/types/constants" - "github.com/sirupsen/logrus" -) - -// Setup represents the configuration necessary for -// creating a Vela service capable of integrating -// with a configured database system. -type Setup struct { - // Database Configuration - - // specifies the driver to use for the database client - Driver string - // specifies the address to use for the database client - Address string - // specifies the level of compression to use for the database client - CompressionLevel int - // specifies the connection duration to use for the database client - ConnectionLife time.Duration - // specifies the maximum idle connections for the database client - ConnectionIdle int - // specifies the maximum open connections for the database client - ConnectionOpen int - // specifies the encryption key to use for the database client - EncryptionKey string - // specifies to skip creating tables and indexes for the database client - SkipCreation bool -} - -// Postgres creates and returns a Vela service capable of -// integrating with a Postgres database system. -func (s *Setup) Postgres() (Interface, error) { - logrus.Trace("creating postgres database client from setup") - - // create new Postgres database service - // - // https://pkg.go.dev/github.com/go-vela/server/database/postgres?tab=doc#New - return postgres.New( - postgres.WithAddress(s.Address), - postgres.WithCompressionLevel(s.CompressionLevel), - postgres.WithConnectionLife(s.ConnectionLife), - postgres.WithConnectionIdle(s.ConnectionIdle), - postgres.WithConnectionOpen(s.ConnectionOpen), - postgres.WithEncryptionKey(s.EncryptionKey), - postgres.WithSkipCreation(s.SkipCreation), - ) -} - -// Sqlite creates and returns a Vela service capable of -// integrating with a Sqlite database system. -func (s *Setup) Sqlite() (Interface, error) { - logrus.Trace("creating sqlite database client from setup") - - // create new Sqlite database service - // - // https://pkg.go.dev/github.com/go-vela/server/database/sqlite?tab=doc#New - return sqlite.New( - sqlite.WithAddress(s.Address), - sqlite.WithCompressionLevel(s.CompressionLevel), - sqlite.WithConnectionLife(s.ConnectionLife), - sqlite.WithConnectionIdle(s.ConnectionIdle), - sqlite.WithConnectionOpen(s.ConnectionOpen), - sqlite.WithEncryptionKey(s.EncryptionKey), - sqlite.WithSkipCreation(s.SkipCreation), - ) -} - -// Validate verifies the necessary fields for the -// provided configuration are populated correctly. -func (s *Setup) Validate() error { - logrus.Trace("validating database setup for client") - - // verify a database driver was provided - if len(s.Driver) == 0 { - return fmt.Errorf("no database driver provided") - } - - // verify a database address was provided - if len(s.Address) == 0 { - return fmt.Errorf("no database address provided") - } - - // check if the database address has a trailing slash - if strings.HasSuffix(s.Address, "/") { - return fmt.Errorf("database address must not have trailing slash") - } - - // verify a database encryption key was provided - if len(s.EncryptionKey) == 0 { - return fmt.Errorf("no database encryption key provided") - } - - // verify the database compression level is valid - switch s.CompressionLevel { - case constants.CompressionNegOne: - fallthrough - case constants.CompressionZero: - fallthrough - case constants.CompressionOne: - fallthrough - case constants.CompressionTwo: - fallthrough - case constants.CompressionThree: - fallthrough - case constants.CompressionFour: - fallthrough - case constants.CompressionFive: - fallthrough - case constants.CompressionSix: - fallthrough - case constants.CompressionSeven: - fallthrough - case constants.CompressionEight: - fallthrough - case constants.CompressionNine: - break - default: - return fmt.Errorf("database compression level must be between %d and %d - provided level: %d", constants.CompressionNegOne, constants.CompressionNine, s.CompressionLevel) - } - - // enforce AES-256 for the encryption key - explicitly check for 32 characters in the key - if len(s.EncryptionKey) != 32 { - return fmt.Errorf("database encryption key must have 32 characters - provided length: %d", len(s.EncryptionKey)) - } - - // setup is valid - return nil -} diff --git a/database/setup_test.go b/database/setup_test.go deleted file mode 100644 index 4ec2c958c..000000000 --- a/database/setup_test.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. -// -// Use of this source code is governed by the LICENSE file in this repository. - -package database - -import ( - "testing" - "time" -) - -func TestDatabase_Setup_Postgres(t *testing.T) { - // setup types - _setup := &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - } - - // setup tests - tests := []struct { - failure bool - setup *Setup - }{ - { - failure: true, - setup: _setup, - }, - { - failure: true, - setup: &Setup{Driver: "postgres"}, - }, - } - - // run tests - for _, test := range tests { - _, err := test.setup.Postgres() - - if test.failure { - if err == nil { - t.Errorf("Postgres should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Postgres returned err: %v", err) - } - } -} - -func TestDatabase_Setup_Sqlite(t *testing.T) { - // setup types - _setup := &Setup{ - Driver: "sqlite3", - Address: "file::memory:?cache=shared", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - } - - // setup tests - tests := []struct { - failure bool - setup *Setup - }{ - { - failure: false, - setup: _setup, - }, - { - failure: true, - setup: &Setup{Driver: "sqlite3"}, - }, - } - - // run tests - for _, test := range tests { - _, err := test.setup.Sqlite() - - if test.failure { - if err == nil { - t.Errorf("Sqlite should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Sqlite returned err: %v", err) - } - } -} - -func TestDatabase_Setup_Validate(t *testing.T) { - // setup tests - tests := []struct { - failure bool - setup *Setup - }{ - { - failure: false, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: false, - setup: &Setup{ - Driver: "sqlite3", - Address: "file::memory:?cache=shared", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: false, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: -1, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela/", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 3, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0", - SkipCreation: false, - }, - }, - { - failure: true, - setup: &Setup{ - Driver: "postgres", - Address: "postgres://foo:bar@localhost:5432/vela", - CompressionLevel: 10, - ConnectionLife: 10 * time.Second, - ConnectionIdle: 5, - ConnectionOpen: 20, - EncryptionKey: "A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW", - SkipCreation: false, - }, - }, - } - - // run tests - for _, test := range tests { - err := test.setup.Validate() - - if test.failure { - if err == nil { - t.Errorf("Validate should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Validate returned err: %v", err) - } - } -}