github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/api/cloudcontroller/ccv2/service_binding_test.go (about)

     1  package ccv2_test
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     8  	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/ghttp"
    13  )
    14  
    15  var _ = Describe("Service Binding", func() {
    16  	var client *Client
    17  
    18  	BeforeEach(func() {
    19  		client = NewTestClient()
    20  	})
    21  
    22  	Describe("CreateServiceBinding", func() {
    23  		var (
    24  			appGUID           string
    25  			serviceGUID       string
    26  			bindingName       string
    27  			acceptsIncomplete bool
    28  			parameters        map[string]interface{}
    29  
    30  			serviceBinding ServiceBinding
    31  			warnings       Warnings
    32  			executeErr     error
    33  		)
    34  
    35  		BeforeEach(func() {
    36  			appGUID = "some-app-guid"
    37  			serviceGUID = "some-service-instance-guid"
    38  			parameters = map[string]interface{}{
    39  				"the-service-broker": "wants this object",
    40  			}
    41  		})
    42  
    43  		JustBeforeEach(func() {
    44  			serviceBinding, warnings, executeErr = client.CreateServiceBinding(appGUID, serviceGUID, bindingName, acceptsIncomplete, parameters)
    45  		})
    46  
    47  		When("the create is successful", func() {
    48  			When("a service binding name is provided", func() {
    49  				BeforeEach(func() {
    50  					bindingName = "some-binding-name"
    51  					acceptsIncomplete = false
    52  
    53  					expectedRequestBody := map[string]interface{}{
    54  						"service_instance_guid": "some-service-instance-guid",
    55  						"app_guid":              "some-app-guid",
    56  						"name":                  "some-binding-name",
    57  						"parameters": map[string]interface{}{
    58  							"the-service-broker": "wants this object",
    59  						},
    60  					}
    61  					response := `
    62  						{
    63  							"metadata": {
    64  								"guid": "some-service-binding-guid"
    65  							}
    66  						}`
    67  					server.AppendHandlers(
    68  						CombineHandlers(
    69  							VerifyRequest(http.MethodPost, "/v2/service_bindings", "accepts_incomplete=false"),
    70  							VerifyJSONRepresenting(expectedRequestBody),
    71  							RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
    72  						),
    73  					)
    74  				})
    75  
    76  				It("returns the created object and warnings", func() {
    77  					Expect(executeErr).NotTo(HaveOccurred())
    78  
    79  					Expect(serviceBinding).To(Equal(ServiceBinding{GUID: "some-service-binding-guid"}))
    80  					Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
    81  				})
    82  			})
    83  
    84  			When("a service binding name is not provided", func() {
    85  				BeforeEach(func() {
    86  					bindingName = ""
    87  					acceptsIncomplete = false
    88  
    89  					expectedRequestBody := map[string]interface{}{
    90  						"service_instance_guid": "some-service-instance-guid",
    91  						"app_guid":              "some-app-guid",
    92  						"parameters": map[string]interface{}{
    93  							"the-service-broker": "wants this object",
    94  						},
    95  					}
    96  					response := `
    97  						{
    98  							"metadata": {
    99  								"guid": "some-service-binding-guid"
   100  							}
   101  						}`
   102  					server.AppendHandlers(
   103  						CombineHandlers(
   104  							VerifyRequest(http.MethodPost, "/v2/service_bindings", "accepts_incomplete=false"),
   105  							VerifyJSONRepresenting(expectedRequestBody),
   106  							RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   107  						),
   108  					)
   109  				})
   110  
   111  				It("returns the created object and warnings", func() {
   112  					Expect(executeErr).NotTo(HaveOccurred())
   113  
   114  					Expect(serviceBinding).To(Equal(ServiceBinding{GUID: "some-service-binding-guid"}))
   115  					Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   116  				})
   117  			})
   118  
   119  			When("accepts_incomplete is true", func() {
   120  				BeforeEach(func() {
   121  					bindingName = "some-binding-name"
   122  					acceptsIncomplete = true
   123  
   124  					expectedRequestBody := map[string]interface{}{
   125  						"service_instance_guid": "some-service-instance-guid",
   126  						"app_guid":              "some-app-guid",
   127  						"name":                  "some-binding-name",
   128  						"parameters": map[string]interface{}{
   129  							"the-service-broker": "wants this object",
   130  						},
   131  					}
   132  					response := `
   133  						{
   134  							"metadata": {
   135  								"guid": "some-service-binding-guid"
   136  							}
   137  						}`
   138  					server.AppendHandlers(
   139  						CombineHandlers(
   140  							VerifyRequest(http.MethodPost, "/v2/service_bindings", "accepts_incomplete=true"),
   141  							VerifyJSONRepresenting(expectedRequestBody),
   142  							RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   143  						),
   144  					)
   145  				})
   146  
   147  				It("returns the created object and warnings", func() {
   148  					Expect(executeErr).NotTo(HaveOccurred())
   149  
   150  					Expect(serviceBinding).To(Equal(ServiceBinding{GUID: "some-service-binding-guid"}))
   151  					Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   152  				})
   153  			})
   154  		})
   155  
   156  		When("the create returns an error", func() {
   157  			BeforeEach(func() {
   158  				response := `
   159  				{
   160  					  "description": "The app space binding to service is taken: some-app-guid some-service-instance-guid",
   161  						"error_code": "CF-ServiceBindingAppServiceTaken",
   162  						"code": 90003
   163  				}
   164  			`
   165  				server.AppendHandlers(
   166  					CombineHandlers(
   167  						VerifyRequest(http.MethodPost, "/v2/service_bindings"),
   168  						RespondWith(http.StatusBadRequest, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   169  					),
   170  				)
   171  			})
   172  
   173  			It("returns the error and warnings", func() {
   174  				Expect(executeErr).To(MatchError(ccerror.ServiceBindingTakenError{Message: "The app space binding to service is taken: some-app-guid some-service-instance-guid"}))
   175  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   176  			})
   177  		})
   178  	})
   179  
   180  	Describe("DeleteServiceBinding", func() {
   181  		var (
   182  			serviceBindingGUID string
   183  			acceptsIncomplete  bool
   184  
   185  			serviceBinding ServiceBinding
   186  			warnings       Warnings
   187  			executeErr     error
   188  		)
   189  
   190  		BeforeEach(func() {
   191  			serviceBindingGUID = "some-service-binding-guid"
   192  		})
   193  
   194  		JustBeforeEach(func() {
   195  			serviceBinding, warnings, executeErr = client.DeleteServiceBinding(serviceBindingGUID, acceptsIncomplete)
   196  		})
   197  
   198  		When("the service binding exist", func() {
   199  			When("accepts_incomplete is true", func() {
   200  				BeforeEach(func() {
   201  					acceptsIncomplete = true
   202  					response := fmt.Sprintf(`{
   203  						 "metadata": {
   204  								"guid": "%s"
   205  						 },
   206  						 "entity": {
   207  								"app_guid": "63af8eb4-6ac6-4baa-b97d-da32d473131c",
   208  								"service_instance_guid": "637a1734-3eec-408e-aeaa-bfc577d893b7",
   209  								"last_operation": {
   210  									 "state": "in progress"
   211  								}
   212  						 }
   213  					 }`, serviceBindingGUID)
   214  					server.AppendHandlers(
   215  						CombineHandlers(
   216  							VerifyRequest(http.MethodDelete, "/v2/service_bindings/some-service-binding-guid", "accepts_incomplete=true"),
   217  							RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   218  						),
   219  					)
   220  				})
   221  
   222  				It("returns the service binding and warnings", func() {
   223  					Expect(executeErr).NotTo(HaveOccurred())
   224  					Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   225  					Expect(serviceBinding).To(Equal(ServiceBinding{
   226  						GUID:                serviceBindingGUID,
   227  						AppGUID:             "63af8eb4-6ac6-4baa-b97d-da32d473131c",
   228  						ServiceInstanceGUID: "637a1734-3eec-408e-aeaa-bfc577d893b7",
   229  						LastOperation: LastOperation{
   230  							State: constant.LastOperationInProgress,
   231  						},
   232  					}))
   233  				})
   234  			})
   235  
   236  			When("accepts_incomplete is false", func() {
   237  				BeforeEach(func() {
   238  					acceptsIncomplete = false
   239  					server.AppendHandlers(
   240  						CombineHandlers(
   241  							VerifyRequest(http.MethodDelete, "/v2/service_bindings/some-service-binding-guid"),
   242  							RespondWith(http.StatusNoContent, "{}", http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   243  						))
   244  				})
   245  
   246  				It("deletes the service binding", func() {
   247  					Expect(executeErr).NotTo(HaveOccurred())
   248  					Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   249  				})
   250  			})
   251  		})
   252  
   253  		When("the service binding does not exist", func() {
   254  			BeforeEach(func() {
   255  				acceptsIncomplete = false
   256  				response := `{
   257  				"code": 90004,
   258  				"description": "The service binding could not be found: some-service-binding-guid",
   259  				"error_code": "CF-ServiceBindingNotFound"
   260  			}`
   261  				server.AppendHandlers(
   262  					CombineHandlers(
   263  						VerifyRequest(http.MethodDelete, "/v2/service_bindings/some-service-binding-guid"),
   264  						RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   265  					),
   266  				)
   267  			})
   268  
   269  			It("returns a not found error", func() {
   270  				Expect(executeErr).To(MatchError(ccerror.ResourceNotFoundError{
   271  					Message: "The service binding could not be found: some-service-binding-guid",
   272  				}))
   273  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   274  			})
   275  		})
   276  	})
   277  
   278  	Describe("GetServiceBinding", func() {
   279  		var (
   280  			serviceBinding ServiceBinding
   281  			warnings       Warnings
   282  			executeErr     error
   283  		)
   284  
   285  		JustBeforeEach(func() {
   286  			serviceBinding, warnings, executeErr = client.GetServiceBinding("some-service-binding-guid")
   287  		})
   288  
   289  		When("the cc returns an error", func() {
   290  			BeforeEach(func() {
   291  				response := `{
   292  					"code": 1,
   293  					"description": "some error description",
   294  					"error_code": "CF-SomeError"
   295  				}`
   296  				server.AppendHandlers(
   297  					CombineHandlers(
   298  						VerifyRequest(http.MethodGet, "/v2/service_bindings/some-service-binding-guid"),
   299  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}}),
   300  					),
   301  				)
   302  			})
   303  
   304  			It("returns the error", func() {
   305  				Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{
   306  					V2ErrorResponse: ccerror.V2ErrorResponse{
   307  						Code:        1,
   308  						Description: "some error description",
   309  						ErrorCode:   "CF-SomeError",
   310  					},
   311  					ResponseCode: http.StatusTeapot,
   312  				}))
   313  
   314  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   315  			})
   316  		})
   317  
   318  		When("there are no errors", func() {
   319  			Context("and entity.last_operation is not present", func() {
   320  				BeforeEach(func() {
   321  					response := `{
   322  						"metadata": {
   323  							"guid": "service-binding-guid-1"
   324  						},
   325  						"entity": {
   326  							"app_guid":"app-guid-1",
   327  							"service_instance_guid": "service-instance-guid-1"
   328  						}
   329  					}`
   330  					server.AppendHandlers(
   331  						CombineHandlers(
   332  							VerifyRequest(http.MethodGet, "/v2/service_bindings/some-service-binding-guid"),
   333  							RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}}),
   334  						),
   335  					)
   336  				})
   337  
   338  				It("returns the service binding", func() {
   339  					Expect(executeErr).ToNot(HaveOccurred())
   340  					Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   341  
   342  					Expect(serviceBinding).To(Equal(ServiceBinding{
   343  						GUID:                "service-binding-guid-1",
   344  						AppGUID:             "app-guid-1",
   345  						ServiceInstanceGUID: "service-instance-guid-1",
   346  					}))
   347  				})
   348  			})
   349  
   350  			Context("and entity.last_operation is present", func() {
   351  				BeforeEach(func() {
   352  					response := `{
   353  						"metadata": {
   354  							"guid": "service-binding-guid-1"
   355  						},
   356  						"entity": {
   357  							"app_guid":"app-guid-1",
   358  							"service_instance_guid": "service-instance-guid-1",
   359  							"last_operation": {
   360  								 "state": "succeeded"
   361  							}
   362  						}
   363  					}`
   364  					server.AppendHandlers(
   365  						CombineHandlers(
   366  							VerifyRequest(http.MethodGet, "/v2/service_bindings/some-service-binding-guid"),
   367  							RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}}),
   368  						),
   369  					)
   370  				})
   371  
   372  				It("returns the service binding", func() {
   373  					Expect(executeErr).ToNot(HaveOccurred())
   374  					Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   375  
   376  					Expect(serviceBinding).To(Equal(ServiceBinding{
   377  						GUID:                "service-binding-guid-1",
   378  						AppGUID:             "app-guid-1",
   379  						ServiceInstanceGUID: "service-instance-guid-1",
   380  						LastOperation:       LastOperation{State: constant.LastOperationSucceeded},
   381  					}))
   382  				})
   383  			})
   384  		})
   385  	})
   386  
   387  	Describe("GetServiceBindings", func() {
   388  		BeforeEach(func() {
   389  			response1 := `{
   390  				"next_url": "/v2/service_bindings?q=app_guid:some-app-guid&page=2",
   391  				"resources": [
   392  					{
   393  						"metadata": {
   394  							"guid": "service-binding-guid-1"
   395  						},
   396  						"entity": {
   397  							"app_guid":"app-guid-1",
   398  							"service_instance_guid": "service-instance-guid-1"
   399  						}
   400  					},
   401  					{
   402  						"metadata": {
   403  							"guid": "service-binding-guid-2"
   404  						},
   405  						"entity": {
   406  							"app_guid":"app-guid-2",
   407  							"service_instance_guid": "service-instance-guid-2"
   408  						}
   409  					}
   410  				]
   411  			}`
   412  			response2 := `{
   413  				"next_url": null,
   414  				"resources": [
   415  					{
   416  						"metadata": {
   417  							"guid": "service-binding-guid-3"
   418  						},
   419  						"entity": {
   420  							"app_guid":"app-guid-3",
   421  							"service_instance_guid": "service-instance-guid-3"
   422  						}
   423  					},
   424  					{
   425  						"metadata": {
   426  							"guid": "service-binding-guid-4"
   427  						},
   428  						"entity": {
   429  							"app_guid":"app-guid-4",
   430  							"service_instance_guid": "service-instance-guid-4"
   431  						}
   432  					}
   433  				]
   434  			}`
   435  			server.AppendHandlers(
   436  				CombineHandlers(
   437  					VerifyRequest(http.MethodGet, "/v2/service_bindings", "q=app_guid:some-app-guid"),
   438  					RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   439  				),
   440  			)
   441  			server.AppendHandlers(
   442  				CombineHandlers(
   443  					VerifyRequest(http.MethodGet, "/v2/service_bindings", "q=app_guid:some-app-guid&page=2"),
   444  					RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}),
   445  				),
   446  			)
   447  		})
   448  
   449  		When("service bindings exist", func() {
   450  			It("returns all the queried service bindings", func() {
   451  				serviceBindings, warnings, err := client.GetServiceBindings(Filter{
   452  					Type:     constant.AppGUIDFilter,
   453  					Operator: constant.EqualOperator,
   454  					Values:   []string{"some-app-guid"},
   455  				})
   456  				Expect(err).NotTo(HaveOccurred())
   457  				Expect(serviceBindings).To(ConsistOf([]ServiceBinding{
   458  					{GUID: "service-binding-guid-1", AppGUID: "app-guid-1", ServiceInstanceGUID: "service-instance-guid-1"},
   459  					{GUID: "service-binding-guid-2", AppGUID: "app-guid-2", ServiceInstanceGUID: "service-instance-guid-2"},
   460  					{GUID: "service-binding-guid-3", AppGUID: "app-guid-3", ServiceInstanceGUID: "service-instance-guid-3"},
   461  					{GUID: "service-binding-guid-4", AppGUID: "app-guid-4", ServiceInstanceGUID: "service-instance-guid-4"},
   462  				}))
   463  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"}))
   464  			})
   465  		})
   466  	})
   467  
   468  	Describe("GetServiceInstanceServiceBindings", func() {
   469  		When("there are service bindings", func() {
   470  			BeforeEach(func() {
   471  				response1 := `{
   472  					"next_url": "/v2/service_instances/some-service-instance-guid/service_bindings?page=2",
   473  					"resources": [
   474  						{
   475  							"metadata": {
   476  								"guid": "service-binding-guid-1"
   477  							},
   478  							"entity": {
   479  								"app_guid":"app-guid-1",
   480  								"service_instance_guid": "service-instance-guid-1"
   481  							}
   482  						},
   483  						{
   484  							"metadata": {
   485  								"guid": "service-binding-guid-2"
   486  							},
   487  							"entity": {
   488  								"app_guid":"app-guid-2",
   489  								"service_instance_guid": "service-instance-guid-2"
   490  							}
   491  						}
   492  					]
   493  				}`
   494  				response2 := `{
   495  					"next_url": null,
   496  					"resources": [
   497  						{
   498  							"metadata": {
   499  								"guid": "service-binding-guid-3"
   500  							},
   501  							"entity": {
   502  								"app_guid":"app-guid-3",
   503  								"service_instance_guid": "service-instance-guid-3"
   504  							}
   505  						},
   506  						{
   507  							"metadata": {
   508  								"guid": "service-binding-guid-4"
   509  							},
   510  							"entity": {
   511  								"app_guid":"app-guid-4",
   512  								"service_instance_guid": "service-instance-guid-4"
   513  							}
   514  						}
   515  					]
   516  				}`
   517  				server.AppendHandlers(
   518  					CombineHandlers(
   519  						VerifyRequest(http.MethodGet, "/v2/service_instances/some-service-instance-guid/service_bindings"),
   520  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   521  					),
   522  				)
   523  				server.AppendHandlers(
   524  					CombineHandlers(
   525  						VerifyRequest(http.MethodGet, "/v2/service_instances/some-service-instance-guid/service_bindings", "page=2"),
   526  						RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}),
   527  					),
   528  				)
   529  			})
   530  
   531  			It("returns all the service bindings and all warnings", func() {
   532  				serviceBindings, warnings, err := client.GetServiceInstanceServiceBindings("some-service-instance-guid")
   533  				Expect(err).NotTo(HaveOccurred())
   534  				Expect(serviceBindings).To(Equal([]ServiceBinding{
   535  					{GUID: "service-binding-guid-1", AppGUID: "app-guid-1", ServiceInstanceGUID: "service-instance-guid-1"},
   536  					{GUID: "service-binding-guid-2", AppGUID: "app-guid-2", ServiceInstanceGUID: "service-instance-guid-2"},
   537  					{GUID: "service-binding-guid-3", AppGUID: "app-guid-3", ServiceInstanceGUID: "service-instance-guid-3"},
   538  					{GUID: "service-binding-guid-4", AppGUID: "app-guid-4", ServiceInstanceGUID: "service-instance-guid-4"},
   539  				}))
   540  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"}))
   541  			})
   542  		})
   543  
   544  		When("there are no service bindings", func() {
   545  			BeforeEach(func() {
   546  				response1 := `{
   547  					"next_url": null,
   548  					"resources": []
   549  				}`
   550  				server.AppendHandlers(
   551  					CombineHandlers(
   552  						VerifyRequest(http.MethodGet, "/v2/service_instances/some-service-instance-guid/service_bindings"),
   553  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   554  					),
   555  				)
   556  			})
   557  			It("returns an empty list of service bindings and all warnings", func() {
   558  				serviceBindings, warnings, err := client.GetServiceInstanceServiceBindings("some-service-instance-guid")
   559  				Expect(err).NotTo(HaveOccurred())
   560  				Expect(serviceBindings).To(HaveLen(0))
   561  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   562  			})
   563  		})
   564  
   565  		When("an error is encountered", func() {
   566  			BeforeEach(func() {
   567  				response := `{
   568  				 "description": "Unknown request",
   569  				 "error_code": "CF-NotFound",
   570  				 "code": 10000
   571  				}`
   572  				server.AppendHandlers(
   573  					CombineHandlers(
   574  						VerifyRequest(http.MethodGet, "/v2/service_instances/some-service-instance-guid/service_bindings"),
   575  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   576  					),
   577  				)
   578  			})
   579  
   580  			It("returns an error and all warnings", func() {
   581  				_, warnings, err := client.GetServiceInstanceServiceBindings("some-service-instance-guid")
   582  				Expect(err).To(MatchError(ccerror.V2UnexpectedResponseError{
   583  					V2ErrorResponse: ccerror.V2ErrorResponse{
   584  						Code:        10000,
   585  						Description: "Unknown request",
   586  						ErrorCode:   "CF-NotFound",
   587  					},
   588  					RequestIDs:   nil,
   589  					ResponseCode: 418,
   590  				}))
   591  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   592  			})
   593  		})
   594  	})
   595  
   596  	Describe("GetUserProvidedServiceInstanceServiceBindings", func() {
   597  		When("there are service bindings", func() {
   598  			BeforeEach(func() {
   599  				response1 := `{
   600  					"next_url": "/v2/user_provided_service_instances/some-user-provided-service-instance-guid/service_bindings?page=2",
   601  					"resources": [
   602  						{
   603  							"metadata": {
   604  								"guid": "service-binding-guid-1"
   605  							},
   606  							"entity": {
   607  								"app_guid":"app-guid-1",
   608  								"service_instance_guid": "user-provided-service-instance-guid-1"
   609  							}
   610  						},
   611  						{
   612  							"metadata": {
   613  								"guid": "service-binding-guid-2"
   614  							},
   615  							"entity": {
   616  								"app_guid":"app-guid-2",
   617  								"service_instance_guid": "user-provided-service-instance-guid-2"
   618  							}
   619  						}
   620  					]
   621  				}`
   622  				response2 := `{
   623  					"next_url": null,
   624  					"resources": [
   625  						{
   626  							"metadata": {
   627  								"guid": "service-binding-guid-3"
   628  							},
   629  							"entity": {
   630  								"app_guid":"app-guid-3",
   631  								"service_instance_guid": "user-provided-service-instance-guid-3"
   632  							}
   633  						},
   634  						{
   635  							"metadata": {
   636  								"guid": "service-binding-guid-4"
   637  							},
   638  							"entity": {
   639  								"app_guid":"app-guid-4",
   640  								"service_instance_guid": "user-provided-service-instance-guid-4"
   641  							}
   642  						}
   643  					]
   644  				}`
   645  				server.AppendHandlers(
   646  					CombineHandlers(
   647  						VerifyRequest(http.MethodGet, "/v2/user_provided_service_instances/some-user-provided-service-instance-guid/service_bindings"),
   648  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   649  					),
   650  				)
   651  				server.AppendHandlers(
   652  					CombineHandlers(
   653  						VerifyRequest(http.MethodGet, "/v2/user_provided_service_instances/some-user-provided-service-instance-guid/service_bindings", "page=2"),
   654  						RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}),
   655  					),
   656  				)
   657  			})
   658  
   659  			It("returns all the service bindings and all warnings", func() {
   660  				serviceBindings, warnings, err := client.GetUserProvidedServiceInstanceServiceBindings("some-user-provided-service-instance-guid")
   661  				Expect(err).NotTo(HaveOccurred())
   662  				Expect(serviceBindings).To(Equal([]ServiceBinding{
   663  					{GUID: "service-binding-guid-1", AppGUID: "app-guid-1", ServiceInstanceGUID: "user-provided-service-instance-guid-1"},
   664  					{GUID: "service-binding-guid-2", AppGUID: "app-guid-2", ServiceInstanceGUID: "user-provided-service-instance-guid-2"},
   665  					{GUID: "service-binding-guid-3", AppGUID: "app-guid-3", ServiceInstanceGUID: "user-provided-service-instance-guid-3"},
   666  					{GUID: "service-binding-guid-4", AppGUID: "app-guid-4", ServiceInstanceGUID: "user-provided-service-instance-guid-4"},
   667  				}))
   668  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning", "this is another warning"}))
   669  			})
   670  		})
   671  
   672  		When("there are no service bindings", func() {
   673  			BeforeEach(func() {
   674  				response := `{
   675  					"next_url": null,
   676  					"resources": []
   677  				}`
   678  				server.AppendHandlers(
   679  					CombineHandlers(
   680  						VerifyRequest(http.MethodGet, "/v2/user_provided_service_instances/some-user-provided-service-instance-guid/service_bindings"),
   681  						RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   682  					),
   683  				)
   684  			})
   685  
   686  			It("returns an empty list of service bindings and all warnings", func() {
   687  				serviceBindings, warnings, err := client.GetUserProvidedServiceInstanceServiceBindings("some-user-provided-service-instance-guid")
   688  				Expect(err).NotTo(HaveOccurred())
   689  				Expect(serviceBindings).To(HaveLen(0))
   690  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   691  			})
   692  		})
   693  
   694  		When("an error is encountered", func() {
   695  			BeforeEach(func() {
   696  				response := `{
   697  				 "description": "Unknown request",
   698  				 "error_code": "CF-NotFound",
   699  				 "code": 10000
   700  				}`
   701  				server.AppendHandlers(
   702  					CombineHandlers(
   703  						VerifyRequest(http.MethodGet, "/v2/user_provided_service_instances/some-user-provided-service-instance-guid/service_bindings"),
   704  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   705  					),
   706  				)
   707  			})
   708  
   709  			It("returns an error and all warnings", func() {
   710  				_, warnings, err := client.GetUserProvidedServiceInstanceServiceBindings("some-user-provided-service-instance-guid")
   711  				Expect(err).To(MatchError(ccerror.V2UnexpectedResponseError{
   712  					V2ErrorResponse: ccerror.V2ErrorResponse{
   713  						Code:        10000,
   714  						Description: "Unknown request",
   715  						ErrorCode:   "CF-NotFound",
   716  					},
   717  					RequestIDs:   nil,
   718  					ResponseCode: 418,
   719  				}))
   720  				Expect(warnings).To(ConsistOf(Warnings{"this is a warning"}))
   721  			})
   722  		})
   723  	})
   724  })