github.com/arunkumar7540/cli@v6.45.0+incompatible/api/cloudcontroller/ccv3/errors_test.go (about)

     1  package ccv3_test
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     7  	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
     8  
     9  	. "github.com/onsi/ginkgo"
    10  	. "github.com/onsi/gomega"
    11  	. "github.com/onsi/gomega/ghttp"
    12  )
    13  
    14  var _ = Describe("Error Wrapper", func() {
    15  	var client *Client
    16  
    17  	BeforeEach(func() {
    18  		client, _ = NewTestClient()
    19  	})
    20  
    21  	Describe("Make", func() {
    22  		var (
    23  			serverResponse     string
    24  			serverResponseCode int
    25  			makeError          error
    26  		)
    27  
    28  		BeforeEach(func() {
    29  			serverResponse = `
    30  {
    31    "errors": [
    32      {
    33        "code": 777,
    34        "detail": "SomeCC Error Message",
    35        "title": "CF-SomeError"
    36      }
    37    ]
    38  }`
    39  
    40  		})
    41  
    42  		JustBeforeEach(func() {
    43  			server.AppendHandlers(
    44  				CombineHandlers(
    45  					VerifyRequest(http.MethodGet, "/v3/apps"),
    46  					RespondWith(serverResponseCode, serverResponse, http.Header{
    47  						"X-Vcap-Request-Id": {
    48  							"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95",
    49  							"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f",
    50  						},
    51  					},
    52  					),
    53  				),
    54  			)
    55  
    56  			_, _, makeError = client.GetApplications()
    57  		})
    58  
    59  		When("we can't unmarshal the response successfully", func() {
    60  			BeforeEach(func() {
    61  				serverResponse = "I am not unmarshallable"
    62  				serverResponseCode = http.StatusNotFound
    63  			})
    64  
    65  			It("returns an unknown http source error", func() {
    66  				Expect(makeError).To(MatchError(ccerror.UnknownHTTPSourceError{StatusCode: serverResponseCode, RawResponse: []byte(serverResponse)}))
    67  			})
    68  		})
    69  
    70  		When("the error is from the cloud controller", func() {
    71  			When("an empty list of errors is returned", func() {
    72  				BeforeEach(func() {
    73  					serverResponseCode = http.StatusUnauthorized
    74  					serverResponse = `{ "errors": [] }`
    75  				})
    76  
    77  				It("returns an UnexpectedResponseError", func() {
    78  					Expect(makeError).To(MatchError(ccerror.V3UnexpectedResponseError{
    79  						ResponseCode:    http.StatusUnauthorized,
    80  						V3ErrorResponse: ccerror.V3ErrorResponse{Errors: []ccerror.V3Error{}},
    81  					}))
    82  				})
    83  			})
    84  
    85  			When("the error is a 4XX error", func() {
    86  				Context("(401) Unauthorized", func() {
    87  					BeforeEach(func() {
    88  						serverResponseCode = http.StatusUnauthorized
    89  					})
    90  
    91  					Context("generic 401", func() {
    92  						It("returns a UnauthorizedError", func() {
    93  							Expect(makeError).To(MatchError(ccerror.UnauthorizedError{Message: "SomeCC Error Message"}))
    94  						})
    95  					})
    96  
    97  					Context("invalid token", func() {
    98  						BeforeEach(func() {
    99  							serverResponse = `{
   100  							"errors": [
   101  								{
   102  									"code": 1000,
   103  									"detail": "Invalid Auth Token",
   104  									"title": "CF-InvalidAuthToken"
   105  								}
   106  							]
   107  						}`
   108  						})
   109  
   110  						It("returns an InvalidAuthTokenError", func() {
   111  							Expect(makeError).To(MatchError(ccerror.InvalidAuthTokenError{Message: "Invalid Auth Token"}))
   112  						})
   113  					})
   114  				})
   115  
   116  				Context("(403) Forbidden", func() {
   117  					BeforeEach(func() {
   118  						serverResponseCode = http.StatusForbidden
   119  					})
   120  
   121  					It("returns a ForbiddenError", func() {
   122  						Expect(makeError).To(MatchError(ccerror.ForbiddenError{Message: "SomeCC Error Message"}))
   123  					})
   124  				})
   125  
   126  				Context("(404) Not Found", func() {
   127  					BeforeEach(func() {
   128  						serverResponseCode = http.StatusNotFound
   129  					})
   130  
   131  					Context("API is not found", func() {
   132  
   133  						BeforeEach(func() {
   134  							serverResponse = `{
   135  								"errors": [
   136  									{
   137  										"detail": "Unknown request",
   138  										"title": "CF-NotFound",
   139  										"code": 10000
   140  									}
   141  								]
   142  							}`
   143  						})
   144  
   145  						It("returns a APINotFoundError", func() {
   146  							Expect(makeError).To(MatchError(ccerror.APINotFoundError{URL: server.URL() + "/v3/apps"}))
   147  						})
   148  					})
   149  
   150  					When("a process is not found", func() {
   151  						BeforeEach(func() {
   152  							serverResponse = `
   153  {
   154    "errors": [
   155      {
   156        "code": 10010,
   157        "detail": "Process not found",
   158        "title": "CF-ResourceNotFound"
   159      }
   160    ]
   161  }`
   162  						})
   163  
   164  						It("returns a ProcessNotFoundError", func() {
   165  							Expect(makeError).To(MatchError(ccerror.ProcessNotFoundError{}))
   166  						})
   167  					})
   168  
   169  					When("an instance is not found", func() {
   170  						BeforeEach(func() {
   171  							serverResponse = `
   172  {
   173    "errors": [
   174      {
   175        "code": 10010,
   176        "detail": "Instance not found",
   177        "title": "CF-ResourceNotFound"
   178      }
   179    ]
   180  }`
   181  						})
   182  
   183  						It("returns an InstanceNotFoundError", func() {
   184  							Expect(makeError).To(MatchError(ccerror.InstanceNotFoundError{}))
   185  						})
   186  					})
   187  
   188  					When("an application is not found", func() {
   189  						BeforeEach(func() {
   190  							serverResponse = `
   191  {
   192    "errors": [
   193      {
   194        "code": 10010,
   195        "detail": "App not found",
   196        "title": "CF-ResourceNotFound"
   197      }
   198    ]
   199  }`
   200  						})
   201  
   202  						It("returns an AppNotFoundError", func() {
   203  							Expect(makeError).To(MatchError(ccerror.ApplicationNotFoundError{}))
   204  						})
   205  					})
   206  
   207  					When("a droplet is not found", func() {
   208  						BeforeEach(func() {
   209  							serverResponse = `
   210  {
   211    "errors": [
   212      {
   213        "code": 10010,
   214        "detail": "Droplet not found",
   215        "title": "CF-ResourceNotFound"
   216      }
   217    ]
   218  }`
   219  						})
   220  
   221  						It("returns a DropletNotFoundError", func() {
   222  							Expect(makeError).To(MatchError(ccerror.DropletNotFoundError{}))
   223  						})
   224  					})
   225  
   226  					Context("generic not found", func() {
   227  
   228  						It("returns a ResourceNotFoundError", func() {
   229  							Expect(makeError).To(MatchError(ccerror.ResourceNotFoundError{Message: "SomeCC Error Message"}))
   230  						})
   231  					})
   232  				})
   233  
   234  				Context("(422) Unprocessable Entity", func() {
   235  					BeforeEach(func() {
   236  						serverResponseCode = http.StatusUnprocessableEntity
   237  					})
   238  
   239  					When("the name isn't unique to space", func() {
   240  						BeforeEach(func() {
   241  							serverResponse = `
   242  {
   243    "errors": [
   244      {
   245        "code": 10008,
   246        "detail": "name must be unique in space",
   247        "title": "CF-UnprocessableEntity"
   248      }
   249    ]
   250  }`
   251  						})
   252  
   253  						It("returns a NameNotUniqueInSpaceError", func() {
   254  							Expect(makeError).To(MatchError(ccerror.NameNotUniqueInSpaceError{}))
   255  						})
   256  					})
   257  
   258  					When("the buildpack is invalid", func() {
   259  						BeforeEach(func() {
   260  							serverResponse = `
   261  {
   262    "errors": [
   263      {
   264        "code": 10008,
   265        "detail": "Buildpack must be an existing admin buildpack or a valid git URI",
   266        "title": "CF-UnprocessableEntity"
   267      }
   268    ]
   269  }`
   270  						})
   271  
   272  						It("returns an InvalidBuildpackError", func() {
   273  							Expect(makeError).To(MatchError(ccerror.InvalidBuildpackError{}))
   274  						})
   275  					})
   276  
   277  					When("the detail describes something else", func() {
   278  						BeforeEach(func() {
   279  							serverResponse = `
   280  {
   281    "errors": [
   282      {
   283        "code": 10008,
   284        "detail": "SomeCC Error Message",
   285        "title": "CF-UnprocessableEntity"
   286      }
   287    ]
   288  }`
   289  						})
   290  
   291  						It("returns a UnprocessableEntityError", func() {
   292  							Expect(makeError).To(MatchError(ccerror.UnprocessableEntityError{Message: "SomeCC Error Message"}))
   293  						})
   294  					})
   295  				})
   296  			})
   297  
   298  			When("the error is a 5XX error", func() {
   299  				Context("(503) Service Unavailable", func() {
   300  					BeforeEach(func() {
   301  						serverResponseCode = http.StatusServiceUnavailable
   302  					})
   303  
   304  					It("returns a ServiceUnavailableError", func() {
   305  						Expect(makeError).To(MatchError(ccerror.ServiceUnavailableError{Message: "SomeCC Error Message"}))
   306  					})
   307  
   308  					When("the title is 'CF-TaskWorkersUnavailable'", func() {
   309  						BeforeEach(func() {
   310  							serverResponse = `{
   311    "errors": [
   312      {
   313        "code": 170020,
   314        "detail": "Task workers are unavailable: Failed to open TCP connection to nsync.service.cf.internal:8787 (getaddrinfo: Name or service not known)",
   315        "title": "CF-TaskWorkersUnavailable"
   316      }
   317    ]
   318  }`
   319  						})
   320  
   321  						It("returns a TaskWorkersUnavailableError", func() {
   322  							Expect(makeError).To(MatchError(ccerror.TaskWorkersUnavailableError{Message: "Task workers are unavailable: Failed to open TCP connection to nsync.service.cf.internal:8787 (getaddrinfo: Name or service not known)"}))
   323  						})
   324  					})
   325  				})
   326  
   327  				Context("all other 5XX", func() {
   328  					BeforeEach(func() {
   329  						serverResponseCode = http.StatusBadGateway
   330  						serverResponse = "I am some text"
   331  					})
   332  
   333  					It("returns a ServiceUnavailableError", func() {
   334  						Expect(makeError).To(MatchError(ccerror.V3UnexpectedResponseError{
   335  							ResponseCode: http.StatusBadGateway,
   336  							RequestIDs: []string{
   337  								"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95",
   338  								"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f",
   339  							},
   340  							V3ErrorResponse: ccerror.V3ErrorResponse{
   341  								Errors: []ccerror.V3Error{{
   342  									Detail: serverResponse,
   343  								}},
   344  							},
   345  						}))
   346  					})
   347  				})
   348  			})
   349  
   350  			Context("Unhandled Error Codes", func() {
   351  				BeforeEach(func() {
   352  					serverResponseCode = http.StatusTeapot
   353  				})
   354  
   355  				It("returns an UnexpectedResponseError", func() {
   356  					Expect(makeError).To(MatchError(ccerror.V3UnexpectedResponseError{
   357  						ResponseCode: http.StatusTeapot,
   358  						V3ErrorResponse: ccerror.V3ErrorResponse{
   359  							Errors: []ccerror.V3Error{
   360  								{
   361  									Code:   777,
   362  									Detail: "SomeCC Error Message",
   363  									Title:  "CF-SomeError",
   364  								},
   365  							},
   366  						},
   367  						RequestIDs: []string{
   368  							"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95",
   369  							"6e0b4379-f5f7-4b2b-56b0-9ab7e96eed95::7445d9db-c31e-410d-8dc5-9f79ec3fc26f",
   370  						},
   371  					}))
   372  				})
   373  			})
   374  
   375  			Context("multiple errors", func() {
   376  				BeforeEach(func() {
   377  					serverResponseCode = http.StatusTeapot
   378  					serverResponse = `{
   379  							"errors": [
   380  								{
   381  									"code": 1000,
   382  									"detail": "Some CC Error Message",
   383  									"title": "CF-UnprocessableEntity"
   384  								},
   385  								{
   386  									"code": 1001,
   387  									"detail": "Some CC Error Message",
   388  									"title": "CF-UnprocessableEntity"
   389  								}
   390  							]
   391  						}`
   392  				})
   393  
   394  				It("returns a MultiError", func() {
   395  					Expect(makeError).To(MatchError(ccerror.MultiError{
   396  						ResponseCode: http.StatusTeapot,
   397  						Errors: []ccerror.V3Error{
   398  							{
   399  								Code:   1000,
   400  								Detail: "Some CC Error Message",
   401  								Title:  "CF-UnprocessableEntity",
   402  							},
   403  							{
   404  								Code:   1001,
   405  								Detail: "Some CC Error Message",
   406  								Title:  "CF-UnprocessableEntity",
   407  							},
   408  						},
   409  					}))
   410  				})
   411  			})
   412  		})
   413  	})
   414  })