graphql-engine/cli/commands/deploy_test.go
Rikin Kachhia c256dcef7b cli: add option to apply seeds with the hasura deploy command
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7231
Co-authored-by: Aravind K P <8335904+scriptonist@users.noreply.github.com>
GitOrigin-RevId: 3cc7510bb16e8bceeb6cd2a678881a3459b6721f
2022-12-22 07:56:56 +00:00

309 lines
11 KiB
Go

package commands
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/spf13/viper"
"github.com/hasura/graphql-engine/cli/v2"
"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/gexec"
)
var commonDeployCommandsTest = func(projectDirectory string, databaseFlags ...string) {
Context("should apply metadata, run migrations and reload metadata", func() {
// Run Deploy
session := testutil.Hasura(testutil.CmdOpts{
Args: []string{"deploy"},
WorkingDirectory: projectDirectory,
})
Eventually(session, timeout).Should(Exit(0))
deployOutput := session.Err.Contents()
Expect(deployOutput).Should(ContainSubstring("Metadata applied"))
Expect(deployOutput).Should(ContainSubstring("migrations applied"))
// incase of config_v3
if len(databaseFlags) != 0 {
Expect(deployOutput).Should(ContainSubstring("Metadata reloaded"))
}
// Ensure metadata is applied
metadataSession := testutil.Hasura(testutil.CmdOpts{
Args: []string{"metadata", "inconsistency", "status"},
WorkingDirectory: projectDirectory,
})
Eventually(metadataSession, timeout).Should(Exit(0))
metadataOutput := string(metadataSession.Err.Contents())
Expect(metadataOutput).Should(ContainSubstring("metadata is consistent"))
// Ensure migrations are applied
migrateSession := testutil.Hasura(testutil.CmdOpts{
Args: append([]string{"migrate", "status"}, databaseFlags...),
WorkingDirectory: projectDirectory,
})
Eventually(migrateSession, timeout).Should(Exit(0))
migrateOutput := string(migrateSession.Out.Contents())
Expect(migrateOutput).Should(ContainSubstring("Present Present"))
})
}
var _ = Describe("hasura deploy config v3", func() {
var projectDirectory string
var teardown func()
sourceName := randomdata.SillyName()
BeforeEach(func() {
projectDirectory = testutil.RandDirName()
hgeEndPort, teardownHGE := testutil.StartHasura(GinkgoT(), testutil.HasuraDockerImage)
hgeEndpoint := fmt.Sprintf("http://0.0.0.0:%s", hgeEndPort)
connectionString, teardownPG := testutil.StartPGContainer(GinkgoT())
testutil.AddPGSourceToHasura(GinkgoT(), hgeEndpoint, connectionString, sourceName)
copyTestConfigV3Project(projectDirectory)
editEndpointInConfig(filepath.Join(projectDirectory, defaultConfigFilename), hgeEndpoint)
editSourceNameInConfigV3ProjectTemplate(projectDirectory, sourceName, connectionString)
teardown = func() {
os.RemoveAll(projectDirectory)
teardownPG()
teardownHGE()
}
})
AfterEach(func() {
teardown()
})
It("deploy", func() {
commonDeployCommandsTest(projectDirectory, "--database-name", sourceName)
})
})
var _ = Describe("hasura deploy config v2", 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("deploy", func() {
commonDeployCommandsTest(projectDirectory)
})
})
var _ = Describe("fsm state transitions: config v2", func() {
var projectDirectory string
var teardown, teardownHGE func()
BeforeEach(func() {
projectDirectory = testutil.RandDirName()
var hgeEndPort string
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)
}
})
AfterEach(func() {
teardown()
})
It("should make correct state transitions", func() {
ctx := &deployCtx{
err: nil,
}
ctx.ec = cli.NewExecutionContext()
ctx.ec.Viper = viper.New()
ctx.ec.ExecutionDirectory = projectDirectory
//ctx.ec.LogLevel = "DEBUG"
Expect(ctx.ec.Prepare()).Should(BeNil())
//ctx.ec.Stderr = io.Discard
Expect(ctx.ec.Validate()).Should(BeNil())
ctx.logger = ctx.ec.Logger
// bad sql migration
configV2FSM := newConfigV2DeployFSM()
migrationFilePath := filepath.Join(projectDirectory, "migrations", "1620138136207_create_table_public_t1/up.sql")
upSQL, err := ioutil.ReadFile(migrationFilePath)
Expect(err).To(BeNil())
badUpSQL := []byte(string(upSQL) + "SOME GARBAGE;")
Expect(ioutil.WriteFile(migrationFilePath, badUpSQL, 0755)).To(BeNil())
Expect(configV2FSM.SendEvent(applyMigrations, ctx)).To(BeNil())
Expect(configV2FSM.Current).Should(Equal(failedOperation))
Expect(configV2FSM.Previous).Should(Equal(applyingMigrationsFailed))
ctx.ec.Logger.Debugf("error: %v", ctx.err)
Expect(ctx.err).Should(Not(BeNil()))
// reset file contents
Expect(ioutil.WriteFile(migrationFilePath, upSQL, 0755)).To(BeNil())
// bad metadata yaml file
tablesYamlFilepath := filepath.Join(projectDirectory, "metadata", "tables.yaml")
tablesYaml, err := ioutil.ReadFile(tablesYamlFilepath)
Expect(err).To(BeNil())
// user error in tables.yaml
configV2FSM = newConfigV2DeployFSM()
badTablesYaml := []byte(`some: key`)
Expect(ioutil.WriteFile(tablesYamlFilepath, badTablesYaml, 0755)).To(BeNil())
Expect(configV2FSM.SendEvent(applyMigrations, ctx)).To(BeNil())
Expect(configV2FSM.Current).Should(Equal(failedOperation))
Expect(configV2FSM.Previous).Should(Equal(applyingMetadataFailed))
ctx.ec.Logger.Debugf("error: %v", ctx.err)
Expect(ctx.err).Should(Not(BeNil()))
// validation error from server
configV2FSM = newConfigV2DeployFSM()
badTablesYaml = []byte(`
- table:
schema: public
# this should be a string not a number
name: 1
`)
Expect(ioutil.WriteFile(tablesYamlFilepath, badTablesYaml, 0755)).To(BeNil())
Expect(configV2FSM.SendEvent(applyMigrations, ctx)).To(BeNil())
ctx.ec.Logger.Debugf("error: %v", ctx.err)
Expect(configV2FSM.Current).Should(Equal(failedOperation))
Expect(configV2FSM.Previous).Should(Equal(applyingMetadataFailed))
Expect(ctx.err).Should(Not(BeNil()))
// reset file contents
Expect(ioutil.WriteFile(tablesYamlFilepath, tablesYaml, 0755)).To(BeNil())
// happy path
configV2FSM = newConfigV2DeployFSM()
Expect(configV2FSM.SendEvent(applyMigrations, ctx)).To(BeNil())
Expect(configV2FSM.Current).Should(Equal(applyingSeeds))
// unreachable HGE
teardownHGE()
configV2FSM = newConfigV2DeployFSM()
Expect(configV2FSM.SendEvent(applyMigrations, ctx)).To(BeNil())
Expect(configV2FSM.Current).Should(Equal(failedOperation))
})
})
var _ = Describe("fsm state transitions: config v3", func() {
var projectDirectory string
var teardown, teardownHGE func()
sourceName := randomdata.SillyName()
BeforeEach(func() {
projectDirectory = testutil.RandDirName()
var hgeEndPort string
hgeEndPort, teardownHGE = testutil.StartHasuraWithMetadataDatabase(GinkgoT(), testutil.HasuraDockerImage)
hgeEndpoint := fmt.Sprintf("http://0.0.0.0:%s", hgeEndPort)
connectionString, teardownPG := testutil.StartPGContainer(GinkgoT())
testutil.AddPGSourceToHasura(GinkgoT(), hgeEndpoint, connectionString, sourceName)
copyTestConfigV3Project(projectDirectory)
editEndpointInConfig(filepath.Join(projectDirectory, defaultConfigFilename), hgeEndpoint)
editSourceNameInConfigV3ProjectTemplate(projectDirectory, sourceName, connectionString)
teardown = func() {
os.RemoveAll(projectDirectory)
teardownPG()
}
})
AfterEach(func() {
teardown()
})
It("should make correct state transitions", func() {
ctx := &deployCtx{
err: nil,
}
ctx.ec = cli.NewExecutionContext()
ctx.ec.Viper = viper.New()
ctx.ec.ExecutionDirectory = projectDirectory
//ctx.ec.LogLevel = "DEBUG"
Expect(ctx.ec.Prepare()).Should(BeNil())
ctx.ec.Stderr = io.Discard
Expect(ctx.ec.Validate()).Should(BeNil())
ctx.logger = ctx.ec.Logger
// bad sql migration
configV3DeployFSM := newConfigV3DeployFSM()
migrationFilePath := filepath.Join(projectDirectory, "migrations", sourceName, "1622047079431_chinook/up.sql")
upSQL, err := ioutil.ReadFile(migrationFilePath)
Expect(err).To(BeNil())
badUpSQL := []byte("SOME GARBAGE;")
Expect(ioutil.WriteFile(migrationFilePath, badUpSQL, 0755)).To(BeNil())
Expect(configV3DeployFSM.SendEvent(applyInitialMetadata, ctx)).To(BeNil())
Expect(configV3DeployFSM.Current).Should(Equal(failedOperation))
Expect(configV3DeployFSM.Previous).Should(Equal(applyingMigrationsFailed))
ctx.ec.Logger.Debugf("error: %v", ctx.err)
Expect(ctx.err).Should(Not(BeNil()))
// reset file contents
Expect(ioutil.WriteFile(migrationFilePath, upSQL, 0755)).To(BeNil())
// bad metadata yaml file
tablesYamlFilepath := filepath.Join(projectDirectory, "metadata", "databases", sourceName, "tables", "tables.yaml")
tablesYaml, err := ioutil.ReadFile(tablesYamlFilepath)
Expect(err).To(BeNil())
// user error in tables.yaml
configV3DeployFSM = newConfigV3DeployFSM()
badTablesYaml := []byte(`some: key`)
Expect(ioutil.WriteFile(tablesYamlFilepath, badTablesYaml, 0755)).To(BeNil())
Expect(configV3DeployFSM.SendEvent(applyInitialMetadata, ctx)).To(BeNil())
Expect(configV3DeployFSM.Current).Should(Equal(failedOperation))
Expect(configV3DeployFSM.Previous).Should(Equal(applyingInitialMetadataFailed))
ctx.ec.Logger.Debugf("error: %v", ctx.err)
Expect(ctx.err).Should(Not(BeNil()))
// validation error from server
configV3DeployFSM = newConfigV3DeployFSM()
badTablesYaml = []byte(`
- table:
schema: public
# this should be a string not a number
name: 1
`)
Expect(ioutil.WriteFile(tablesYamlFilepath, badTablesYaml, 0755)).To(BeNil())
Expect(configV3DeployFSM.SendEvent(applyInitialMetadata, ctx)).To(BeNil())
ctx.ec.Logger.Debugf("error: %v", ctx.err)
Expect(configV3DeployFSM.Current).Should(Equal(failedOperation))
Expect(configV3DeployFSM.Previous).Should(Equal(applyingInitialMetadataFailed))
Expect(ctx.err).Should(Not(BeNil()))
// reset file contents
Expect(ioutil.WriteFile(tablesYamlFilepath, tablesYaml, 0755)).To(BeNil())
// happy path
configV3DeployFSM = newConfigV3DeployFSM()
Expect(configV3DeployFSM.SendEvent(applyInitialMetadata, ctx)).To(BeNil())
Expect(configV3DeployFSM.Current).Should(Equal(applyingSeeds))
// unreachable HGE
teardownHGE()
configV3DeployFSM = newConfigV3DeployFSM()
Expect(configV3DeployFSM.SendEvent(applyInitialMetadata, ctx)).To(BeNil())
Expect(configV3DeployFSM.Current).Should(Equal(failedOperation))
})
})