Skip to content

Commit

Permalink
Add tests parser
Browse files Browse the repository at this point in the history
  • Loading branch information
qbart committed Mar 5, 2023
1 parent a6b0dfe commit 053c3fe
Show file tree
Hide file tree
Showing 13 changed files with 402 additions and 355 deletions.
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
.PHONY: default build install test docker_test docker_build docker_push docker_nightly

default:
export DATABASE_URL="postgres://krab:secret@localhost:5432/krab?sslmode=disable"
export KRAB_ENV=test
export KRAB_DIR=./test/fixtures/tests
make build
./bin/krab test versions
ok
export DATABASE_URL="postgres://krab:secret@localhost:5432/krab?sslmode=disable" && \
export KRAB_ENV=test && \
export KRAB_DIR=./test/fixtures/tests && \
make build && \
./bin/krab test && \
echo "ok"

build:
mkdir -p bin/
Expand Down
13 changes: 4 additions & 9 deletions krab/cmd_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,9 @@ func (r *CmdRegistry) RegisterAll(config *Config, conn krabdb.Connection) {
}

if krabenv.Test() {
for _, suite := range config.TestSuites {
suite := suite

r.Register(&CmdTestRun{
Registry: r,
Suite: suite,
Connection: conn,
})
}
r.Register(&CmdTestRun{
Suite: config.TestSuite,
Connection: conn,
})
}
}
171 changes: 40 additions & 131 deletions krab/cmd_test_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net/http"
"strings"

