Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arbitrary params #452

Merged
merged 20 commits into from
Jun 2, 2015
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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