cli: update tests (#47)

* remove docker from migrate cmd test

* export migration status

* [cli] add fake writer for spinner

* Update console.go

* Update migrate_test.go
This commit is contained in:
Aravind Shankar
2018-07-06 10:36:27 +05:30
committed by Shahidh K Muhammed
parent 2cab15ede4
commit 1998e211af
12 changed files with 198 additions and 90 deletions

View File

@@ -8,8 +8,11 @@ import (
"testing"
"time"
"github.com/briandowns/spinner"
"github.com/hasura/graphql-engine/cli"
"github.com/hasura/graphql-engine/cli/commands"
"github.com/hasura/graphql-engine/cli/util/fake"
"github.com/sirupsen/logrus/hooks/test"
"github.com/spf13/viper"
)
@@ -18,7 +21,12 @@ func init() {
}
func TestPrepare(t *testing.T) {
ec := &cli.ExecutionContext{}
logger, _ := test.NewNullLogger()
ec := &cli.ExecutionContext{
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
}
ec.Spinner.Writer = &fake.FakeWriter{}
err := ec.Prepare()
if err != nil {
t.Fatalf("prepare failed: %v", err)
@@ -44,7 +52,12 @@ func TestPrepare(t *testing.T) {
}
func TestValidate(t *testing.T) {
ec := &cli.ExecutionContext{}
logger, _ := test.NewNullLogger()
ec := &cli.ExecutionContext{
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
}
ec.Spinner.Writer = &fake.FakeWriter{}
ec.ExecutionDirectory = filepath.Join(os.TempDir(), "hasura-gql-tests-"+strconv.Itoa(rand.Intn(1000)))
ec.Viper = viper.New()

View File

@@ -93,6 +93,9 @@ func (o *consoleOptions) run() error {
router.setRoutes(u.Host, o.EC.Config.AccessKey, o.EC.MigrationDir)
if o.EC.Version == nil {
return errors.New("cannot validate version, object is nil")
}
consoleTemplateVersion := o.EC.Version.GetConsoleTemplateVersion()
consoleAssetsVersion := o.EC.Version.GetConsoleAssetsVersion()
@@ -218,7 +221,7 @@ func serveConsole(assetsVersion string, opts gin.H) (*gin.Engine, error) {
// An Engine instance with the Logger and Recovery middleware already attached.
r := gin.New()
// Template index.html
// Template console.html
templateRender, err := util.LoadTemplates("assets/"+assetsVersion+"/", "console.html")
if err != nil {
return nil, errors.Wrap(err, "cannot fetch template")

View File

@@ -6,6 +6,8 @@ import (
"github.com/briandowns/spinner"
"github.com/hasura/graphql-engine/cli"
"github.com/hasura/graphql-engine/cli/util/fake"
"github.com/hasura/graphql-engine/cli/version"
"github.com/sirupsen/logrus/hooks/test"
)
@@ -19,12 +21,14 @@ func TestConsoleCmd(t *testing.T) {
Endpoint: "http://localhost:8080",
AccessKey: "",
},
Version: version.New(),
},
APIPort: "9693",
ConsolePort: "9695",
Address: "localhost",
DontOpenBrowser: true,
}
opts.EC.Spinner.Writer = &fake.FakeWriter{}
go func() {
t.Log("waiting for console to start")

View File

@@ -8,7 +8,9 @@ import (
"testing"
"time"
"github.com/briandowns/spinner"
"github.com/hasura/graphql-engine/cli"
"github.com/hasura/graphql-engine/cli/util/fake"
"github.com/sirupsen/logrus/hooks/test"
)
@@ -25,7 +27,8 @@ func TestInitCmd(t *testing.T) {
}{
{"only-init-dir", &initOptions{
EC: &cli.ExecutionContext{
Logger: logger,
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
},
Endpoint: "",
AccessKey: "",
@@ -33,7 +36,8 @@ func TestInitCmd(t *testing.T) {
}, nil},
{"with-endpoint-flag", &initOptions{
EC: &cli.ExecutionContext{
Logger: logger,
Logger: logger,
Spinner: spinner.New(spinner.CharSets[7], 100*time.Millisecond),
},
Endpoint: "https://localhost:8080",
AccessKey: "",
@@ -43,6 +47,7 @@ func TestInitCmd(t *testing.T) {
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
tc.opts.EC.Spinner.Writer = &fake.FakeWriter{}
err := tc.opts.EC.Prepare()
if err != nil {
t.Fatalf("%s: prep failed: %v", tc.name, err)

View File

@@ -1,9 +1,13 @@
package commands
import (
"bytes"
"fmt"
"net/url"
"text/tabwriter"
"github.com/hasura/graphql-engine/cli"
"github.com/hasura/graphql-engine/cli/migrate"
"github.com/hasura/graphql-engine/cli/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -18,7 +22,12 @@ func newMigrateStatusCmd(ec *cli.ExecutionContext) *cobra.Command {
Short: "Display current status of migrations on a database",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
return opts.run()
status, err := opts.run()
if err != nil {
return err
}
printStatus(status)
return nil
},
}
@@ -29,18 +38,44 @@ type migrateStatusOptions struct {
EC *cli.ExecutionContext
}
func (o *migrateStatusOptions) run() error {
func (o *migrateStatusOptions) run() (*migrate.Status, error) {
dbURL, err := url.Parse(o.EC.Config.Endpoint)
if err != nil {
return errors.Wrap(err, "error parsing Endpoint")
return nil, errors.Wrap(err, "error parsing Endpoint")
}
dbURL.Scheme = "hasuradb"
dbURL.User = url.UserPassword("admin", o.EC.Config.AccessKey)
status, err := util.ExecuteStatus("file://"+o.EC.MigrationDir, dbURL.String())
if err != nil {
return errors.Wrap(err, "cannot fetch migrate status")
return nil, errors.Wrap(err, "cannot fetch migrate status")
}
o.EC.Logger.Println(status)
return nil
return status, nil
}
func printStatus(status *migrate.Status) {
out := new(tabwriter.Writer)
buf := &bytes.Buffer{}
out.Init(buf, 0, 8, 2, ' ', 0)
w := util.NewPrefixWriter(out)
w.Write(util.LEVEL_0, "VERSION\tSOURCE STATUS\tDATABASE STATUS\n")
for _, version := range status.Index {
w.Write(util.LEVEL_0, "%d\t%s\t%s\n",
version,
convertBool(status.Migrations[version].IsPresent),
convertBool(status.Migrations[version].IsApplied),
)
}
out.Flush()
fmt.Println(buf.String())
}
func convertBool(ok bool) string {
switch ok {
case true:
return "Present"
case false:
return "Not Present"
}
return ""
}

View File

@@ -10,12 +10,13 @@ import (
"github.com/briandowns/spinner"
"github.com/hasura/graphql-engine/cli"
"github.com/hasura/graphql-engine/cli/migrate"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
)
func testMigrateStatus(t *testing.T, endpoint string, migrationsDir string, expectedStatus string) {
logger, hook := test.NewNullLogger()
func testMigrateStatus(t *testing.T, endpoint string, migrationsDir string, expectedStatus *migrate.Status) {
logger, _ := test.NewNullLogger()
opts := &migrateStatusOptions{
EC: &cli.ExecutionContext{
Logger: logger,
@@ -28,11 +29,11 @@ func testMigrateStatus(t *testing.T, endpoint string, migrationsDir string, expe
},
}
err := opts.run()
status, err := opts.run()
if err != nil {
t.Fatalf("failed fetching migration status: %v", err)
}
assert.Equal(t, expectedStatus, hook.LastEntry().Message)
assert.Equal(t, expectedStatus, status)
}
func TestMigrateStatusWithInvalidEndpoint(t *testing.T) {
@@ -49,7 +50,7 @@ func TestMigrateStatusWithInvalidEndpoint(t *testing.T) {
},
}
err := opts.run()
_, err := opts.run()
if err == nil {
t.Fatalf("expected err not to be nil")
}

View File

@@ -11,6 +11,7 @@ import (
"path/filepath"
"testing"
"github.com/hasura/graphql-engine/cli/migrate"
mt "github.com/hasura/graphql-engine/cli/migrate/testing"
_ "github.com/lib/pq"
"github.com/parnurzeal/gorequest"
@@ -69,7 +70,7 @@ func isReadyRaven(i mt.Instance) bool {
return false
}
func TestMigrateCmd(t *testing.T) {
func testMigrateWithDocker(t *testing.T, migrationsDir, executionDir string) {
mt.ParallelTest(t, postgresVersions, isReadyPostgres,
func(t *testing.T, pi mt.Instance) {
for i, v := range ravenVersions {
@@ -80,7 +81,7 @@ func TestMigrateCmd(t *testing.T) {
defer pi.Remove()
defer ri.Remove()
endpoint := fmt.Sprintf("http://%s:%d", ri.Host(), ri.Port())
endpointURL := fmt.Sprintf("http://%s:%d", ri.Host(), ri.Port())
// Create migration Dir
migrationsDir, err := ioutil.TempDir("", "")
if err != nil {
@@ -94,59 +95,126 @@ func TestMigrateCmd(t *testing.T) {
}
defer os.RemoveAll(executionDir)
// Create 1_create_table_test.up.sql which creates table test
mustWriteFile(t, migrationsDir, "1_create_table_test.up.sql", `CREATE TABLE "test"("id" serial NOT NULL, PRIMARY KEY ("id") )`)
// Create 1_create_table_test.down.sql which creates table test
mustWriteFile(t, migrationsDir, "1_create_table_test.down.sql", `DROP TABLE "test";`)
// Create 2_add_table_test.up.yaml which adds table test to metadata
mustWriteFile(t, migrationsDir, "2_add_table_test.up.yaml", `- args:
testMigrate(t, endpointURL, migrationsDir, executionDir)
})
})
}
func TestMigrateCmd(t *testing.T) {
endpointURL := os.Getenv("HASURA_GRAPHQL_TEST_ENDPOINT")
// Create migration Dir
migrationsDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(migrationsDir)
// Create Execution Dir
executionDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(executionDir)
testMigrate(t, endpointURL, migrationsDir, executionDir)
}
func testMigrate(t *testing.T, endpoint, migrationsDir, executionDir string) {
// Create 1_create_table_test.up.sql which creates table test
mustWriteFile(t, migrationsDir, "1_create_table_test.up.sql", `CREATE TABLE "test"("id" serial NOT NULL, PRIMARY KEY ("id") )`)
// Create 1_create_table_test.down.sql which creates table test
mustWriteFile(t, migrationsDir, "1_create_table_test.down.sql", `DROP TABLE "test";`)
// Create 2_add_table_test.up.yaml which adds table test to metadata
mustWriteFile(t, migrationsDir, "2_add_table_test.up.yaml", `- args:
name: test
type: add_existing_table_or_view
`)
mustWriteFile(t, migrationsDir, "2_add_table_test.down.yaml", `- args:
mustWriteFile(t, migrationsDir, "2_add_table_test.down.yaml", `- args:
table: test
type: untrack_table
`)
// Apply 1_create_table_test.up.sql
testMigrateApply(t, endpoint, migrationsDir, "1", "", "", "")
// Apply 1_create_table_test.up.sql
testMigrateApply(t, endpoint, migrationsDir, "1", "", "", "")
// Check Migration status
testMigrateStatus(t, endpoint, migrationsDir, "VERSION SOURCE STATUS DATABASE STATUS\n1 Present Present\n2 Present Not Present\n")
// Check Migration status
expectedStatus := migrate.NewStatus()
expectedStatus.Append(&migrate.MigrationStatus{
Version: 1,
IsApplied: true,
IsPresent: true,
})
expectedStatus.Append(&migrate.MigrationStatus{
Version: 2,
IsApplied: false,
IsPresent: true,
})
testMigrateStatus(t, endpoint, migrationsDir, expectedStatus)
// Apply 2_add_table_test.up.yaml
testMigrateApply(t, endpoint, migrationsDir, "", "", "2", "")
// Apply 2_add_table_test.up.yaml
testMigrateApply(t, endpoint, migrationsDir, "", "", "2", "")
// Check Migration status
testMigrateStatus(t, endpoint, migrationsDir, "VERSION SOURCE STATUS DATABASE STATUS\n1 Present Present\n2 Present Present\n")
// Check Migration status
expectedStatus = migrate.NewStatus()
expectedStatus.Append(&migrate.MigrationStatus{
Version: 1,
IsApplied: true,
IsPresent: true,
})
expectedStatus.Append(&migrate.MigrationStatus{
Version: 2,
IsApplied: true,
IsPresent: true,
})
testMigrateStatus(t, endpoint, migrationsDir, expectedStatus)
// Apply 2_add_table_test.down.yaml
testMigrateApply(t, endpoint, migrationsDir, "", "1", "", "")
// Apply 2_add_table_test.down.yaml
testMigrateApply(t, endpoint, migrationsDir, "", "1", "", "")
// Check Migration status
testMigrateStatus(t, endpoint, migrationsDir, "VERSION SOURCE STATUS DATABASE STATUS\n1 Present Present\n2 Present Not Present\n")
// Check Migration status
expectedStatus = migrate.NewStatus()
expectedStatus.Append(&migrate.MigrationStatus{
Version: 1,
IsApplied: true,
IsPresent: true,
})
expectedStatus.Append(&migrate.MigrationStatus{
Version: 2,
IsApplied: false,
IsPresent: true,
})
testMigrateStatus(t, endpoint, migrationsDir, expectedStatus)
// Apply 1_create_table_test.down.sql
testMigrateApply(t, endpoint, migrationsDir, "", "", "1", "down")
// Apply 1_create_table_test.down.sql
testMigrateApply(t, endpoint, migrationsDir, "", "", "1", "down")
// Check Migration status
testMigrateStatus(t, endpoint, migrationsDir, "VERSION SOURCE STATUS DATABASE STATUS\n1 Present Not Present\n2 Present Not Present\n")
// Check Migration status
expectedStatus = migrate.NewStatus()
expectedStatus.Append(&migrate.MigrationStatus{
Version: 1,
IsApplied: false,
IsPresent: true,
})
expectedStatus.Append(&migrate.MigrationStatus{
Version: 2,
IsApplied: false,
IsPresent: true,
})
testMigrateStatus(t, endpoint, migrationsDir, expectedStatus)
// Apply both 1 and 2
testMigrateApply(t, endpoint, migrationsDir, "", "", "", "")
// Apply both 1 and 2
testMigrateApply(t, endpoint, migrationsDir, "", "", "", "")
testMetadataExport(t, executionDir, endpoint)
compareMetadata(t, executionDir, testMetadata["metadata"])
testMetadataExport(t, executionDir, endpoint)
compareMetadata(t, executionDir, testMetadata["metadata"])
testMetadataApply(t, executionDir, endpoint)
testMetadataExport(t, executionDir, endpoint)
compareMetadata(t, executionDir, testMetadata["metadata"])
testMetadataApply(t, executionDir, endpoint)
testMetadataExport(t, executionDir, endpoint)
compareMetadata(t, executionDir, testMetadata["metadata"])
testMetadataReset(t, executionDir, endpoint)
testMetadataExport(t, executionDir, endpoint)
compareMetadata(t, executionDir, testMetadata["empty-metadata"])
})
})
testMetadataReset(t, executionDir, endpoint)
testMetadataExport(t, executionDir, endpoint)
compareMetadata(t, executionDir, testMetadata["empty-metadata"])
}
func mustWriteFile(t testing.TB, dir, file string, body string) {

View File

@@ -125,7 +125,7 @@ func New(sourceUrl string, databaseUrl string, cmd bool) (*Migrate, error) {
}
m.databaseDrv = databaseDrv
m.status = NewMigrations()
m.status = NewStatus()
return m, nil
}
@@ -174,7 +174,7 @@ func (m *Migrate) Close() (source error) {
}
func (m *Migrate) calculateStatus() (err error) {
m.status = NewMigrations()
m.status = NewStatus()
err = m.readStatusFromSource()
if err != nil {
return err

View File

@@ -1,9 +1,7 @@
package migrate
import (
"bytes"
"sort"
"text/tabwriter"
)
type MigrationStatus struct {
@@ -22,7 +20,7 @@ type Status struct {
Migrations map[uint64]*MigrationStatus
}
func NewMigrations() *Status {
func NewStatus() *Status {
return &Status{
Index: make(uint64Slice, 0),
Migrations: make(map[uint64]*MigrationStatus),
@@ -70,33 +68,6 @@ func (i *Status) findPos(version uint64) int {
return -1
}
func (i *Status) String() string {
out := new(tabwriter.Writer)
buf := &bytes.Buffer{}
out.Init(buf, 0, 8, 2, ' ', 0)
w := NewPrefixWriter(out)
w.Write(LEVEL_0, "VERSION\tSOURCE STATUS\tDATABASE STATUS\n")
for _, version := range i.Index {
w.Write(LEVEL_0, "%d\t%s\t%s\n",
version,
convertBool(i.Migrations[version].IsPresent),
convertBool(i.Migrations[version].IsApplied),
)
}
out.Flush()
return string(buf.String())
}
func convertBool(ok bool) string {
switch ok {
case true:
return "Present"
case false:
return "Not Present"
}
return ""
}
type uint64Slice []uint64
func (s uint64Slice) Len() int {

8
cli/util/fake/writer.go Normal file
View File

@@ -0,0 +1,8 @@
package fake
type FakeWriter struct {
}
func (fw *FakeWriter) Write(p []byte) (n int, err error) {
return 0, nil
}

View File

@@ -108,17 +108,17 @@ func ExecuteMetadata(cmd, dir, db, metadata string) error {
return nil
}
func ExecuteStatus(dir, db string) (string, error) {
func ExecuteStatus(dir, db string) (*migrate.Status, error) {
var err error
t, err := migrate.New(dir, db, true)
if err != nil {
return "", errors.Wrap(err, "cannot create migrate instance")
return nil, errors.Wrap(err, "cannot create migrate instance")
}
status, err := t.GetStatus()
if err != nil {
return "", err
return nil, err
}
return status.String(), nil
return status, nil
}

View File

@@ -1,4 +1,4 @@
package migrate
package util
import (
"fmt"