2016-09-15 01:11:57 +00:00
|
|
|
package sql
|
2016-09-18 01:01:15 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"runtime"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2017-07-25 20:45:17 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2018-09-03 06:44:44 +00:00
|
|
|
|
|
|
|
"github.com/dexidp/dex/storage"
|
|
|
|
"github.com/dexidp/dex/storage/conformance"
|
2016-09-18 01:01:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func withTimeout(t time.Duration, f func()) {
|
|
|
|
c := make(chan struct{})
|
|
|
|
defer close(c)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
select {
|
|
|
|
case <-c:
|
|
|
|
case <-time.After(t):
|
|
|
|
// Dump a stack trace of the program. Useful for debugging deadlocks.
|
|
|
|
buf := make([]byte, 2<<20)
|
|
|
|
fmt.Fprintf(os.Stderr, "%s\n", buf[:runtime.Stack(buf, true)])
|
|
|
|
panic("test took too long")
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
f()
|
|
|
|
}
|
|
|
|
|
|
|
|
func cleanDB(c *conn) error {
|
|
|
|
_, err := c.Exec(`
|
|
|
|
delete from client;
|
|
|
|
delete from auth_request;
|
|
|
|
delete from auth_code;
|
|
|
|
delete from refresh_token;
|
|
|
|
delete from keys;
|
2016-11-01 06:00:55 +00:00
|
|
|
delete from password;
|
2016-09-18 01:01:15 +00:00
|
|
|
`)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-11-22 23:35:46 +00:00
|
|
|
var logger = &logrus.Logger{
|
|
|
|
Out: os.Stderr,
|
|
|
|
Formatter: &logrus.TextFormatter{DisableColors: true},
|
|
|
|
Level: logrus.DebugLevel,
|
|
|
|
}
|
|
|
|
|
2016-09-18 01:01:15 +00:00
|
|
|
func TestSQLite3(t *testing.T) {
|
|
|
|
newStorage := func() storage.Storage {
|
|
|
|
// NOTE(ericchiang): In memory means we only get one connection at a time. If we
|
|
|
|
// ever write tests that require using multiple connections, for instance to test
|
|
|
|
// transactions, we need to move to a file based system.
|
|
|
|
s := &SQLite3{":memory:"}
|
2016-11-22 23:35:46 +00:00
|
|
|
conn, err := s.open(logger)
|
2016-09-18 01:01:15 +00:00
|
|
|
if err != nil {
|
2016-11-01 06:00:55 +00:00
|
|
|
fmt.Fprintln(os.Stdout, err)
|
2016-09-18 01:01:15 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
return conn
|
|
|
|
}
|
|
|
|
|
|
|
|
withTimeout(time.Second*10, func() {
|
2016-10-13 01:48:09 +00:00
|
|
|
conformance.RunTests(t, newStorage)
|
2016-09-18 01:01:15 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-11-01 06:00:55 +00:00
|
|
|
func getenv(key, defaultVal string) string {
|
|
|
|
if val := os.Getenv(key); val != "" {
|
|
|
|
return val
|
|
|
|
}
|
|
|
|
return defaultVal
|
|
|
|
}
|
|
|
|
|
|
|
|
const testPostgresEnv = "DEX_POSTGRES_HOST"
|
|
|
|
|
2018-08-23 19:36:08 +00:00
|
|
|
func TestCreateDataSourceName(t *testing.T) {
|
|
|
|
var testCases = []struct {
|
|
|
|
description string
|
|
|
|
input *Postgres
|
|
|
|
expected string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
description: "with no configuration",
|
|
|
|
input: &Postgres{},
|
|
|
|
expected: "connect_timeout=0 sslmode='verify-full'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "with typical configuration",
|
|
|
|
input: &Postgres{
|
|
|
|
Host: "1.2.3.4",
|
|
|
|
Port: 6543,
|
|
|
|
User: "some-user",
|
|
|
|
Password: "some-password",
|
|
|
|
Database: "some-db",
|
|
|
|
},
|
|
|
|
expected: "connect_timeout=0 host='1.2.3.4' port=6543 user='some-user' password='some-password' dbname='some-db' sslmode='verify-full'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "with unix socket host",
|
|
|
|
input: &Postgres{
|
|
|
|
Host: "/var/run/postgres",
|
|
|
|
SSL: PostgresSSL{
|
|
|
|
Mode: "disable",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: "connect_timeout=0 host='/var/run/postgres' sslmode='disable'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "with tcp host",
|
|
|
|
input: &Postgres{
|
|
|
|
Host: "coreos.com",
|
|
|
|
SSL: PostgresSSL{
|
|
|
|
Mode: "disable",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: "connect_timeout=0 host='coreos.com' sslmode='disable'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "with tcp host and port",
|
|
|
|
input: &Postgres{
|
|
|
|
Host: "coreos.com",
|
|
|
|
Port: 6543,
|
|
|
|
},
|
|
|
|
expected: "connect_timeout=0 host='coreos.com' port=6543 sslmode='verify-full'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "with ssl ca cert",
|
|
|
|
input: &Postgres{
|
|
|
|
Host: "coreos.com",
|
|
|
|
SSL: PostgresSSL{
|
|
|
|
Mode: "verify-ca",
|
|
|
|
CAFile: "/some/file/path",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: "connect_timeout=0 host='coreos.com' sslmode='verify-ca' sslrootcert='/some/file/path'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "with ssl client cert",
|
|
|
|
input: &Postgres{
|
|
|
|
Host: "coreos.com",
|
|
|
|
SSL: PostgresSSL{
|
|
|
|
Mode: "verify-ca",
|
|
|
|
CAFile: "/some/ca/path",
|
|
|
|
CertFile: "/some/cert/path",
|
|
|
|
KeyFile: "/some/key/path",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
expected: "connect_timeout=0 host='coreos.com' sslmode='verify-ca' sslrootcert='/some/ca/path' sslcert='/some/cert/path' sslkey='/some/key/path'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
description: "with funny characters in credentials",
|
|
|
|
input: &Postgres{
|
|
|
|
Host: "coreos.com",
|
|
|
|
User: `some'user\slashed`,
|
|
|
|
Password: "some'password!",
|
|
|
|
},
|
|
|
|
expected: `connect_timeout=0 host='coreos.com' user='some\'user\\slashed' password='some\'password!' sslmode='verify-full'`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var actual string
|
|
|
|
for _, testCase := range testCases {
|
|
|
|
t.Run(testCase.description, func(t *testing.T) {
|
|
|
|
actual = testCase.input.createDataSourceName()
|
|
|
|
|
|
|
|
if actual != testCase.expected {
|
|
|
|
t.Fatalf("%s != %s", actual, testCase.expected)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-18 01:01:15 +00:00
|
|
|
func TestPostgres(t *testing.T) {
|
2016-11-01 06:00:55 +00:00
|
|
|
host := os.Getenv(testPostgresEnv)
|
|
|
|
if host == "" {
|
|
|
|
t.Skipf("test environment variable %q not set, skipping", testPostgresEnv)
|
2016-09-18 01:01:15 +00:00
|
|
|
}
|
|
|
|
p := Postgres{
|
2016-11-01 06:00:55 +00:00
|
|
|
Database: getenv("DEX_POSTGRES_DATABASE", "postgres"),
|
|
|
|
User: getenv("DEX_POSTGRES_USER", "postgres"),
|
|
|
|
Password: getenv("DEX_POSTGRES_PASSWORD", "postgres"),
|
|
|
|
Host: host,
|
2016-09-18 01:01:15 +00:00
|
|
|
SSL: PostgresSSL{
|
|
|
|
Mode: sslDisable, // Postgres container doesn't support SSL.
|
|
|
|
},
|
|
|
|
ConnectionTimeout: 5,
|
|
|
|
}
|
2016-10-13 04:56:47 +00:00
|
|
|
|
|
|
|
// t.Fatal has a bad habbit of not actually printing the error
|
|
|
|
fatal := func(i interface{}) {
|
|
|
|
fmt.Fprintln(os.Stdout, i)
|
|
|
|
t.Fatal(i)
|
2016-09-18 01:01:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
newStorage := func() storage.Storage {
|
2018-08-23 19:36:08 +00:00
|
|
|
conn, err := p.open(logger, p.createDataSourceName())
|
2016-10-13 04:56:47 +00:00
|
|
|
if err != nil {
|
|
|
|
fatal(err)
|
|
|
|
}
|
2016-09-18 01:01:15 +00:00
|
|
|
if err := cleanDB(conn); err != nil {
|
2016-10-13 04:56:47 +00:00
|
|
|
fatal(err)
|
2016-09-18 01:01:15 +00:00
|
|
|
}
|
|
|
|
return conn
|
|
|
|
}
|
|
|
|
withTimeout(time.Minute*1, func() {
|
2016-10-13 01:48:09 +00:00
|
|
|
conformance.RunTests(t, newStorage)
|
2016-09-18 01:01:15 +00:00
|
|
|
})
|
2016-11-01 06:00:55 +00:00
|
|
|
withTimeout(time.Minute*1, func() {
|
|
|
|
conformance.RunTransactionTests(t, newStorage)
|
|
|
|
})
|
2016-09-18 01:01:15 +00:00
|
|
|
}
|