diff --git a/cf-plugin/cmd/allow_ssh.go b/cf-plugin/cmd/allow_ssh.go index 6c61d3f..db2b295 100644 --- a/cf-plugin/cmd/allow_ssh.go +++ b/cf-plugin/cmd/allow_ssh.go @@ -2,17 +2,15 @@ package cmd import ( "fmt" - "io" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/space" ) const AllowSSHUsage = "cf allow-space-ssh SPACE_NAME" -func AllowSSH(args []string, spaceFactory space.SpaceFactory, output io.Writer) error { +func AllowSSH(args []string, spaceFactory space.SpaceFactory) error { if len(args) != 2 || args[0] != "allow-space-ssh" { - fmt.Fprintf(output, "FAILED\n\n%s\n%s", "Invalid usage", AllowSSHUsage) - return nil + return fmt.Errorf("%s\n%s", "Invalid usage", AllowSSHUsage) } space, err := spaceFactory.Get(args[1]) diff --git a/cf-plugin/cmd/allow_ssh_test.go b/cf-plugin/cmd/allow_ssh_test.go index 2ca8d6e..be425b8 100644 --- a/cf-plugin/cmd/allow_ssh_test.go +++ b/cf-plugin/cmd/allow_ssh_test.go @@ -1,7 +1,6 @@ package cmd_test import ( - "bytes" "errors" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/cmd" @@ -23,26 +22,21 @@ var _ = Describe("AllowSSH", func() { Context("validation", func() { It("requires an space name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.AllowSSH([]string{"allow-space-ssh"}, fakeSpaceFactory, writer) + err := cmd.AllowSSH([]string{"allow-space-ssh"}, fakeSpaceFactory) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.AllowSSHUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.AllowSSHUsage)) }) It("validates the command name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.AllowSSH([]string{"bogus", "space"}, fakeSpaceFactory, writer) - - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.AllowSSHUsage)) + err := cmd.AllowSSH([]string{"bogus", "space"}, fakeSpaceFactory) + Expect(err).To(MatchError("Invalid usage\n" + cmd.AllowSSHUsage)) }) }) It("allows SSH on an space endpoint", func() { fakeSpaceFactory.GetReturns(mySpace, nil) - err := cmd.AllowSSH([]string{"allow-space-ssh", "myspace"}, fakeSpaceFactory, nil) + err := cmd.AllowSSH([]string{"allow-space-ssh", "myspace"}, fakeSpaceFactory) Expect(err).NotTo(HaveOccurred()) Expect(fakeSpaceFactory.GetCallCount()).To(Equal(1)) @@ -61,7 +55,7 @@ var _ = Describe("AllowSSH", func() { }) It("returns an err", func() { - err := cmd.AllowSSH([]string{"allow-space-ssh", "myspace"}, fakeSpaceFactory, nil) + err := cmd.AllowSSH([]string{"allow-space-ssh", "myspace"}, fakeSpaceFactory) Expect(err).To(MatchError("get failed")) Expect(fakeSpaceFactory.GetCallCount()).To(Equal(1)) Expect(fakeSpaceFactory.SetBoolCallCount()).To(Equal(0)) @@ -75,7 +69,7 @@ var _ = Describe("AllowSSH", func() { }) It("returns an err", func() { - err := cmd.AllowSSH([]string{"allow-space-ssh", "myspace"}, fakeSpaceFactory, nil) + err := cmd.AllowSSH([]string{"allow-space-ssh", "myspace"}, fakeSpaceFactory) Expect(err).To(MatchError("set failed")) Expect(fakeSpaceFactory.GetCallCount()).To(Equal(1)) Expect(fakeSpaceFactory.SetBoolCallCount()).To(Equal(1)) diff --git a/cf-plugin/cmd/disable_ssh.go b/cf-plugin/cmd/disable_ssh.go index 0dc25f0..4d3db93 100644 --- a/cf-plugin/cmd/disable_ssh.go +++ b/cf-plugin/cmd/disable_ssh.go @@ -2,17 +2,15 @@ package cmd import ( "fmt" - "io" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/app" ) const DisableSSHUsage = "cf disable-ssh APP_NAME" -func DisableSSH(args []string, appFactory app.AppFactory, output io.Writer) error { +func DisableSSH(args []string, appFactory app.AppFactory) error { if len(args) != 2 || args[0] != "disable-ssh" { - fmt.Fprintf(output, "FAILED\n\n%s\n%s", "Invalid usage", DisableSSHUsage) - return nil + return fmt.Errorf("%s\n%s", "Invalid usage", DisableSSHUsage) } app, err := appFactory.Get(args[1]) diff --git a/cf-plugin/cmd/disable_ssh_test.go b/cf-plugin/cmd/disable_ssh_test.go index 478f90f..b9a5b5d 100644 --- a/cf-plugin/cmd/disable_ssh_test.go +++ b/cf-plugin/cmd/disable_ssh_test.go @@ -1,7 +1,6 @@ package cmd_test import ( - "bytes" "errors" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/cmd" @@ -23,26 +22,22 @@ var _ = Describe("DisableSsh", func() { Context("validation", func() { It("requires an application name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.DisableSSH([]string{"disable-ssh"}, fakeAppFactory, writer) + err := cmd.DisableSSH([]string{"disable-ssh"}, fakeAppFactory) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.DisableSSHUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.DisableSSHUsage)) }) It("validates the command name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.DisableSSH([]string{"disable-ss", "app"}, fakeAppFactory, writer) + err := cmd.DisableSSH([]string{"disable-ss", "app"}, fakeAppFactory) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.DisableSSHUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.DisableSSHUsage)) }) }) It("disables SSH on an app endpoint", func() { fakeAppFactory.GetReturns(myApp, nil) - err := cmd.DisableSSH([]string{"disable-ssh", "myapp"}, fakeAppFactory, nil) + err := cmd.DisableSSH([]string{"disable-ssh", "myapp"}, fakeAppFactory) Expect(err).NotTo(HaveOccurred()) Expect(fakeAppFactory.GetCallCount()).To(Equal(1)) @@ -61,7 +56,7 @@ var _ = Describe("DisableSsh", func() { }) It("returns an err", func() { - err := cmd.DisableSSH([]string{"disable-ssh", "myapp"}, fakeAppFactory, nil) + err := cmd.DisableSSH([]string{"disable-ssh", "myapp"}, fakeAppFactory) Expect(err).To(MatchError("get failed")) Expect(fakeAppFactory.GetCallCount()).To(Equal(1)) Expect(fakeAppFactory.SetBoolCallCount()).To(Equal(0)) @@ -75,7 +70,7 @@ var _ = Describe("DisableSsh", func() { }) It("returns an err", func() { - err := cmd.DisableSSH([]string{"disable-ssh", "myapp"}, fakeAppFactory, nil) + err := cmd.DisableSSH([]string{"disable-ssh", "myapp"}, fakeAppFactory) Expect(err).To(MatchError("set failed")) Expect(fakeAppFactory.GetCallCount()).To(Equal(1)) Expect(fakeAppFactory.SetBoolCallCount()).To(Equal(1)) diff --git a/cf-plugin/cmd/disallow_ssh.go b/cf-plugin/cmd/disallow_ssh.go index 6e93638..9874be9 100644 --- a/cf-plugin/cmd/disallow_ssh.go +++ b/cf-plugin/cmd/disallow_ssh.go @@ -2,17 +2,15 @@ package cmd import ( "fmt" - "io" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/space" ) const DisallowSSHUsage = "cf disallow-space-ssh SPACE_NAME" -func DisallowSSH(args []string, spaceFactory space.SpaceFactory, output io.Writer) error { +func DisallowSSH(args []string, spaceFactory space.SpaceFactory) error { if len(args) != 2 || args[0] != "disallow-space-ssh" { - fmt.Fprintf(output, "FAILED\n\n%s\n%s", "Invalid usage", DisallowSSHUsage) - return nil + return fmt.Errorf("%s\n%s", "Invalid usage", DisallowSSHUsage) } space, err := spaceFactory.Get(args[1]) diff --git a/cf-plugin/cmd/disallow_ssh_test.go b/cf-plugin/cmd/disallow_ssh_test.go index 0b3b682..c0f010d 100644 --- a/cf-plugin/cmd/disallow_ssh_test.go +++ b/cf-plugin/cmd/disallow_ssh_test.go @@ -1,7 +1,6 @@ package cmd_test import ( - "bytes" "errors" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/cmd" @@ -23,26 +22,22 @@ var _ = Describe("DisallowSSH", func() { Context("validation", func() { It("requires an space name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.DisallowSSH([]string{"disallow-space-ssh"}, fakeSpaceFactory, writer) + err := cmd.DisallowSSH([]string{"disallow-space-ssh"}, fakeSpaceFactory) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.DisallowSSHUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.DisallowSSHUsage)) }) It("validates the command name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.DisallowSSH([]string{"bogus", "space"}, fakeSpaceFactory, writer) + err := cmd.DisallowSSH([]string{"bogus", "space"}, fakeSpaceFactory) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.DisallowSSHUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.DisallowSSHUsage)) }) }) It("disallows SSH on an space endpoint", func() { fakeSpaceFactory.GetReturns(mySpace, nil) - err := cmd.DisallowSSH([]string{"disallow-space-ssh", "myspace"}, fakeSpaceFactory, nil) + err := cmd.DisallowSSH([]string{"disallow-space-ssh", "myspace"}, fakeSpaceFactory) Expect(err).NotTo(HaveOccurred()) Expect(fakeSpaceFactory.GetCallCount()).To(Equal(1)) @@ -61,7 +56,7 @@ var _ = Describe("DisallowSSH", func() { }) It("returns an err", func() { - err := cmd.DisallowSSH([]string{"disallow-space-ssh", "myspace"}, fakeSpaceFactory, nil) + err := cmd.DisallowSSH([]string{"disallow-space-ssh", "myspace"}, fakeSpaceFactory) Expect(err).To(MatchError("get failed")) Expect(fakeSpaceFactory.GetCallCount()).To(Equal(1)) Expect(fakeSpaceFactory.SetBoolCallCount()).To(Equal(0)) @@ -75,7 +70,7 @@ var _ = Describe("DisallowSSH", func() { }) It("returns an err", func() { - err := cmd.DisallowSSH([]string{"disallow-space-ssh", "myspace"}, fakeSpaceFactory, nil) + err := cmd.DisallowSSH([]string{"disallow-space-ssh", "myspace"}, fakeSpaceFactory) Expect(err).To(MatchError("set failed")) Expect(fakeSpaceFactory.GetCallCount()).To(Equal(1)) Expect(fakeSpaceFactory.SetBoolCallCount()).To(Equal(1)) diff --git a/cf-plugin/cmd/enable_ssh.go b/cf-plugin/cmd/enable_ssh.go index 2f37c3e..c7816a7 100644 --- a/cf-plugin/cmd/enable_ssh.go +++ b/cf-plugin/cmd/enable_ssh.go @@ -2,17 +2,15 @@ package cmd import ( "fmt" - "io" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/app" ) const EnableSSHUsage = "cf enable-ssh APP_NAME" -func EnableSSH(args []string, appFactory app.AppFactory, output io.Writer) error { +func EnableSSH(args []string, appFactory app.AppFactory) error { if len(args) != 2 || args[0] != "enable-ssh" { - fmt.Fprintf(output, "FAILED\n\n%s\n%s", "Invalid usage", EnableSSHUsage) - return nil + return fmt.Errorf("%s\n%s", "Invalid usage", EnableSSHUsage) } app, err := appFactory.Get(args[1]) diff --git a/cf-plugin/cmd/enable_ssh_test.go b/cf-plugin/cmd/enable_ssh_test.go index 2c5fe76..a92f627 100644 --- a/cf-plugin/cmd/enable_ssh_test.go +++ b/cf-plugin/cmd/enable_ssh_test.go @@ -1,7 +1,6 @@ package cmd_test import ( - "bytes" "errors" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/cmd" @@ -23,26 +22,22 @@ var _ = Describe("EnableSsh", func() { Context("validation", func() { It("requires an application name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.EnableSSH([]string{"enable-ssh"}, fakeAppFactory, writer) + err := cmd.EnableSSH([]string{"enable-ssh"}, fakeAppFactory) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.EnableSSHUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.EnableSSHUsage)) }) It("validates the command name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.EnableSSH([]string{"enable-ss", "app"}, fakeAppFactory, writer) + err := cmd.EnableSSH([]string{"enable-ss", "app"}, fakeAppFactory) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.EnableSSHUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.EnableSSHUsage)) }) }) It("enables SSH on an app endpoint", func() { fakeAppFactory.GetReturns(myApp, nil) - err := cmd.EnableSSH([]string{"enable-ssh", "myapp"}, fakeAppFactory, nil) + err := cmd.EnableSSH([]string{"enable-ssh", "myapp"}, fakeAppFactory) Expect(err).NotTo(HaveOccurred()) Expect(fakeAppFactory.GetCallCount()).To(Equal(1)) @@ -61,7 +56,7 @@ var _ = Describe("EnableSsh", func() { }) It("returns an err", func() { - err := cmd.EnableSSH([]string{"enable-ssh", "myapp"}, fakeAppFactory, nil) + err := cmd.EnableSSH([]string{"enable-ssh", "myapp"}, fakeAppFactory) Expect(err).To(MatchError("get failed")) Expect(fakeAppFactory.GetCallCount()).To(Equal(1)) Expect(fakeAppFactory.SetBoolCallCount()).To(Equal(0)) @@ -75,7 +70,7 @@ var _ = Describe("EnableSsh", func() { }) It("returns an err", func() { - err := cmd.EnableSSH([]string{"enable-ssh", "myapp"}, fakeAppFactory, nil) + err := cmd.EnableSSH([]string{"enable-ssh", "myapp"}, fakeAppFactory) Expect(err).To(MatchError("set failed")) Expect(fakeAppFactory.GetCallCount()).To(Equal(1)) Expect(fakeAppFactory.SetBoolCallCount()).To(Equal(1)) diff --git a/cf-plugin/cmd/ssh_allowed.go b/cf-plugin/cmd/ssh_allowed.go index e83af1e..7ad8dff 100644 --- a/cf-plugin/cmd/ssh_allowed.go +++ b/cf-plugin/cmd/ssh_allowed.go @@ -11,8 +11,7 @@ const SSHAllowedUsage = "cf space-ssh-allowed SPACE_NAME" func SSHAllowed(args []string, spaceFactory space.SpaceFactory, output io.Writer) error { if len(args) != 2 || args[0] != "space-ssh-allowed" { - fmt.Fprintf(output, "FAILED\n\n%s\n%s", "Invalid usage", SSHAllowedUsage) - return nil + return fmt.Errorf("%s\n%s", "Invalid usage", SSHAllowedUsage) } space, err := spaceFactory.Get(args[1]) diff --git a/cf-plugin/cmd/ssh_allowed_test.go b/cf-plugin/cmd/ssh_allowed_test.go index 163d892..15aa923 100644 --- a/cf-plugin/cmd/ssh_allowed_test.go +++ b/cf-plugin/cmd/ssh_allowed_test.go @@ -23,19 +23,15 @@ var _ = Describe("SSHAllowed", func() { Context("validation", func() { It("requires an spacelication name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.SSHAllowed([]string{"space-ssh-allowed"}, fakeSpaceFactory, writer) + err := cmd.SSHAllowed([]string{"space-ssh-allowed"}, fakeSpaceFactory, nil) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.SSHAllowedUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.SSHAllowedUsage)) }) It("validates the command name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.SSHAllowed([]string{"bogus", "space"}, fakeSpaceFactory, writer) + err := cmd.SSHAllowed([]string{"bogus", "space"}, fakeSpaceFactory, nil) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.SSHAllowedUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.SSHAllowedUsage)) }) }) diff --git a/cf-plugin/cmd/ssh_enabled.go b/cf-plugin/cmd/ssh_enabled.go index f59f52d..39a9419 100644 --- a/cf-plugin/cmd/ssh_enabled.go +++ b/cf-plugin/cmd/ssh_enabled.go @@ -11,8 +11,7 @@ const SSHEnabledUsage = "cf ssh-enabled APP_NAME" func SSHEnabled(args []string, appFactory app.AppFactory, output io.Writer) error { if len(args) != 2 || args[0] != "ssh-enabled" { - fmt.Fprintf(output, "FAILED\n\n%s\n%s", "Invalid usage", SSHEnabledUsage) - return nil + return fmt.Errorf("%s\n%s", "Invalid usage", SSHEnabledUsage) } app, err := appFactory.Get(args[1]) diff --git a/cf-plugin/cmd/ssh_enabled_test.go b/cf-plugin/cmd/ssh_enabled_test.go index 60d5527..05c0a8a 100644 --- a/cf-plugin/cmd/ssh_enabled_test.go +++ b/cf-plugin/cmd/ssh_enabled_test.go @@ -23,19 +23,15 @@ var _ = Describe("SSHEnabled", func() { Context("validation", func() { It("requires an application name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.SSHEnabled([]string{"ssh-enabled"}, fakeAppFactory, writer) + err := cmd.SSHEnabled([]string{"ssh-enabled"}, fakeAppFactory, nil) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.SSHEnabledUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.SSHEnabledUsage)) }) It("validates the command name", func() { - writer := bytes.NewBuffer(nil) - err := cmd.SSHEnabled([]string{"ssh-enable", "app"}, fakeAppFactory, writer) + err := cmd.SSHEnabled([]string{"ssh-enable", "app"}, fakeAppFactory, nil) - Expect(err).NotTo(HaveOccurred()) - Expect(writer.String()).To(Equal("FAILED\n\nInvalid usage\n" + cmd.SSHEnabledUsage)) + Expect(err).To(MatchError("Invalid usage\n" + cmd.SSHEnabledUsage)) }) }) diff --git a/cf-plugin/main.go b/cf-plugin/main.go new file mode 100644 index 0000000..940c8eb --- /dev/null +++ b/cf-plugin/main.go @@ -0,0 +1,8 @@ +package main + +import "github.com/cloudfoundry/cli/plugin" + +func main() { + sshPlugin := &SSHPlugin{} + plugin.Start(sshPlugin) +} diff --git a/cf-plugin/models/app/app.go b/cf-plugin/models/app/app.go index 3bcf9a0..af3f054 100644 --- a/cf-plugin/models/app/app.go +++ b/cf-plugin/models/app/app.go @@ -1,11 +1,11 @@ package app import ( - "encoding/json" "errors" "strconv" "strings" + "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models" "github.com/cloudfoundry/cli/plugin" ) @@ -16,11 +16,12 @@ type AppFactory interface { } type appFactory struct { - cli plugin.CliConnection + cli plugin.CliConnection + curl models.Curler } -func NewAppFactory(cli plugin.CliConnection) AppFactory { - return &appFactory{cli: cli} +func NewAppFactory(cli plugin.CliConnection, curl models.Curler) AppFactory { + return &appFactory{cli: cli, curl: curl} } type App struct { @@ -40,7 +41,7 @@ type entity struct { State string `json:"state"` } -type cfApp struct { +type CFApp struct { Metadata metadata `json:"metadata"` Entity entity `json:"entity"` } @@ -53,34 +54,20 @@ func (af *appFactory) Get(appName string) (App, error) { guid := strings.TrimSpace(output[0]) - output, err = af.cli.CliCommandWithoutTerminalOutput("curl", "/v2/apps/"+guid) + app := CFApp{} + err = af.curl(af.cli, &app, "/v2/apps/"+guid) if err != nil { return App{}, errors.New("Failed to acquire " + appName + " info") } - response := []byte(output[0]) - app := cfApp{} - - err = json.Unmarshal(response, &app) - if err != nil { - return App{}, err - } - return App{ Guid: app.Metadata.Guid, EnableSSH: app.Entity.EnableSSH, Diego: app.Entity.Diego, State: app.Entity.State, }, nil - - return App{}, nil } func (af *appFactory) SetBool(anApp App, key string, value bool) error { - output, err := af.cli.CliCommandWithoutTerminalOutput("curl", "/v2/apps/"+anApp.Guid, "-X", "PUT", "-d", `{"`+key+`":`+strconv.FormatBool(value)+`}`) - if err != nil { - return errors.New(output[len(output)-1]) - } - - return nil + return af.curl(af.cli, nil, "/v2/apps/"+anApp.Guid, "-X", "PUT", "-d", `{"`+key+`":`+strconv.FormatBool(value)+`}`) } diff --git a/cf-plugin/models/app/app_test.go b/cf-plugin/models/app/app_test.go index 0041992..25bbb13 100644 --- a/cf-plugin/models/app/app_test.go +++ b/cf-plugin/models/app/app_test.go @@ -3,7 +3,9 @@ package app_test import ( "errors" + "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/app" + "github.com/cloudfoundry/cli/plugin" "github.com/cloudfoundry/cli/plugin/fakes" . "github.com/onsi/ginkgo" @@ -13,114 +15,64 @@ import ( var _ = Describe("App", func() { var ( fakeCliConnection *fakes.FakeCliConnection + curler models.Curler af app.AppFactory ) BeforeEach(func() { fakeCliConnection = &fakes.FakeCliConnection{} - af = app.NewAppFactory(fakeCliConnection) + }) + + JustBeforeEach(func() { + af = app.NewAppFactory(fakeCliConnection, curler) }) Describe("Get", func() { - Context("when CC returns a valid response", func() { + Context("when CC returns a valid app guid", func() { BeforeEach(func() { - expectedJson := `{ - "metadata": { - "guid": "app1-guid" - }, - "entity": { - "instances": 1, - "state": "STARTED", - "diego": true, - "enable_ssh": true - } - }` - fakeCliConnection.CliCommandWithoutTerminalOutputStub = func(args ...string) ([]string, error) { - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 1 { - Expect(args).To(ConsistOf("app", "app1", "--guid")) - return []string{"app1-guid\n"}, nil - } - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 2 { - Expect(args).To(ConsistOf("curl", "/v2/apps/app1-guid")) - return []string{expectedJson}, nil - } - Expect(false).To(BeTrue()) - return []string{}, nil + Expect(args).To(ConsistOf("app", "app1", "--guid")) + return []string{"app1-guid\n"}, nil } }) - It("returns a populated App model", func() { - model, err := af.Get("app1") - - Expect(err).NotTo(HaveOccurred()) - Expect(model.Guid).To(Equal("app1-guid")) - Expect(model.EnableSSH).To(BeTrue()) - Expect(model.Diego).To(BeTrue()) - Expect(model.State).To(Equal("STARTED")) - }) - }) + Context("when an App is returned", func() { + BeforeEach(func() { + curler = func(cli plugin.CliConnection, result interface{}, args ...string) error { + a, ok := result.(*app.CFApp) + Expect(ok).To(BeTrue()) + a.Metadata.Guid = "app1-guid" + a.Entity.EnableSSH = true + a.Entity.Diego = true + a.Entity.State = "STARTED" + return nil + } + }) - Context("when the app does not exist", func() { - BeforeEach(func() { - fakeCliConnection.CliCommandWithoutTerminalOutputReturns( - []string{"FAILED", "App app1 is not found"}, - errors.New("Error executing cli core command"), - ) - }) + It("returns a populated App model", func() { + model, err := af.Get("app1") - It("returns 'App not found' error", func() { - _, err := af.Get("app1") - Expect(err).To(MatchError("App app1 is not found")) - - Expect(fakeCliConnection.CliCommandWithoutTerminalOutputCallCount()).To(Equal(1)) - args := fakeCliConnection.CliCommandWithoutTerminalOutputArgsForCall(0) - Expect(args).To(ConsistOf("app", "app1", "--guid")) + Expect(err).NotTo(HaveOccurred()) + Expect(model.Guid).To(Equal("app1-guid")) + Expect(model.EnableSSH).To(BeTrue()) + Expect(model.Diego).To(BeTrue()) + Expect(model.State).To(Equal("STARTED")) + }) }) - }) - Context("when curling the app model fails", func() { - Context("when CC returns a valid response", func() { + Context("when curling the App fails", func() { BeforeEach(func() { - fakeCliConnection.CliCommandWithoutTerminalOutputStub = func(args ...string) ([]string, error) { - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 1 { - Expect(args).To(ConsistOf("app", "app1", "--guid")) - return []string{"app1-guid\n"}, nil - } - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 2 { - Expect(args).To(ConsistOf("curl", "/v2/apps/app1-guid")) - return []string{"{}"}, errors.New("Failed to acquire app1 info") - } - Expect(false).To(BeTrue()) - return []string{}, nil + curler = func(cli plugin.CliConnection, result interface{}, args ...string) error { + return errors.New("not good") } }) - It("returns 'fail to acquire app info' error", func() { + It("returns an error", func() { _, err := af.Get("app1") - Expect(err).To(MatchError("Failed to acquire app1 info")) }) }) }) - }) - - Describe("SetBool", func() { - var anApp app.App - - BeforeEach(func() { - anApp = app.App{ - Guid: "myguid", - } - }) - - It("it sends a cli command", func() { - af.SetBool(anApp, "foobar", true) - - Expect(fakeCliConnection.CliCommandWithoutTerminalOutputCallCount()).To(Equal(1)) - args := fakeCliConnection.CliCommandWithoutTerminalOutputArgsForCall(0) - Expect(args).To(Equal([]string{"curl", "/v2/apps/myguid", "-X", "PUT", "-d", `{"foobar":true}`})) - }) Context("when the app does not exist", func() { BeforeEach(func() { @@ -131,8 +83,12 @@ var _ = Describe("App", func() { }) It("returns 'App not found' error", func() { - err := af.SetBool(anApp, "foobar", true) + _, err := af.Get("app1") Expect(err).To(MatchError("App app1 is not found")) + + Expect(fakeCliConnection.CliCommandWithoutTerminalOutputCallCount()).To(Equal(1)) + args := fakeCliConnection.CliCommandWithoutTerminalOutputArgsForCall(0) + Expect(args).To(ConsistOf("app", "app1", "--guid")) }) }) }) diff --git a/cf-plugin/models/curl.go b/cf-plugin/models/curl.go new file mode 100644 index 0000000..f84fd26 --- /dev/null +++ b/cf-plugin/models/curl.go @@ -0,0 +1,45 @@ +package models + +import ( + "encoding/json" + "errors" + "strings" + + "github.com/cloudfoundry/cli/plugin" +) + +type curlError struct { + Code int `json:"code"` + Description string `json:"description"` + ErrorCode string `json:"error_code"` +} + +type Curler func(cli plugin.CliConnection, result interface{}, args ...string) error + +func Curl(cli plugin.CliConnection, result interface{}, args ...string) error { + output, err := cli.CliCommandWithoutTerminalOutput(append([]string{"curl"}, args...)...) + if err != nil { + return err + } + + buf := []byte(strings.Join(output, "\n")) + + var errorResponse curlError + err = json.Unmarshal(buf, &errorResponse) + if err != nil { + return err + } + + if errorResponse.Code != 0 { + return errors.New(errorResponse.Description) + } + + if result != nil { + err = json.Unmarshal(buf, result) + if err != nil { + return err + } + } + + return nil +} diff --git a/cf-plugin/models/curl_test.go b/cf-plugin/models/curl_test.go new file mode 100644 index 0000000..0b8ab46 --- /dev/null +++ b/cf-plugin/models/curl_test.go @@ -0,0 +1,79 @@ +package models_test + +import ( + "encoding/json" + "errors" + + . "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models" + "github.com/cloudfoundry/cli/plugin/fakes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Curl", func() { + var fakeCliConnection *fakes.FakeCliConnection + + BeforeEach(func() { + fakeCliConnection = &fakes.FakeCliConnection{} + }) + + Context("with a valid response", func() { + type MyStruct struct { + SomeString string + } + + BeforeEach(func() { + input := []string{"{", `"somestring": "foo"`, "}"} + fakeCliConnection.CliCommandWithoutTerminalOutputReturns(input, nil) + }) + + It("unmarshals a successful response", func() { + var result MyStruct + err := Curl(fakeCliConnection, &result, "a", "b", "c") + Expect(err).NotTo(HaveOccurred()) + Expect(result.SomeString).To(Equal("foo")) + + Expect(fakeCliConnection.CliCommandWithoutTerminalOutputCallCount()).To(Equal(1)) + Expect(fakeCliConnection.CliCommandWithoutTerminalOutputArgsForCall(0)).To(Equal([]string{"curl", "a", "b", "c"})) + }) + + It("succeeds with no response object", func() { + err := Curl(fakeCliConnection, nil, "a", "b", "c") + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Context("when the cli errors", func() { + BeforeEach(func() { + fakeCliConnection.CliCommandWithoutTerminalOutputReturns(nil, errors.New("an error")) + }) + + It("returns an error", func() { + err := Curl(fakeCliConnection, nil, "a", "b", "c") + Expect(err).To(MatchError("an error")) + }) + }) + + Context("when the response cannot be unmarshalled", func() { + BeforeEach(func() { + fakeCliConnection.CliCommandWithoutTerminalOutputReturns([]string{"abcd"}, nil) + }) + + It("returns an error", func() { + err := Curl(fakeCliConnection, nil, "a", "b", "c") + Expect(err).To(BeAssignableToTypeOf(&json.SyntaxError{})) + }) + }) + + Context("when the response is a CF Error", func() { + BeforeEach(func() { + fakeCliConnection.CliCommandWithoutTerminalOutputReturns([]string{"{", `"code": 1234,`, `"description":"another error"`, "}"}, nil) + }) + + It("returns an error", func() { + err := Curl(fakeCliConnection, nil, "a", "b", "c") + Expect(err).To(MatchError("another error")) + }) + }) +}) diff --git a/cf-plugin/plugin_suite_test.go b/cf-plugin/models/models_suite_test.go similarity index 57% rename from cf-plugin/plugin_suite_test.go rename to cf-plugin/models/models_suite_test.go index c00bce9..2d4c6de 100644 --- a/cf-plugin/plugin_suite_test.go +++ b/cf-plugin/models/models_suite_test.go @@ -1,4 +1,4 @@ -package main_test +package models_test import ( . "github.com/onsi/ginkgo" @@ -7,7 +7,7 @@ import ( "testing" ) -func TestPlugin(t *testing.T) { +func TestModels(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Plugin Suite") + RunSpecs(t, "Models Suite") } diff --git a/cf-plugin/models/space/space.go b/cf-plugin/models/space/space.go index 6c73518..ee5c9d7 100644 --- a/cf-plugin/models/space/space.go +++ b/cf-plugin/models/space/space.go @@ -1,11 +1,11 @@ package space import ( - "encoding/json" "errors" "strconv" "strings" + "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models" "github.com/cloudfoundry/cli/plugin" ) @@ -16,11 +16,12 @@ type SpaceFactory interface { } type spaceFactory struct { - cli plugin.CliConnection + cli plugin.CliConnection + curl models.Curler } -func NewSpaceFactory(cli plugin.CliConnection) SpaceFactory { - return &spaceFactory{cli: cli} +func NewSpaceFactory(cli plugin.CliConnection, curl models.Curler) SpaceFactory { + return &spaceFactory{cli: cli, curl: curl} } type Space struct { @@ -36,7 +37,7 @@ type entity struct { AllowSSH bool `json:"allow_ssh"` } -type cfSpace struct { +type CFSpace struct { Metadata metadata `json:"metadata"` Entity entity `json:"entity"` } @@ -48,33 +49,19 @@ func (sf *spaceFactory) Get(spaceName string) (Space, error) { } guid := strings.TrimSpace(output[0]) + space := CFSpace{} + err = sf.curl(sf.cli, &space, "/v2/spaces/"+guid) - output, err = sf.cli.CliCommandWithoutTerminalOutput("curl", "/v2/spaces/"+guid) if err != nil { return Space{}, errors.New("Failed to acquire " + spaceName + " info") } - response := []byte(output[0]) - space := cfSpace{} - - err = json.Unmarshal(response, &space) - if err != nil { - return Space{}, err - } - return Space{ Guid: space.Metadata.Guid, AllowSSH: space.Entity.AllowSSH, }, nil - - return Space{}, nil } func (sf *spaceFactory) SetBool(aSpace Space, key string, value bool) error { - output, err := sf.cli.CliCommandWithoutTerminalOutput("curl", "/v2/spaces/"+aSpace.Guid, "-X", "PUT", "-d", `{"`+key+`":`+strconv.FormatBool(value)+`}`) - if err != nil { - return errors.New(output[len(output)-1]) - } - - return nil + return sf.curl(sf.cli, nil, "/v2/spaces/"+aSpace.Guid, "-X", "PUT", "-d", `{"`+key+`":`+strconv.FormatBool(value)+`}`) } diff --git a/cf-plugin/models/space/space_test.go b/cf-plugin/models/space/space_test.go index 3ae6e16..20b6709 100644 --- a/cf-plugin/models/space/space_test.go +++ b/cf-plugin/models/space/space_test.go @@ -3,7 +3,9 @@ package space_test import ( "errors" + "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/space" + "github.com/cloudfoundry/cli/plugin" "github.com/cloudfoundry/cli/plugin/fakes" . "github.com/onsi/ginkgo" @@ -13,109 +15,61 @@ import ( var _ = Describe("Space", func() { var ( fakeCliConnection *fakes.FakeCliConnection + curler models.Curler sf space.SpaceFactory ) BeforeEach(func() { fakeCliConnection = &fakes.FakeCliConnection{} - sf = space.NewSpaceFactory(fakeCliConnection) + + }) + + JustBeforeEach(func() { + sf = space.NewSpaceFactory(fakeCliConnection, curler) }) Describe("Get", func() { - Context("when CC returns a valid response", func() { + Context("when CC returns a valid space guid", func() { BeforeEach(func() { - expectedJson := `{ - "metadata": { - "guid": "space1-guid" - }, - "entity": { - "allow_ssh": true - } - }` - fakeCliConnection.CliCommandWithoutTerminalOutputStub = func(args ...string) ([]string, error) { - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 1 { - Expect(args).To(ConsistOf("space", "space1", "--guid")) - return []string{"space1-guid\n"}, nil - } - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 2 { - Expect(args).To(ConsistOf("curl", "/v2/spaces/space1-guid")) - return []string{expectedJson}, nil - } - Expect(false).To(BeTrue()) - return []string{}, nil + Expect(args).To(ConsistOf("space", "space1", "--guid")) + return []string{"space1-guid\n"}, nil } }) - It("returns a populated Space model", func() { - model, err := sf.Get("space1") - - Expect(err).NotTo(HaveOccurred()) - Expect(model.Guid).To(Equal("space1-guid")) - Expect(model.AllowSSH).To(BeTrue()) - }) - }) - - Context("when the space does not exist", func() { - BeforeEach(func() { - fakeCliConnection.CliCommandWithoutTerminalOutputReturns( - []string{"FAILED", "Space space1 is not found"}, - errors.New("Error executing cli core command"), - ) - }) + Context("when a Space is returned", func() { + BeforeEach(func() { + curler = func(cli plugin.CliConnection, result interface{}, args ...string) error { + s, ok := result.(*space.CFSpace) + Expect(ok).To(BeTrue()) + s.Metadata.Guid = "space1-guid" + s.Entity.AllowSSH = true + return nil + } + }) - It("returns 'Space not found' error", func() { - _, err := sf.Get("space1") - Expect(err).To(MatchError("Space space1 is not found")) + It("returns a populated Space model", func() { + model, err := sf.Get("space1") - Expect(fakeCliConnection.CliCommandWithoutTerminalOutputCallCount()).To(Equal(1)) - args := fakeCliConnection.CliCommandWithoutTerminalOutputArgsForCall(0) - Expect(args).To(ConsistOf("space", "space1", "--guid")) + Expect(err).NotTo(HaveOccurred()) + Expect(model.Guid).To(Equal("space1-guid")) + Expect(model.AllowSSH).To(BeTrue()) + }) }) - }) - Context("when curling the space model fails", func() { - Context("when CC returns a valid response", func() { + Context("when curling the Space fails", func() { BeforeEach(func() { - fakeCliConnection.CliCommandWithoutTerminalOutputStub = func(args ...string) ([]string, error) { - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 1 { - Expect(args).To(ConsistOf("space", "space1", "--guid")) - return []string{"space1-guid\n"}, nil - } - if fakeCliConnection.CliCommandWithoutTerminalOutputCallCount() == 2 { - Expect(args).To(ConsistOf("curl", "/v2/spaces/space1-guid")) - return []string{"{}"}, errors.New("Failed to acquire space1 info") - } - Expect(false).To(BeTrue()) - return []string{}, nil + curler = func(cli plugin.CliConnection, result interface{}, args ...string) error { + return errors.New("not good") } }) - It("returns 'fail to acquire space info' error", func() { + It("returns an error", func() { _, err := sf.Get("space1") - Expect(err).To(MatchError("Failed to acquire space1 info")) }) }) }) - }) - - Describe("SetBool", func() { - var aSpace space.Space - - BeforeEach(func() { - aSpace = space.Space{ - Guid: "myguid", - } - }) - - It("it sends a cli command", func() { - sf.SetBool(aSpace, "foobar", true) - - Expect(fakeCliConnection.CliCommandWithoutTerminalOutputCallCount()).To(Equal(1)) - args := fakeCliConnection.CliCommandWithoutTerminalOutputArgsForCall(0) - Expect(args).To(Equal([]string{"curl", "/v2/spaces/myguid", "-X", "PUT", "-d", `{"foobar":true}`})) - }) Context("when the space does not exist", func() { BeforeEach(func() { @@ -126,8 +80,12 @@ var _ = Describe("Space", func() { }) It("returns 'Space not found' error", func() { - err := sf.SetBool(aSpace, "foobar", true) + _, err := sf.Get("space1") Expect(err).To(MatchError("Space space1 is not found")) + + Expect(fakeCliConnection.CliCommandWithoutTerminalOutputCallCount()).To(Equal(1)) + args := fakeCliConnection.CliCommandWithoutTerminalOutputArgsForCall(0) + Expect(args).To(ConsistOf("space", "space1", "--guid")) }) }) }) diff --git a/cf-plugin/plugin.go b/cf-plugin/ssh_plugin.go similarity index 86% rename from cf-plugin/plugin.go rename to cf-plugin/ssh_plugin.go index 5065aad..efc96ed 100644 --- a/cf-plugin/plugin.go +++ b/cf-plugin/ssh_plugin.go @@ -7,6 +7,7 @@ import ( "time" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/cmd" + "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/app" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/credential" "github.com/cloudfoundry-incubator/diego-ssh/cf-plugin/models/info" @@ -85,47 +86,41 @@ func (p *SSHPlugin) GetMetadata() plugin.PluginMetadata { func (p *SSHPlugin) Run(cli plugin.CliConnection, args []string) { p.OutputWriter = os.Stdout - appFactory := app.NewAppFactory(cli) - spaceFactory := space.NewSpaceFactory(cli) + appFactory := app.NewAppFactory(cli, models.Curl) + spaceFactory := space.NewSpaceFactory(cli, models.Curl) switch args[0] { case "CLI-MESSAGE-UNINSTALL": return case "enable-ssh": - err := cmd.EnableSSH(args, appFactory, p.OutputWriter) + err := cmd.EnableSSH(args, appFactory) if err != nil { - p.Fail(err.Error()) - return + p.Fatal(err) } case "disable-ssh": - err := cmd.DisableSSH(args, appFactory, p.OutputWriter) + err := cmd.DisableSSH(args, appFactory) if err != nil { - p.Fail(err.Error()) - return + p.Fatal(err) } case "ssh-enabled": err := cmd.SSHEnabled(args, appFactory, p.OutputWriter) if err != nil { - p.Fail(err.Error()) - return + p.Fatal(err) } case "allow-space-ssh": - err := cmd.AllowSSH(args, spaceFactory, p.OutputWriter) + err := cmd.AllowSSH(args, spaceFactory) if err != nil { - p.Fail(err.Error()) - return + p.Fatal(err) } case "disallow-space-ssh": - err := cmd.DisallowSSH(args, spaceFactory, p.OutputWriter) + err := cmd.DisallowSSH(args, spaceFactory) if err != nil { - p.Fail(err.Error()) - return + p.Fatal(err) } case "space-ssh-allowed": err := cmd.SSHAllowed(args, spaceFactory, p.OutputWriter) if err != nil { - p.Fail(err.Error()) - return + p.Fatal(err) } case "ssh": opts := options.NewSSHOptions() @@ -183,9 +178,9 @@ func (p *SSHPlugin) Run(cli plugin.CliConnection, args []string) { } } -func main() { - sshPlugin := &SSHPlugin{} - plugin.Start(sshPlugin) +func (p *SSHPlugin) Fatal(err error) { + p.Fail(err.Error()) + os.Exit(1) } func (p *SSHPlugin) Fail(message string) {