github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/cloudcontroller/ccv3/deployment_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/constant" 9 "code.cloudfoundry.org/cli/resources" 10 11 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 . "github.com/onsi/gomega/ghttp" 15 ) 16 17 var _ = Describe("Deployment", func() { 18 var client *Client 19 20 BeforeEach(func() { 21 client, _ = NewTestClient() 22 }) 23 24 Describe("GetDeployments", func() { 25 var ( 26 deployments []resources.Deployment 27 warnings Warnings 28 executeErr error 29 ) 30 31 JustBeforeEach(func() { 32 deployments, warnings, executeErr = client.GetDeployments(Query{Key: AppGUIDFilter, Values: []string{"some-app-guid"}}, Query{Key: OrderBy, Values: []string{"-created_at"}}, Query{Key: PerPage, Values: []string{"1"}}) 33 }) 34 35 var response string 36 var response2 string 37 BeforeEach(func() { 38 response = fmt.Sprintf(`{ 39 "pagination": { 40 "next": { 41 "href": "%s/v3/deployments?app_guids=some-app-guid&order_by=-created_at&page=2&per_page=1" 42 } 43 }, 44 "resources": [ 45 { 46 "guid": "newest-deployment-guid", 47 "created_at": "2018-05-25T22:42:10Z" 48 } 49 ] 50 }`, server.URL()) 51 response2 = `{ 52 "pagination": { 53 "next": null 54 }, 55 "resources": [ 56 { 57 "guid": "oldest-deployment-guid", 58 "created_at": "2018-04-25T22:42:10Z" 59 } 60 ] 61 }` 62 }) 63 64 Context("when the deployment exists", func() { 65 BeforeEach(func() { 66 server.AppendHandlers( 67 CombineHandlers( 68 VerifyRequest(http.MethodGet, "/v3/deployments", "app_guids=some-app-guid&order_by=-created_at&per_page=1"), 69 RespondWith(http.StatusAccepted, response), 70 ), 71 ) 72 73 server.AppendHandlers( 74 CombineHandlers( 75 VerifyRequest(http.MethodGet, "/v3/deployments", "app_guids=some-app-guid&order_by=-created_at&page=2&per_page=1"), 76 RespondWith(http.StatusAccepted, response2, http.Header{"X-Cf-Warnings": {"warning"}}), 77 ), 78 ) 79 80 }) 81 82 It("returns the deployment guid of the most recent deployment", func() { 83 Expect(executeErr).ToNot(HaveOccurred()) 84 Expect(warnings).To(ConsistOf("warning")) 85 Expect(deployments).To(ConsistOf( 86 resources.Deployment{GUID: "newest-deployment-guid", CreatedAt: "2018-05-25T22:42:10Z"}, 87 resources.Deployment{GUID: "oldest-deployment-guid", CreatedAt: "2018-04-25T22:42:10Z"}, 88 )) 89 }) 90 91 }) 92 93 Context("when the request fails", func() { 94 BeforeEach(func() { 95 response := `{ 96 "errors": [ 97 { 98 "code": 10008, 99 "detail": "The request is semantically invalid: command presence", 100 "title": "CF-UnprocessableEntity" 101 }, 102 { 103 "code": 10010, 104 "detail": "App not found", 105 "title": "CF-ResourceNotFound" 106 } 107 ] 108 }` 109 110 server.AppendHandlers( 111 CombineHandlers( 112 VerifyRequest(http.MethodGet, "/v3/deployments", "app_guids=some-app-guid&order_by=-created_at&per_page=1"), 113 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning"}}), 114 ), 115 ) 116 }) 117 118 It("returns CC warnings and error", func() { 119 Expect(executeErr).To(MatchError(ccerror.MultiError{ 120 ResponseCode: http.StatusTeapot, 121 Errors: []ccerror.V3Error{ 122 { 123 Code: 10008, 124 Detail: "The request is semantically invalid: command presence", 125 Title: "CF-UnprocessableEntity", 126 }, 127 { 128 Code: 10010, 129 Detail: "App not found", 130 Title: "CF-ResourceNotFound", 131 }, 132 }, 133 })) 134 Expect(warnings).To(ConsistOf("warning")) 135 }) 136 }) 137 }) 138 139 Describe("CancelDeployment", func() { 140 var ( 141 warnings Warnings 142 executeErr error 143 ) 144 145 JustBeforeEach(func() { 146 warnings, executeErr = client.CancelDeployment("some-deployment-guid") 147 }) 148 149 Context("when the deployment exists", func() { 150 Context("when cancelling the deployment succeeds", func() { 151 BeforeEach(func() { 152 server.AppendHandlers( 153 CombineHandlers( 154 VerifyRequest(http.MethodPost, "/v3/deployments/some-deployment-guid/actions/cancel"), 155 RespondWith(http.StatusAccepted, "", http.Header{"X-Cf-Warnings": {"warning"}}), 156 ), 157 ) 158 }) 159 160 It("cancels the deployment with no errors and returns all warnings", func() { 161 Expect(executeErr).ToNot(HaveOccurred()) 162 Expect(warnings).To(ConsistOf("warning")) 163 }) 164 }) 165 }) 166 }) 167 168 Describe("CreateApplicationDeployment", func() { 169 var ( 170 deploymentGUID string 171 warnings Warnings 172 executeErr error 173 dropletGUID string 174 ) 175 176 JustBeforeEach(func() { 177 deploymentGUID, warnings, executeErr = client.CreateApplicationDeployment("some-app-guid", dropletGUID) 178 }) 179 180 Context("when the application exists", func() { 181 var response string 182 BeforeEach(func() { 183 dropletGUID = "some-droplet-guid" 184 response = `{ 185 "guid": "some-deployment-guid", 186 "created_at": "2018-04-25T22:42:10Z", 187 "relationships": { 188 "app": { 189 "data": { 190 "guid": "some-app-guid" 191 } 192 } 193 } 194 }` 195 }) 196 197 Context("when creating the deployment succeeds", func() { 198 BeforeEach(func() { 199 server.AppendHandlers( 200 CombineHandlers( 201 VerifyRequest(http.MethodPost, "/v3/deployments"), 202 VerifyJSON(`{"droplet":{ "guid":"some-droplet-guid" }, "relationships":{"app":{"data":{"guid":"some-app-guid"}}}}`), 203 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 204 ), 205 ) 206 }) 207 208 It("creates the deployment with no errors and returns all warnings", func() { 209 Expect(deploymentGUID).To(Equal("some-deployment-guid")) 210 Expect(executeErr).ToNot(HaveOccurred()) 211 Expect(warnings).To(ConsistOf("warning")) 212 }) 213 214 }) 215 216 Context("when no droplet guid is provided", func() { 217 BeforeEach(func() { 218 dropletGUID = "" 219 server.AppendHandlers( 220 CombineHandlers( 221 VerifyRequest(http.MethodPost, "/v3/deployments"), 222 VerifyJSON(`{"relationships":{"app":{"data":{"guid":"some-app-guid"}}}}`), 223 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 224 ), 225 ) 226 }) 227 228 It("omits the droplet object in the JSON", func() { 229 Expect(executeErr).ToNot(HaveOccurred()) 230 Expect(warnings).To(ConsistOf("warning")) 231 }) 232 }) 233 }) 234 }) 235 236 Describe("CreateApplicationDeploymentByRevision", func() { 237 var ( 238 deploymentGUID string 239 warnings Warnings 240 executeErr error 241 revisionGUID string 242 ) 243 244 JustBeforeEach(func() { 245 deploymentGUID, warnings, executeErr = client.CreateApplicationDeploymentByRevision("some-app-guid", revisionGUID) 246 }) 247 248 Context("when the application exists", func() { 249 var response string 250 BeforeEach(func() { 251 revisionGUID = "some-revision-guid" 252 response = `{ 253 "guid": "some-deployment-guid", 254 "created_at": "2018-04-25T22:42:10Z", 255 "relationships": { 256 "app": { 257 "data": { 258 "guid": "some-app-guid" 259 } 260 } 261 } 262 }` 263 }) 264 265 Context("when creating the deployment succeeds", func() { 266 BeforeEach(func() { 267 server.AppendHandlers( 268 CombineHandlers( 269 VerifyRequest(http.MethodPost, "/v3/deployments"), 270 VerifyJSON(`{"revision":{ "guid":"some-revision-guid" }, "relationships":{"app":{"data":{"guid":"some-app-guid"}}}}`), 271 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 272 ), 273 ) 274 }) 275 276 It("creates the deployment with no errors and returns all warnings", func() { 277 Expect(deploymentGUID).To(Equal("some-deployment-guid")) 278 Expect(executeErr).ToNot(HaveOccurred()) 279 Expect(warnings).To(ConsistOf("warning")) 280 }) 281 }) 282 }) 283 }) 284 285 Describe("GetDeployment", func() { 286 var response string 287 Context("When the deployments exists", func() { 288 BeforeEach(func() { 289 response = `{ 290 "guid": "some-deployment-guid", 291 "state": "DEPLOYED", 292 "status": { 293 "value": "FINALIZED", 294 "reason": "SUPERSEDED" 295 }, 296 "droplet": { 297 "guid": "some-droplet-guid" 298 }, 299 "previous_droplet": { 300 "guid": "some-other-droplet-guid" 301 }, 302 "created_at": "some-time", 303 "updated_at": "some-later-time", 304 "relationships": { 305 "app": { 306 "data": { 307 "guid": "some-app-guid" 308 } 309 } 310 } 311 }` 312 server.AppendHandlers( 313 CombineHandlers( 314 VerifyRequest(http.MethodGet, "/v3/deployments/some-deployment-guid"), 315 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 316 ), 317 ) 318 }) 319 It("Successfully returns a deployment object", func() { 320 deployment, warnings, err := client.GetDeployment("some-deployment-guid") 321 Expect(err).ToNot(HaveOccurred()) 322 Expect(warnings).To(ConsistOf("warning")) 323 Expect(deployment).To(Not(BeNil())) 324 Expect(deployment.GUID).To(Equal("some-deployment-guid")) 325 Expect(deployment.State).To(Equal(constant.DeploymentDeployed)) 326 Expect(deployment.StatusValue).To(Equal(constant.DeploymentStatusValueFinalized)) 327 Expect(deployment.StatusReason).To(Equal(constant.DeploymentStatusReasonSuperseded)) 328 }) 329 }) 330 331 Context("when the deployment doesn't exist", func() { 332 BeforeEach(func() { 333 response := `{ 334 "errors": [ 335 { 336 "code": 10010, 337 "detail": "Deployment not found", 338 "title": "CF-ResourceNotFound" 339 } 340 ] 341 }` 342 server.AppendHandlers( 343 CombineHandlers( 344 VerifyRequest(http.MethodGet, "/v3/deployments/not-a-deployment"), 345 RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"warning-deployment"}}), 346 ), 347 ) 348 }) 349 350 It("returns the error", func() { 351 _, warnings, err := client.GetDeployment("not-a-deployment") 352 Expect(err).To(MatchError(ccerror.DeploymentNotFoundError{})) 353 Expect(warnings).To(ConsistOf("warning-deployment")) 354 }) 355 }) 356 }) 357 })