github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/api/cloudcontroller/ccv3/relationship_test.go (about) 1 package ccv3_test 2 3 import ( 4 "encoding/json" 5 "net/http" 6 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 8 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 . "github.com/onsi/gomega/ghttp" 12 ) 13 14 var _ = Describe("Relationship", func() { 15 var ( 16 client *Client 17 ) 18 19 BeforeEach(func() { 20 client = NewTestClient() 21 }) 22 23 Describe("Relationship.MarshalJSON", func() { 24 Context("when the isolation segment is specified by name", func() { 25 It("contains the name in the marshaled JSON", func() { 26 body, err := json.Marshal(Relationship{GUID: "some-iso-guid"}) 27 expectedJSON := `{ 28 "data": { 29 "guid": "some-iso-guid" 30 } 31 }` 32 33 Expect(err).NotTo(HaveOccurred()) 34 Expect(body).To(MatchJSON(expectedJSON)) 35 }) 36 }) 37 38 Context("when the isolation segment is the empty string", func() { 39 It("contains null in the marshaled JSON", func() { 40 body, err := json.Marshal(Relationship{GUID: ""}) 41 expectedJSON := `{ 42 "data": null 43 }` 44 45 Expect(err).NotTo(HaveOccurred()) 46 Expect(body).To(MatchJSON(expectedJSON)) 47 }) 48 }) 49 }) 50 51 Describe("AssignSpaceToIsolationSegment", func() { 52 Context("when the assignment is successful", func() { 53 BeforeEach(func() { 54 response := `{ 55 "data": { 56 "guid": "some-isolation-segment-guid" 57 } 58 }` 59 60 requestBody := map[string]map[string]string{ 61 "data": {"guid": "some-iso-guid"}, 62 } 63 server.AppendHandlers( 64 CombineHandlers( 65 VerifyRequest(http.MethodPatch, "/v3/spaces/some-space-guid/relationships/isolation_segment"), 66 VerifyJSONRepresenting(requestBody), 67 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 68 ), 69 ) 70 }) 71 72 It("returns all relationships and warnings", func() { 73 relationship, warnings, err := client.AssignSpaceToIsolationSegment("some-space-guid", "some-iso-guid") 74 Expect(err).NotTo(HaveOccurred()) 75 Expect(warnings).To(ConsistOf("this is a warning")) 76 Expect(relationship).To(Equal(Relationship{ 77 GUID: "some-isolation-segment-guid", 78 })) 79 }) 80 }) 81 }) 82 83 Describe("GetSpaceIsolationSegment", func() { 84 Context("when getting the isolation segment is successful", func() { 85 BeforeEach(func() { 86 response := `{ 87 "data": { 88 "guid": "some-isolation-segment-guid" 89 } 90 }` 91 92 server.AppendHandlers( 93 CombineHandlers( 94 VerifyRequest(http.MethodGet, "/v3/spaces/some-space-guid/relationships/isolation_segment"), 95 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 96 ), 97 ) 98 }) 99 100 It("returns the relationship and warnings", func() { 101 relationship, warnings, err := client.GetSpaceIsolationSegment("some-space-guid") 102 Expect(err).NotTo(HaveOccurred()) 103 Expect(warnings).To(ConsistOf("this is a warning")) 104 Expect(relationship).To(Equal(Relationship{ 105 GUID: "some-isolation-segment-guid", 106 })) 107 }) 108 }) 109 }) 110 111 Describe("RevokeIsolationSegmentFromOrganization", func() { 112 Context("when relationship exists", func() { 113 BeforeEach(func() { 114 server.AppendHandlers( 115 CombineHandlers( 116 VerifyRequest(http.MethodDelete, "/v3/isolation_segments/segment-guid/relationships/organizations/org-guid"), 117 RespondWith(http.StatusOK, "", http.Header{"X-Cf-Warnings": {"this is a warning"}}), 118 ), 119 ) 120 }) 121 122 It("revoke the relationship", func() { 123 warnings, err := client.RevokeIsolationSegmentFromOrganization("segment-guid", "org-guid") 124 Expect(err).ToNot(HaveOccurred()) 125 Expect(warnings).To(ConsistOf("this is a warning")) 126 127 Expect(server.ReceivedRequests()).To(HaveLen(3)) 128 }) 129 }) 130 }) 131 132 Context("when an error occurs", func() { 133 BeforeEach(func() { 134 response := `{ 135 "errors": [ 136 { 137 "code": 10008, 138 "detail": "The request is semantically invalid: command presence", 139 "title": "CF-UnprocessableEntity" 140 } 141 ] 142 }` 143 144 server.AppendHandlers( 145 CombineHandlers( 146 VerifyRequest(http.MethodDelete, "/v3/isolation_segments/segment-guid/relationships/organizations/org-guid"), 147 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 148 ), 149 ) 150 }) 151 152 It("returns the error and warnings", func() { 153 warnings, err := client.RevokeIsolationSegmentFromOrganization("segment-guid", "org-guid") 154 Expect(err).To(MatchError(ccerror.V3UnexpectedResponseError{ 155 ResponseCode: http.StatusTeapot, 156 V3ErrorResponse: ccerror.V3ErrorResponse{ 157 Errors: []ccerror.V3Error{ 158 { 159 Code: 10008, 160 Detail: "The request is semantically invalid: command presence", 161 Title: "CF-UnprocessableEntity", 162 }, 163 }, 164 }, 165 })) 166 Expect(warnings).To(ConsistOf("this is a warning")) 167 }) 168 }) 169 170 Describe("GetOrganizationDefaultIsolationSegment", func() { 171 Context("when getting the isolation segment is successful", func() { 172 BeforeEach(func() { 173 response := `{ 174 "data": { 175 "guid": "some-isolation-segment-guid" 176 } 177 }` 178 179 server.AppendHandlers( 180 CombineHandlers( 181 VerifyRequest(http.MethodGet, "/v3/organizations/some-org-guid/relationships/default_isolation_segment"), 182 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 183 ), 184 ) 185 }) 186 187 It("returns the relationship and warnings", func() { 188 relationship, warnings, err := client.GetOrganizationDefaultIsolationSegment("some-org-guid") 189 Expect(err).NotTo(HaveOccurred()) 190 Expect(warnings).To(ConsistOf("this is a warning")) 191 Expect(relationship).To(Equal(Relationship{ 192 GUID: "some-isolation-segment-guid", 193 })) 194 }) 195 }) 196 197 Context("when getting the isolation segment fails with an error", func() { 198 BeforeEach(func() { 199 response := `{ 200 "errors": [ 201 { 202 "detail": "Organization not found", 203 "title": "CF-ResourceNotFound", 204 "code": 10010 205 } 206 ] 207 }` 208 server.AppendHandlers( 209 CombineHandlers( 210 VerifyRequest(http.MethodGet, "/v3/organizations/some-org-guid/relationships/default_isolation_segment"), 211 RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 212 ), 213 ) 214 }) 215 216 It("returns an error and warnings", func() { 217 _, warnings, err := client.GetOrganizationDefaultIsolationSegment("some-org-guid") 218 Expect(err).To(MatchError(ccerror.ResourceNotFoundError{ 219 Message: "Organization not found", 220 })) 221 Expect(warnings).To(ConsistOf("this is a warning")) 222 }) 223 }) 224 }) 225 226 Describe("PatchOrganizationDefaultIsolationSegment", func() { 227 Context("when patching the default organization isolation segment with non-empty isolation segment guid", func() { 228 BeforeEach(func() { 229 expectedBody := `{ 230 "data": { 231 "guid": "some-isolation-segment-guid" 232 } 233 }` 234 responseBody := `{ 235 "data": { 236 "guid": "some-isolation-segment-guid" 237 } 238 }` 239 240 server.AppendHandlers( 241 CombineHandlers( 242 VerifyRequest(http.MethodPatch, "/v3/organizations/some-org-guid/relationships/default_isolation_segment"), 243 VerifyJSON(expectedBody), 244 RespondWith(http.StatusOK, responseBody, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 245 ), 246 ) 247 }) 248 249 It("patches the organization's default isolation segment", func() { 250 relationship, warnings, err := client.PatchOrganizationDefaultIsolationSegment("some-org-guid", "some-isolation-segment-guid") 251 Expect(relationship).To(Equal(Relationship{GUID: "some-isolation-segment-guid"})) 252 Expect(err).ToNot(HaveOccurred()) 253 Expect(warnings).To(ConsistOf("this is a warning")) 254 }) 255 }) 256 257 Context("when patching the default organization isolation segment with empty isolation segment guid", func() { 258 BeforeEach(func() { 259 expectedBody := `{ 260 "data": null 261 }` 262 responseBody := `{ 263 "data": null 264 }` 265 server.AppendHandlers( 266 CombineHandlers( 267 VerifyRequest(http.MethodPatch, "/v3/organizations/some-org-guid/relationships/default_isolation_segment"), 268 VerifyJSON(expectedBody), 269 RespondWith(http.StatusOK, responseBody, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 270 ), 271 ) 272 }) 273 274 It("patches the organization's default isolation segment with nil guid", func() { 275 relationship, warnings, err := client.PatchOrganizationDefaultIsolationSegment("some-org-guid", "") 276 Expect(relationship).To(BeZero()) 277 Expect(err).ToNot(HaveOccurred()) 278 Expect(warnings).To(ConsistOf("this is a warning")) 279 }) 280 }) 281 282 Context("when patching the isolation segment fails with an error", func() { 283 BeforeEach(func() { 284 response := `{ 285 "errors": [ 286 { 287 "detail": "Organization not found", 288 "title": "CF-ResourceNotFound", 289 "code": 10010 290 } 291 ] 292 }` 293 294 server.AppendHandlers( 295 CombineHandlers( 296 VerifyRequest(http.MethodPatch, "/v3/organizations/some-org-guid/relationships/default_isolation_segment"), 297 RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 298 ), 299 ) 300 }) 301 302 It("returns the empty relationship, an error and warnings", func() { 303 relationship, warnings, err := client.PatchOrganizationDefaultIsolationSegment("some-org-guid", "some-isolation-segment-guid") 304 Expect(relationship).To(BeZero()) 305 Expect(err).To(MatchError(ccerror.ResourceNotFoundError{ 306 Message: "Organization not found", 307 })) 308 Expect(warnings).To(ConsistOf("this is a warning")) 309 }) 310 }) 311 }) 312 313 Describe("DeleteServiceInstanceRelationshipsSharedSpace", func() { 314 var ( 315 serviceInstanceGUID string 316 spaceGUID string 317 318 warnings Warnings 319 executeErr error 320 ) 321 322 BeforeEach(func() { 323 serviceInstanceGUID = "some-service-instance-guid" 324 spaceGUID = "some-space-guid" 325 }) 326 327 JustBeforeEach(func() { 328 warnings, executeErr = client.DeleteServiceInstanceRelationshipsSharedSpace(serviceInstanceGUID, spaceGUID) 329 }) 330 331 Context("when no errors occur deleting the shared space relationship", func() { 332 BeforeEach(func() { 333 server.AppendHandlers( 334 CombineHandlers( 335 VerifyRequest(http.MethodDelete, "/v3/service_instances/some-service-instance-guid/relationships/shared_spaces/some-space-guid"), 336 RespondWith(http.StatusNoContent, "{}", http.Header{"X-Cf-Warnings": {"this is a warning"}}), 337 ), 338 ) 339 }) 340 341 It("does not return any errors and returns all warnings", func() { 342 Expect(executeErr).NotTo(HaveOccurred()) 343 Expect(warnings).To(ConsistOf("this is a warning")) 344 }) 345 }) 346 347 Context("when an error occurs deleting the shared space relationship", func() { 348 BeforeEach(func() { 349 response := `{ 350 "errors": [ 351 { 352 "code": 10008, 353 "detail": "The request is semantically invalid: command presence", 354 "title": "CF-UnprocessableEntity" 355 } 356 ] 357 }` 358 server.AppendHandlers( 359 CombineHandlers( 360 VerifyRequest(http.MethodDelete, "/v3/service_instances/some-service-instance-guid/relationships/shared_spaces/some-space-guid"), 361 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 362 ), 363 ) 364 }) 365 366 It("returns the errors and all warnings", func() { 367 Expect(executeErr).To(MatchError(ccerror.V3UnexpectedResponseError{ 368 ResponseCode: http.StatusTeapot, 369 V3ErrorResponse: ccerror.V3ErrorResponse{ 370 Errors: []ccerror.V3Error{ 371 { 372 Code: 10008, 373 Detail: "The request is semantically invalid: command presence", 374 Title: "CF-UnprocessableEntity", 375 }, 376 }, 377 }, 378 })) 379 Expect(warnings).To(ConsistOf("this is a warning")) 380 }) 381 }) 382 }) 383 })