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  })