Skip to content

Commit

Permalink
A unit test that uses the XML files in the examples directory
Browse files Browse the repository at this point in the history
  • Loading branch information
williammoran committed May 7, 2024
1 parent 25b7121 commit 0493b65
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 100 deletions.
102 changes: 2 additions & 100 deletions lib/format/pgsql8/oneeighty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ package pgsql8

import (
"context"
"fmt"
"os"
"testing"

"github.com/dbsteward/dbsteward/lib"
"github.com/dbsteward/dbsteward/lib/format"
"github.com/dbsteward/dbsteward/lib/ir"
"github.com/jackc/pgconn"
"github.com/jackc/pgx/v4"
"github.com/stretchr/testify/assert"
)

Expand All @@ -26,11 +23,11 @@ import (
// * Data types are not normalized nor standardized nor anything like that

func TestOneEighty(t *testing.T) {
c := initdb(t)
c := Initdb(t)
if c == nil {
t.SkipNow()
}
defer teardowndb(t, c)
defer Teardowndb(t, c)
role := os.Getenv("DB_USER")
lib.GlobalDBSteward = lib.NewDBSteward(format.LookupMap{
ir.SqlFormatPgsql8: GlobalLookup,
Expand Down Expand Up @@ -63,98 +60,3 @@ func TestOneEighty(t *testing.T) {
}
assert.Equal(t, ir.FullFeatureSchema(role), *reflection, "reflection does not match original")
}

func initdb(t *testing.T) *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")))
if err != nil {
t.Fatal(err)
return nil
}
_, err = conn.Exec(context.TODO(), fmt.Sprintf("CREATE DATABASE %s", os.Getenv("DB_NAME")))
if err != nil {
t.Fatal(err)
return nil
}
_, err = conn.Exec(context.TODO(), fmt.Sprintf("CREATE ROLE %s", ir.AdditionalRole))
if err != nil {
if (err.(*pgconn.PgError)).Code != "42710" { // Role exists
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())
if err != nil {
t.Fatal(err)
return nil
}
return conn
}

func teardowndb(t *testing.T, c *pgx.Conn) {
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")))
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() string {
host := os.Getenv("DB_HOST")
user := os.Getenv("DB_USER")
password := os.Getenv("DB_PASSWORD")
dbName := os.Getenv("DB_NAME")
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
}
28 changes: 28 additions & 0 deletions lib/format/pgsql8/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,34 @@ func (ops *Operations) BuildUpgrade(
return nil
}

func (ops *Operations) Upgrade(l *slog.Logger, oldDoc *ir.Definition, newDoc *ir.Definition) ([]output.DDLStatement, error) {
var err error
ops.differ.OldTableDependency, err = oldDoc.TableDependencyOrder()
if err != nil {
return nil, fmt.Errorf("old document: %w", err)
}
ops.differ.NewTableDependency, err = newDoc.TableDependencyOrder()
if err != nil {
return nil, fmt.Errorf("new document: %w", err)
}
lib.GlobalDBSteward.OldDatabase = oldDoc
lib.GlobalDBSteward.NewDatabase = newDoc

stage1 := output.NewSegmenter(ops.GetQuoter())
stage2 := output.NewSegmenter(ops.GetQuoter())
stage3 := output.NewSegmenter(ops.GetQuoter())
stage4 := output.NewSegmenter(ops.GetQuoter())
err = ops.differ.DiffDocWork(stage1, stage2, stage3, stage4)
if err != nil {
return nil, err
}
stmts := stage1.AllStatements()
stmts = append(stmts, stage2.AllStatements()...)
stmts = append(stmts, stage3.AllStatements()...)
stmts = append(stmts, stage4.AllStatements()...)
return stmts, nil
}

func (ops *Operations) ExtractSchemaConn(ctx context.Context, c *pgx.Conn) (*ir.Definition, error) {
conn := &liveConnection{c}
return ops.extractSchema(ctx, conn)
Expand Down
107 changes: 107 additions & 0 deletions lib/format/pgsql8/testutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
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) *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")))
if err != nil {
t.Fatal(err)
return nil
}
_, err = conn.Exec(context.TODO(), fmt.Sprintf("CREATE DATABASE %s", os.Getenv("DB_NAME")))
if err != nil {
t.Fatal(err)
return nil
}
_, err = conn.Exec(context.TODO(), fmt.Sprintf("CREATE ROLE %s", ir.AdditionalRole))
if err != nil {
if (err.(*pgconn.PgError)).Code != "42710" { // Role exists
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())
if err != nil {
t.Fatal(err)
return nil
}
return conn
}

func Teardowndb(t *testing.T, c *pgx.Conn) {
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")))
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() string {
host := os.Getenv("DB_HOST")
user := os.Getenv("DB_USER")
password := os.Getenv("DB_PASSWORD")
dbName := os.Getenv("DB_NAME")
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
}
102 changes: 102 additions & 0 deletions xmlpostgresintegration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
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)
if c == nil {
t.SkipNow()
}
defer pgsql8.Teardowndb(t, c)
//role := os.Getenv("DB_USER")
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
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.
}

0 comments on commit 0493b65

Please sign in to comment.