Skip to content

Commit

Permalink
Merge pull request #452 from cloudfoundry/arbitrary-params-final
Browse files Browse the repository at this point in the history
Arbitrary params for create-service, update-service, bind-service, create-service-key
  • Loading branch information
jberkhahn committed Jun 2, 2015
2 parents 203c213 + eea2164 commit 1ab7cb9
Show file tree
Hide file tree
Showing 33 changed files with 849 additions and 251 deletions.
5 changes: 4 additions & 1 deletion cf/api/fakes/fake_service_binding_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ type FakeServiceBindingRepo struct {
CreateServiceInstanceGuid string
CreateApplicationGuid string
CreateErrorCode string
CreateParams map[string]interface{}

DeleteServiceInstance models.ServiceInstance
DeleteApplicationGuid string
DeleteBindingNotFound bool
CreateNonHttpErrCode string
}

func (repo *FakeServiceBindingRepo) Create(instanceGuid, appGuid string) (apiErr error) {
func (repo *FakeServiceBindingRepo) Create(instanceGuid, appGuid string, paramsMap map[string]interface{}) (apiErr error) {
repo.CreateServiceInstanceGuid = instanceGuid
repo.CreateApplicationGuid = appGuid
repo.CreateParams = paramsMap

if repo.CreateNonHttpErrCode != "" {
apiErr = errors.New(repo.CreateNonHttpErrCode)
return
Expand Down
4 changes: 3 additions & 1 deletion cf/api/fakes/fake_service_key_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type FakeServiceKeyRepo struct {
type CreateServiceKeyType struct {
InstanceGuid string
KeyName string
Params map[string]interface{}

Error error
}
Expand Down Expand Up @@ -48,9 +49,10 @@ func NewFakeServiceKeyRepo() *FakeServiceKeyRepo {
}
}

func (f *FakeServiceKeyRepo) CreateServiceKey(instanceGuid string, serviceKeyName string) error {
func (f *FakeServiceKeyRepo) CreateServiceKey(instanceGuid string, serviceKeyName string, params map[string]interface{}) error {
f.CreateServiceKeyMethod.InstanceGuid = instanceGuid
f.CreateServiceKeyMethod.KeyName = serviceKeyName
f.CreateServiceKeyMethod.Params = params

return f.CreateServiceKeyMethod.Error
}
Expand Down
4 changes: 3 additions & 1 deletion cf/api/fakes/fake_service_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type FakeServiceRepo struct {
UpdateServiceInstanceArgs struct {
InstanceGuid string
PlanGuid string
Params map[string]interface{}
}

UpdateServiceInstanceReturnsErr bool
Expand Down Expand Up @@ -149,13 +150,14 @@ func (repo *FakeServiceRepo) CreateServiceInstance(name, planGuid string, params
return repo.CreateServiceInstanceReturns.Error
}

func (repo *FakeServiceRepo) UpdateServiceInstance(instanceGuid, planGuid string) (apiErr error) {
func (repo *FakeServiceRepo) UpdateServiceInstance(instanceGuid, planGuid string, params map[string]interface{}) (apiErr error) {

if repo.UpdateServiceInstanceReturnsErr {
apiErr = errors.New("Error updating service instance")
} else {
repo.UpdateServiceInstanceArgs.InstanceGuid = instanceGuid
repo.UpdateServiceInstanceArgs.PlanGuid = planGuid
repo.UpdateServiceInstanceArgs.Params = params
}

return
Expand Down
25 changes: 16 additions & 9 deletions cf/api/service_bindings.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package api

import (
"fmt"
"strings"
"bytes"
"encoding/json"

"github.com/cloudfoundry/cli/cf/configuration/core_config"
"github.com/cloudfoundry/cli/cf/models"
"github.com/cloudfoundry/cli/cf/net"
)

type ServiceBindingRepository interface {
Create(instanceGuid, appGuid string) (apiErr error)
Create(instanceGuid, appGuid string, paramsMap map[string]interface{}) (apiErr error)
Delete(instance models.ServiceInstance, appGuid string) (found bool, apiErr error)
}

Expand All @@ -25,13 +25,20 @@ func NewCloudControllerServiceBindingRepository(config core_config.Reader, gatew
return
}

func (repo CloudControllerServiceBindingRepository) Create(instanceGuid, appGuid string) (apiErr error) {
func (repo CloudControllerServiceBindingRepository) Create(instanceGuid, appGuid string, paramsMap map[string]interface{}) (apiErr error) {
path := "/v2/service_bindings"
body := fmt.Sprintf(
`{"app_guid":"%s","service_instance_guid":"%s","async":true}`,
appGuid, instanceGuid,
)
return repo.gateway.CreateResource(repo.config.ApiEndpoint(), path, strings.NewReader(body))
request := models.ServiceBindingRequest{
AppGuid: appGuid,
ServiceInstanceGuid: instanceGuid,
Params: paramsMap,
}

jsonBytes, err := json.Marshal(request)
if err != nil {
return err
}

return repo.gateway.CreateResource(repo.config.ApiEndpoint(), path, bytes.NewReader(jsonBytes))
}

func (repo CloudControllerServiceBindingRepository) Delete(instance models.ServiceInstance, appGuid string) (found bool, apiErr error) {
Expand Down
39 changes: 34 additions & 5 deletions cf/api/service_bindings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,59 @@ var _ = Describe("ServiceBindingsRepository", func() {
})

Describe("Create", func() {
var requestMatcher testnet.RequestMatcher
Context("when the service binding can be created", func() {
BeforeEach(func() {
requestMatcher = testnet.RequestBodyMatcher(`{"app_guid":"my-app-guid","service_instance_guid":"my-service-instance-guid"}`)
})

JustBeforeEach(func() {
setupTestServer(testapi.NewCloudControllerTestRequest(testnet.TestRequest{
Method: "POST",
Path: "/v2/service_bindings",
Matcher: testnet.RequestBodyMatcher(`{"app_guid":"my-app-guid","service_instance_guid":"my-service-instance-guid","async":true}`),
Matcher: requestMatcher,
Response: testnet.TestResponse{Status: http.StatusCreated},
}))
})

It("creates the service binding", func() {
apiErr := repo.Create("my-service-instance-guid", "my-app-guid")
apiErr := repo.Create("my-service-instance-guid", "my-app-guid", nil)

Expect(testHandler).To(HaveAllRequestsCalled())
Expect(apiErr).NotTo(HaveOccurred())
})

Context("when there are arbitrary parameters", func() {
BeforeEach(func() {
requestMatcher = testnet.RequestBodyMatcher(`{"app_guid":"my-app-guid","service_instance_guid":"my-service-instance-guid", "parameters": { "foo": "bar"}}`)
})

It("send the parameters as part of the request body", func() {
paramsMap := map[string]interface{}{"foo": "bar"}
apiErr := repo.Create("my-service-instance-guid", "my-app-guid", paramsMap)

Expect(testHandler).To(HaveAllRequestsCalled())
Expect(apiErr).NotTo(HaveOccurred())
})

Context("and there is a failure during serialization", func() {
It("returns the serialization error", func() {
paramsMap := make(map[string]interface{})
paramsMap["data"] = make(chan bool)

err := repo.Create("my-service-instance-guid", "my-app-guid", paramsMap)
Expect(err).To(MatchError("json: unsupported type: chan bool"))
})
})
})
})

Context("when an error occurs", func() {
Context("when an API error occurs", func() {
BeforeEach(func() {
setupTestServer(testapi.NewCloudControllerTestRequest(testnet.TestRequest{
Method: "POST",
Path: "/v2/service_bindings",
Matcher: testnet.RequestBodyMatcher(`{"app_guid":"my-app-guid","service_instance_guid":"my-service-instance-guid","async":true}`),
Matcher: testnet.RequestBodyMatcher(`{"app_guid":"my-app-guid","service_instance_guid":"my-service-instance-guid"}`),
Response: testnet.TestResponse{
Status: http.StatusBadRequest,
Body: `{"code":90003,"description":"The app space binding to service is taken: 7b959018-110a-4913-ac0a-d663e613cdea 346bf237-7eef-41a7-b892-68fb08068f09"}`,
Expand All @@ -77,7 +106,7 @@ var _ = Describe("ServiceBindingsRepository", func() {
})

It("returns an error", func() {
apiErr := repo.Create("my-service-instance-guid", "my-app-guid")
apiErr := repo.Create("my-service-instance-guid", "my-app-guid", nil)

Expect(testHandler).To(HaveAllRequestsCalled())
Expect(apiErr).To(HaveOccurred())
Expand Down
20 changes: 15 additions & 5 deletions cf/api/service_keys.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package api

import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"strings"

"github.com/cloudfoundry/cli/cf/api/resources"
"github.com/cloudfoundry/cli/cf/configuration/core_config"
Expand All @@ -13,7 +14,7 @@ import (
)

type ServiceKeyRepository interface {
CreateServiceKey(serviceKeyGuid string, keyName string) error
CreateServiceKey(serviceKeyGuid string, keyName string, params map[string]interface{}) error
ListServiceKeys(serviceKeyGuid string) ([]models.ServiceKey, error)
GetServiceKey(serviceKeyGuid string, keyName string) (models.ServiceKey, error)
DeleteServiceKey(serviceKeyGuid string) error
Expand All @@ -31,11 +32,20 @@ func NewCloudControllerServiceKeyRepository(config core_config.Reader, gateway n
}
}

func (c CloudControllerServiceKeyRepository) CreateServiceKey(instanceGuid string, keyName string) error {
func (c CloudControllerServiceKeyRepository) CreateServiceKey(instanceGuid string, keyName string, params map[string]interface{}) error {
path := "/v2/service_keys"
data := fmt.Sprintf(`{"service_instance_guid":"%s","name":"%s"}`, instanceGuid, keyName)

err := c.gateway.CreateResource(c.config.ApiEndpoint(), path, strings.NewReader(data))
request := models.ServiceKeyRequest{
Name: keyName,
ServiceInstanceGuid: instanceGuid,
Params: params,
}
jsonBytes, err := json.Marshal(request)
if err != nil {
return err
}

err = c.gateway.CreateResource(c.config.ApiEndpoint(), path, bytes.NewReader(jsonBytes))

if httpErr, ok := err.(errors.HttpError); ok && httpErr.ErrorCode() == errors.SERVICE_KEY_NAME_TAKEN {
return errors.NewModelAlreadyExistsError("Service key", keyName)
Expand Down
34 changes: 31 additions & 3 deletions cf/api/service_keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var _ = Describe("Service Keys Repo", func() {
Response: testnet.TestResponse{Status: http.StatusCreated},
}))

err := repo.CreateServiceKey("fake-instance-guid", "fake-key-name")
err := repo.CreateServiceKey("fake-instance-guid", "fake-key-name", nil)
Expect(testHandler).To(HaveAllRequestsCalled())
Expect(err).NotTo(HaveOccurred())
})
Expand All @@ -67,7 +67,7 @@ var _ = Describe("Service Keys Repo", func() {
Body: `{"code":360001,"description":"The service key name is taken: exist-service-key"}`},
}))

err := repo.CreateServiceKey("fake-instance-guid", "exist-service-key")
err := repo.CreateServiceKey("fake-instance-guid", "exist-service-key", nil)
Expect(testHandler).To(HaveAllRequestsCalled())
Expect(err).To(BeAssignableToTypeOf(&errors.ModelAlreadyExistsError{}))
})
Expand All @@ -82,11 +82,39 @@ var _ = Describe("Service Keys Repo", func() {
Body: `{"code":10003,"description":"You are not authorized to perform the requested action"}`},
}))

err := repo.CreateServiceKey("fake-instance-guid", "fake-service-key")
err := repo.CreateServiceKey("fake-instance-guid", "fake-service-key", nil)
Expect(testHandler).To(HaveAllRequestsCalled())
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("You are not authorized to perform the requested action"))
})

Context("when there are parameters", func() {
It("sends the parameters as part of the request body", func() {
setupTestServer(testapi.NewCloudControllerTestRequest(testnet.TestRequest{
Method: "POST",
Path: "/v2/service_keys",
Matcher: testnet.RequestBodyMatcher(`{"service_instance_guid":"fake-instance-guid","name":"fake-service-key","parameters": {"data": "hello"}}`),
Response: testnet.TestResponse{Status: http.StatusCreated},
}))

paramsMap := make(map[string]interface{})
paramsMap["data"] = "hello"

err := repo.CreateServiceKey("fake-instance-guid", "fake-service-key", paramsMap)
Expect(testHandler).To(HaveAllRequestsCalled())
Expect(err).NotTo(HaveOccurred())
})

Context("and there is a failure during serialization", func() {
It("returns the serialization error", func() {
paramsMap := make(map[string]interface{})
paramsMap["data"] = make(chan bool)

err := repo.CreateServiceKey("instance-name", "plan-guid", paramsMap)
Expect(err).To(MatchError("json: unsupported type: chan bool"))
})
})
})
})

Describe("ListServiceKeys", func() {
Expand Down
19 changes: 13 additions & 6 deletions cf/api/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type ServiceRepository interface {
GetServiceOfferingsForSpace(spaceGuid string) (offerings models.ServiceOfferings, apiErr error)
FindInstanceByName(name string) (instance models.ServiceInstance, apiErr error)
CreateServiceInstance(name, planGuid string, params map[string]interface{}) (apiErr error)
UpdateServiceInstance(instanceGuid, planGuid string) (apiErr error)
UpdateServiceInstance(instanceGuid, planGuid string, params map[string]interface{}) (apiErr error)
RenameService(instance models.ServiceInstance, newName string) (apiErr error)
DeleteService(instance models.ServiceInstance) (apiErr error)
FindServicePlanByDescription(planDescription resources.ServicePlanDescription) (planGuid string, apiErr error)
Expand Down Expand Up @@ -136,7 +136,7 @@ func (repo CloudControllerServiceRepository) FindInstanceByName(name string) (in

func (repo CloudControllerServiceRepository) CreateServiceInstance(name, planGuid string, params map[string]interface{}) (err error) {
path := "/v2/service_instances?accepts_incomplete=true"
request := models.ServiceInstanceRequest{
request := models.ServiceInstanceCreateRequest{
Name: name,
PlanGuid: planGuid,
SpaceGuid: repo.config.SpaceFields().Guid,
Expand All @@ -145,7 +145,6 @@ func (repo CloudControllerServiceRepository) CreateServiceInstance(name, planGui

jsonBytes, err := json.Marshal(request)
if err != nil {
fmt.Println(err.Error())
return err
}

Expand All @@ -162,11 +161,19 @@ func (repo CloudControllerServiceRepository) CreateServiceInstance(name, planGui
return
}

func (repo CloudControllerServiceRepository) UpdateServiceInstance(instanceGuid, planGuid string) (err error) {
func (repo CloudControllerServiceRepository) UpdateServiceInstance(instanceGuid, planGuid string, params map[string]interface{}) (err error) {
path := fmt.Sprintf("/v2/service_instances/%s?accepts_incomplete=true", instanceGuid)
data := fmt.Sprintf(`{"service_plan_guid":"%s"}`, planGuid)
request := models.ServiceInstanceUpdateRequest{
PlanGuid: planGuid,
Params: params,
}

jsonBytes, err := json.Marshal(request)
if err != nil {
return err
}

err = repo.gateway.UpdateResource(repo.config.ApiEndpoint(), path, strings.NewReader(data))
err = repo.gateway.UpdateResource(repo.config.ApiEndpoint(), path, bytes.NewReader(jsonBytes))

return
}
Expand Down
Loading

0 comments on commit 1ab7cb9

Please sign in to comment.