github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/api/cloudcontroller/ccv3/task_test.go (about) 1 package ccv3_test 2 3 import ( 4 "fmt" 5 "net/http" 6 "net/url" 7 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 9 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 . "github.com/onsi/gomega/ghttp" 13 ) 14 15 var _ = Describe("Task", func() { 16 var client *Client 17 18 BeforeEach(func() { 19 client = NewTestClient() 20 }) 21 22 Describe("CreateApplicationTask", func() { 23 Context("when the application exists", func() { 24 var response string 25 26 BeforeEach(func() { 27 response = `{ 28 "sequence_id": 3 29 }` 30 }) 31 32 Context("when the name is empty", func() { 33 BeforeEach(func() { 34 server.AppendHandlers( 35 CombineHandlers( 36 VerifyRequest(http.MethodPost, "/v3/apps/some-app-guid/tasks"), 37 VerifyJSON(`{"command":"some command"}`), 38 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 39 ), 40 ) 41 }) 42 43 It("creates and returns the task and all warnings", func() { 44 task, warnings, err := client.CreateApplicationTask("some-app-guid", Task{Command: "some command"}) 45 Expect(err).ToNot(HaveOccurred()) 46 47 Expect(task).To(Equal(Task{SequenceID: 3})) 48 Expect(warnings).To(ConsistOf("warning")) 49 }) 50 }) 51 52 Context("when the name is not empty", func() { 53 BeforeEach(func() { 54 server.AppendHandlers( 55 CombineHandlers( 56 VerifyRequest(http.MethodPost, "/v3/apps/some-app-guid/tasks"), 57 VerifyJSON(`{"command":"some command", "name":"some-task-name"}`), 58 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 59 ), 60 ) 61 }) 62 63 It("creates and returns the task and all warnings", func() { 64 task, warnings, err := client.CreateApplicationTask("some-app-guid", Task{Command: "some command", Name: "some-task-name"}) 65 Expect(err).ToNot(HaveOccurred()) 66 67 Expect(task).To(Equal(Task{SequenceID: 3})) 68 Expect(warnings).To(ConsistOf("warning")) 69 }) 70 }) 71 72 Context("when the disk size is not 0", func() { 73 BeforeEach(func() { 74 response := `{ 75 "disk_in_mb": 123, 76 "sequence_id": 3 77 }` 78 server.AppendHandlers( 79 CombineHandlers( 80 VerifyRequest(http.MethodPost, "/v3/apps/some-app-guid/tasks"), 81 VerifyJSON(`{"command":"some command", "disk_in_mb": 123}`), 82 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 83 ), 84 ) 85 }) 86 87 It("creates and returns the task and all warnings with the provided disk size", func() { 88 task, warnings, err := client.CreateApplicationTask("some-app-guid", Task{Command: "some command", DiskInMB: uint64(123)}) 89 Expect(err).ToNot(HaveOccurred()) 90 91 Expect(task).To(Equal(Task{DiskInMB: uint64(123), SequenceID: 3})) 92 Expect(warnings).To(ConsistOf("warning")) 93 }) 94 }) 95 96 Context("when the memory is not 0", func() { 97 BeforeEach(func() { 98 response := `{ 99 "memory_in_mb": 123, 100 "sequence_id": 3 101 }` 102 server.AppendHandlers( 103 CombineHandlers( 104 VerifyRequest(http.MethodPost, "/v3/apps/some-app-guid/tasks"), 105 VerifyJSON(`{"command":"some command", "memory_in_mb": 123}`), 106 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 107 ), 108 ) 109 }) 110 111 It("creates and returns the task and all warnings with the provided memory", func() { 112 task, warnings, err := client.CreateApplicationTask("some-app-guid", Task{Command: "some command", MemoryInMB: uint64(123)}) 113 Expect(err).ToNot(HaveOccurred()) 114 115 Expect(task).To(Equal(Task{MemoryInMB: uint64(123), SequenceID: 3})) 116 Expect(warnings).To(ConsistOf("warning")) 117 }) 118 }) 119 120 }) 121 122 Context("when the cloud controller returns errors and warnings", func() { 123 BeforeEach(func() { 124 response := `{ 125 "errors": [ 126 { 127 "code": 10008, 128 "detail": "The request is semantically invalid: command presence", 129 "title": "CF-UnprocessableEntity" 130 }, 131 { 132 "code": 10010, 133 "detail": "App not found", 134 "title": "CF-ResourceNotFound" 135 } 136 ] 137 }` 138 server.AppendHandlers( 139 CombineHandlers( 140 VerifyRequest(http.MethodPost, "/v3/apps/some-app-guid/tasks"), 141 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning"}}), 142 ), 143 ) 144 }) 145 146 It("returns the errors and all warnings", func() { 147 _, warnings, err := client.CreateApplicationTask("some-app-guid", Task{Command: "some command"}) 148 Expect(err).To(MatchError(ccerror.V3UnexpectedResponseError{ 149 ResponseCode: http.StatusTeapot, 150 V3ErrorResponse: ccerror.V3ErrorResponse{ 151 Errors: []ccerror.V3Error{ 152 { 153 Code: 10008, 154 Detail: "The request is semantically invalid: command presence", 155 Title: "CF-UnprocessableEntity", 156 }, 157 { 158 Code: 10010, 159 Detail: "App not found", 160 Title: "CF-ResourceNotFound", 161 }, 162 }, 163 }, 164 })) 165 Expect(warnings).To(ConsistOf("warning")) 166 }) 167 }) 168 }) 169 170 Describe("GetApplicationTasks", func() { 171 Context("when the application exists", func() { 172 BeforeEach(func() { 173 response1 := fmt.Sprintf(`{ 174 "pagination": { 175 "next": { 176 "href": "%s/v3/apps/some-app-guid/tasks?per_page=2&page=2" 177 } 178 }, 179 "resources": [ 180 { 181 "guid": "task-1-guid", 182 "sequence_id": 1, 183 "name": "task-1", 184 "command": "some-command", 185 "state": "SUCCEEDED", 186 "created_at": "2016-11-07T05:59:01Z" 187 }, 188 { 189 "guid": "task-2-guid", 190 "sequence_id": 2, 191 "name": "task-2", 192 "command": "some-command", 193 "state": "FAILED", 194 "created_at": "2016-11-07T06:59:01Z" 195 } 196 ] 197 }`, server.URL()) 198 response2 := `{ 199 "pagination": { 200 "next": null 201 }, 202 "resources": [ 203 { 204 "guid": "task-3-guid", 205 "sequence_id": 3, 206 "name": "task-3", 207 "command": "some-command", 208 "state": "RUNNING", 209 "created_at": "2016-11-07T07:59:01Z" 210 } 211 ] 212 }` 213 server.AppendHandlers( 214 CombineHandlers( 215 VerifyRequest(http.MethodGet, "/v3/apps/some-app-guid/tasks", "per_page=2"), 216 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}), 217 ), 218 ) 219 server.AppendHandlers( 220 CombineHandlers( 221 VerifyRequest(http.MethodGet, "/v3/apps/some-app-guid/tasks", "per_page=2&page=2"), 222 RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}), 223 ), 224 ) 225 }) 226 227 It("returns a list of tasks associated with the application and all warnings", func() { 228 tasks, warnings, err := client.GetApplicationTasks("some-app-guid", url.Values{"per_page": []string{"2"}}) 229 Expect(err).ToNot(HaveOccurred()) 230 231 Expect(tasks).To(ConsistOf( 232 Task{ 233 GUID: "task-1-guid", 234 SequenceID: 1, 235 Name: "task-1", 236 State: "SUCCEEDED", 237 CreatedAt: "2016-11-07T05:59:01Z", 238 Command: "some-command", 239 }, 240 Task{ 241 GUID: "task-2-guid", 242 SequenceID: 2, 243 Name: "task-2", 244 State: "FAILED", 245 CreatedAt: "2016-11-07T06:59:01Z", 246 Command: "some-command", 247 }, 248 Task{ 249 GUID: "task-3-guid", 250 SequenceID: 3, 251 Name: "task-3", 252 State: "RUNNING", 253 CreatedAt: "2016-11-07T07:59:01Z", 254 Command: "some-command", 255 }, 256 )) 257 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 258 }) 259 }) 260 261 Context("when the application does not exist", func() { 262 BeforeEach(func() { 263 response := `{ 264 "errors": [ 265 { 266 "code": 10010, 267 "detail": "App not found", 268 "title": "CF-ResourceNotFound" 269 } 270 ] 271 }` 272 server.AppendHandlers( 273 CombineHandlers( 274 VerifyRequest(http.MethodGet, "/v3/apps/some-app-guid/tasks"), 275 RespondWith(http.StatusNotFound, response), 276 ), 277 ) 278 }) 279 280 It("returns a ResourceNotFoundError", func() { 281 _, _, err := client.GetApplicationTasks("some-app-guid", nil) 282 Expect(err).To(MatchError(ccerror.ApplicationNotFoundError{})) 283 }) 284 }) 285 286 Context("when the cloud controller returns errors and warnings", func() { 287 BeforeEach(func() { 288 response := `{ 289 "errors": [ 290 { 291 "code": 10008, 292 "detail": "The request is semantically invalid: command presence", 293 "title": "CF-UnprocessableEntity" 294 }, 295 { 296 "code": 10010, 297 "detail": "App not found", 298 "title": "CF-ResourceNotFound" 299 } 300 ] 301 }` 302 server.AppendHandlers( 303 CombineHandlers( 304 VerifyRequest(http.MethodGet, "/v3/apps/some-app-guid/tasks"), 305 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning"}}), 306 ), 307 ) 308 }) 309 310 It("returns the errors and all warnings", func() { 311 _, warnings, err := client.GetApplicationTasks("some-app-guid", nil) 312 Expect(err).To(MatchError(ccerror.V3UnexpectedResponseError{ 313 ResponseCode: http.StatusTeapot, 314 V3ErrorResponse: ccerror.V3ErrorResponse{ 315 Errors: []ccerror.V3Error{ 316 { 317 Code: 10008, 318 Detail: "The request is semantically invalid: command presence", 319 Title: "CF-UnprocessableEntity", 320 }, 321 { 322 Code: 10010, 323 Detail: "App not found", 324 Title: "CF-ResourceNotFound", 325 }, 326 }, 327 }, 328 })) 329 Expect(warnings).To(ConsistOf("warning")) 330 }) 331 }) 332 }) 333 334 Describe("UpdateTask", func() { 335 Context("when the request succeeds", func() { 336 BeforeEach(func() { 337 response := `{ 338 "guid": "task-3-guid", 339 "sequence_id": 3, 340 "name": "task-3", 341 "command": "some-command", 342 "state": "CANCELING", 343 "created_at": "2016-11-07T07:59:01Z" 344 }` 345 server.AppendHandlers( 346 CombineHandlers( 347 VerifyRequest(http.MethodPut, "/v3/tasks/some-task-guid/cancel"), 348 RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}), 349 ), 350 ) 351 }) 352 353 It("returns the task and warnings", func() { 354 task, warnings, err := client.UpdateTask("some-task-guid") 355 Expect(err).ToNot(HaveOccurred()) 356 357 Expect(task).To(Equal(Task{ 358 GUID: "task-3-guid", 359 SequenceID: 3, 360 Name: "task-3", 361 Command: "some-command", 362 State: "CANCELING", 363 CreatedAt: "2016-11-07T07:59:01Z", 364 })) 365 Expect(warnings).To(ConsistOf("warning")) 366 }) 367 }) 368 369 Context("when the request fails", func() { 370 BeforeEach(func() { 371 response := `{ 372 "errors": [ 373 { 374 "code": 10008, 375 "detail": "The request is semantically invalid: command presence", 376 "title": "CF-UnprocessableEntity" 377 }, 378 { 379 "code": 10010, 380 "detail": "App not found", 381 "title": "CF-ResourceNotFound" 382 } 383 ] 384 }` 385 server.AppendHandlers( 386 CombineHandlers( 387 VerifyRequest(http.MethodPut, "/v3/tasks/some-task-guid/cancel"), 388 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning"}}), 389 ), 390 ) 391 }) 392 393 It("returns the errors and all warnings", func() { 394 _, warnings, err := client.UpdateTask("some-task-guid") 395 Expect(err).To(MatchError(ccerror.V3UnexpectedResponseError{ 396 ResponseCode: http.StatusTeapot, 397 V3ErrorResponse: ccerror.V3ErrorResponse{ 398 Errors: []ccerror.V3Error{ 399 { 400 Code: 10008, 401 Detail: "The request is semantically invalid: command presence", 402 Title: "CF-UnprocessableEntity", 403 }, 404 { 405 Code: 10010, 406 Detail: "App not found", 407 Title: "CF-ResourceNotFound", 408 }, 409 }, 410 }, 411 })) 412 Expect(warnings).To(ConsistOf("warning")) 413 }) 414 }) 415 }) 416 })