github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/api/cloudcontroller/ccv3/service_instance_test.go (about)

     1  package ccv3_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    10  	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/ccv3fakes"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal"
    13  	"code.cloudfoundry.org/cli/resources"
    14  	"code.cloudfoundry.org/cli/types"
    15  	"code.cloudfoundry.org/jsonry"
    16  	. "github.com/onsi/ginkgo"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  var _ = Describe("Service Instance", func() {
    21  	var (
    22  		requester *ccv3fakes.FakeRequester
    23  		client    *Client
    24  	)
    25  
    26  	BeforeEach(func() {
    27  		requester = new(ccv3fakes.FakeRequester)
    28  		client, _ = NewFakeRequesterTestClient(requester)
    29  	})
    30  
    31  	Describe("GetServiceInstances", func() {
    32  		var (
    33  			query      Query
    34  			instances  []resources.ServiceInstance
    35  			included   IncludedResources
    36  			warnings   Warnings
    37  			executeErr error
    38  		)
    39  
    40  		JustBeforeEach(func() {
    41  			instances, included, warnings, executeErr = client.GetServiceInstances(query)
    42  		})
    43  
    44  		When("service instances exist", func() {
    45  			BeforeEach(func() {
    46  				requester.MakeListRequestCalls(func(requestParams RequestParams) (IncludedResources, Warnings, error) {
    47  					for i := 1; i <= 3; i++ {
    48  						Expect(requestParams.AppendToList(resources.ServiceInstance{
    49  							GUID: fmt.Sprintf("service-instance-%d-guid", i),
    50  							Name: fmt.Sprintf("service-instance-%d-name", i),
    51  						})).NotTo(HaveOccurred())
    52  					}
    53  					return IncludedResources{ServiceOfferings: []resources.ServiceOffering{{GUID: "fake-service-offering"}}}, Warnings{"warning-1", "warning-2"}, nil
    54  				})
    55  
    56  				query = Query{
    57  					Key:    NameFilter,
    58  					Values: []string{"some-service-instance-name"},
    59  				}
    60  			})
    61  
    62  			It("returns a list of service instances with warnings and included resources", func() {
    63  				Expect(executeErr).ToNot(HaveOccurred())
    64  
    65  				Expect(instances).To(ConsistOf(
    66  					resources.ServiceInstance{
    67  						GUID: "service-instance-1-guid",
    68  						Name: "service-instance-1-name",
    69  					},
    70  					resources.ServiceInstance{
    71  						GUID: "service-instance-2-guid",
    72  						Name: "service-instance-2-name",
    73  					},
    74  					resources.ServiceInstance{
    75  						GUID: "service-instance-3-guid",
    76  						Name: "service-instance-3-name",
    77  					},
    78  				))
    79  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
    80  				Expect(included).To(Equal(IncludedResources{ServiceOfferings: []resources.ServiceOffering{{GUID: "fake-service-offering"}}}))
    81  
    82  				Expect(requester.MakeListRequestCallCount()).To(Equal(1))
    83  				actualParams := requester.MakeListRequestArgsForCall(0)
    84  				Expect(actualParams.RequestName).To(Equal(internal.GetServiceInstancesRequest))
    85  				Expect(actualParams.Query).To(ConsistOf(query))
    86  				Expect(actualParams.ResponseBody).To(BeAssignableToTypeOf(resources.ServiceInstance{}))
    87  			})
    88  		})
    89  
    90  		When("the cloud controller returns errors and warnings", func() {
    91  			BeforeEach(func() {
    92  				errors := []ccerror.V3Error{
    93  					{
    94  						Code:   42424,
    95  						Detail: "Some detailed error message",
    96  						Title:  "CF-SomeErrorTitle",
    97  					},
    98  					{
    99  						Code:   11111,
   100  						Detail: "Some other detailed error message",
   101  						Title:  "CF-SomeOtherErrorTitle",
   102  					},
   103  				}
   104  
   105  				requester.MakeListRequestReturns(
   106  					IncludedResources{},
   107  					Warnings{"this is a warning"},
   108  					ccerror.MultiError{ResponseCode: http.StatusTeapot, Errors: errors},
   109  				)
   110  			})
   111  
   112  			It("returns the error and all warnings", func() {
   113  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   114  					ResponseCode: http.StatusTeapot,
   115  					Errors: []ccerror.V3Error{
   116  						{
   117  							Code:   42424,
   118  							Detail: "Some detailed error message",
   119  							Title:  "CF-SomeErrorTitle",
   120  						},
   121  						{
   122  							Code:   11111,
   123  							Detail: "Some other detailed error message",
   124  							Title:  "CF-SomeOtherErrorTitle",
   125  						},
   126  					},
   127  				}))
   128  				Expect(warnings).To(ConsistOf("this is a warning"))
   129  			})
   130  		})
   131  	})
   132  
   133  	Describe("GetServiceInstanceByNameAndSpace", func() {
   134  		const (
   135  			name      = "fake-service-instance-name"
   136  			spaceGUID = "fake-space-guid"
   137  		)
   138  		var (
   139  			instance   resources.ServiceInstance
   140  			included   IncludedResources
   141  			warnings   Warnings
   142  			executeErr error
   143  			query      []Query
   144  		)
   145  
   146  		BeforeEach(func() {
   147  			query = []Query{{Key: Include, Values: []string{"unicorns"}}}
   148  		})
   149  
   150  		JustBeforeEach(func() {
   151  			instance, included, warnings, executeErr = client.GetServiceInstanceByNameAndSpace(name, spaceGUID, query...)
   152  		})
   153  
   154  		It("makes the correct API request", func() {
   155  			Expect(requester.MakeListRequestCallCount()).To(Equal(1))
   156  			actualParams := requester.MakeListRequestArgsForCall(0)
   157  			Expect(actualParams.RequestName).To(Equal(internal.GetServiceInstancesRequest))
   158  			Expect(actualParams.Query).To(ConsistOf(
   159  				Query{
   160  					Key:    NameFilter,
   161  					Values: []string{name},
   162  				},
   163  				Query{
   164  					Key:    SpaceGUIDFilter,
   165  					Values: []string{spaceGUID},
   166  				},
   167  				Query{
   168  					Key:    Include,
   169  					Values: []string{"unicorns"},
   170  				},
   171  			))
   172  			Expect(actualParams.ResponseBody).To(BeAssignableToTypeOf(resources.ServiceInstance{}))
   173  		})
   174  
   175  		When("there are no matches", func() {
   176  			BeforeEach(func() {
   177  				requester.MakeListRequestReturns(
   178  					IncludedResources{},
   179  					Warnings{"this is a warning"},
   180  					nil,
   181  				)
   182  			})
   183  
   184  			It("returns an error and warnings", func() {
   185  				Expect(instance).To(Equal(resources.ServiceInstance{}))
   186  				Expect(warnings).To(ConsistOf("this is a warning"))
   187  				Expect(executeErr).To(MatchError(ccerror.ServiceInstanceNotFoundError{
   188  					Name:      name,
   189  					SpaceGUID: spaceGUID,
   190  				}))
   191  			})
   192  		})
   193  
   194  		When("there is a single match", func() {
   195  			BeforeEach(func() {
   196  				requester.MakeListRequestCalls(func(requestParams RequestParams) (IncludedResources, Warnings, error) {
   197  					Expect(requestParams.AppendToList(resources.ServiceInstance{
   198  						Name: name,
   199  						GUID: "service-instance-guid",
   200  					})).NotTo(HaveOccurred())
   201  
   202  					return IncludedResources{ServiceOfferings: []resources.ServiceOffering{{GUID: "fake-offering-guid"}}},
   203  						Warnings{"warning-1", "warning-2"},
   204  						nil
   205  				})
   206  			})
   207  
   208  			It("returns the resource, included resources, and warnings", func() {
   209  				Expect(instance).To(Equal(resources.ServiceInstance{
   210  					Name: name,
   211  					GUID: "service-instance-guid",
   212  				}))
   213  				Expect(included).To(Equal(IncludedResources{ServiceOfferings: []resources.ServiceOffering{{GUID: "fake-offering-guid"}}}))
   214  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   215  				Expect(executeErr).NotTo(HaveOccurred())
   216  			})
   217  		})
   218  
   219  		When("there are multiple matches", func() {
   220  			BeforeEach(func() {
   221  				requester.MakeListRequestCalls(func(requestParams RequestParams) (IncludedResources, Warnings, error) {
   222  					for i := 1; i <= 3; i++ {
   223  						Expect(requestParams.AppendToList(resources.ServiceInstance{
   224  							GUID: fmt.Sprintf("service-instance-%d-guid", i),
   225  							Name: fmt.Sprintf("service-instance-%d-name", i),
   226  						})).NotTo(HaveOccurred())
   227  					}
   228  					return IncludedResources{}, Warnings{"warning-1", "warning-2"}, nil
   229  				})
   230  			})
   231  
   232  			It("returns the first resource and warnings", func() {
   233  				Expect(instance).To(Equal(resources.ServiceInstance{
   234  					Name: "service-instance-1-name",
   235  					GUID: "service-instance-1-guid",
   236  				}))
   237  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   238  				Expect(executeErr).NotTo(HaveOccurred())
   239  			})
   240  		})
   241  
   242  		When("the cloud controller returns errors and warnings", func() {
   243  			BeforeEach(func() {
   244  				errors := []ccerror.V3Error{
   245  					{
   246  						Code:   42424,
   247  						Detail: "Some detailed error message",
   248  						Title:  "CF-SomeErrorTitle",
   249  					},
   250  					{
   251  						Code:   11111,
   252  						Detail: "Some other detailed error message",
   253  						Title:  "CF-SomeOtherErrorTitle",
   254  					},
   255  				}
   256  
   257  				requester.MakeListRequestCalls(func(requestParams RequestParams) (IncludedResources, Warnings, error) {
   258  					Expect(requestParams.AppendToList(resources.ServiceInstance{
   259  						GUID: "service-instance-guid",
   260  						Name: "service-instance-name",
   261  					})).NotTo(HaveOccurred())
   262  
   263  					return IncludedResources{},
   264  						Warnings{"warning-1", "warning-2"},
   265  						ccerror.MultiError{ResponseCode: http.StatusTeapot, Errors: errors}
   266  				})
   267  			})
   268  
   269  			It("returns the error and all warnings", func() {
   270  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   271  					ResponseCode: http.StatusTeapot,
   272  					Errors: []ccerror.V3Error{
   273  						{
   274  							Code:   42424,
   275  							Detail: "Some detailed error message",
   276  							Title:  "CF-SomeErrorTitle",
   277  						},
   278  						{
   279  							Code:   11111,
   280  							Detail: "Some other detailed error message",
   281  							Title:  "CF-SomeOtherErrorTitle",
   282  						},
   283  					},
   284  				}))
   285  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   286  			})
   287  		})
   288  	})
   289  
   290  	Describe("GetServiceInstanceParameters", func() {
   291  		const guid = "fake-service-instance-guid"
   292  
   293  		BeforeEach(func() {
   294  			requester.MakeRequestCalls(func(params RequestParams) (JobURL, Warnings, error) {
   295  				json.Unmarshal([]byte(`{"foo":"bar"}`), params.ResponseBody)
   296  				return "", Warnings{"one", "two"}, nil
   297  			})
   298  		})
   299  
   300  		It("makes the correct API request", func() {
   301  			client.GetServiceInstanceParameters(guid)
   302  
   303  			Expect(requester.MakeRequestCallCount()).To(Equal(1))
   304  			actualRequest := requester.MakeRequestArgsForCall(0)
   305  			Expect(actualRequest.RequestName).To(Equal(internal.GetServiceInstanceParametersRequest))
   306  			Expect(actualRequest.URIParams).To(Equal(internal.Params{"service_instance_guid": guid}))
   307  		})
   308  
   309  		It("returns the parameters", func() {
   310  			params, warnings, err := client.GetServiceInstanceParameters(guid)
   311  			Expect(err).NotTo(HaveOccurred())
   312  			Expect(warnings).To(ConsistOf("one", "two"))
   313  			Expect(params).To(Equal(types.JSONObject{"foo": "bar"}))
   314  		})
   315  
   316  		When("there is an error getting the parameters", func() {
   317  			BeforeEach(func() {
   318  				requester.MakeRequestReturns("", Warnings{"one", "two"}, errors.New("boom"))
   319  			})
   320  
   321  			It("returns warnings and an error", func() {
   322  				params, warnings, err := client.GetServiceInstanceParameters(guid)
   323  				Expect(err).To(MatchError("boom"))
   324  				Expect(warnings).To(ConsistOf("one", "two"))
   325  				Expect(params).To(BeEmpty())
   326  			})
   327  		})
   328  	})
   329  
   330  	Describe("CreateServiceInstance", func() {
   331  		Context("synchronous response", func() {
   332  			When("the request succeeds", func() {
   333  				It("returns warnings and no errors", func() {
   334  					requester.MakeRequestReturns("", Warnings{"fake-warning"}, nil)
   335  
   336  					si := resources.ServiceInstance{
   337  						Type:            resources.UserProvidedServiceInstance,
   338  						Name:            "fake-user-provided-service-instance",
   339  						SpaceGUID:       "fake-space-guid",
   340  						Tags:            types.NewOptionalStringSlice("foo", "bar"),
   341  						RouteServiceURL: types.NewOptionalString("https://fake-route.com"),
   342  						SyslogDrainURL:  types.NewOptionalString("https://fake-sylogg.com"),
   343  						Credentials: types.NewOptionalObject(map[string]interface{}{
   344  							"foo": "bar",
   345  							"baz": 42,
   346  						}),
   347  					}
   348  
   349  					jobURL, warnings, err := client.CreateServiceInstance(si)
   350  
   351  					Expect(jobURL).To(BeEmpty())
   352  					Expect(warnings).To(ConsistOf("fake-warning"))
   353  					Expect(err).NotTo(HaveOccurred())
   354  
   355  					Expect(requester.MakeRequestCallCount()).To(Equal(1))
   356  					Expect(requester.MakeRequestArgsForCall(0)).To(Equal(RequestParams{
   357  						RequestName: internal.PostServiceInstanceRequest,
   358  						RequestBody: si,
   359  					}))
   360  				})
   361  			})
   362  
   363  			When("the request fails", func() {
   364  				It("returns errors and warnings", func() {
   365  					requester.MakeRequestReturns("", Warnings{"fake-warning"}, errors.New("bang"))
   366  
   367  					si := resources.ServiceInstance{
   368  						Type:            resources.UserProvidedServiceInstance,
   369  						Name:            "fake-user-provided-service-instance",
   370  						SpaceGUID:       "fake-space-guid",
   371  						Tags:            types.NewOptionalStringSlice("foo", "bar"),
   372  						RouteServiceURL: types.NewOptionalString("https://fake-route.com"),
   373  						SyslogDrainURL:  types.NewOptionalString("https://fake-sylogg.com"),
   374  						Credentials: types.NewOptionalObject(map[string]interface{}{
   375  							"foo": "bar",
   376  							"baz": 42,
   377  						}),
   378  					}
   379  
   380  					jobURL, warnings, err := client.CreateServiceInstance(si)
   381  
   382  					Expect(jobURL).To(BeEmpty())
   383  					Expect(warnings).To(ConsistOf("fake-warning"))
   384  					Expect(err).To(MatchError("bang"))
   385  				})
   386  			})
   387  		})
   388  	})
   389  
   390  	Describe("UpdateServiceInstance", func() {
   391  		const (
   392  			guid   = "fake-service-instance-guid"
   393  			jobURL = JobURL("fake-job-url")
   394  		)
   395  
   396  		var serviceInstance resources.ServiceInstance
   397  
   398  		Context("user provided", func() {
   399  			BeforeEach(func() {
   400  				serviceInstance = resources.ServiceInstance{
   401  					Name:            "fake-new-user-provided-service-instance",
   402  					Tags:            types.NewOptionalStringSlice("foo", "bar"),
   403  					RouteServiceURL: types.NewOptionalString("https://fake-route.com"),
   404  					SyslogDrainURL:  types.NewOptionalString("https://fake-sylogg.com"),
   405  					Credentials: types.NewOptionalObject(map[string]interface{}{
   406  						"foo": "bar",
   407  						"baz": 42,
   408  					}),
   409  					MaintenanceInfoVersion: "9.1.2",
   410  				}
   411  			})
   412  
   413  			When("the request succeeds", func() {
   414  				BeforeEach(func() {
   415  					requester.MakeRequestReturns(jobURL, Warnings{"fake-warning"}, nil)
   416  				})
   417  
   418  				It("returns warnings and no errors", func() {
   419  					job, warnings, err := client.UpdateServiceInstance(guid, serviceInstance)
   420  
   421  					Expect(job).To(Equal(jobURL))
   422  					Expect(warnings).To(ConsistOf("fake-warning"))
   423  					Expect(err).NotTo(HaveOccurred())
   424  
   425  					Expect(requester.MakeRequestCallCount()).To(Equal(1))
   426  					Expect(requester.MakeRequestArgsForCall(0)).To(Equal(RequestParams{
   427  						RequestName: internal.PatchServiceInstanceRequest,
   428  						URIParams:   internal.Params{"service_instance_guid": guid},
   429  						RequestBody: serviceInstance,
   430  					}))
   431  				})
   432  			})
   433  		})
   434  
   435  		Context("managed", func() {
   436  			BeforeEach(func() {
   437  				serviceInstance = resources.ServiceInstance{
   438  					Name:            "fake-new-user-provided-service-instance",
   439  					Tags:            types.NewOptionalStringSlice("foo", "bar"),
   440  					ServicePlanGUID: guid,
   441  					Parameters:      types.NewOptionalObject(map[string]interface{}{"some-param": "some-value"}),
   442  				}
   443  			})
   444  
   445  			When("the request succeeds", func() {
   446  				BeforeEach(func() {
   447  					requester.MakeRequestReturns(jobURL, Warnings{"fake-warning"}, nil)
   448  				})
   449  
   450  				It("returns warnings and no errors", func() {
   451  					job, warnings, err := client.UpdateServiceInstance(guid, serviceInstance)
   452  
   453  					Expect(job).To(Equal(jobURL))
   454  					Expect(warnings).To(ConsistOf("fake-warning"))
   455  					Expect(err).NotTo(HaveOccurred())
   456  
   457  					Expect(requester.MakeRequestCallCount()).To(Equal(1))
   458  					Expect(requester.MakeRequestArgsForCall(0)).To(Equal(RequestParams{
   459  						RequestName: internal.PatchServiceInstanceRequest,
   460  						URIParams:   internal.Params{"service_instance_guid": guid},
   461  						RequestBody: serviceInstance,
   462  					}))
   463  				})
   464  			})
   465  		})
   466  
   467  		When("the request fails", func() {
   468  			BeforeEach(func() {
   469  				requester.MakeRequestReturns("", Warnings{"fake-warning"}, errors.New("bang"))
   470  			})
   471  
   472  			It("returns errors and warnings", func() {
   473  				jobURL, warnings, err := client.UpdateServiceInstance(guid, serviceInstance)
   474  
   475  				Expect(jobURL).To(BeEmpty())
   476  				Expect(warnings).To(ConsistOf("fake-warning"))
   477  				Expect(err).To(MatchError("bang"))
   478  			})
   479  		})
   480  	})
   481  
   482  	Describe("DeleteServiceInstance", func() {
   483  		const (
   484  			guid   = "fake-service-instance-guid"
   485  			jobURL = JobURL("fake-job-url")
   486  		)
   487  
   488  		It("makes the right request", func() {
   489  			client.DeleteServiceInstance(guid)
   490  
   491  			Expect(requester.MakeRequestCallCount()).To(Equal(1))
   492  			Expect(requester.MakeRequestArgsForCall(0)).To(Equal(RequestParams{
   493  				RequestName: internal.DeleteServiceInstanceRequest,
   494  				URIParams:   internal.Params{"service_instance_guid": guid},
   495  			}))
   496  		})
   497  
   498  		When("there are query parameters", func() {
   499  			It("passes them through", func() {
   500  				client.DeleteServiceInstance(guid, Query{Key: NameFilter, Values: []string{"foo"}})
   501  
   502  				Expect(requester.MakeRequestCallCount()).To(Equal(1))
   503  				Expect(requester.MakeRequestArgsForCall(0).Query).To(ConsistOf(Query{Key: NameFilter, Values: []string{"foo"}}))
   504  			})
   505  		})
   506  
   507  		When("the request succeeds", func() {
   508  			BeforeEach(func() {
   509  				requester.MakeRequestReturns(jobURL, Warnings{"fake-warning"}, nil)
   510  			})
   511  
   512  			It("returns warnings and no errors", func() {
   513  				job, warnings, err := client.DeleteServiceInstance(guid)
   514  
   515  				Expect(job).To(Equal(jobURL))
   516  				Expect(warnings).To(ConsistOf("fake-warning"))
   517  				Expect(err).NotTo(HaveOccurred())
   518  			})
   519  		})
   520  
   521  		When("the request fails", func() {
   522  			BeforeEach(func() {
   523  				requester.MakeRequestReturns("", Warnings{"fake-warning"}, errors.New("bang"))
   524  			})
   525  
   526  			It("returns errors and warnings", func() {
   527  				jobURL, warnings, err := client.DeleteServiceInstance(guid)
   528  
   529  				Expect(jobURL).To(BeEmpty())
   530  				Expect(warnings).To(ConsistOf("fake-warning"))
   531  				Expect(err).To(MatchError("bang"))
   532  			})
   533  		})
   534  	})
   535  
   536  	Describe("shared service instances", func() {
   537  		Describe("ShareServiceInstanceToSpaces", func() {
   538  			var (
   539  				serviceInstanceGUID string
   540  				spaceGUIDs          []string
   541  			)
   542  
   543  			BeforeEach(func() {
   544  				serviceInstanceGUID = "some-service-instance-guid"
   545  				spaceGUIDs = []string{"some-space-guid", "some-other-space-guid"}
   546  			})
   547  
   548  			It("makes the right request", func() {
   549  				client.ShareServiceInstanceToSpaces(serviceInstanceGUID, spaceGUIDs)
   550  
   551  				Expect(requester.MakeRequestCallCount()).To(Equal(1))
   552  
   553  				actualRequest := requester.MakeRequestArgsForCall(0)
   554  				Expect(actualRequest.RequestName).To(Equal(internal.PostServiceInstanceRelationshipsSharedSpacesRequest))
   555  				Expect(actualRequest.URIParams).To(Equal(internal.Params{"service_instance_guid": serviceInstanceGUID}))
   556  				Expect(actualRequest.RequestBody).To(Equal(resources.RelationshipList{
   557  					GUIDs: spaceGUIDs,
   558  				}))
   559  			})
   560  
   561  			When("the request succeeds", func() {
   562  				BeforeEach(func() {
   563  					requester.MakeRequestCalls(func(params RequestParams) (JobURL, Warnings, error) {
   564  						json.Unmarshal([]byte(`{"data":[{"guid":"some-space-guid"}, {"guid":"some-other-space-guid"}]}`), params.ResponseBody)
   565  						return "", Warnings{"fake-warning"}, nil
   566  					})
   567  				})
   568  
   569  				It("returns warnings and no errors", func() {
   570  					relationships, warnings, err := client.ShareServiceInstanceToSpaces(serviceInstanceGUID, spaceGUIDs)
   571  
   572  					Expect(warnings).To(ConsistOf("fake-warning"))
   573  					Expect(err).NotTo(HaveOccurred())
   574  					Expect(relationships).To(Equal(resources.RelationshipList{GUIDs: spaceGUIDs}))
   575  				})
   576  			})
   577  
   578  			When("the request fails", func() {
   579  				BeforeEach(func() {
   580  					requester.MakeRequestReturns("", Warnings{"fake-warning"}, errors.New("bang"))
   581  				})
   582  
   583  				It("returns errors and warnings", func() {
   584  					_, warnings, err := client.ShareServiceInstanceToSpaces(serviceInstanceGUID, spaceGUIDs)
   585  
   586  					Expect(warnings).To(ConsistOf("fake-warning"))
   587  					Expect(err).To(MatchError("bang"))
   588  				})
   589  			})
   590  		})
   591  
   592  		Describe("UnshareServiceInstanceFromSpace", func() {
   593  			var (
   594  				serviceInstanceGUID string
   595  				spaceGUID           string
   596  			)
   597  
   598  			BeforeEach(func() {
   599  				serviceInstanceGUID = "some-service-instance-guid"
   600  				spaceGUID = "some-space-guid"
   601  			})
   602  
   603  			It("makes the right request", func() {
   604  				client.UnshareServiceInstanceFromSpace(serviceInstanceGUID, spaceGUID)
   605  
   606  				Expect(requester.MakeRequestCallCount()).To(Equal(1))
   607  				Expect(requester.MakeRequestArgsForCall(0)).To(Equal(RequestParams{
   608  					RequestName: internal.DeleteServiceInstanceRelationshipsSharedSpaceRequest,
   609  					URIParams: internal.Params{
   610  						"service_instance_guid": serviceInstanceGUID,
   611  						"space_guid":            spaceGUID},
   612  				}))
   613  			})
   614  
   615  			When("the request succeeds", func() {
   616  				BeforeEach(func() {
   617  					requester.MakeRequestReturns("", Warnings{"fake-warning"}, nil)
   618  				})
   619  
   620  				It("returns warnings and no errors", func() {
   621  					warnings, err := client.UnshareServiceInstanceFromSpace(serviceInstanceGUID, spaceGUID)
   622  
   623  					Expect(warnings).To(ConsistOf("fake-warning"))
   624  					Expect(err).NotTo(HaveOccurred())
   625  				})
   626  			})
   627  
   628  			When("the request fails", func() {
   629  				BeforeEach(func() {
   630  					requester.MakeRequestReturns("", Warnings{"fake-warning"}, errors.New("bang"))
   631  				})
   632  
   633  				It("returns errors and warnings", func() {
   634  					warnings, err := client.UnshareServiceInstanceFromSpace(serviceInstanceGUID, spaceGUID)
   635  
   636  					Expect(warnings).To(ConsistOf("fake-warning"))
   637  					Expect(err).To(MatchError("bang"))
   638  				})
   639  			})
   640  		})
   641  
   642  		Describe("GetServiceInstanceSharedSpaces", func() {
   643  			var (
   644  				serviceInstanceGUID string
   645  			)
   646  
   647  			BeforeEach(func() {
   648  				serviceInstanceGUID = "some-service-instance-guid"
   649  			})
   650  
   651  			It("makes the right request", func() {
   652  				client.GetServiceInstanceSharedSpaces(serviceInstanceGUID)
   653  
   654  				Expect(requester.MakeRequestCallCount()).To(Equal(1))
   655  
   656  				actualRequest := requester.MakeRequestArgsForCall(0)
   657  				Expect(actualRequest.RequestName).To(Equal(internal.GetServiceInstanceRelationshipsSharedSpacesRequest))
   658  				Expect(actualRequest.URIParams).To(Equal(internal.Params{"service_instance_guid": serviceInstanceGUID}))
   659  				Expect(actualRequest.Query).To(ConsistOf(
   660  					Query{
   661  						Key:    FieldsSpace,
   662  						Values: []string{"guid", "name", "relationships.organization"},
   663  					},
   664  					Query{
   665  						Key:    FieldsSpaceOrganization,
   666  						Values: []string{"guid", "name"},
   667  					},
   668  				))
   669  			})
   670  
   671  			When("the request succeeds", func() {
   672  				BeforeEach(func() {
   673  					requester.MakeRequestCalls(func(params RequestParams) (JobURL, Warnings, error) {
   674  						jsonry.Unmarshal([]byte(`{
   675  								   "data": [{"guid":"some-space-guid"},{"guid":"some-other-space-guid"}],
   676  								   "links": {
   677  									  "self": {
   678  										 "href": "https://some-url/v3/service_instances/7915bc51-8203-4758-b0e2-f77bfcdc38cb/relationships/shared_spaces"
   679  									  }
   680  								   },
   681  								   "included": {
   682  									  "spaces": [
   683  										 {
   684  											"name": "some-space-name",
   685  											"guid": "some-space-guid",
   686  											"relationships": {
   687  											   "organization": {
   688  												  "data": {
   689  													 "guid": "some-org-guid"
   690  												  }
   691  											   }
   692  											}
   693  										 },
   694  										{
   695  											"name": "some-other-space-name",
   696  											"guid": "some-other-space-guid",
   697  											"relationships": {
   698  											   "organization": {
   699  												  "data": {
   700  													 "guid": "some-org-guid"
   701  												  }
   702  											   }
   703  											}
   704  										 }
   705  									  ],
   706  									  "organizations": [
   707  										 {
   708  											"name": "some-org-name",
   709  											"guid": "some-org-guid"
   710  										 }
   711  									  ]
   712  								   }
   713  								}`), params.ResponseBody)
   714  						return "", Warnings{"fake-warning"}, nil
   715  					})
   716  				})
   717  
   718  				It("returns warnings and no errors", func() {
   719  					spaces, warnings, err := client.GetServiceInstanceSharedSpaces(serviceInstanceGUID)
   720  
   721  					Expect(warnings).To(ConsistOf("fake-warning"))
   722  					Expect(err).NotTo(HaveOccurred())
   723  					Expect(spaces).To(Equal([]SpaceWithOrganization{
   724  						{
   725  							SpaceGUID:        "some-space-guid",
   726  							SpaceName:        "some-space-name",
   727  							OrganizationName: "some-org-name",
   728  						},
   729  						{
   730  							SpaceGUID:        "some-other-space-guid",
   731  							SpaceName:        "some-other-space-name",
   732  							OrganizationName: "some-org-name",
   733  						},
   734  					}))
   735  				})
   736  			})
   737  
   738  			When("the request fails", func() {
   739  				BeforeEach(func() {
   740  					requester.MakeRequestReturns("", Warnings{"fake-warning"}, errors.New("bang"))
   741  				})
   742  
   743  				It("returns errors and warnings", func() {
   744  					_, warnings, err := client.GetServiceInstanceSharedSpaces(serviceInstanceGUID)
   745  
   746  					Expect(warnings).To(ConsistOf("fake-warning"))
   747  					Expect(err).To(MatchError("bang"))
   748  				})
   749  			})
   750  		})
   751  
   752  		Describe("GetServiceInstanceUsageSummary", func() {
   753  			var (
   754  				serviceInstanceGUID string
   755  				spaceGUIDs          []string
   756  			)
   757  
   758  			BeforeEach(func() {
   759  				serviceInstanceGUID = "some-service-instance-guid"
   760  				spaceGUIDs = []string{"some-space-guid", "some-other-space-guid"}
   761  			})
   762  
   763  			It("makes the right request", func() {
   764  				client.GetServiceInstanceUsageSummary(serviceInstanceGUID)
   765  
   766  				Expect(requester.MakeRequestCallCount()).To(Equal(1))
   767  
   768  				actualRequest := requester.MakeRequestArgsForCall(0)
   769  				Expect(actualRequest.RequestName).To(Equal(internal.GetServiceInstanceSharedSpacesUsageSummaryRequest))
   770  				Expect(actualRequest.URIParams).To(Equal(internal.Params{"service_instance_guid": serviceInstanceGUID}))
   771  			})
   772  
   773  			When("the request succeeds", func() {
   774  				BeforeEach(func() {
   775  					requester.MakeRequestCalls(func(params RequestParams) (JobURL, Warnings, error) {
   776  						jsonry.Unmarshal([]byte(`{
   777  							"usage_summary": [
   778  								{
   779  									"space": {
   780  										"guid": "some-space-guid"
   781  									},
   782  									"bound_app_count": 2
   783  								},
   784  								{
   785  									"space": {
   786  										"guid": "some-other-space-guid"
   787  									},
   788  									"bound_app_count": 1
   789  								}
   790  							],
   791  							"links": {
   792  								"self": {
   793  									"href": "https://api.example.org/v3/service_instances/some_instance_guid/relationships/shared_spaces/usage_summary"
   794  								},
   795  								"shared_spaces": {
   796  									"href": "https://api.example.org/v3/service_instances/some_instance_guid/relationships/shared_spaces"
   797  								},
   798  								"service_instance": {
   799  									"href": "https://api.example.org/v3/service_instances/some_instance_guid"
   800  								}
   801  							}
   802  						}`), params.ResponseBody)
   803  						return "", Warnings{"fake-warning"}, nil
   804  					})
   805  				})
   806  
   807  				It("returns warnings and no errors", func() {
   808  					usageSummary, warnings, err := client.GetServiceInstanceUsageSummary(serviceInstanceGUID)
   809  
   810  					Expect(warnings).To(ConsistOf("fake-warning"))
   811  					Expect(err).NotTo(HaveOccurred())
   812  					Expect(usageSummary).To(Equal([]resources.ServiceInstanceUsageSummary{{SpaceGUID: spaceGUIDs[0], BoundAppCount: 2}, {SpaceGUID: spaceGUIDs[1], BoundAppCount: 1}}))
   813  				})
   814  			})
   815  
   816  			When("the request fails", func() {
   817  				BeforeEach(func() {
   818  					requester.MakeRequestReturns("", Warnings{"fake-warning"}, errors.New("bang"))
   819  				})
   820  
   821  				It("returns errors and warnings", func() {
   822  					_, warnings, err := client.GetServiceInstanceUsageSummary(serviceInstanceGUID)
   823  
   824  					Expect(warnings).To(ConsistOf("fake-warning"))
   825  					Expect(err).To(MatchError("bang"))
   826  				})
   827  			})
   828  		})
   829  	})
   830  })