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