"github.com/ohkrab/krab/krabdb"
"github.com/ohkrab/krab/krabhcl"
Expand All @@ -15,7 +14,6 @@ import (
type CmdTestRun struct {
Connection krabdb.Connection
Suite *TestSuite
Registry *CmdRegistry
}

// ResponseTestRun json
Expand All @@ -24,47 +22,47 @@ type ResponseTestRun struct {

func (c *CmdTestRun) Addr() krabhcl.Addr { return c.Suite.Addr() }

func (c *CmdTestRun) Name() []string { return append([]string{"test"}, c.Suite.Addr().Labels...) }
func (c *CmdTestRun) Name() []string { return []string{"test"} }

func (c *CmdTestRun) HttpMethod() string { return http.MethodPost }

func (c *CmdTestRun) Do(ctx context.Context, o CmdOpts) (interface{}, error) {
var result ResponseTestRun

for _, do := range c.Suite.Before.Dos {
for _, migrate := range do.Migrate {
addr, err := krabhcl.Expression{Expr: migrate.SetExpr}.Addr()
if err != nil {
return nil, fmt.Errorf("Failed to parse MigrationSet reference: %w", err)
}

for _, cmd := range c.Registry.Commands {
if addr.Equal(cmd.Addr()) {
if cmd.Name()[1] == migrate.Type {
inputs := InputsFromCtyInputs(do.CtyInputs)
migrateInputs := InputsFromCtyInputs(migrate.CtyInputs)
inputs.Merge(migrateInputs)
result, err := cmd.Do(ctx, CmdOpts{NamedInputs: inputs})
if err != nil {
return nil, fmt.Errorf("Failed to execute before hook: %w", err)
}
respUp, ok := result.([]ResponseMigrateUp)
if ok {
for _, migration := range respUp {
fmt.Println(ctc.ForegroundYellow, "UP ", migration.Success, migration.Version, migration.Name, ctc.Reset)
}
}
respDown, ok := result.([]ResponseMigrateDown)
if ok {
for _, migration := range respDown {
fmt.Println(ctc.ForegroundYellow, "DOWN", migration.Success, migration.Version, migration.Name, ctc.Reset)
}
}
}
}
}
}
}
// for _, do := range c.Suite.Before.Dos {
// for _, migrate := range do.Migrate {
// addr, err := krabhcl.Expression{Expr: migrate.SetExpr}.Addr()
// if err != nil {
// return nil, fmt.Errorf("Failed to parse MigrationSet reference: %w", err)
// }
//
// for _, cmd := range c.Registry.Commands {
// if addr.Equal(cmd.Addr()) {
// if cmd.Name()[1] == migrate.Type {
// inputs := InputsFromCtyInputs(do.CtyInputs)
// migrateInputs := InputsFromCtyInputs(migrate.CtyInputs)
// inputs.Merge(migrateInputs)
// result, err := cmd.Do(ctx, CmdOpts{NamedInputs: inputs})
// if err != nil {
// return nil, fmt.Errorf("Failed to execute before hook: %w", err)
// }
// respUp, ok := result.([]ResponseMigrateUp)
// if ok {
// for _, migration := range respUp {
// fmt.Println(ctc.ForegroundYellow, "UP ", migration.Success, migration.Version, migration.Name, ctc.Reset)
// }
// }
// respDown, ok := result.([]ResponseMigrateDown)
// if ok {
// for _, migration := range respDown {
// fmt.Println(ctc.ForegroundYellow, "DOWN", migration.Success, migration.Version, migration.Name, ctc.Reset)
// }
// }
// }
// }
// }
// }
// }

err := c.Connection.Get(func(db krabdb.DB) error {
resp, err := c.run(ctx, db, o.NamedInputs)
Expand All @@ -79,105 +77,16 @@ func (c *CmdTestRun) run(ctx context.Context, db krabdb.DB, inputs NamedInputs)
result := ResponseTestRun{}

for _, testCase := range c.Suite.Tests {
fmt.Println(ctc.ForegroundBlue, testCase.Name, ctc.Reset)
fmt.Printf("%s%s%s\n", ctc.ForegroundBlue, testCase.Name, ctc.Reset)
for _, it := range testCase.Xits {
fmt.Printf(" %sSKIP %s%s\n", ctc.ForegroundYellow, it.Name, ctc.Reset)
}
for _, it := range testCase.Its {
fmt.Println(" ", ctc.ForegroundBlue, it.Comment, ctc.Reset)

// apply SET parameters
if testCase.Set != nil {
sb := &strings.Builder{}
testCase.Set.ToSQL(sb)
_, err := db.ExecContext(ctx, sb.String())
if err != nil {
panic(fmt.Errorf("SET parameters not set: %w", err))
}
}

// execute `do` from `it` and collect results for further expectations
// fmt.Println(" ", it.Do.SQL)
queryResult := []map[string]interface{}{}
typeResult := map[string]string{}
rows, capturedErr := db.QueryContext(ctx, it.Do.SQL)
capturedErrConsumed := false

if capturedErr == nil {
defer rows.Close()

types, _ := rows.ColumnTypes()
for _, colType := range types {
typeResult[colType.Name()] = colType.DatabaseTypeName()
}
for rows.Next() {
row := map[string]interface{}{}
rows.MapScan(row)
queryResult = append(queryResult, row)
}
} else {
// if query errored we can populate result map for easier processing later
queryResult = append(queryResult, map[string]interface{}{
"error": capturedErr.Error(),
})
}

for _, asserts := range it.RowsAsserts {
for _, expect := range asserts.Expectations {
if expect.Subject == "error" {
capturedErrConsumed = true
fmt.Println(ctc.ForegroundGreen, *expect.Contains, ctc.ForegroundYellow, capturedErr.Error(), ctc.Reset)
}
if expect.Equal == nil {
fmt.Println(" ", ctc.ForegroundGreen, expect.Subject, "= null", ctc.Reset)
} else {
fmt.Println(" ", ctc.ForegroundGreen, expect.Subject, "=", *expect.Equal, ctc.Reset)
}
}
}

if !capturedErrConsumed && capturedErr != nil {
panic(fmt.Errorf("query `%s` failed to execute: %w", it.Do.SQL, capturedErr))
}

for _, rowAssert := range it.RowAsserts {
rowAssert.EachRow(func(i int64) {
query := &strings.Builder{}
query.WriteString("SELECT key, value FROM ( VALUES\n")

rowData := queryResult[i]
for i, expect := range rowAssert.Expectations {
value, ok := rowData[expect.Subject]
if i != 0 {
query.WriteString("\n,")
}
query.WriteString(fmt.Sprintf("(%s, %s)", krabdb.QuoteIdent(expect.Subject), krabdb.Quote(value)))
fmt.Println(value)
if !ok {
panic("Expectation defined for missing column")
}

color := ctc.ForegroundGreen
success := makeAssertion(expect, value)
if !success {
color = ctc.ForegroundRed
}
fmt.Println(" ", color, expect.Subject, value, *expect.Equal, ctc.Reset)
}
query.WriteString("\n) AS t(key, value)")
fmt.Println(" ", ctc.ForegroundGreen, query.String(), ctc.Reset)
})
}
fmt.Printf(" %s%s%s\n", ctc.ForegroundRed, it.Name, ctc.Reset)
}
}

// _, err := db.ExecContext(ctx, sql)

return result, nil
}

func makeAssertion(expect *Expect, value interface{}) bool {
if expect.Equal == nil {
return value == nil
}
// fmt.Printf("// expect: %T, value: %T\n", *expect.Equal, value)

return *expect.Equal == value
}
41 changes: 5 additions & 36 deletions krab/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import (
)

// Config represents all configuration loaded from directory.
//
type Config struct {
MigrationSets map[string]*MigrationSet
Migrations map[string]*Migration
Actions map[string]*Action
Wasms map[string]*WebAssembly
TestSuites map[string]*TestSuite
TestSuite *TestSuite
TestExamples map[string]*TestExample
}

Expand All @@ -22,8 +20,7 @@ func NewConfig(files []*File) (*Config, error) {
MigrationSets: map[string]*MigrationSet{},
Migrations: map[string]*Migration{},
Actions: map[string]*Action{},
Wasms: map[string]*WebAssembly{},
TestSuites: map[string]*TestSuite{},
TestSuite: &TestSuite{},
TestExamples: map[string]*TestExample{},
}

Expand Down Expand Up @@ -64,24 +61,12 @@ func NewConfig(files []*File) (*Config, error) {
}
}

for _, validatable := range c.TestSuites {
if err := validatable.Validate(); err != nil {
return nil, err
}
}

for _, validatable := range c.TestExamples {
if err := validatable.Validate(); err != nil {
return nil, err
}
}

for _, validatable := range c.Wasms {
if err := validatable.Validate(); err != nil {
return nil, err
}
}

return c, nil
}

Expand Down Expand Up @@ -110,30 +95,14 @@ func (c *Config) appendFile(file *File) error {
c.Actions[a.Addr().OnlyRefNames()] = a
}

for _, t := range file.TestSuites {
if _, found := c.TestSuites[t.Addr().OnlyRefNames()]; found {
return fmt.Errorf("TestSuite with the name '%s' already exists", t.Addr().OnlyRefNames())
}

c.TestSuites[t.Addr().OnlyRefNames()] = t
}
c.TestSuite = file.TestSuite
c.TestSuite.Tests = []*TestExample{}

for _, t := range file.TestExamples {
if _, found := c.TestExamples[t.Addr().OnlyRefNames()]; found {
return fmt.Errorf("Test with the name '%s' already exists", t.Addr().OnlyRefNames())
}

c.TestExamples[t.Addr().OnlyRefNames()] = t
suite, ok := c.TestSuites[t.Addr().Labels[0]] // first label is a test suite reference
if ok {
if suite.Tests == nil {
suite.Tests = []*TestExample{}
}

suite.Tests = append(suite.Tests, t)
} else {
return fmt.Errorf("Test suite '%s' is missing", suite.RefName)
}
c.TestSuite.Tests = append(c.TestSuite.Tests, t)
}

return nil
Expand Down
18 changes: 14 additions & 4 deletions krab/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ type File struct {
Migrations []*Migration
MigrationSets []*MigrationSet
Actions []*Action
TestSuites []*TestSuite
TestSuite *TestSuite
TestExamples []*TestExample
Wasms []*WebAssembly
}

var schemaFile = &hcl.BodySchema{
Expand All @@ -32,6 +31,10 @@ var schemaFile = &hcl.BodySchema{
Type: "action",
LabelNames: []string{"namespace", "name"},
},
{
Type: "test",
LabelNames: []string{"name"},
},
},
Attributes: []hcl.AttributeSchema{},
}
Expand All @@ -41,9 +44,8 @@ func (f *File) Decode(ctx *hcl.EvalContext) error {
f.Migrations = []*Migration{}
f.MigrationSets = []*MigrationSet{}
f.Actions = []*Action{}
f.TestSuites = []*TestSuite{}
f.TestSuite = &TestSuite{}
f.TestExamples = []*TestExample{}
f.Wasms = []*WebAssembly{}

content, diags := f.File.Body.Content(schemaFile)
if diags.HasErrors() {
Expand Down Expand Up @@ -76,6 +78,14 @@ func (f *File) Decode(ctx *hcl.EvalContext) error {
}
f.Actions = append(f.Actions, action)

case "test":
test := new(TestExample)
err := test.DecodeHCL(ctx, b)
if err != nil {
return err
}
f.TestExamples = append(f.TestExamples, test)

default:
return fmt.Errorf("Unknown block `%s`", b.Type)
}
Expand Down
Loading

0 comments on commit 053c3fe

Please sign in to comment.