-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pull example XML into an autmated test
- Loading branch information
1 parent
25b7121
commit 2998703
Showing
4 changed files
with
263 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package pgsql8 | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/dbsteward/dbsteward/lib/ir" | ||
"github.com/jackc/pgconn" | ||
"github.com/jackc/pgx/v4" | ||
) | ||
|
||
func Initdb(t *testing.T, dbSuffix string) *pgx.Conn { | ||
if os.Getenv("DB_NAME") == "" { | ||
return nil | ||
} | ||
conn, err := pgx.Connect(context.TODO(), adminDSNFromEnv()) | ||
if err != nil { | ||
t.Fatal(err) | ||
return nil | ||
} | ||
defer conn.Close(context.TODO()) | ||
_, err = conn.Exec(context.TODO(), fmt.Sprintf("DROP DATABASE IF EXISTS %s", os.Getenv("DB_NAME")+dbSuffix)) | ||
if err != nil { | ||
t.Fatal(err) | ||
return nil | ||
} | ||
_, err = conn.Exec(context.TODO(), fmt.Sprintf("CREATE DATABASE %s", os.Getenv("DB_NAME")+dbSuffix)) | ||
if err != nil { | ||
t.Fatal(err) | ||
return nil | ||
} | ||
err = CreateRoleIfNotExists(conn, ir.AdditionalRole) | ||
if err != nil { | ||
t.Fatal(err) | ||
return nil | ||
} | ||
err = conn.Close(context.TODO()) | ||
if err != nil { | ||
t.Fatal(err) | ||
return nil | ||
} | ||
conn, err = pgx.Connect(context.TODO(), userDSNFromEnv(dbSuffix)) | ||
if err != nil { | ||
t.Fatal(err) | ||
return nil | ||
} | ||
return conn | ||
} | ||
|
||
func CreateRoleIfNotExists(conn *pgx.Conn, name string) error { | ||
_, err := conn.Exec(context.TODO(), fmt.Sprintf("CREATE ROLE %s", name)) | ||
if err != nil { | ||
code := (err.(*pgconn.PgError)).Code | ||
if code != "42710" && code != "23505" { // Role exists | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func Teardowndb(t *testing.T, c *pgx.Conn, dbSuffix string) { | ||
err := c.Close(context.TODO()) | ||
if err != nil { | ||
t.Fatal(err) | ||
return | ||
} | ||
conn, err := pgx.Connect(context.TODO(), adminDSNFromEnv()) | ||
if err != nil { | ||
t.Fatal(err) | ||
return | ||
} | ||
defer conn.Close(context.TODO()) | ||
_, err = conn.Exec(context.TODO(), fmt.Sprintf("DROP DATABASE IF EXISTS %s", os.Getenv("DB_NAME")+dbSuffix)) | ||
if err != nil { | ||
t.Log(err) | ||
} | ||
_, err = conn.Exec(context.TODO(), fmt.Sprintf("DROP ROLE IF EXISTS %s", ir.AdditionalRole)) | ||
if err != nil { | ||
t.Log(err) | ||
} | ||
} | ||
|
||
func adminDSNFromEnv() string { | ||
host := os.Getenv("DB_HOST") | ||
user := os.Getenv("DB_SUPERUSER") | ||
password := os.Getenv("DB_PASSWORD") | ||
dbName := "postgres" | ||
port := os.Getenv("DB_PORT") | ||
return fmt.Sprintf( | ||
"host=%s user=%s password=%s dbname=%s port=%s", | ||
host, | ||
user, | ||
password, | ||
dbName, | ||
port, | ||
) | ||
} | ||
|
||
func userDSNFromEnv(suffix string) string { | ||
host := os.Getenv("DB_HOST") | ||
user := os.Getenv("DB_USER") | ||
password := os.Getenv("DB_PASSWORD") | ||
dbName := os.Getenv("DB_NAME") + suffix | ||
port := os.Getenv("DB_PORT") | ||
cs := fmt.Sprintf( | ||
"host=%s user=%s password=%s dbname=%s port=%s", | ||
host, | ||
user, | ||
password, | ||
dbName, | ||
port, | ||
) | ||
return cs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"log/slog" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/dbsteward/dbsteward/lib" | ||
"github.com/dbsteward/dbsteward/lib/encoding/xml" | ||
"github.com/dbsteward/dbsteward/lib/format" | ||
"github.com/dbsteward/dbsteward/lib/format/pgsql8" | ||
"github.com/dbsteward/dbsteward/lib/ir" | ||
) | ||
|
||
//go:embed example/someapp_v1.xml | ||
var v1 string | ||
|
||
//go:embed example/someapp_v2.xml | ||
var v2 string | ||
|
||
// To run: | ||
// DB_HOST=localhost DB_USER=postgres DB_SUPERUSER=postgres DB_NAME=test DB_PORT=5432 go test ./... | ||
|
||
// This test uses the definitions in the examples table to | ||
// create a database and then create a set of upgrade commands | ||
// and ensure those commands work. It is limited: see the comments | ||
// at the end of the test for explanation. | ||
func TestXMLPostgresIngegration(t *testing.T) { | ||
c := pgsql8.Initdb(t, "tl") | ||
if c == nil { | ||
t.SkipNow() | ||
} | ||
defer pgsql8.Teardowndb(t, c, "tl") | ||
def1, err := xml.ReadDef(strings.NewReader(v1)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
lib.GlobalDBSteward = lib.NewDBSteward(format.LookupMap{ | ||
ir.SqlFormatPgsql8: pgsql8.GlobalLookup, | ||
}) | ||
lib.GlobalDBSteward.SqlFormat = ir.SqlFormatPgsql8 | ||
err = pgsql8.CreateRoleIfNotExists(c, def1.Database.Roles.Application) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
err = pgsql8.CreateRoleIfNotExists(c, def1.Database.Roles.Owner) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
err = pgsql8.CreateRoleIfNotExists(c, def1.Database.Roles.ReadOnly) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
err = pgsql8.CreateRoleIfNotExists(c, def1.Database.Roles.Replication) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
ops := pgsql8.NewOperations().(*pgsql8.Operations) | ||
statements, err := ops.CreateStatements(*def1) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
tx, err := c.Begin(context.TODO()) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer tx.Rollback(context.TODO()) | ||
for _, s := range statements { | ||
t.Log(s.Statement) | ||
_, err = tx.Exec(context.TODO(), s.Statement) | ||
if err != nil { | ||
t.Fatal(err.Error()) | ||
} | ||
} | ||
err = tx.Commit(context.TODO()) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
def2, err := xml.ReadDef(strings.NewReader(v2)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
ops = pgsql8.NewOperations().(*pgsql8.Operations) | ||
statements, err = ops.Upgrade(slog.Default(), def1, def2) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
tx, err = c.Begin(context.TODO()) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer tx.Rollback(context.TODO()) | ||
for _, s := range statements { | ||
t.Log(s.Statement) | ||
_, err = tx.Exec(context.TODO(), s.Statement) | ||
if err != nil { | ||
t.Fatal(err.Error()) | ||
} | ||
} | ||
err = tx.Commit(context.TODO()) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
ops = pgsql8.NewOperations().(*pgsql8.Operations) | ||
_, err = ops.ExtractSchemaConn(context.TODO(), c) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
// It's impractical to verify that the extraction is | ||
// correct without massively rewriting the XML. Due to | ||
// differences in object ordering and other things that | ||
// produce unequal but functionally equivalent code. | ||
// It's probably best to do that level of precision | ||
// testing at a more unit level. | ||
} |