Skip to content

Commit

Permalink
v8(services): bind-service cmd use V3 API
Browse files Browse the repository at this point in the history
  • Loading branch information
blgm authored and pivotal-marcela-campo committed Nov 3, 2020
1 parent e17be57 commit 1cbbeb9
Show file tree
Hide file tree
Showing 18 changed files with 1,381 additions and 285 deletions.
1 change: 1 addition & 0 deletions actor/v7action/cloud_controller_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type CloudControllerClient interface {
CreateRoute(route resources.Route) (resources.Route, ccv3.Warnings, error)
CreateRouteBinding(binding resources.RouteBinding) (ccv3.JobURL, ccv3.Warnings, error)
CreateServiceBroker(serviceBroker resources.ServiceBroker) (ccv3.JobURL, ccv3.Warnings, error)
CreateServiceCredentialBinding(binding resources.ServiceCredentialBinding) (ccv3.JobURL, ccv3.Warnings, error)
CreateServiceInstance(serviceInstance resources.ServiceInstance) (ccv3.JobURL, ccv3.Warnings, error)
CreateSecurityGroup(securityGroup resources.SecurityGroup) (resources.SecurityGroup, ccv3.Warnings, error)
CreateSpace(space resources.Space) (resources.Space, ccv3.Warnings, error)
Expand Down
73 changes: 73 additions & 0 deletions actor/v7action/service_app_binding.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package v7action

import (
"code.cloudfoundry.org/cli/actor/actionerror"
"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
"code.cloudfoundry.org/cli/resources"
"code.cloudfoundry.org/cli/types"
"code.cloudfoundry.org/cli/util/railway"
)

type CreateServiceAppBindingParams struct {
SpaceGUID string
ServiceInstanceName string
AppName string
BindingName string
Parameters types.OptionalObject
}

func (actor Actor) CreateServiceAppBinding(params CreateServiceAppBindingParams) (chan PollJobEvent, Warnings, error) {
var (
serviceInstance resources.ServiceInstance
app resources.Application
jobURL ccv3.JobURL
stream chan PollJobEvent
)

warnings, err := railway.Sequentially(
func() (warnings ccv3.Warnings, err error) {
serviceInstance, _, warnings, err = actor.getServiceInstanceByNameAndSpace(params.ServiceInstanceName, params.SpaceGUID)
return
},
func() (warnings ccv3.Warnings, err error) {
app, warnings, err = actor.CloudControllerClient.GetApplicationByNameAndSpace(params.AppName, params.SpaceGUID)
return
},
func() (warnings ccv3.Warnings, err error) {
jobURL, warnings, err = actor.createServiceAppBinding(serviceInstance.GUID, app.GUID, params.BindingName, params.Parameters)
return
},
func() (warnings ccv3.Warnings, err error) {
stream = actor.PollJobToEventStream(jobURL)
return
},
)

switch err.(type) {
case nil:
return stream, Warnings(warnings), nil
case ccerror.ApplicationNotFoundError:
return nil, Warnings(warnings), actionerror.ApplicationNotFoundError{Name: params.AppName}
default:
return nil, Warnings(warnings), err
}
}

func (actor Actor) createServiceAppBinding(serviceInstanceGUID, appGUID, bindingName string, parameters types.OptionalObject) (ccv3.JobURL, ccv3.Warnings, error) {
jobURL, warnings, err := actor.CloudControllerClient.CreateServiceCredentialBinding(resources.ServiceCredentialBinding{
Type: resources.AppBinding,
Name: bindingName,
ServiceInstanceGUID: serviceInstanceGUID,
AppGUID: appGUID,
Parameters: parameters,
})
switch err.(type) {
case nil:
return jobURL, warnings, nil
case ccerror.ResourceAlreadyExistsError:
return "", warnings, actionerror.ResourceAlreadyExistsError{Message: err.Error()}
default:
return "", warnings, err
}
}
250 changes: 250 additions & 0 deletions actor/v7action/service_app_binding_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
package v7action_test

import (
"errors"

"code.cloudfoundry.org/cli/actor/actionerror"
. "code.cloudfoundry.org/cli/actor/v7action"
"code.cloudfoundry.org/cli/actor/v7action/v7actionfakes"
"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
"code.cloudfoundry.org/cli/resources"
"code.cloudfoundry.org/cli/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Service App Binding Action", func() {
var (
actor *Actor
fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
)

BeforeEach(func() {
fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient)
actor = NewActor(fakeCloudControllerClient, nil, nil, nil, nil, nil)
})

Describe("CreateServiceAppBinding", func() {
const (
serviceInstanceName = "fake-service-instance-name"
serviceInstanceGUID = "fake-service-instance-guid"
appName = "fake-app-name"
appGUID = "fake-app-guid"
bindingName = "fake-binding-name"
spaceGUID = "fake-space-guid"
fakeJobURL = ccv3.JobURL("fake-job-url")
)

var (
params CreateServiceAppBindingParams
warnings Warnings
executionError error
stream chan PollJobEvent
)

BeforeEach(func() {
fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns(
resources.ServiceInstance{
Name: serviceInstanceName,
GUID: serviceInstanceGUID,
},
ccv3.IncludedResources{},
ccv3.Warnings{"get instance warning"},
nil,
)

fakeCloudControllerClient.GetApplicationByNameAndSpaceReturns(
resources.Application{
GUID: appGUID,
Name: appName,
},
ccv3.Warnings{"get app warning"},
nil,
)

fakeCloudControllerClient.CreateServiceCredentialBindingReturns(
fakeJobURL,
ccv3.Warnings{"create binding warning"},
nil,
)

fakeStream := make(chan ccv3.PollJobEvent)
fakeCloudControllerClient.PollJobToEventStreamReturns(fakeStream)
go func() {
fakeStream <- ccv3.PollJobEvent{
State: constant.JobPolling,
Warnings: ccv3.Warnings{"poll warning"},
}
}()

params = CreateServiceAppBindingParams{
SpaceGUID: spaceGUID,
ServiceInstanceName: serviceInstanceName,
AppName: appName,
BindingName: bindingName,
Parameters: types.NewOptionalObject(map[string]interface{}{
"foo": "bar",
}),
}
})

JustBeforeEach(func() {
stream, warnings, executionError = actor.CreateServiceAppBinding(params)
})

It("returns an event stream, warnings, and no errors", func() {
Expect(executionError).NotTo(HaveOccurred())

Expect(warnings).To(ConsistOf(Warnings{
"get instance warning",
"get app warning",
"create binding warning",
}))

Eventually(stream).Should(Receive(Equal(PollJobEvent{
State: JobPolling,
Warnings: Warnings{"poll warning"},
Err: nil,
})))
})

Describe("service instance lookup", func() {
It("makes the correct call", func() {
Expect(fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceCallCount()).To(Equal(1))
actualServiceInstanceName, actualSpaceGUID, actualQuery := fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceArgsForCall(0)
Expect(actualServiceInstanceName).To(Equal(serviceInstanceName))
Expect(actualSpaceGUID).To(Equal(spaceGUID))
Expect(actualQuery).To(BeEmpty())
})

When("not found", func() {
BeforeEach(func() {
fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns(
resources.ServiceInstance{},
ccv3.IncludedResources{},
ccv3.Warnings{"get instance warning"},
ccerror.ServiceInstanceNotFoundError{Name: serviceInstanceName},
)
})

It("returns the error and warning", func() {
Expect(warnings).To(ContainElement("get instance warning"))
Expect(executionError).To(MatchError(actionerror.ServiceInstanceNotFoundError{Name: serviceInstanceName}))
})
})

When("fails", func() {
BeforeEach(func() {
fakeCloudControllerClient.GetServiceInstanceByNameAndSpaceReturns(
resources.ServiceInstance{},
ccv3.IncludedResources{},
ccv3.Warnings{"get instance warning"},
errors.New("boof"),
)
})

It("returns the error and warning", func() {
Expect(warnings).To(ContainElement("get instance warning"))
Expect(executionError).To(MatchError("boof"))
})
})
})

Describe("app lookup", func() {
It("makes the correct call", func() {
Expect(fakeCloudControllerClient.GetApplicationByNameAndSpaceCallCount()).To(Equal(1))
actualAppName, actualSpaceGUID := fakeCloudControllerClient.GetApplicationByNameAndSpaceArgsForCall(0)
Expect(actualAppName).To(Equal(appName))
Expect(actualSpaceGUID).To(Equal(spaceGUID))
})

When("not found", func() {
BeforeEach(func() {
fakeCloudControllerClient.GetApplicationByNameAndSpaceReturns(
resources.Application{},
ccv3.Warnings{"get app warning"},
ccerror.ApplicationNotFoundError{Name: appName},
)
})

It("returns the error and warning", func() {
Expect(warnings).To(ContainElement("get app warning"))
Expect(executionError).To(MatchError(actionerror.ApplicationNotFoundError{Name: appName}))
})
})

When("fails", func() {
BeforeEach(func() {
fakeCloudControllerClient.GetApplicationByNameAndSpaceReturns(
resources.Application{},
ccv3.Warnings{"get app warning"},
errors.New("boom"),
)
})

It("returns the error and warning", func() {
Expect(warnings).To(ContainElement("get app warning"))
Expect(executionError).To(MatchError("boom"))
})
})
})

Describe("initiating the create", func() {
It("makes the correct call", func() {
Expect(fakeCloudControllerClient.CreateServiceCredentialBindingCallCount()).To(Equal(1))
Expect(fakeCloudControllerClient.CreateServiceCredentialBindingArgsForCall(0)).To(Equal(resources.ServiceCredentialBinding{
Type: resources.AppBinding,
Name: bindingName,
ServiceInstanceGUID: serviceInstanceGUID,
AppGUID: appGUID,
Parameters: types.NewOptionalObject(map[string]interface{}{
"foo": "bar",
}),
}))
})

When("binding already exists", func() {
BeforeEach(func() {
fakeCloudControllerClient.CreateServiceCredentialBindingReturns(
"",
ccv3.Warnings{"create binding warning"},
ccerror.ResourceAlreadyExistsError{
Message: "The app is already bound to the service instance",
},
)
})

It("returns an actionerror and warnings", func() {
Expect(warnings).To(ContainElement("create binding warning"))
Expect(executionError).To(MatchError(actionerror.ResourceAlreadyExistsError{
Message: "The app is already bound to the service instance",
}))
})
})

When("fails", func() {
BeforeEach(func() {
fakeCloudControllerClient.CreateServiceCredentialBindingReturns(
"",
ccv3.Warnings{"create binding warning"},
errors.New("boop"),
)
})

It("returns the error and warnings", func() {
Expect(warnings).To(ContainElement("create binding warning"))
Expect(executionError).To(MatchError("boop"))
})
})
})

Describe("polling the job", func() {
It("polls the job", func() {
Expect(fakeCloudControllerClient.PollJobToEventStreamCallCount()).To(Equal(1))
Expect(fakeCloudControllerClient.PollJobToEventStreamArgsForCall(0)).To(Equal(fakeJobURL))
})
})
})
})
Loading

0 comments on commit 1cbbeb9

Please sign in to comment.