github.com/randomtask1155/cli@v6.41.1-0.20181227003417-a98eed78cbde+incompatible/api/cloudcontroller/ccv2/errors_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  
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/ghttp"
    13  )
    14  
    15  var _ = Describe("Error Wrapper", func() {
    16  	var (
    17  		serverResponse     string
    18  		serverResponseCode int
    19  		executeErr         error
    20  
    21  		client *Client
    22  	)
    23  
    24  	Describe("Make", func() {
    25  		BeforeEach(func() {
    26  			serverResponse = `{
    27  					"code": 777,
    28  					"description": "SomeCC Error Message",
    29  					"error_code": "CF-SomeError"
    30  				}`
    31  
    32  			client = NewTestClient()
    33  		})
    34  
    35  		JustBeforeEach(func() {
    36  			server.AppendHandlers(
    37  				CombineHandlers(
    38  					VerifyRequest(http.MethodGet, "/v2/apps"),
    39  					RespondWith(serverResponseCode, serverResponse, http.Header{
    40  						"X-Vcap-Request-Id": {
    41  							"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95",
    42  							"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f",
    43  						},
    44  					},
    45  					),
    46  				),
    47  			)
    48  
    49  			// Make a request to a CC endpoint - we stub the response, so the actual endpoint isn't relevant
    50  			_, _, executeErr = client.GetApplications()
    51  		})
    52  
    53  		When("we can't unmarshal the response successfully", func() {
    54  			BeforeEach(func() {
    55  				serverResponse = "I am not unmarshallable"
    56  			})
    57  
    58  			When("response code is 4XX", func() {
    59  				BeforeEach(func() {
    60  					serverResponseCode = http.StatusNotFound
    61  				})
    62  
    63  				It("returns an unknown http source error", func() {
    64  					Expect(executeErr).To(MatchError(ccerror.UnknownHTTPSourceError{StatusCode: serverResponseCode, RawResponse: []byte(serverResponse)}))
    65  				})
    66  			})
    67  
    68  			When("response code is 5XX", func() {
    69  				BeforeEach(func() {
    70  					serverResponseCode = http.StatusBadGateway
    71  				})
    72  
    73  				It("returns an unknown http source error", func() {
    74  					Expect(executeErr).To(MatchError(ccerror.UnknownHTTPSourceError{StatusCode: serverResponseCode, RawResponse: []byte(serverResponse)}))
    75  				})
    76  			})
    77  		})
    78  
    79  		When("the error is from the cloud controller", func() {
    80  			When("the error is a 4XX error", func() {
    81  				Context("(400) Bad Request", func() {
    82  					BeforeEach(func() {
    83  						serverResponseCode = http.StatusBadRequest
    84  					})
    85  
    86  					Context("generic 400", func() {
    87  						BeforeEach(func() {
    88  							serverResponse = `{
    89  							"description": "bad request",
    90  							"error_code": "CF-BadRequest"
    91  						}`
    92  						})
    93  
    94  						It("returns a BadRequestError", func() {
    95  							Expect(executeErr).To(MatchError(ccerror.BadRequestError{
    96  								Message: "bad request",
    97  							}))
    98  						})
    99  					})
   100  
   101  					When("a not staged error is encountered", func() {
   102  						BeforeEach(func() {
   103  							serverResponse = `{
   104  								"description": "App has not finished staging",
   105  								"error_code": "CF-NotStaged"
   106  							}`
   107  						})
   108  
   109  						It("returns a NotStagedError", func() {
   110  							Expect(executeErr).To(MatchError(ccerror.NotStagedError{
   111  								Message: "App has not finished staging",
   112  							}))
   113  						})
   114  					})
   115  
   116  					When("an instances error is encountered", func() {
   117  						BeforeEach(func() {
   118  							serverResponse = `{
   119  								"description": "instances went bananas",
   120  								"error_code": "CF-InstancesError"
   121  							}`
   122  						})
   123  
   124  						It("returns an InstancesError", func() {
   125  							Expect(executeErr).To(MatchError(ccerror.InstancesError{
   126  								Message: "instances went bananas",
   127  							}))
   128  						})
   129  					})
   130  
   131  					When("creating a relation that is invalid", func() {
   132  						BeforeEach(func() {
   133  							serverResponse = `{
   134  							"code": 1002,
   135  							"description": "The requested app relation is invalid: the app and route must belong to the same space",
   136  							"error_code": "CF-InvalidRelation"
   137  						}`
   138  						})
   139  
   140  						It("returns an InvalidRelationError", func() {
   141  							Expect(executeErr).To(MatchError(ccerror.InvalidRelationError{
   142  								Message: "The requested app relation is invalid: the app and route must belong to the same space",
   143  							}))
   144  						})
   145  					})
   146  
   147  					Context("getting stats for a stopped app", func() {
   148  						BeforeEach(func() {
   149  							serverResponse = `{
   150  							"code": 200003,
   151  							"description": "Could not fetch stats for stopped app: some-app",
   152  							"error_code": "CF-AppStoppedStatsError"
   153  						}`
   154  						})
   155  
   156  						It("returns an AppStoppedStatsError", func() {
   157  							Expect(executeErr).To(MatchError(ccerror.ApplicationStoppedStatsError{
   158  								Message: "Could not fetch stats for stopped app: some-app",
   159  							}))
   160  						})
   161  					})
   162  
   163  					When("creating a buildpack with nil stack that already exists", func() {
   164  						BeforeEach(func() {
   165  							serverResponse = `{
   166  							 "description": "Buildpack is invalid: stack unique",
   167  							 "error_code": "CF-BuildpackInvalid",
   168  							 "code": 290003
   169  						}`
   170  						})
   171  
   172  						It("returns an BuildpackAlreadyExistsWithoutStackError", func() {
   173  							Expect(executeErr).To(MatchError(ccerror.BuildpackAlreadyExistsWithoutStackError{
   174  								Message: "Buildpack is invalid: stack unique",
   175  							}))
   176  						})
   177  					})
   178  
   179  					When("creating a buildpack causes a name collision", func() {
   180  						BeforeEach(func() {
   181  							serverResponse = `{
   182  							 "code": 290001,
   183  							 "description": "The buildpack name is already in use: foo",
   184  							 "error_code": "CF-BuildpackNameTaken"
   185  						}`
   186  						})
   187  
   188  						It("returns an BuildpackNameTakenError", func() {
   189  							Expect(executeErr).To(MatchError(ccerror.BuildpackNameTakenError{
   190  								Message: "The buildpack name is already in use: foo",
   191  							}))
   192  						})
   193  					})
   194  
   195  					When("creating an organization fails because the name is taken", func() {
   196  						BeforeEach(func() {
   197  							serverResponse = `{
   198  								"code": 30002,
   199  								"description": "The organization name is taken: potato",
   200  								"error_code": "CF-OrganizationNameTaken"
   201  							  }`
   202  						})
   203  
   204  						It("returns a OrganizationNameTakenError", func() {
   205  							Expect(executeErr).To(MatchError(ccerror.OrganizationNameTakenError{
   206  								Message: "The organization name is taken: potato",
   207  							}))
   208  						})
   209  					})
   210  
   211  					When("creating a space fails because the name is taken", func() {
   212  						BeforeEach(func() {
   213  							serverResponse = `{
   214  								"code": 40002,
   215  								"description": "The app space name is taken: potato",
   216  								"error_code": "CF-SpaceNameTaken"
   217  							  }`
   218  						})
   219  
   220  						It("returns a SpaceNameTakenError", func() {
   221  							if e, ok := executeErr.(ccerror.UnknownHTTPSourceError); ok {
   222  								fmt.Printf("TV %s", string(e.RawResponse))
   223  							}
   224  							Expect(executeErr).To(MatchError(ccerror.SpaceNameTakenError{
   225  								Message: "The app space name is taken: potato",
   226  							}))
   227  						})
   228  					})
   229  				})
   230  
   231  				Context("(401) Unauthorized", func() {
   232  					BeforeEach(func() {
   233  						serverResponseCode = http.StatusUnauthorized
   234  					})
   235  
   236  					Context("generic 401", func() {
   237  						It("returns a UnauthorizedError", func() {
   238  							Expect(executeErr).To(MatchError(ccerror.UnauthorizedError{Message: "SomeCC Error Message"}))
   239  						})
   240  					})
   241  
   242  					Context("invalid token", func() {
   243  						BeforeEach(func() {
   244  							serverResponse = `{
   245  						"code": 1000,
   246  						"description": "Invalid Auth Token",
   247  						"error_code": "CF-InvalidAuthToken"
   248  					}`
   249  						})
   250  
   251  						It("returns an InvalidAuthTokenError", func() {
   252  							Expect(executeErr).To(MatchError(ccerror.InvalidAuthTokenError{Message: "Invalid Auth Token"}))
   253  						})
   254  					})
   255  				})
   256  
   257  				Context("(403) Forbidden", func() {
   258  					BeforeEach(func() {
   259  						serverResponseCode = http.StatusForbidden
   260  					})
   261  
   262  					It("returns a ForbiddenError", func() {
   263  						Expect(executeErr).To(MatchError(ccerror.ForbiddenError{Message: "SomeCC Error Message"}))
   264  					})
   265  				})
   266  
   267  				Context("(404) Not Found", func() {
   268  					BeforeEach(func() {
   269  						serverResponseCode = http.StatusNotFound
   270  					})
   271  
   272  					When("the error is a json response from the cloud controller", func() {
   273  						It("returns a ResourceNotFoundError", func() {
   274  							Expect(executeErr).To(MatchError(ccerror.ResourceNotFoundError{Message: "SomeCC Error Message"}))
   275  						})
   276  					})
   277  				})
   278  
   279  				Context("(422) Unprocessable Entity", func() {
   280  					BeforeEach(func() {
   281  						serverResponseCode = http.StatusUnprocessableEntity
   282  					})
   283  
   284  					Context("generic Unprocessable entity", func() {
   285  						It("returns a UnprocessableEntityError", func() {
   286  							Expect(executeErr).To(MatchError(ccerror.UnprocessableEntityError{Message: "SomeCC Error Message"}))
   287  						})
   288  					})
   289  
   290  					When("creating a buildpack causes a name and stack collision", func() {
   291  						BeforeEach(func() {
   292  							serverResponse = `{
   293  							 "code": 290000,
   294  							 "description": "The buildpack name foo is already in use for the stack bar",
   295  							 "error_code": "CF-BuildpackNameStackTaken"
   296  						}`
   297  						})
   298  
   299  						It("returns an BuildpackAlreadyExistsForStackError", func() {
   300  							Expect(executeErr).To(MatchError(ccerror.BuildpackAlreadyExistsForStackError{
   301  								Message: "The buildpack name foo is already in use for the stack bar",
   302  							}))
   303  						})
   304  					})
   305  
   306  				})
   307  
   308  				Context("unhandled Error Codes", func() {
   309  					BeforeEach(func() {
   310  						serverResponseCode = http.StatusTeapot
   311  					})
   312  
   313  					It("returns an UnexpectedResponseError", func() {
   314  						Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{
   315  							ResponseCode: http.StatusTeapot,
   316  							V2ErrorResponse: ccerror.V2ErrorResponse{
   317  								Code:        777,
   318  								Description: "SomeCC Error Message",
   319  								ErrorCode:   "CF-SomeError",
   320  							},
   321  							RequestIDs: []string{
   322  								"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95",
   323  								"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f",
   324  							},
   325  						}))
   326  					})
   327  				})
   328  			})
   329  
   330  			When("the error is a 5XX error", func() {
   331  				BeforeEach(func() {
   332  					serverResponseCode = http.StatusInternalServerError
   333  					serverResponse = "{}"
   334  				})
   335  
   336  				Context("(502) Bad Gateway", func() {
   337  					BeforeEach(func() {
   338  						serverResponseCode = http.StatusBadGateway
   339  					})
   340  
   341  					When("the service broker catalog is invalid", func() {
   342  						BeforeEach(func() {
   343  							serverResponse = `{
   344  								"description": "Service broker catalog is invalid: \nService overview-service\n  Service dashboard client id must be unique\n",
   345  								"error_code": "CF-ServiceBrokerCatalogInvalid",
   346  								"code": 270012
   347  							}`
   348  						})
   349  
   350  						It("returns a ServiceBrokerCatalogInvalidError", func() {
   351  							Expect(executeErr).To(MatchError(ccerror.ServiceBrokerCatalogInvalidError{
   352  								Message: "Service broker catalog is invalid: \nService overview-service\n  Service dashboard client id must be unique\n",
   353  							}))
   354  						})
   355  					})
   356  
   357  					When("the error_code is unknown", func() {
   358  						It("returns a V2UnexpectedResponseError with no json", func() {
   359  							Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{
   360  								ResponseCode: http.StatusBadGateway,
   361  								V2ErrorResponse: ccerror.V2ErrorResponse{
   362  									Description: serverResponse,
   363  								},
   364  								RequestIDs: []string{
   365  									"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95",
   366  									"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f",
   367  								},
   368  							}))
   369  						})
   370  					})
   371  				})
   372  
   373  				Context("unhandled error codes", func() {
   374  					It("returns a V2UnexpectedResponseError with no json", func() {
   375  						Expect(executeErr).To(MatchError(ccerror.V2UnexpectedResponseError{
   376  							ResponseCode: http.StatusInternalServerError,
   377  							V2ErrorResponse: ccerror.V2ErrorResponse{
   378  								Description: serverResponse,
   379  							},
   380  							RequestIDs: []string{
   381  								"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95",
   382  								"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f",
   383  							},
   384  						}))
   385  					})
   386  				})
   387  			})
   388  		})
   389  	})
   390  })