storage/sql: use isolation level "serializable" for transactions
This commit is contained in:
parent
651b406cfd
commit
52e2a1668c
@ -36,6 +36,7 @@ func cleanDB(c *conn) error {
|
|||||||
delete from auth_code;
|
delete from auth_code;
|
||||||
delete from refresh_token;
|
delete from refresh_token;
|
||||||
delete from keys;
|
delete from keys;
|
||||||
|
delete from password;
|
||||||
`)
|
`)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -48,6 +49,7 @@ func TestSQLite3(t *testing.T) {
|
|||||||
s := &SQLite3{":memory:"}
|
s := &SQLite3{":memory:"}
|
||||||
conn, err := s.open()
|
conn, err := s.open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stdout, err)
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return conn
|
return conn
|
||||||
@ -58,15 +60,25 @@ func TestSQLite3(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getenv(key, defaultVal string) string {
|
||||||
|
if val := os.Getenv(key); val != "" {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return defaultVal
|
||||||
|
}
|
||||||
|
|
||||||
|
const testPostgresEnv = "DEX_POSTGRES_HOST"
|
||||||
|
|
||||||
func TestPostgres(t *testing.T) {
|
func TestPostgres(t *testing.T) {
|
||||||
if os.Getenv("DEX_POSTGRES_HOST") == "" {
|
host := os.Getenv(testPostgresEnv)
|
||||||
t.Skip("postgres envs not set, skipping tests")
|
if host == "" {
|
||||||
|
t.Skipf("test environment variable %q not set, skipping", testPostgresEnv)
|
||||||
}
|
}
|
||||||
p := Postgres{
|
p := Postgres{
|
||||||
Database: os.Getenv("DEX_POSTGRES_DATABASE"),
|
Database: getenv("DEX_POSTGRES_DATABASE", "postgres"),
|
||||||
User: os.Getenv("DEX_POSTGRES_USER"),
|
User: getenv("DEX_POSTGRES_USER", "postgres"),
|
||||||
Password: os.Getenv("DEX_POSTGRES_PASSWORD"),
|
Password: getenv("DEX_POSTGRES_PASSWORD", "postgres"),
|
||||||
Host: os.Getenv("DEX_POSTGRES_HOST"),
|
Host: host,
|
||||||
SSL: PostgresSSL{
|
SSL: PostgresSSL{
|
||||||
Mode: sslDisable, // Postgres container doesn't support SSL.
|
Mode: sslDisable, // Postgres container doesn't support SSL.
|
||||||
},
|
},
|
||||||
@ -92,4 +104,7 @@ func TestPostgres(t *testing.T) {
|
|||||||
withTimeout(time.Minute*1, func() {
|
withTimeout(time.Minute*1, func() {
|
||||||
conformance.RunTests(t, newStorage)
|
conformance.RunTests(t, newStorage)
|
||||||
})
|
})
|
||||||
|
withTimeout(time.Minute*1, func() {
|
||||||
|
conformance.RunTransactionTests(t, newStorage)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,30 @@ func matchLiteral(s string) *regexp.Regexp {
|
|||||||
var (
|
var (
|
||||||
// The "github.com/lib/pq" driver is the default flavor. All others are
|
// The "github.com/lib/pq" driver is the default flavor. All others are
|
||||||
// translations of this.
|
// translations of this.
|
||||||
flavorPostgres = flavor{}
|
flavorPostgres = flavor{
|
||||||
|
// The default behavior for Postgres transactions is consistent reads, not consistent writes.
|
||||||
|
// For each transaction opened, ensure it has the correct isolation level.
|
||||||
|
//
|
||||||
|
// See: https://www.postgresql.org/docs/9.3/static/sql-set-transaction.html
|
||||||
|
//
|
||||||
|
// NOTE(ericchiang): For some reason using `SET SESSION CHARACTERISTICS AS TRANSACTION` at a
|
||||||
|
// session level didn't work for some edge cases. Might be something worth exploring.
|
||||||
|
executeTx: func(db *sql.DB, fn func(sqlTx *sql.Tx) error) error {
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
if _, err := tx.Exec(`SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := fn(tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tx.Commit()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
flavorSQLite3 = flavor{
|
flavorSQLite3 = flavor{
|
||||||
queryReplacers: []replacer{
|
queryReplacers: []replacer{
|
||||||
|
Reference in New Issue
Block a user