graphql-engine/cli/commands/migrate_apply_test.go
Kali Vara Purushotham Santhati f0bef2b482 cli: add All option for migrate sub-commands (apply, delete and status) and seed apply command
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/2509
Co-authored-by: Aravind K P <8335904+scriptonist@users.noreply.github.com>
GitOrigin-RevId: 03ee878072b58c6dc7f43af9d26d30a5594d9a50
2021-12-23 15:59:56 +00:00

388 lines
13 KiB
Go

package commands
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/Pallinder/go-randomdata"
"github.com/hasura/graphql-engine/cli/v2/internal/testutil"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gbytes"
. "github.com/onsi/gomega/gexec"
)
func AddDatabaseToHasura(hgeEndpoint, sourceName, databaseKind string) (string, func()) {
if databaseKind == "postgres" {
connectionStringPG, teardownPG := testutil.StartPGContainer(GinkgoT())
testutil.AddPGSourceToHasura(GinkgoT(), hgeEndpoint, connectionStringPG, sourceName)
return connectionStringPG, teardownPG
}
if databaseKind == "citus" {
connectionStringCitus, teardownCitus := testutil.StartCitusContainer(GinkgoT())
testutil.AddCitusSourceToHasura(GinkgoT(), hgeEndpoint, connectionStringCitus, sourceName)
return connectionStringCitus, teardownCitus
}
if databaseKind == "mssql" {
mssqlPort, teardownMSSQL := testutil.StartMSSQLContainer(GinkgoT())
connectionStringMSSQL := fmt.Sprintf("DRIVER={ODBC Driver 17 for SQL Server};SERVER=%s,%s;DATABASE=master;Uid=SA;Pwd=%s;Encrypt=no", testutil.DockerSwitchIP, mssqlPort, testutil.MSSQLPassword)
testutil.AddMSSQLSourceToHasura(GinkgoT(), hgeEndpoint, connectionStringMSSQL, sourceName)
return connectionStringMSSQL, teardownMSSQL
}
return "", nil
}
var testMigrateApply = func(projectDirectory string, globalFlags []string) {
Context("migrate apply", func() {
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: append(
[]string{"migrate", "create", "schema_creation", "--up-sql", "create schema \"testing\";", "--down-sql", "drop schema \"testing\" cascade;"},
globalFlags...,
),
WorkingDirectory: projectDirectory,
})
session := testutil.Hasura(testutil.CmdOpts{
Args: append(
[]string{"migrate", "apply"},
globalFlags...,
),
WorkingDirectory: projectDirectory,
})
wantKeywordList := []string{
"migrations applied",
}
Eventually(session, timeout).Should(Exit(0))
for _, keyword := range wantKeywordList {
Expect(session.Err.Contents()).Should(ContainSubstring(keyword))
}
})
}
var testMigrateApplySkipExecution = func(projectDirectory string, globalFlags []string) {
Context("migrate apply --skip-execution", func() {
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: append(
[]string{"migrate", "create", "schema_creation", "--up-sql", "create schema \"testing\";", "--down-sql", "drop schema \"testing\" cascade;"},
globalFlags...,
),
WorkingDirectory: projectDirectory,
})
session := testutil.Hasura(testutil.CmdOpts{
Args: append(
[]string{"migrate", "apply"},
globalFlags...,
),
WorkingDirectory: projectDirectory,
})
wantKeywordList := []string{
"migrations applied",
}
Eventually(session, timeout).Should(Exit(0))
for _, keyword := range wantKeywordList {
Expect(session.Err.Contents()).Should(ContainSubstring(keyword))
}
session = testutil.Hasura(testutil.CmdOpts{
Args: append(
[]string{"migrate", "apply", "--skip-execution", "--down", "all"},
globalFlags...,
),
WorkingDirectory: projectDirectory,
})
wantKeywordList = []string{
"migrations applied",
}
Eventually(session, timeout).Should(Exit(0))
for _, keyword := range wantKeywordList {
Expect(session.Err.Contents()).Should(ContainSubstring(keyword))
}
session = testutil.Hasura(testutil.CmdOpts{
Args: append(
[]string{"migrate", "status"},
globalFlags...,
),
WorkingDirectory: projectDirectory,
})
wantKeywordList = []string{
".*VERSION*.",
".*SOURCE STATUS*.",
".*DATABASE STATUS*.",
".*schema_creation*.",
".*Present Not Present*.",
}
Eventually(session, timeout).Should(Exit(0))
for _, keyword := range wantKeywordList {
Expect(session.Wait(timeout).Out).Should(Say(keyword))
}
})
}
var testMigrateApplyAllDatabases = func(projectDirectory string, databases ...string) {
Context("migrate apply", func() {
for _, database := range databases {
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"migrate", "create", "schema_creation", "--up-sql", "create schema \"testing\";", "--down-sql", "drop schema \"testing\" cascade;", "--database-name", database},
WorkingDirectory: projectDirectory,
})
}
session := testutil.Hasura(testutil.CmdOpts{
Args: []string{"migrate", "apply", "--all-databases"},
WorkingDirectory: projectDirectory,
})
wantKeywordList := []string{
"migrations applied",
}
Eventually(session, timeout).Should(Exit(0))
for _, keyword := range wantKeywordList {
Expect(session.Err.Contents()).Should(ContainSubstring(keyword))
}
})
}
var testMigrateApplyAllDatabasesWithError = func(projectDirectory string, databases ...string) {
Context("migrate apply", func() {
for _, database := range databases {
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"migrate", "create", "schema_creation", "--up-sql", "create schema \"testing\";", "--down-sql", "drop schema \"testing\" cascade;", "--database-name", database},
WorkingDirectory: projectDirectory,
})
}
if len(databases) > 0 {
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"migrate", "create", "schema_creation", "--up-sql", "create schema \"testing\";", "--down-sql", "drop schema \"testing\" cascade;", "--database-name", databases[0]},
WorkingDirectory: projectDirectory,
})
}
session := testutil.Hasura(testutil.CmdOpts{
Args: []string{"migrate", "apply", "--all-databases"},
WorkingDirectory: projectDirectory,
})
wantKeywordList := []string{
fmt.Sprintf("operation failed on : %s", databases[0]),
}
if len(databases) > 0 {
Eventually(session, timeout).Should(Exit(1))
for _, keyword := range wantKeywordList {
Expect(session.Err.Contents()).Should(ContainSubstring(keyword))
}
} else {
Eventually(session, timeout).Should(Exit(0))
}
})
}
var testProgressBar = func(projectDirectory string) {
progressBar := "Applying migrations: . / 8 .*%"
Context("migrate apply should display progress bar", func() {
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"migrate", "create", "schema_creation", "--up-sql", "create schema \"testing\";", "--down-sql", "drop schema \"testing\" cascade;"},
WorkingDirectory: projectDirectory,
})
session := testutil.Hasura(testutil.CmdOpts{
Args: []string{"migrate", "apply", "--progressbar-logs"},
WorkingDirectory: projectDirectory,
})
wantKeywordList := []string{
progressBar,
"migrations applied",
}
Eventually(session, 60*40).Should(Exit(0))
for _, keyword := range wantKeywordList {
Eventually(session.Err, 60*40).Should(Say(keyword))
}
})
Context("migrate apply shouldn't display progress bar in non-terminal (default behaviour)", func() {
session := testutil.Hasura(testutil.CmdOpts{
Args: []string{"migrate", "apply", "--down", "all"},
WorkingDirectory: projectDirectory,
})
Eventually(session.Err, 60*40).ShouldNot(Say(progressBar))
Eventually(session, 60*40).Should(Exit(0))
})
}
var _ = Describe("hasura migrate apply", func() {
var hgeEndpoint string
var teardown func()
BeforeEach(func() {
var hgeEndPort string
hgeEndPort, teardown = testutil.StartHasura(GinkgoT(), testutil.HasuraDockerImage)
hgeEndpoint = fmt.Sprintf("http://0.0.0.0:%s", hgeEndPort)
})
AfterEach(func() { teardown() })
It("can apply the migrations on server (single database config v3)", func() {
projectDirectoryV3 := testutil.RandDirName()
defer os.RemoveAll(projectDirectoryV3)
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"init", projectDirectoryV3},
})
editEndpointInConfig(filepath.Join(projectDirectoryV3, defaultConfigFilename), hgeEndpoint)
testMigrateApply(projectDirectoryV3, []string{"--database-name", "default"})
})
It("can apply the migrations on server (single database config v2)", func() {
projectDirectoryV2 := testutil.RandDirName()
defer os.RemoveAll(projectDirectoryV2)
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"init", projectDirectoryV2, "--version", "2"},
})
editEndpointInConfig(filepath.Join(projectDirectoryV2, defaultConfigFilename), hgeEndpoint)
testMigrateApply(projectDirectoryV2, nil)
})
It("should mark the migrations as apply ", func() {
projectDirectoryV2 := testutil.RandDirName()
defer os.RemoveAll(projectDirectoryV2)
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"init", projectDirectoryV2, "--version", "2"},
})
editEndpointInConfig(filepath.Join(projectDirectoryV2, defaultConfigFilename), hgeEndpoint)
testMigrateApplySkipExecution(projectDirectoryV2, nil)
createTable := strings.NewReader(`
{
"type": "run_sql",
"args": {
"sql": "CREATE TABLE testing.test();"
}
}
`)
assertHGEAPIRequestSucceedsAndGetResponseBody(hgeEndpoint, "v2/query", createTable)
})
})
var _ = Describe("hasura migrate apply (config v3)", func() {
// automatic state migration should not affect new config v3 projects
var projectDirectory string
var hgeEndpoint string
var teardown func()
var pgSource = randomdata.SillyName()
var citusSource = randomdata.SillyName()
var mssqlSource = randomdata.SillyName()
BeforeEach(func() {
projectDirectory = testutil.RandDirName()
hgeEndPort, teardownHGE := testutil.StartHasuraWithMetadataDatabase(GinkgoT(), testutil.HasuraDockerImage)
hgeEndpoint = fmt.Sprintf("http://0.0.0.0:%s", hgeEndPort)
_, teardownPG := AddDatabaseToHasura(hgeEndpoint, pgSource, "postgres")
_, teardownCitus := AddDatabaseToHasura(hgeEndpoint, citusSource, "citus")
_, teardownMSSQL := AddDatabaseToHasura(hgeEndpoint, mssqlSource, "mssql")
testutil.RunCommandAndSucceed(testutil.CmdOpts{
Args: []string{"init", projectDirectory},
})
editEndpointInConfig(filepath.Join(projectDirectory, defaultConfigFilename), hgeEndpoint)
teardown = func() {
os.RemoveAll(projectDirectory)
teardownHGE()
teardownPG()
teardownCitus()
teardownMSSQL()
}
})
AfterEach(func() { teardown() })
It("should apply the migrations on server", func() {
testMigrateApply(projectDirectory, []string{"--database-name", pgSource})
testMigrateApply(projectDirectory, []string{"--database-name", citusSource})
testMigrateApply(projectDirectory, []string{"--database-name", mssqlSource})
})
It("should mark the migrations as applied ", func() {
testMigrateApplySkipExecution(projectDirectory, []string{"--database-name", pgSource})
createTableString := fmt.Sprintf(`
{
"type": "run_sql",
"args": {
"sql": "CREATE TABLE testing.test();",
"source": "%s"
}
}
`, pgSource)
createTable := strings.NewReader(createTableString)
assertHGEAPIRequestSucceedsAndGetResponseBody(hgeEndpoint, "v2/query", createTable)
})
It("should apply the migrations on all-databases", func() {
testMigrateApplyAllDatabases(projectDirectory, pgSource, citusSource, mssqlSource)
pgBody := fmt.Sprintf(`
{
"type": "run_sql",
"args": {
"sql": "CREATE TABLE testing.test();",
"source": "%s"
}
}
`, pgSource)
createTable := strings.NewReader(pgBody)
assertHGEAPIRequestSucceedsAndGetResponseBody(hgeEndpoint, "v2/query", createTable)
citusBody := fmt.Sprintf(`
{
"type": "citus_run_sql",
"args": {
"sql": "CREATE TABLE testing.test();",
"source": "%s"
}
}
`, citusSource)
createTable = strings.NewReader(citusBody)
assertHGEAPIRequestSucceedsAndGetResponseBody(hgeEndpoint, "v2/query", createTable)
})
It("should the migrations on all-databases except first database and it should exit with code 1", func() {
testMigrateApplyAllDatabasesWithError(projectDirectory, pgSource, citusSource, mssqlSource)
citusBody := fmt.Sprintf(`
{
"type": "citus_run_sql",
"args": {
"sql": "CREATE TABLE testing.test();",
"source": "%s"
}
}
`, citusSource)
createTable := strings.NewReader(citusBody)
assertHGEAPIRequestSucceedsAndGetResponseBody(hgeEndpoint, "v2/query", createTable)
})
})
var _ = Describe("hasura migrate apply progress bar", func() {
var projectDirectory string
var teardown func()
BeforeEach(func() {
projectDirectory = testutil.RandDirName()
hgeEndPort, teardownHGE := testutil.StartHasura(GinkgoT(), testutil.HasuraDockerImage)
hgeEndpoint := fmt.Sprintf("http://0.0.0.0:%s", hgeEndPort)
copyTestConfigV2Project(projectDirectory)
editEndpointInConfig(filepath.Join(projectDirectory, defaultConfigFilename), hgeEndpoint)
teardown = func() {
os.RemoveAll(projectDirectory)
teardownHGE()
}
})
AfterEach(func() {
teardown()
})
It("test the progress bar of migrate apply", func() {
testProgressBar(projectDirectory)
})
})