From 7b711bf13f207d235120383730efff1f6e912239 Mon Sep 17 00:00:00 2001 From: Eric Hu Date: Thu, 28 Jun 2018 02:40:16 +0700 Subject: [PATCH 1/8] WIP: failing test --- cmd/orb.go | 88 ++++++++++++++++ cmd/orb_test.go | 266 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 354 insertions(+) create mode 100644 cmd/orb_test.go diff --git a/cmd/orb.go b/cmd/orb.go index 01cd58201..80fd37932 100644 --- a/cmd/orb.go +++ b/cmd/orb.go @@ -2,6 +2,9 @@ package cmd import ( "context" + "fmt" + "io/ioutil" + "os" "github.com/CircleCI-Public/circleci-cli/client" "github.com/pkg/errors" @@ -11,6 +14,20 @@ import ( "github.com/spf13/viper" ) +var orbPath string + +type orbConfigResponse struct { + OrbConfig struct { + Valid bool + SourceYaml string + OutputYaml string + + Errors []struct { + Message string + } + } +} + func newOrbCommand() *cobra.Command { orbListCommand := &cobra.Command{ @@ -19,12 +36,20 @@ func newOrbCommand() *cobra.Command { RunE: listOrbs, } + orbValidateCommand := &cobra.Command{ + Use: "validate", + Short: "validate an orb.yml", + RunE: validateOrb, + } + orbCommand := &cobra.Command{ Use: "orb", Short: "Operate on orbs", } + orbValidateCommand.PersistentFlags().StringVarP(&orbPath, "path", "p", "orb.yml", "path to orb config") orbCommand.AddCommand(orbListCommand) + orbCommand.AddCommand(orbValidateCommand) return orbCommand } @@ -97,3 +122,66 @@ query ListOrbs ($after: String!) { return nil } + +func loadOrbYaml(path string) (string, error) { + + config, err := ioutil.ReadFile(path) + + fmt.Fprintln(os.Stderr, "******************** orb.go") + fmt.Fprintln(os.Stderr, path) + fmt.Fprintln(os.Stderr, err) + if err != nil { + return "", errors.Wrapf(err, "Could not load orb file at %s", path) + } + + return string(config), nil +} + +func orbValidateQuery(ctx context.Context) (*orbConfigResponse, error) { + + query := ` + query ValidateOrb ($orb: String!) { + orbConfig(configYaml: $orb) { + valid, + errors { message }, + sourceYaml, + outputYaml + } + }` + + fmt.Fprintln(os.Stderr, "********************asdfasdfasdfsa") + fmt.Fprintln(os.Stderr, orbPath) + + config, err := loadOrbYaml(orbPath) + if err != nil { + return nil, err + } + + variables := map[string]string{ + "config": config, + } + + var response orbConfigResponse + err = queryAPI(ctx, query, variables, &response) + if err != nil { + return nil, errors.Wrap(err, "Unable to validate config") + } + + return &response, nil +} + +func validateOrb(cmd *cobra.Command, args []string) error { + ctx := context.Background() + response, err := configQuery(ctx) + + if err != nil { + return err + } + + if !response.BuildConfig.Valid { + return response.processErrors() + } + + Logger.Infof("Orb at %s is valid", orbPath) + return nil +} diff --git a/cmd/orb_test.go b/cmd/orb_test.go new file mode 100644 index 000000000..8b3283a2a --- /dev/null +++ b/cmd/orb_test.go @@ -0,0 +1,266 @@ +package cmd_test + +import ( + "fmt" + "io/ioutil" + "net/http" + "os" + "os/exec" + "path/filepath" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/onsi/gomega/gexec" + "github.com/onsi/gomega/ghttp" +) + +// func appendPostHandler(server *ghttp.Server, authToken string, statusCode int, expectedRequestJson string, responseBody string) { +// server.AppendHandlers( +// ghttp.CombineHandlers( +// ghttp.VerifyRequest("POST", "/"), +// ghttp.VerifyHeader(http.Header{ +// "Authorization": []string{authToken}, +// }), +// ghttp.VerifyContentType("application/json; charset=utf-8"), +// // From Gomegas ghttp.VerifyJson to avoid the +// // VerifyContentType("application/json") check +// // that fails with "application/json; charset=utf-8" +// func(w http.ResponseWriter, req *http.Request) { +// body, err := ioutil.ReadAll(req.Body) +// req.Body.Close() +// Expect(err).ShouldNot(HaveOccurred()) +// Expect(body).Should(MatchJSON(expectedRequestJson), "JSON Mismatch") +// }, +// ghttp.RespondWith(statusCode, `{ "data": `+responseBody+`}`), +// ), +// ) +// } + +type orbYaml struct { + TempHome string + Path string + YamlFile *os.File +} + +func openOrbYaml() (orbYaml, error) { + var ( + orb orbYaml = orbYaml{} + err error + ) + + const ( + orbDir = "myorb" + orbFile = "orb.yml" + ) + + tempHome, err := ioutil.TempDir("", "circleci-cli-test-") + if err != nil { + return orb, err + } + + err = os.Mkdir(filepath.Join(tempHome, orbDir), 0700) + if err != nil { + return orb, err + } + + orb.Path = filepath.Join(tempHome, orbDir, orbFile) + + var file *os.File + file, err = os.OpenFile( + orb.Path, + os.O_RDWR|os.O_CREATE, + 0600, + ) + if err != nil { + return orb, err + } + + orb.YamlFile = file + + return orb, nil +} + +var _ = Describe("Orb", func() { + Describe("with an api and orb.yml", func() { + var ( + testServer *ghttp.Server + orb orbYaml + ) + + BeforeEach(func() { + var err error + orb, err = openOrbYaml() + Expect(err).ToNot(HaveOccurred()) + + testServer = ghttp.NewServer() + }) + + AfterEach(func() { + orb.YamlFile.Close() + os.RemoveAll(orb.TempHome) + + testServer.Close() + }) + + Describe("when validating orb", func() { + var ( + token string + command *exec.Cmd + ) + + BeforeEach(func() { + token = "testtoken" + fmt.Fprintln(os.Stderr, "******************** Path CLI") + fmt.Fprintln(os.Stderr, pathCLI) + fmt.Fprintln(os.Stderr, token) + fmt.Fprintln(os.Stderr, testServer.URL()) + fmt.Fprintln(os.Stderr, orb.Path) + command = exec.Command(pathCLI, + "orb", "validate", + "-t", token, + "-e", testServer.URL(), + "-p", orb.Path, + ) + }) + + FIt("works", func() { + _, err := orb.YamlFile.Write([]byte(`{}`)) + Expect(err).ToNot(HaveOccurred()) + + gqlResponse := `{ + "orbConfig": { + "sourceYaml": "{}", + "valid": true, + "errors": [] + } + }` + + expectedRequestJson := ` { + "query": "\n\t\tquery ValidateOrb ($orb: String!) {\n\t\t\torbConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", + "variables": { + "orb": "{}" + } + }` + + appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + + session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + Expect(err).ShouldNot(HaveOccurred()) + Eventually(session.Out).Should(gbytes.Say("Orb at myorb/orb.yml is valid")) + Eventually(session).Should(gexec.Exit(0)) + }) + + // It("prints errors if invalid", func() { + // _, err := orb.YamlFile.Write([]byte(`some orb`)) + // Expect(err).ToNot(HaveOccurred()) + + // gqlResponse := `{ + // "buildConfig": { + // "sourceYaml": "hello world", + // "valid": false, + // "errors": [ + // {"message": "invalid_orb"} + // ] + // } + // }` + + // expectedRequestJson := ` { + // "query": "\n\t\tquery ValidateConfig ($orb: String!) {\n\t\t\tbuildConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", + // "variables": { + // "orb": "some orb" + // } + // }` + // appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + + // session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + // Expect(err).ShouldNot(HaveOccurred()) + // Eventually(session.Err).Should(gbytes.Say("Error:")) + // Eventually(session.Err).Should(gbytes.Say("-- invalid_orb")) + // Eventually(session).Should(gexec.Exit(255)) + + // }) + }) + + // Describe("when expanding orb", func() { + // var ( + // token string + // command *exec.Cmd + // ) + + // BeforeEach(func() { + // token = "testtoken" + // command = exec.Command(pathCLI, + // "orb", "expand", + // "-t", token, + // "-e", testServer.URL(), + // "-p", orb.Path, + // ) + // }) + + // It("works", func() { + // _, err := orb.YamlFile.Write([]byte(`some orb`)) + // Expect(err).ToNot(HaveOccurred()) + + // gqlResponse := `{ + // "buildConfig": { + // "outputYaml": "hello world", + // "valid": true, + // "errors": [] + // } + // }` + + // expectedRequestJson := ` { + // "query": "\n\t\tquery ValidateConfig ($orb: String!) {\n\t\t\tbuildConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", + // "variables": { + // "orb": "some orb" + // } + // }` + + // appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + + // session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + // Expect(err).ShouldNot(HaveOccurred()) + // Eventually(session.Out).Should(gbytes.Say("hello world")) + // Eventually(session).Should(gexec.Exit(0)) + // }) + + // It("prints errors if invalid", func() { + // _, err := orb.YamlFile.Write([]byte(`some orb`)) + // Expect(err).ToNot(HaveOccurred()) + + // gqlResponse := `{ + // "buildConfig": { + // "outputYaml": "hello world", + // "valid": false, + // "errors": [ + // {"message": "error1"}, + // {"message": "error2"} + // ] + // } + // }` + + // expectedRequestJson := ` { + // "query": "\n\t\tquery ValidateConfig ($orb: String!) {\n\t\t\tbuildConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", + // "variables": { + // "orb": "some orb" + // } + // }` + + // appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + + // session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + // Expect(err).ShouldNot(HaveOccurred()) + // Eventually(session.Err).Should(gbytes.Say("Error:")) + // Eventually(session.Err).Should(gbytes.Say("-- error1,")) + // Eventually(session.Err).Should(gbytes.Say("-- error2,")) + // Eventually(session).Should(gexec.Exit(255)) + + // }) + // }) + }) +}) From 70d53950fb7b35d9a467e07a36fb6e1e2fe439fc Mon Sep 17 00:00:00 2001 From: Cayenne Geis Date: Thu, 28 Jun 2018 11:15:34 -0400 Subject: [PATCH 2/8] WIP: passing test, needs refactoring --- cmd/orb.go | 36 ++++++++++++++++++++++++------------ cmd/orb_test.go | 3 ++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/cmd/orb.go b/cmd/orb.go index 80fd37932..01dcab134 100644 --- a/cmd/orb.go +++ b/cmd/orb.go @@ -1,6 +1,7 @@ package cmd import ( + "bytes" "context" "fmt" "io/ioutil" @@ -47,7 +48,7 @@ func newOrbCommand() *cobra.Command { Short: "Operate on orbs", } - orbValidateCommand.PersistentFlags().StringVarP(&orbPath, "path", "p", "orb.yml", "path to orb config") + orbValidateCommand.PersistentFlags().StringVarP(&orbPath, "path", "p", "orb.yml", "path to orb file") orbCommand.AddCommand(orbListCommand) orbCommand.AddCommand(orbValidateCommand) @@ -125,7 +126,7 @@ query ListOrbs ($after: String!) { func loadOrbYaml(path string) (string, error) { - config, err := ioutil.ReadFile(path) + orb, err := ioutil.ReadFile(path) fmt.Fprintln(os.Stderr, "******************** orb.go") fmt.Fprintln(os.Stderr, path) @@ -134,14 +135,28 @@ func loadOrbYaml(path string) (string, error) { return "", errors.Wrapf(err, "Could not load orb file at %s", path) } - return string(config), nil + return string(orb), nil +} + + +func (response orbConfigResponse) processErrors() error { + var buffer bytes.Buffer + + buffer.WriteString("\n") + for i := range response.OrbConfig.Errors { + buffer.WriteString("-- ") + buffer.WriteString(response.OrbConfig.Errors[i].Message) + buffer.WriteString(",\n") + } + + return errors.New(buffer.String()) } func orbValidateQuery(ctx context.Context) (*orbConfigResponse, error) { query := ` query ValidateOrb ($orb: String!) { - orbConfig(configYaml: $orb) { + orbConfig(orbYaml: $orb) { valid, errors { message }, sourceYaml, @@ -149,22 +164,19 @@ func orbValidateQuery(ctx context.Context) (*orbConfigResponse, error) { } }` - fmt.Fprintln(os.Stderr, "********************asdfasdfasdfsa") - fmt.Fprintln(os.Stderr, orbPath) - - config, err := loadOrbYaml(orbPath) + orb, err := loadOrbYaml(orbPath) if err != nil { return nil, err } variables := map[string]string{ - "config": config, + "orb": orb, } var response orbConfigResponse err = queryAPI(ctx, query, variables, &response) if err != nil { - return nil, errors.Wrap(err, "Unable to validate config") + return nil, errors.Wrap(err, "Unable to validate orb") } return &response, nil @@ -172,13 +184,13 @@ func orbValidateQuery(ctx context.Context) (*orbConfigResponse, error) { func validateOrb(cmd *cobra.Command, args []string) error { ctx := context.Background() - response, err := configQuery(ctx) + response, err := orbValidateQuery(ctx) if err != nil { return err } - if !response.BuildConfig.Valid { + if !response.OrbConfig.Valid { return response.processErrors() } diff --git a/cmd/orb_test.go b/cmd/orb_test.go index 8b3283a2a..a0ee45837 100644 --- a/cmd/orb_test.go +++ b/cmd/orb_test.go @@ -148,7 +148,8 @@ var _ = Describe("Orb", func() { session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) Expect(err).ShouldNot(HaveOccurred()) - Eventually(session.Out).Should(gbytes.Say("Orb at myorb/orb.yml is valid")) + // the .* is because the full path with temp dir is printed + Eventually(session.Out).Should(gbytes.Say("Orb at .*myorb/orb.yml is valid")) Eventually(session).Should(gexec.Exit(0)) }) From 07f0f79120b5e4052ffcf394111e2bea7af75fe6 Mon Sep 17 00:00:00 2001 From: Eric Hu Date: Fri, 29 Jun 2018 03:56:14 +0700 Subject: [PATCH 3/8] Uncomment remaining tests and get them passing --- cmd/orb.go | 29 +++++- cmd/orb_test.go | 234 ++++++++++++++++++++++++------------------------ 2 files changed, 146 insertions(+), 117 deletions(-) diff --git a/cmd/orb.go b/cmd/orb.go index 01dcab134..9d044676b 100644 --- a/cmd/orb.go +++ b/cmd/orb.go @@ -43,15 +43,25 @@ func newOrbCommand() *cobra.Command { RunE: validateOrb, } + orbExpandCommand := &cobra.Command{ + Use: "expand", + Short: "expand an orb.yml", + RunE: expandOrb, + } + orbCommand := &cobra.Command{ Use: "orb", Short: "Operate on orbs", } - orbValidateCommand.PersistentFlags().StringVarP(&orbPath, "path", "p", "orb.yml", "path to orb file") orbCommand.AddCommand(orbListCommand) + + orbValidateCommand.PersistentFlags().StringVarP(&orbPath, "path", "p", "orb.yml", "path to orb file") orbCommand.AddCommand(orbValidateCommand) + orbExpandCommand.PersistentFlags().StringVarP(&orbPath, "path", "p", "orb.yml", "path to orb file") + orbCommand.AddCommand(orbExpandCommand) + return orbCommand } @@ -197,3 +207,20 @@ func validateOrb(cmd *cobra.Command, args []string) error { Logger.Infof("Orb at %s is valid", orbPath) return nil } + +func expandOrb(cmd *cobra.Command, args []string) error { + ctx := context.Background() + + response, err := orbValidateQuery(ctx) + + if err != nil { + return err + } + + if !response.OrbConfig.Valid { + return response.processErrors() + } + + Logger.Info(response.OrbConfig.OutputYaml) + return nil +} diff --git a/cmd/orb_test.go b/cmd/orb_test.go index a0ee45837..c4998676d 100644 --- a/cmd/orb_test.go +++ b/cmd/orb_test.go @@ -1,7 +1,6 @@ package cmd_test import ( - "fmt" "io/ioutil" "net/http" "os" @@ -111,11 +110,6 @@ var _ = Describe("Orb", func() { BeforeEach(func() { token = "testtoken" - fmt.Fprintln(os.Stderr, "******************** Path CLI") - fmt.Fprintln(os.Stderr, pathCLI) - fmt.Fprintln(os.Stderr, token) - fmt.Fprintln(os.Stderr, testServer.URL()) - fmt.Fprintln(os.Stderr, orb.Path) command = exec.Command(pathCLI, "orb", "validate", "-t", token, @@ -124,7 +118,8 @@ var _ = Describe("Orb", func() { ) }) - FIt("works", func() { + It("works", func() { + By("setting up a mock server") _, err := orb.YamlFile.Write([]byte(`{}`)) Expect(err).ToNot(HaveOccurred()) @@ -145,123 +140,130 @@ var _ = Describe("Orb", func() { appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + By("running the command") session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) Expect(err).ShouldNot(HaveOccurred()) - // the .* is because the full path with temp dir is printed + // the .* is because the full path with temp dir is printed Eventually(session.Out).Should(gbytes.Say("Orb at .*myorb/orb.yml is valid")) Eventually(session).Should(gexec.Exit(0)) }) - // It("prints errors if invalid", func() { - // _, err := orb.YamlFile.Write([]byte(`some orb`)) - // Expect(err).ToNot(HaveOccurred()) - - // gqlResponse := `{ - // "buildConfig": { - // "sourceYaml": "hello world", - // "valid": false, - // "errors": [ - // {"message": "invalid_orb"} - // ] - // } - // }` - - // expectedRequestJson := ` { - // "query": "\n\t\tquery ValidateConfig ($orb: String!) {\n\t\t\tbuildConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", - // "variables": { - // "orb": "some orb" - // } - // }` - // appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) - - // session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) - - // Expect(err).ShouldNot(HaveOccurred()) - // Eventually(session.Err).Should(gbytes.Say("Error:")) - // Eventually(session.Err).Should(gbytes.Say("-- invalid_orb")) - // Eventually(session).Should(gexec.Exit(255)) - - // }) + It("prints errors if invalid", func() { + By("setting up a mock server") + _, err := orb.YamlFile.Write([]byte(`some orb`)) + Expect(err).ToNot(HaveOccurred()) + + gqlResponse := `{ + "orbConfig": { + "sourceYaml": "hello world", + "valid": false, + "errors": [ + {"message": "invalid_orb"} + ] + } + }` + + expectedRequestJson := ` { + "query": "\n\t\tquery ValidateOrb ($orb: String!) {\n\t\t\torbConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", + "variables": { + "orb": "some orb" + } + }` + appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + + By("running the command") + session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + Expect(err).ShouldNot(HaveOccurred()) + Eventually(session.Err).Should(gbytes.Say("Error:")) + Eventually(session.Err).Should(gbytes.Say("-- invalid_orb")) + Eventually(session).Should(gexec.Exit(255)) + + }) }) - // Describe("when expanding orb", func() { - // var ( - // token string - // command *exec.Cmd - // ) - - // BeforeEach(func() { - // token = "testtoken" - // command = exec.Command(pathCLI, - // "orb", "expand", - // "-t", token, - // "-e", testServer.URL(), - // "-p", orb.Path, - // ) - // }) - - // It("works", func() { - // _, err := orb.YamlFile.Write([]byte(`some orb`)) - // Expect(err).ToNot(HaveOccurred()) - - // gqlResponse := `{ - // "buildConfig": { - // "outputYaml": "hello world", - // "valid": true, - // "errors": [] - // } - // }` - - // expectedRequestJson := ` { - // "query": "\n\t\tquery ValidateConfig ($orb: String!) {\n\t\t\tbuildConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", - // "variables": { - // "orb": "some orb" - // } - // }` - - // appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) - - // session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) - - // Expect(err).ShouldNot(HaveOccurred()) - // Eventually(session.Out).Should(gbytes.Say("hello world")) - // Eventually(session).Should(gexec.Exit(0)) - // }) - - // It("prints errors if invalid", func() { - // _, err := orb.YamlFile.Write([]byte(`some orb`)) - // Expect(err).ToNot(HaveOccurred()) - - // gqlResponse := `{ - // "buildConfig": { - // "outputYaml": "hello world", - // "valid": false, - // "errors": [ - // {"message": "error1"}, - // {"message": "error2"} - // ] - // } - // }` - - // expectedRequestJson := ` { - // "query": "\n\t\tquery ValidateConfig ($orb: String!) {\n\t\t\tbuildConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", - // "variables": { - // "orb": "some orb" - // } - // }` - - // appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) - - // session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) - - // Expect(err).ShouldNot(HaveOccurred()) - // Eventually(session.Err).Should(gbytes.Say("Error:")) - // Eventually(session.Err).Should(gbytes.Say("-- error1,")) - // Eventually(session.Err).Should(gbytes.Say("-- error2,")) - // Eventually(session).Should(gexec.Exit(255)) - - // }) - // }) + Describe("when expanding orb", func() { + var ( + token string + command *exec.Cmd + ) + + BeforeEach(func() { + token = "testtoken" + command = exec.Command(pathCLI, + "orb", "expand", + "-t", token, + "-e", testServer.URL(), + "-p", orb.Path, + ) + }) + + It("works", func() { + By("setting up a mock server") + _, err := orb.YamlFile.Write([]byte(`some orb`)) + Expect(err).ToNot(HaveOccurred()) + + gqlResponse := `{ + "orbConfig": { + "outputYaml": "hello world", + "valid": true, + "errors": [] + } + }` + + expectedRequestJson := ` { + "query": "\n\t\tquery ValidateOrb ($orb: String!) {\n\t\t\torbConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", + "variables": { + "orb": "some orb" + } + }` + + appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + + By("running the command") + session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + Expect(err).ShouldNot(HaveOccurred()) + Eventually(session.Out).Should(gbytes.Say("hello world")) + Eventually(session).Should(gexec.Exit(0)) + }) + + It("prints errors if invalid", func() { + By("setting up a mock server") + _, err := orb.YamlFile.Write([]byte(`some orb`)) + Expect(err).ToNot(HaveOccurred()) + + gqlResponse := `{ + "orbConfig": { + "outputYaml": "hello world", + "valid": false, + "errors": [ + {"message": "error1"}, + {"message": "error2"} + ] + } + }` + + expectedRequestJson := ` { + "query": "\n\t\tquery ValidateOrb ($orb: String!) {\n\t\t\torbConfig(orbYaml: $orb) {\n\t\t\t\tvalid,\n\t\t\t\terrors { message },\n\t\t\t\tsourceYaml,\n\t\t\t\toutputYaml\n\t\t\t}\n\t\t}", + "variables": { + "orb": "some orb" + } + }` + + appendPostHandler(testServer, token, http.StatusOK, expectedRequestJson, gqlResponse) + + By("running the command") + session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter) + + Expect(err).ShouldNot(HaveOccurred()) + Eventually(session.Err).Should(gbytes.Say("Error:")) + Eventually(session.Err).Should(gbytes.Say("-- error1,")) + Eventually(session.Err).Should(gbytes.Say("-- error2,")) + Eventually(session).Should(gexec.Exit(255)) + + }) + }) }) }) From da23b93080069d71bf604b6ac6c73dde00f131bd Mon Sep 17 00:00:00 2001 From: Brady Lill Date: Fri, 29 Jun 2018 08:58:01 -0600 Subject: [PATCH 4/8] Removing dead code. --- cmd/orb_test.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/cmd/orb_test.go b/cmd/orb_test.go index c4998676d..70752f07e 100644 --- a/cmd/orb_test.go +++ b/cmd/orb_test.go @@ -14,28 +14,6 @@ import ( "github.com/onsi/gomega/ghttp" ) -// func appendPostHandler(server *ghttp.Server, authToken string, statusCode int, expectedRequestJson string, responseBody string) { -// server.AppendHandlers( -// ghttp.CombineHandlers( -// ghttp.VerifyRequest("POST", "/"), -// ghttp.VerifyHeader(http.Header{ -// "Authorization": []string{authToken}, -// }), -// ghttp.VerifyContentType("application/json; charset=utf-8"), -// // From Gomegas ghttp.VerifyJson to avoid the -// // VerifyContentType("application/json") check -// // that fails with "application/json; charset=utf-8" -// func(w http.ResponseWriter, req *http.Request) { -// body, err := ioutil.ReadAll(req.Body) -// req.Body.Close() -// Expect(err).ShouldNot(HaveOccurred()) -// Expect(body).Should(MatchJSON(expectedRequestJson), "JSON Mismatch") -// }, -// ghttp.RespondWith(statusCode, `{ "data": `+responseBody+`}`), -// ), -// ) -// } - type orbYaml struct { TempHome string Path string From b5da8da64851c71f14062c9304885ca09412c03d Mon Sep 17 00:00:00 2001 From: Brady Lill Date: Fri, 29 Jun 2018 09:00:17 -0600 Subject: [PATCH 5/8] Checking for non 0 exit codes. --- cmd/config_test.go | 6 ++---- cmd/orb_test.go | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/cmd/config_test.go b/cmd/config_test.go index 0becff835..d5f07adf9 100644 --- a/cmd/config_test.go +++ b/cmd/config_test.go @@ -174,8 +174,7 @@ var _ = Describe("Config", func() { Expect(err).ShouldNot(HaveOccurred()) Eventually(session.Err).Should(gbytes.Say("Error:")) Eventually(session.Err).Should(gbytes.Say("-- invalid_config")) - Eventually(session).Should(gexec.Exit(255)) - + Eventually(session).ShouldNot(gexec.Exit(0)) }) }) @@ -253,8 +252,7 @@ var _ = Describe("Config", func() { Eventually(session.Err).Should(gbytes.Say("Error:")) Eventually(session.Err).Should(gbytes.Say("-- error1,")) Eventually(session.Err).Should(gbytes.Say("-- error2,")) - Eventually(session).Should(gexec.Exit(255)) - + Eventually(session).ShouldNot(gexec.Exit(0)) }) }) }) diff --git a/cmd/orb_test.go b/cmd/orb_test.go index 70752f07e..02817d652 100644 --- a/cmd/orb_test.go +++ b/cmd/orb_test.go @@ -156,8 +156,7 @@ var _ = Describe("Orb", func() { Expect(err).ShouldNot(HaveOccurred()) Eventually(session.Err).Should(gbytes.Say("Error:")) Eventually(session.Err).Should(gbytes.Say("-- invalid_orb")) - Eventually(session).Should(gexec.Exit(255)) - + Eventually(session).ShouldNot(gexec.Exit(0)) }) }) @@ -239,7 +238,7 @@ var _ = Describe("Orb", func() { Eventually(session.Err).Should(gbytes.Say("Error:")) Eventually(session.Err).Should(gbytes.Say("-- error1,")) Eventually(session.Err).Should(gbytes.Say("-- error2,")) - Eventually(session).Should(gexec.Exit(255)) + Eventually(session).ShouldNot(gexec.Exit(0)) }) }) From 6f76c6f4055e598e5201983ace0b7ae3aff477bc Mon Sep 17 00:00:00 2001 From: Brady Lill Date: Fri, 29 Jun 2018 09:08:22 -0600 Subject: [PATCH 6/8] Moving request verification test helper function up. --- cmd/cmd_suite_test.go | 27 +++++++++++++++++++++++++++ cmd/config_test.go | 22 ---------------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/cmd/cmd_suite_test.go b/cmd/cmd_suite_test.go index 4c2a4f02d..78c622b8c 100644 --- a/cmd/cmd_suite_test.go +++ b/cmd/cmd_suite_test.go @@ -1,11 +1,14 @@ package cmd_test import ( + "io/ioutil" + "net/http" "testing" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" + "github.com/onsi/gomega/ghttp" ) var pathCLI string @@ -24,3 +27,27 @@ func TestCmd(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Cmd Suite") } + +// Test helpers + +func appendPostHandler(server *ghttp.Server, authToken string, statusCode int, expectedRequestJson string, responseBody string) { + server.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest("POST", "/"), + ghttp.VerifyHeader(http.Header{ + "Authorization": []string{authToken}, + }), + ghttp.VerifyContentType("application/json; charset=utf-8"), + // From Gomegas ghttp.VerifyJson to avoid the + // VerifyContentType("application/json") check + // that fails with "application/json; charset=utf-8" + func(w http.ResponseWriter, req *http.Request) { + body, err := ioutil.ReadAll(req.Body) + req.Body.Close() + Expect(err).ShouldNot(HaveOccurred()) + Expect(body).Should(MatchJSON(expectedRequestJson), "JSON Mismatch") + }, + ghttp.RespondWith(statusCode, `{ "data": `+responseBody+`}`), + ), + ) +} diff --git a/cmd/config_test.go b/cmd/config_test.go index d5f07adf9..5f1b1fc39 100644 --- a/cmd/config_test.go +++ b/cmd/config_test.go @@ -14,28 +14,6 @@ import ( "github.com/onsi/gomega/ghttp" ) -func appendPostHandler(server *ghttp.Server, authToken string, statusCode int, expectedRequestJson string, responseBody string) { - server.AppendHandlers( - ghttp.CombineHandlers( - ghttp.VerifyRequest("POST", "/"), - ghttp.VerifyHeader(http.Header{ - "Authorization": []string{authToken}, - }), - ghttp.VerifyContentType("application/json; charset=utf-8"), - // From Gomegas ghttp.VerifyJson to avoid the - // VerifyContentType("application/json") check - // that fails with "application/json; charset=utf-8" - func(w http.ResponseWriter, req *http.Request) { - body, err := ioutil.ReadAll(req.Body) - req.Body.Close() - Expect(err).ShouldNot(HaveOccurred()) - Expect(body).Should(MatchJSON(expectedRequestJson), "JSON Mismatch") - }, - ghttp.RespondWith(statusCode, `{ "data": `+responseBody+`}`), - ), - ) -} - type configYaml struct { TempHome string Path string From d5fe937a9191a08c81f3976445cfb4de3f9412e7 Mon Sep 17 00:00:00 2001 From: Brady Lill Date: Fri, 29 Jun 2018 09:37:44 -0600 Subject: [PATCH 7/8] Pulling tmp file management out into cmd test helpers --- cmd/cmd_suite_test.go | 53 ++++++++++++++++++++++++++++++++++++ cmd/config_test.go | 62 +++++-------------------------------------- cmd/orb_test.go | 62 +++++-------------------------------------- 3 files changed, 67 insertions(+), 110 deletions(-) diff --git a/cmd/cmd_suite_test.go b/cmd/cmd_suite_test.go index 78c622b8c..7ad0862f2 100644 --- a/cmd/cmd_suite_test.go +++ b/cmd/cmd_suite_test.go @@ -3,6 +3,8 @@ package cmd_test import ( "io/ioutil" "net/http" + "os" + "path/filepath" "testing" . "github.com/onsi/ginkgo" @@ -51,3 +53,54 @@ func appendPostHandler(server *ghttp.Server, authToken string, statusCode int, e ), ) } + +type tmpFile struct { + RootDir string + Path string + File *os.File +} + +func (f tmpFile) close() { + f.File.Close() + os.RemoveAll(f.RootDir) +} + +func (f tmpFile) write(fileContent string) error { + _, err := f.File.Write([]byte(fileContent)) + + return err +} + +func openTmpFile(path string) (tmpFile, error) { + var ( + config tmpFile = tmpFile{} + err error + ) + + tmpDir, err := ioutil.TempDir("", "circleci-cli-test-") + if err != nil { + return config, err + } + + config.RootDir = tmpDir + config.Path = filepath.Join(tmpDir, path) + + err = os.MkdirAll(filepath.Dir(config.Path), 0700) + if err != nil { + return config, err + } + + var file *os.File + file, err = os.OpenFile( + config.Path, + os.O_RDWR|os.O_CREATE, + 0600, + ) + if err != nil { + return config, err + } + + config.File = file + + return config, nil +} diff --git a/cmd/config_test.go b/cmd/config_test.go index 5f1b1fc39..ad7636f16 100644 --- a/cmd/config_test.go +++ b/cmd/config_test.go @@ -1,9 +1,7 @@ package cmd_test import ( - "io/ioutil" "net/http" - "os" "os/exec" "path/filepath" @@ -14,69 +12,23 @@ import ( "github.com/onsi/gomega/ghttp" ) -type configYaml struct { - TempHome string - Path string - YamlFile *os.File -} - -func openConfigYaml() (configYaml, error) { - var ( - config configYaml = configYaml{} - err error - ) - - const ( - configDir = ".circleci" - configFile = "config.yaml" - ) - - tempHome, err := ioutil.TempDir("", "circleci-cli-test-") - if err != nil { - return config, err - } - - err = os.Mkdir(filepath.Join(tempHome, configDir), 0700) - if err != nil { - return config, err - } - - config.Path = filepath.Join(tempHome, configDir, configFile) - - var file *os.File - file, err = os.OpenFile( - config.Path, - os.O_RDWR|os.O_CREATE, - 0600, - ) - if err != nil { - return config, err - } - - config.YamlFile = file - - return config, nil -} - var _ = Describe("Config", func() { Describe("with an api and config.yml", func() { var ( testServer *ghttp.Server - config configYaml + config tmpFile ) BeforeEach(func() { var err error - config, err = openConfigYaml() + config, err = openTmpFile(filepath.Join(".circleci", "config.yaml")) Expect(err).ToNot(HaveOccurred()) testServer = ghttp.NewServer() }) AfterEach(func() { - config.YamlFile.Close() - os.RemoveAll(config.TempHome) - + config.close() testServer.Close() }) @@ -97,7 +49,7 @@ var _ = Describe("Config", func() { }) It("works", func() { - _, err := config.YamlFile.Write([]byte(`some config`)) + err := config.write(`some config`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ @@ -125,7 +77,7 @@ var _ = Describe("Config", func() { }) It("prints errors if invalid", func() { - _, err := config.YamlFile.Write([]byte(`some config`)) + err := config.write(`some config`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ @@ -173,7 +125,7 @@ var _ = Describe("Config", func() { }) It("works", func() { - _, err := config.YamlFile.Write([]byte(`some config`)) + err := config.write(`some config`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ @@ -201,7 +153,7 @@ var _ = Describe("Config", func() { }) It("prints errors if invalid", func() { - _, err := config.YamlFile.Write([]byte(`some config`)) + err := config.write(`some config`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ diff --git a/cmd/orb_test.go b/cmd/orb_test.go index 02817d652..a1615587a 100644 --- a/cmd/orb_test.go +++ b/cmd/orb_test.go @@ -1,9 +1,7 @@ package cmd_test import ( - "io/ioutil" "net/http" - "os" "os/exec" "path/filepath" @@ -14,69 +12,23 @@ import ( "github.com/onsi/gomega/ghttp" ) -type orbYaml struct { - TempHome string - Path string - YamlFile *os.File -} - -func openOrbYaml() (orbYaml, error) { - var ( - orb orbYaml = orbYaml{} - err error - ) - - const ( - orbDir = "myorb" - orbFile = "orb.yml" - ) - - tempHome, err := ioutil.TempDir("", "circleci-cli-test-") - if err != nil { - return orb, err - } - - err = os.Mkdir(filepath.Join(tempHome, orbDir), 0700) - if err != nil { - return orb, err - } - - orb.Path = filepath.Join(tempHome, orbDir, orbFile) - - var file *os.File - file, err = os.OpenFile( - orb.Path, - os.O_RDWR|os.O_CREATE, - 0600, - ) - if err != nil { - return orb, err - } - - orb.YamlFile = file - - return orb, nil -} - var _ = Describe("Orb", func() { Describe("with an api and orb.yml", func() { var ( testServer *ghttp.Server - orb orbYaml + orb tmpFile ) BeforeEach(func() { var err error - orb, err = openOrbYaml() + orb, err = openTmpFile(filepath.Join("myorb", "orb.yml")) Expect(err).ToNot(HaveOccurred()) testServer = ghttp.NewServer() }) AfterEach(func() { - orb.YamlFile.Close() - os.RemoveAll(orb.TempHome) - + orb.close() testServer.Close() }) @@ -98,7 +50,7 @@ var _ = Describe("Orb", func() { It("works", func() { By("setting up a mock server") - _, err := orb.YamlFile.Write([]byte(`{}`)) + err := orb.write(`{}`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ @@ -129,7 +81,7 @@ var _ = Describe("Orb", func() { It("prints errors if invalid", func() { By("setting up a mock server") - _, err := orb.YamlFile.Write([]byte(`some orb`)) + err := orb.write(`some orb`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ @@ -178,7 +130,7 @@ var _ = Describe("Orb", func() { It("works", func() { By("setting up a mock server") - _, err := orb.YamlFile.Write([]byte(`some orb`)) + err := orb.write(`some orb`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ @@ -208,7 +160,7 @@ var _ = Describe("Orb", func() { It("prints errors if invalid", func() { By("setting up a mock server") - _, err := orb.YamlFile.Write([]byte(`some orb`)) + err := orb.write(`some orb`) Expect(err).ToNot(HaveOccurred()) gqlResponse := `{ From 8dcb8870f96428676847bfd7e0c08ba54223c111 Mon Sep 17 00:00:00 2001 From: Brady Lill Date: Fri, 29 Jun 2018 09:51:53 -0600 Subject: [PATCH 8/8] Removing debug code. --- cmd/orb.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cmd/orb.go b/cmd/orb.go index 9d044676b..e6c2359cb 100644 --- a/cmd/orb.go +++ b/cmd/orb.go @@ -3,9 +3,7 @@ package cmd import ( "bytes" "context" - "fmt" "io/ioutil" - "os" "github.com/CircleCI-Public/circleci-cli/client" "github.com/pkg/errors" @@ -138,9 +136,6 @@ func loadOrbYaml(path string) (string, error) { orb, err := ioutil.ReadFile(path) - fmt.Fprintln(os.Stderr, "******************** orb.go") - fmt.Fprintln(os.Stderr, path) - fmt.Fprintln(os.Stderr, err) if err != nil { return "", errors.Wrapf(err, "Could not load orb file at %s", path) } @@ -148,7 +143,6 @@ func loadOrbYaml(path string) (string, error) { return string(orb), nil } - func (response orbConfigResponse) processErrors() error { var buffer bytes.Buffer