diff --git a/physical/postgresql/postgresql_test.go b/physical/postgresql/postgresql_test.go index 1341533d19..ffa44fa50e 100644 --- a/physical/postgresql/postgresql_test.go +++ b/physical/postgresql/postgresql_test.go @@ -1,6 +1,7 @@ package postgresql import ( + "fmt" "os" "testing" @@ -9,12 +10,18 @@ import ( "github.com/hashicorp/vault/physical" _ "github.com/lib/pq" + "github.com/ory/dockertest" ) func TestPostgreSQLBackend(t *testing.T) { + logger := logging.NewVaultLogger(log.Debug) + + // Use docker as pg backend if no url is provided via environment variables + var cleanup func() connURL := os.Getenv("PGURL") if connURL == "" { - t.SkipNow() + cleanup, connURL = prepareTestContainer(t, logger) + defer cleanup() } table := os.Getenv("PGTABLE") @@ -22,8 +29,7 @@ func TestPostgreSQLBackend(t *testing.T) { table = "vault_kv_store" } - // Run vault tests - logger := logging.NewVaultLogger(log.Debug) + logger.Info(fmt.Sprintf("Connection URL: %v", connURL)) b, err := NewPostgreSQLBackend(map[string]string{ "connection_url": connURL, @@ -32,15 +38,89 @@ func TestPostgreSQLBackend(t *testing.T) { if err != nil { t.Fatalf("Failed to create new backend: %v", err) } + pg := b.(*PostgreSQLBackend) + + //Read postgres version to test basic connects works + var pgversion string + if err = pg.client.QueryRow("SELECT current_setting('server_version_num')").Scan(&pgversion); err != nil { + t.Fatalf("Failed to check for Postgres version: %v", err) + } + logger.Info(fmt.Sprintf("Postgres Version: %v", pgversion)) + + //Setup tables and indexes if not exists. + createTableSQL := fmt.Sprintf( + " CREATE TABLE IF NOT EXISTS %v ( "+ + " parent_path TEXT COLLATE \"C\" NOT NULL, "+ + " path TEXT COLLATE \"C\", "+ + " key TEXT COLLATE \"C\", "+ + " value BYTEA, "+ + " CONSTRAINT pkey PRIMARY KEY (path, key) "+ + " ); ", table) + + _, err = pg.client.Exec(createTableSQL) + if err != nil { + t.Fatalf("Failed to create table: %v", err) + } + + createIndexSQL := fmt.Sprintf(" CREATE INDEX IF NOT EXISTS parent_path_idx ON %v (parent_path); ", table) + + _, err = pg.client.Exec(createIndexSQL) + if err != nil { + t.Fatalf("Failed to create index: %v", err) + } defer func() { pg := b.(*PostgreSQLBackend) - _, err := pg.client.Exec("TRUNCATE TABLE " + pg.table) + _, err := pg.client.Exec(fmt.Sprintf(" TRUNCATE TABLE %v ", pg.table)) if err != nil { - t.Fatalf("Failed to drop table: %v", err) + t.Fatalf("Failed to truncate table: %v", err) } }() physical.ExerciseBackend(t, b) physical.ExerciseBackend_ListPrefix(t, b) } + +func prepareTestContainer(t *testing.T, logger log.Logger) (cleanup func(), retConnString string) { + // If environment variable is set, use this connectionstring without starting docker container + if os.Getenv("PGURL") != "" { + return func() {}, os.Getenv("PGURL") + } + + pool, err := dockertest.NewPool("") + if err != nil { + t.Fatalf("Failed to connect to docker: %s", err) + } + //using 11.1 which is currently latest, use hard version for stabillity of tests + resource, err := pool.Run("postgres", "11.1", []string{}) + if err != nil { + t.Fatalf("Could not start docker Postgres: %s", err) + } + + retConnString = fmt.Sprintf("postgres://postgres@localhost:%v/postgres?sslmode=disable", resource.GetPort("5432/tcp")) + + cleanup = func() { + err := pool.Purge(resource) + if err != nil { + t.Fatalf("Failed to cleanup docker Postgres: %s", err) + } + } + + // Provide a test function to the pool to test if docker instance service is up. + // We try to setup a pg backend as test for successful connect + // exponential backoff-retry, because the dockerinstance may not be able to accept + // connections yet, test by trying to setup a postgres backend, max-timeout is 60s + if err := pool.Retry(func() error { + var err error + _, err = NewPostgreSQLBackend(map[string]string{ + "connection_url": retConnString, + }, logger) + return err + + }); err != nil { + cleanup() + t.Fatalf("Could not connect to docker: %s", err) + } + + return cleanup, retConnString +}