github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/cloudcontroller/ccv3/service_plan_test.go (about)

     1  package ccv3_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/ccv3"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/ccv3fakes"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/internal"
    11  	"code.cloudfoundry.org/cli/resources"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/ghttp"
    15  )
    16  
    17  var _ = Describe("Service Plan", func() {
    18  	var client *Client
    19  	var query []Query
    20  
    21  	BeforeEach(func() {
    22  		client, _ = NewTestClient()
    23  		query = []Query{}
    24  	})
    25  
    26  	Describe("GetServicePlanByGUID", func() {
    27  		const guid = "fake-guid"
    28  
    29  		var requester *ccv3fakes.FakeRequester
    30  
    31  		BeforeEach(func() {
    32  			requester = new(ccv3fakes.FakeRequester)
    33  			client, _ = NewFakeRequesterTestClient(requester)
    34  		})
    35  
    36  		When("service plan exists", func() {
    37  			BeforeEach(func() {
    38  				requester.MakeRequestCalls(func(params RequestParams) (JobURL, Warnings, error) {
    39  					Expect(params.URIParams).To(BeEquivalentTo(map[string]string{"service_plan_guid": guid}))
    40  					Expect(params.RequestName).To(Equal(internal.GetServicePlanRequest))
    41  					params.ResponseBody.(*resources.ServicePlan).GUID = guid
    42  					return "", Warnings{"one", "two"}, nil
    43  				})
    44  			})
    45  
    46  			It("returns the service offering with warnings", func() {
    47  				plan, warnings, err := client.GetServicePlanByGUID(guid)
    48  				Expect(err).ToNot(HaveOccurred())
    49  
    50  				Expect(plan).To(Equal(resources.ServicePlan{
    51  					GUID: guid,
    52  				}))
    53  				Expect(warnings).To(ConsistOf("one", "two"))
    54  			})
    55  		})
    56  
    57  		When("the cloud controller returns errors and warnings", func() {
    58  			BeforeEach(func() {
    59  				requester.MakeRequestReturns(
    60  					"",
    61  					Warnings{"one", "two"},
    62  					ccerror.MultiError{
    63  						ResponseCode: http.StatusTeapot,
    64  						Errors: []ccerror.V3Error{
    65  							{
    66  								Code:   42424,
    67  								Detail: "Some detailed error message",
    68  								Title:  "CF-SomeErrorTitle",
    69  							},
    70  							{
    71  								Code:   11111,
    72  								Detail: "Some other detailed error message",
    73  								Title:  "CF-SomeOtherErrorTitle",
    74  							},
    75  						},
    76  					},
    77  				)
    78  			})
    79  
    80  			It("returns the error and all warnings", func() {
    81  				_, warnings, err := client.GetServicePlanByGUID(guid)
    82  				Expect(err).To(MatchError(ccerror.MultiError{
    83  					ResponseCode: http.StatusTeapot,
    84  					Errors: []ccerror.V3Error{
    85  						{
    86  							Code:   42424,
    87  							Detail: "Some detailed error message",
    88  							Title:  "CF-SomeErrorTitle",
    89  						},
    90  						{
    91  							Code:   11111,
    92  							Detail: "Some other detailed error message",
    93  							Title:  "CF-SomeOtherErrorTitle",
    94  						},
    95  					},
    96  				}))
    97  				Expect(warnings).To(ConsistOf("one", "two"))
    98  			})
    99  		})
   100  
   101  		When("the guid is not specified", func() {
   102  			It("fails with an error", func() {
   103  				_, _, err := client.GetServicePlanByGUID("")
   104  				Expect(err).To(MatchError(ccerror.ServicePlanNotFound{}))
   105  			})
   106  		})
   107  	})
   108  
   109  	Describe("GetServicePlans", func() {
   110  		var (
   111  			plans      []resources.ServicePlan
   112  			warnings   Warnings
   113  			executeErr error
   114  		)
   115  
   116  		JustBeforeEach(func() {
   117  			plans, warnings, executeErr = client.GetServicePlans(query...)
   118  		})
   119  
   120  		When("service plans exist", func() {
   121  			BeforeEach(func() {
   122  				response1 := fmt.Sprintf(`
   123  					{
   124  						"pagination": {
   125  							"next": {
   126  								"href": "%s/v3/service_plans?names=myServicePlan&service_broker_names=myServiceBroker&service_offering_names=someOffering&page=2"
   127  							}
   128  						},
   129  						"resources": [
   130  							{
   131  								"guid": "service-plan-1-guid",
   132  								"name": "service-plan-1-name",
   133  								"description": "service-plan-1-description",
   134                                  "available": true,
   135  								"free": true,
   136  								"visibility_type": "public",
   137  								"relationships": {
   138  									"service_offering": {
   139  									   "data": {
   140  										  "guid": "79d428b9-75b4-44db-addf-19c85c7f0f1e"
   141  									   }
   142  									}
   143  								}
   144  							},
   145  							{
   146  								"guid": "service-plan-2-guid",
   147  								"name": "service-plan-2-name",
   148  								"available": false,
   149  								"visibility_type": "admin",
   150  								"description": "service-plan-2-description",
   151  								"free": false,
   152  								"relationships": {
   153  									"service_offering": {
   154  									   "data": {
   155  										  "guid": "69d428b9-75b4-44db-addf-19c85c7f0f1e"
   156  									   }
   157  									}
   158  								}
   159  							}
   160  						]
   161  					}`,
   162  					server.URL())
   163  
   164  				response2 := `
   165  					{
   166  						"pagination": {
   167  							"next": {
   168  								"href": null
   169  							}
   170  						},
   171  						"resources": [
   172  							{
   173  								"guid": "service-plan-3-guid",
   174  								"name": "service-plan-3-name",
   175  								"visibility_type": "organization",
   176  								"description": "service-plan-3-description",
   177                                  "available": true,
   178  								"free": true,
   179  								"relationships": {
   180  									"service_offering": {
   181  									   "data": {
   182  										  "guid": "59d428b9-75b4-44db-addf-19c85c7f0f1e"
   183  									   }
   184  									}
   185  								}
   186  							}
   187  						]
   188  					}`
   189  
   190  				server.AppendHandlers(
   191  					CombineHandlers(
   192  						VerifyRequest(http.MethodGet, "/v3/service_plans", "names=myServicePlan&service_broker_names=myServiceBroker&service_offering_names=someOffering"),
   193  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   194  					),
   195  					CombineHandlers(
   196  						VerifyRequest(http.MethodGet, "/v3/service_plans", "names=myServicePlan&service_broker_names=myServiceBroker&service_offering_names=someOffering&page=2"),
   197  						RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}),
   198  					),
   199  				)
   200  
   201  				query = []Query{
   202  					{
   203  						Key:    NameFilter,
   204  						Values: []string{"myServicePlan"},
   205  					},
   206  					{
   207  						Key:    ServiceBrokerNamesFilter,
   208  						Values: []string{"myServiceBroker"},
   209  					},
   210  					{
   211  						Key:    ServiceOfferingNamesFilter,
   212  						Values: []string{"someOffering"},
   213  					},
   214  				}
   215  			})
   216  
   217  			It("returns a list of service plans with their associated warnings", func() {
   218  				Expect(executeErr).ToNot(HaveOccurred())
   219  
   220  				Expect(plans).To(ConsistOf(
   221  					resources.ServicePlan{
   222  						GUID:                "service-plan-1-guid",
   223  						Name:                "service-plan-1-name",
   224  						Description:         "service-plan-1-description",
   225  						Available:           true,
   226  						Free:                true,
   227  						VisibilityType:      "public",
   228  						ServiceOfferingGUID: "79d428b9-75b4-44db-addf-19c85c7f0f1e",
   229  					},
   230  					resources.ServicePlan{
   231  						GUID:                "service-plan-2-guid",
   232  						Name:                "service-plan-2-name",
   233  						Description:         "service-plan-2-description",
   234  						Available:           false,
   235  						Free:                false,
   236  						VisibilityType:      "admin",
   237  						ServiceOfferingGUID: "69d428b9-75b4-44db-addf-19c85c7f0f1e",
   238  					},
   239  					resources.ServicePlan{
   240  						GUID:                "service-plan-3-guid",
   241  						Name:                "service-plan-3-name",
   242  						Description:         "service-plan-3-description",
   243  						Available:           true,
   244  						Free:                true,
   245  						VisibilityType:      "organization",
   246  						ServiceOfferingGUID: "59d428b9-75b4-44db-addf-19c85c7f0f1e",
   247  					},
   248  				))
   249  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   250  			})
   251  		})
   252  
   253  		When("the cloud controller returns errors and warnings", func() {
   254  			BeforeEach(func() {
   255  				response := `{
   256  					"errors": [
   257  						{
   258  							"code": 42424,
   259  							"detail": "Some detailed error message",
   260  							"title": "CF-SomeErrorTitle"
   261  						},
   262  						{
   263  							"code": 11111,
   264  							"detail": "Some other detailed error message",
   265  							"title": "CF-SomeOtherErrorTitle"
   266  						}
   267  					]
   268  				}`
   269  				server.AppendHandlers(
   270  					CombineHandlers(
   271  						VerifyRequest(http.MethodGet, "/v3/service_plans"),
   272  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   273  					),
   274  				)
   275  			})
   276  
   277  			It("returns the error and all warnings", func() {
   278  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   279  					ResponseCode: http.StatusTeapot,
   280  					Errors: []ccerror.V3Error{
   281  						{
   282  							Code:   42424,
   283  							Detail: "Some detailed error message",
   284  							Title:  "CF-SomeErrorTitle",
   285  						},
   286  						{
   287  							Code:   11111,
   288  							Detail: "Some other detailed error message",
   289  							Title:  "CF-SomeOtherErrorTitle",
   290  						},
   291  					},
   292  				}))
   293  				Expect(warnings).To(ConsistOf("this is a warning"))
   294  			})
   295  		})
   296  	})
   297  
   298  	Describe("GetServicePlansWithSpaceAndOrganization", func() {
   299  		var (
   300  			plans      []ServicePlanWithSpaceAndOrganization
   301  			warnings   Warnings
   302  			executeErr error
   303  		)
   304  
   305  		JustBeforeEach(func() {
   306  			plans, warnings, executeErr = client.GetServicePlansWithSpaceAndOrganization(query...)
   307  		})
   308  
   309  		When("when the query succeeds", func() {
   310  			BeforeEach(func() {
   311  				response1 := fmt.Sprintf(`
   312  					{
   313  						"pagination": {
   314  							"next": {
   315  								"href": "%s/v3/service_plans?include=space.organization&service_offering_names=someOffering&page=2"
   316  							}
   317  						},
   318  						"resources": [
   319  							{
   320  								"guid": "service-plan-1-guid",
   321  								"name": "service-plan-1-name",
   322  								"visibility_type": "public",
   323  								"relationships": {
   324  									"service_offering": {
   325  									   "data": {
   326  										  "guid": "79d428b9-75b4-44db-addf-19c85c7f0f1e"
   327  									   }
   328  									}
   329  								}
   330  							},
   331  							{
   332  								"guid": "service-plan-2-guid",
   333  								"name": "service-plan-2-name",
   334  								"visibility_type": "space",
   335  								"relationships": {
   336  									"service_offering": {
   337  									   "data": {
   338  										  "guid": "69d428b9-75b4-44db-addf-19c85c7f0f1e"
   339  									   }
   340  									},
   341  									"space": {
   342  										"data": {
   343  											"guid": "fake-space-guid"
   344  										}
   345  									}
   346  								}
   347  							}
   348  						],
   349  						"included": {
   350  							"spaces": [
   351  								{
   352  									"name": "matching-space",
   353  									"guid": "fake-space-guid",
   354  									"relationships": {
   355  										"organization": {
   356  											"data": {
   357  												"guid": "matching-org-guid"
   358  											}
   359  										}
   360  									}
   361  								},
   362  								{
   363  									"name": "non-matching-space",
   364  									"guid": "fake-other-space-guid",
   365  									"relationships": {
   366  										"organization": {
   367  											"data": {
   368  												"guid": "other-org-guid"
   369  											}
   370  										}
   371  									}
   372  								}
   373  							],
   374  							"organizations": [
   375  								{
   376  									"name": "matching-org",
   377  									"guid": "matching-org-guid"
   378  								},
   379  								{
   380  									"name": "non-matching-org",
   381  									"guid": "other-org-guid"
   382  								}
   383  							]
   384  						}
   385  					}`,
   386  					server.URL())
   387  
   388  				response2 := `
   389  					{
   390  						"pagination": {
   391  							"next": {
   392  								"href": null
   393  							}
   394  						},
   395  						"resources": [
   396  							{
   397  								"guid": "service-plan-3-guid",
   398  								"name": "service-plan-3-name",
   399  								"visibility_type": "organization",
   400  								"relationships": {
   401  									"service_offering": {
   402  									   "data": {
   403  										  "guid": "59d428b9-75b4-44db-addf-19c85c7f0f1e"
   404  									   }
   405  									}
   406  								}
   407  							}
   408  						]
   409  					}`
   410  
   411  				server.AppendHandlers(
   412  					CombineHandlers(
   413  						VerifyRequest(http.MethodGet, "/v3/service_plans", "include=space.organization&service_offering_names=someOffering"),
   414  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   415  					),
   416  					CombineHandlers(
   417  						VerifyRequest(http.MethodGet, "/v3/service_plans", "include=space.organization&service_offering_names=someOffering&page=2"),
   418  						RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}),
   419  					),
   420  				)
   421  
   422  				query = []Query{
   423  					{
   424  						Key:    ServiceOfferingNamesFilter,
   425  						Values: []string{"someOffering"},
   426  					},
   427  				}
   428  			})
   429  
   430  			It("returns space and org name for space-scoped plans", func() {
   431  				Expect(executeErr).ToNot(HaveOccurred())
   432  
   433  				Expect(plans).To(ConsistOf(
   434  					ServicePlanWithSpaceAndOrganization{
   435  						GUID:                "service-plan-1-guid",
   436  						Name:                "service-plan-1-name",
   437  						VisibilityType:      "public",
   438  						ServiceOfferingGUID: "79d428b9-75b4-44db-addf-19c85c7f0f1e",
   439  					},
   440  					ServicePlanWithSpaceAndOrganization{
   441  						GUID:                "service-plan-2-guid",
   442  						Name:                "service-plan-2-name",
   443  						VisibilityType:      "space",
   444  						ServiceOfferingGUID: "69d428b9-75b4-44db-addf-19c85c7f0f1e",
   445  						SpaceGUID:           "fake-space-guid",
   446  						SpaceName:           "matching-space",
   447  						OrganizationName:    "matching-org",
   448  					},
   449  					ServicePlanWithSpaceAndOrganization{
   450  						GUID:                "service-plan-3-guid",
   451  						Name:                "service-plan-3-name",
   452  						VisibilityType:      "organization",
   453  						ServiceOfferingGUID: "59d428b9-75b4-44db-addf-19c85c7f0f1e",
   454  					},
   455  				))
   456  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   457  			})
   458  		})
   459  
   460  		When("the query fails", func() {
   461  			BeforeEach(func() {
   462  				response := `{
   463  					"errors": [
   464  						{
   465  							"code": 42424,
   466  							"detail": "Some detailed error message",
   467  							"title": "CF-SomeErrorTitle"
   468  						},
   469  						{
   470  							"code": 11111,
   471  							"detail": "Some other detailed error message",
   472  							"title": "CF-SomeOtherErrorTitle"
   473  						}
   474  					]
   475  				}`
   476  				server.AppendHandlers(
   477  					CombineHandlers(
   478  						VerifyRequest(http.MethodGet, "/v3/service_plans", "include=space.organization"),
   479  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   480  					),
   481  				)
   482  			})
   483  
   484  			It("returns the error and all warnings", func() {
   485  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   486  					ResponseCode: http.StatusTeapot,
   487  					Errors: []ccerror.V3Error{
   488  						{
   489  							Code:   42424,
   490  							Detail: "Some detailed error message",
   491  							Title:  "CF-SomeErrorTitle",
   492  						},
   493  						{
   494  							Code:   11111,
   495  							Detail: "Some other detailed error message",
   496  							Title:  "CF-SomeOtherErrorTitle",
   497  						},
   498  					},
   499  				}))
   500  				Expect(warnings).To(ConsistOf("this is a warning"))
   501  			})
   502  		})
   503  	})
   504  
   505  	Describe("GetServicePlansWithOfferings", func() {
   506  		var (
   507  			offerings  []ServiceOfferingWithPlans
   508  			warnings   Warnings
   509  			executeErr error
   510  		)
   511  
   512  		JustBeforeEach(func() {
   513  			offerings, warnings, executeErr = client.GetServicePlansWithOfferings(query...)
   514  		})
   515  
   516  		When("when the query succeeds", func() {
   517  			BeforeEach(func() {
   518  
   519  				response1Template := `
   520  					{
   521  						"pagination": {
   522  							"next": {
   523  								"href": "%s/v3/service_plans?include=service_offering&space_guids=some-space-guid&organization_guids=some-org-guid&fields[service_offering.service_broker]=name,guid&page=2"
   524  							}
   525  						},
   526  						"resources": [
   527  							{
   528  								"guid": "service-plan-1-guid",
   529  								"name": "service-plan-1-name",
   530  								"description": "service-plan-1-description",
   531  								"available": true,
   532  								"free": true,
   533  								"relationships": {
   534  									"service_offering": {
   535  									   "data": {
   536  										  "guid": "79d428b9-75b4-44db-addf-19c85c7f0f1e"
   537  									   }
   538  									}
   539  								}
   540  							},
   541  							{
   542  								"guid": "service-plan-2-guid",
   543  								"name": "service-plan-2-name",
   544  								"description": "service-plan-2-description",
   545  								"available": false,
   546  								"free": false,
   547  								"costs": [
   548  									{
   549  										"amount": 649.00,
   550  										"currency": "USD",
   551  										"unit": "MONTHLY"
   552  									},
   553  									{
   554  										"amount": 649.123,
   555  										"currency": "GBP",
   556  										"unit": "MONTHLY"
   557  									}
   558  								],
   559  								"broker_catalog": {
   560  									"metadata": {
   561  										"costs":[
   562  											{
   563  												"amount": {
   564  													"usd": 649.0,
   565  													"gpb": 649.0
   566  												},
   567  												"unit": "MONTHLY"
   568  											}
   569  										]
   570  									}
   571  								},
   572  								"relationships": {
   573  									"service_offering": {
   574  									   "data": {
   575  										  "guid": "69d428b9-75b4-44db-addf-19c85c7f0f1e"
   576  									   }
   577  									}
   578  								}
   579  							}
   580  						],
   581  						"included": {
   582  							"service_offerings": [
   583  								{
   584  									"name": "service-offering-1",
   585  									"guid": "79d428b9-75b4-44db-addf-19c85c7f0f1e",
   586  									"description": "something about service offering 1",
   587  									"relationships": {
   588  										"service_broker": {
   589  											"data": {
   590  												"guid": "service-broker-1-guid"
   591  											}
   592  										}
   593  									}
   594  								},
   595  								{
   596  									"name": "service-offering-2",
   597  									"guid": "69d428b9-75b4-44db-addf-19c85c7f0f1e",
   598  									"description": "something about service offering 2",
   599  									"relationships": {
   600  										"service_broker": {
   601  											"data": {
   602  												"guid": "service-broker-2-guid"
   603  											}
   604  										}
   605  									}
   606  								}
   607  							],
   608  							"service_brokers": [
   609  								{
   610  									"name": "service-broker-1",
   611  									"guid": "service-broker-1-guid"
   612  								},
   613  								{
   614  									"name": "service-broker-2",
   615  									"guid": "service-broker-2-guid"
   616  								}
   617  							]
   618  						}
   619  					}`
   620  
   621  				response1 := fmt.Sprintf(response1Template, server.URL())
   622  				response2 := `
   623  					{
   624  						"pagination": {
   625  							"next": {
   626  								"href": null
   627  							}
   628  						},
   629  						"resources": [
   630  							{
   631  								"guid": "service-plan-3-guid",
   632  								"name": "service-plan-3-name",
   633  								"description": "service-plan-3-description",
   634  								"available": true,
   635  								"free": true,
   636  								"relationships": {
   637  									"service_offering": {
   638  									   "data": {
   639  										  "guid": "79d428b9-75b4-44db-addf-19c85c7f0f1e"
   640  									   }
   641  									}
   642  								}
   643  							}
   644  						],
   645  						"included": {
   646  							"service_offerings": [
   647  								{
   648  									"name": "service-offering-1",
   649  									"guid": "79d428b9-75b4-44db-addf-19c85c7f0f1e",
   650  									"description": "something about service offering 1",
   651  									"relationships": {
   652  										"service_broker": {
   653  											"data": {
   654  												"guid": "service-broker-1-guid"
   655  											}
   656  										}
   657  									}
   658  								}
   659  							],
   660  							"service_brokers": [
   661  								{
   662  									"name": "service-broker-1",
   663  									"guid": "service-broker-1-guid"
   664  								}
   665  							]
   666  						}
   667  					}`
   668  
   669  				server.AppendHandlers(
   670  					CombineHandlers(
   671  						VerifyRequest(http.MethodGet, "/v3/service_plans", "include=service_offering&space_guids=some-space-guid&organization_guids=some-org-guid&fields[service_offering.service_broker]=name,guid"),
   672  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   673  					),
   674  					CombineHandlers(
   675  						VerifyRequest(http.MethodGet, "/v3/service_plans", "include=service_offering&space_guids=some-space-guid&organization_guids=some-org-guid&fields[service_offering.service_broker]=name,guid&page=2"),
   676  						RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}),
   677  					),
   678  				)
   679  
   680  				query = []Query{
   681  					{
   682  						Key:    OrganizationGUIDFilter,
   683  						Values: []string{"some-org-guid"},
   684  					},
   685  					{
   686  						Key:    SpaceGUIDFilter,
   687  						Values: []string{"some-space-guid"},
   688  					},
   689  				}
   690  			})
   691  
   692  			It("returns service offerings and service plans", func() {
   693  				Expect(executeErr).NotTo(HaveOccurred())
   694  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   695  				Expect(offerings).To(Equal([]ServiceOfferingWithPlans{
   696  					{
   697  						GUID:              "79d428b9-75b4-44db-addf-19c85c7f0f1e",
   698  						Name:              "service-offering-1",
   699  						Description:       "something about service offering 1",
   700  						ServiceBrokerName: "service-broker-1",
   701  						Plans: []resources.ServicePlan{
   702  							{
   703  								GUID:                "service-plan-1-guid",
   704  								Name:                "service-plan-1-name",
   705  								Description:         "service-plan-1-description",
   706  								Available:           true,
   707  								Free:                true,
   708  								ServiceOfferingGUID: "79d428b9-75b4-44db-addf-19c85c7f0f1e",
   709  							},
   710  							{
   711  								GUID:                "service-plan-3-guid",
   712  								Name:                "service-plan-3-name",
   713  								Description:         "service-plan-3-description",
   714  								Available:           true,
   715  								Free:                true,
   716  								ServiceOfferingGUID: "79d428b9-75b4-44db-addf-19c85c7f0f1e",
   717  							},
   718  						},
   719  					},
   720  					{
   721  						GUID:              "69d428b9-75b4-44db-addf-19c85c7f0f1e",
   722  						Name:              "service-offering-2",
   723  						Description:       "something about service offering 2",
   724  						ServiceBrokerName: "service-broker-2",
   725  						Plans: []resources.ServicePlan{
   726  							{
   727  								GUID:        "service-plan-2-guid",
   728  								Name:        "service-plan-2-name",
   729  								Available:   false,
   730  								Description: "service-plan-2-description",
   731  								Free:        false,
   732  								Costs: []resources.ServicePlanCost{
   733  									{
   734  										Amount:   649.00,
   735  										Currency: "USD",
   736  										Unit:     "MONTHLY",
   737  									},
   738  									{
   739  										Amount:   649.123,
   740  										Currency: "GBP",
   741  										Unit:     "MONTHLY",
   742  									},
   743  								},
   744  								ServiceOfferingGUID: "69d428b9-75b4-44db-addf-19c85c7f0f1e",
   745  							},
   746  						},
   747  					},
   748  				}))
   749  			})
   750  		})
   751  
   752  		When("the query fails", func() {
   753  			BeforeEach(func() {
   754  				response := `{
   755  					"errors": [
   756  						{
   757  							"code": 42424,
   758  							"detail": "Some detailed error message",
   759  							"title": "CF-SomeErrorTitle"
   760  						},
   761  						{
   762  							"code": 11111,
   763  							"detail": "Some other detailed error message",
   764  							"title": "CF-SomeOtherErrorTitle"
   765  						}
   766  					]
   767  				}`
   768  				server.AppendHandlers(
   769  					CombineHandlers(
   770  						VerifyRequest(http.MethodGet, "/v3/service_plans", "include=service_offering&fields[service_offering.service_broker]=name,guid"),
   771  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   772  					),
   773  				)
   774  			})
   775  
   776  			It("returns the error and all warnings", func() {
   777  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   778  					ResponseCode: http.StatusTeapot,
   779  					Errors: []ccerror.V3Error{
   780  						{
   781  							Code:   42424,
   782  							Detail: "Some detailed error message",
   783  							Title:  "CF-SomeErrorTitle",
   784  						},
   785  						{
   786  							Code:   11111,
   787  							Detail: "Some other detailed error message",
   788  							Title:  "CF-SomeOtherErrorTitle",
   789  						},
   790  					},
   791  				}))
   792  				Expect(warnings).To(ConsistOf("this is a warning"))
   793  			})
   794  		})
   795  
   796  	})
   797  })