github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/api/cloudcontroller/ccv3/space_test.go (about)

     1  package ccv3_test
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  
     7  	"code.cloudfoundry.org/cli/types"
     8  
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    10  	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/ghttp"
    15  )
    16  
    17  var _ = Describe("Spaces", func() {
    18  	var client *Client
    19  
    20  	BeforeEach(func() {
    21  		client, _ = NewTestClient()
    22  	})
    23  
    24  	Describe("CreateSpace", func() {
    25  		var (
    26  			space         Space
    27  			spaceToCreate Space
    28  			warnings      Warnings
    29  			executeErr    error
    30  		)
    31  
    32  		JustBeforeEach(func() {
    33  			spaceToCreate = Space{Name: "some-space", Relationships: Relationships{constant.RelationshipTypeOrganization: Relationship{GUID: "some-org-guid"}}}
    34  			space, warnings, executeErr = client.CreateSpace(spaceToCreate)
    35  		})
    36  
    37  		When("spaces exist", func() {
    38  			BeforeEach(func() {
    39  				response := `{
    40        "name": "some-space",
    41        "guid": "some-space-guid"
    42      }`
    43  
    44  				expectedBody := `{
    45  "name": "some-space",
    46  "relationships": {
    47        "organization": {
    48        "data": { "guid": "some-org-guid" }
    49      }
    50    }
    51  }`
    52  				server.AppendHandlers(
    53  					CombineHandlers(
    54  						VerifyRequest(http.MethodPost, "/v3/spaces"),
    55  						VerifyJSON(expectedBody),
    56  						RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
    57  					),
    58  				)
    59  			})
    60  
    61  			It("returns the given space and all warnings", func() {
    62  				Expect(executeErr).ToNot(HaveOccurred())
    63  				Expect(warnings).To(ConsistOf("this is a warning"))
    64  
    65  				Expect(space).To(Equal(Space{
    66  					GUID: "some-space-guid",
    67  					Name: "some-space",
    68  				}))
    69  			})
    70  		})
    71  
    72  		When("the cloud controller returns errors and warnings", func() {
    73  			BeforeEach(func() {
    74  				response := `{
    75    "errors": [
    76      {
    77        "code": 10008,
    78        "detail": "The request is semantically invalid: command presence",
    79        "title": "CF-UnprocessableEntity"
    80      },
    81  		{
    82        "code": 10010,
    83        "detail": "Isolation segment not found",
    84        "title": "CF-ResourceNotFound"
    85      }
    86    ]
    87  }`
    88  				server.AppendHandlers(
    89  					CombineHandlers(
    90  						VerifyRequest(http.MethodPost, "/v3/spaces"),
    91  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
    92  					),
    93  				)
    94  			})
    95  
    96  			It("returns the error and all warnings", func() {
    97  				Expect(executeErr).To(MatchError(ccerror.MultiError{
    98  					ResponseCode: http.StatusTeapot,
    99  					Errors: []ccerror.V3Error{
   100  						{
   101  							Code:   10008,
   102  							Detail: "The request is semantically invalid: command presence",
   103  							Title:  "CF-UnprocessableEntity",
   104  						},
   105  						{
   106  							Code:   10010,
   107  							Detail: "Isolation segment not found",
   108  							Title:  "CF-ResourceNotFound",
   109  						},
   110  					},
   111  				}))
   112  				Expect(warnings).To(ConsistOf("this is a warning"))
   113  			})
   114  		})
   115  
   116  	})
   117  
   118  	Describe("GetSpaces", func() {
   119  		var (
   120  			query Query
   121  
   122  			spaces     []Space
   123  			warnings   Warnings
   124  			executeErr error
   125  		)
   126  
   127  		JustBeforeEach(func() {
   128  			spaces, warnings, executeErr = client.GetSpaces(query)
   129  		})
   130  
   131  		When("spaces exist", func() {
   132  			BeforeEach(func() {
   133  				response1 := fmt.Sprintf(`{
   134  	"pagination": {
   135  		"next": {
   136  			"href": "%s/v3/spaces?names=some-space-name&page=2&per_page=2"
   137  		}
   138  	},
   139    "resources": [
   140      {
   141        "name": "space-name-1",
   142        "guid": "space-guid-1",
   143        "relationships": {
   144          "organization": {
   145            "data": { "guid": "org-guid-1" }
   146          }
   147        }
   148      },
   149      {
   150        "name": "space-name-2",
   151        "guid": "space-guid-2",
   152        "relationships": {
   153          "organization": {
   154            "data": { "guid": "org-guid-2" }
   155          }
   156        }
   157      }
   158    ]
   159  }`, server.URL())
   160  				response2 := `{
   161    "pagination": {
   162      "next": null
   163    },
   164    "resources": [
   165      {
   166        "name": "space-name-3",
   167        "guid": "space-guid-3",
   168        "relationships": {
   169          "organization": {
   170            "data": { "guid": "org-guid-3" }
   171          }
   172        }
   173      }
   174    ]
   175  }`
   176  
   177  				server.AppendHandlers(
   178  					CombineHandlers(
   179  						VerifyRequest(http.MethodGet, "/v3/spaces", "names=some-space-name"),
   180  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   181  					),
   182  				)
   183  				server.AppendHandlers(
   184  					CombineHandlers(
   185  						VerifyRequest(http.MethodGet, "/v3/spaces", "names=some-space-name&page=2&per_page=2"),
   186  						RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"this is another warning"}}),
   187  					),
   188  				)
   189  
   190  				query = Query{
   191  					Key:    NameFilter,
   192  					Values: []string{"some-space-name"},
   193  				}
   194  			})
   195  
   196  			It("returns the queried spaces and all warnings", func() {
   197  				Expect(executeErr).NotTo(HaveOccurred())
   198  
   199  				Expect(spaces).To(ConsistOf(
   200  					Space{Name: "space-name-1", GUID: "space-guid-1", Relationships: Relationships{
   201  						constant.RelationshipTypeOrganization: Relationship{GUID: "org-guid-1"},
   202  					}},
   203  					Space{Name: "space-name-2", GUID: "space-guid-2", Relationships: Relationships{
   204  						constant.RelationshipTypeOrganization: Relationship{GUID: "org-guid-2"},
   205  					}},
   206  					Space{Name: "space-name-3", GUID: "space-guid-3", Relationships: Relationships{
   207  						constant.RelationshipTypeOrganization: Relationship{GUID: "org-guid-3"},
   208  					}},
   209  				))
   210  				Expect(warnings).To(ConsistOf("this is a warning", "this is another warning"))
   211  			})
   212  		})
   213  
   214  		When("the cloud controller returns errors and warnings", func() {
   215  			BeforeEach(func() {
   216  				response := `{
   217    "errors": [
   218      {
   219        "code": 10008,
   220        "detail": "The request is semantically invalid: command presence",
   221        "title": "CF-UnprocessableEntity"
   222      },
   223      {
   224        "code": 10010,
   225        "detail": "Space not found",
   226        "title": "CF-SpaceNotFound"
   227      }
   228    ]
   229  }`
   230  				server.AppendHandlers(
   231  					CombineHandlers(
   232  						VerifyRequest(http.MethodGet, "/v3/spaces"),
   233  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   234  					),
   235  				)
   236  			})
   237  
   238  			It("returns the error and all warnings", func() {
   239  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   240  					ResponseCode: http.StatusTeapot,
   241  					Errors: []ccerror.V3Error{
   242  						{
   243  							Code:   10008,
   244  							Detail: "The request is semantically invalid: command presence",
   245  							Title:  "CF-UnprocessableEntity",
   246  						},
   247  						{
   248  							Code:   10010,
   249  							Detail: "Space not found",
   250  							Title:  "CF-SpaceNotFound",
   251  						},
   252  					},
   253  				}))
   254  				Expect(warnings).To(ConsistOf("this is a warning"))
   255  			})
   256  		})
   257  	})
   258  
   259  	Describe("UpdateSpace", func() {
   260  		var (
   261  			spaceToUpdate Space
   262  			updatedSpace  Space
   263  			warnings      Warnings
   264  			executeErr    error
   265  		)
   266  
   267  		JustBeforeEach(func() {
   268  			updatedSpace, warnings, executeErr = client.UpdateSpace(spaceToUpdate)
   269  		})
   270  
   271  		When("the organization is updated successfully", func() {
   272  			BeforeEach(func() {
   273  				response := `{
   274  					"guid": "some-space-guid",
   275  					"name": "some-space-name",
   276  					"metadata": {
   277  						"labels": {
   278  							"k1":"v1",
   279  							"k2":"v2"
   280  						}
   281  					}
   282  				}`
   283  
   284  				expectedBody := map[string]interface{}{
   285  					"name": "some-space-name",
   286  					"metadata": map[string]interface{}{
   287  						"labels": map[string]string{
   288  							"k1": "v1",
   289  							"k2": "v2",
   290  						},
   291  					},
   292  				}
   293  
   294  				server.AppendHandlers(
   295  					CombineHandlers(
   296  						VerifyRequest(http.MethodPatch, "/v3/spaces/some-guid"),
   297  						VerifyJSONRepresenting(expectedBody),
   298  						RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   299  					),
   300  				)
   301  
   302  				spaceToUpdate = Space{
   303  					Name: "some-space-name",
   304  					GUID: "some-guid",
   305  					Metadata: &Metadata{
   306  						Labels: map[string]types.NullString{
   307  							"k1": types.NewNullString("v1"),
   308  							"k2": types.NewNullString("v2"),
   309  						},
   310  					},
   311  				}
   312  			})
   313  
   314  			It("should include the labels in the JSON", func() {
   315  				Expect(executeErr).ToNot(HaveOccurred())
   316  				Expect(server.ReceivedRequests()).To(HaveLen(3))
   317  				Expect(len(warnings)).To(Equal(1))
   318  				Expect(warnings).To(ConsistOf("this is a warning"))
   319  				Expect(updatedSpace.Metadata.Labels).To(BeEquivalentTo(
   320  					map[string]types.NullString{
   321  						"k1": types.NewNullString("v1"),
   322  						"k2": types.NewNullString("v2"),
   323  					}))
   324  			})
   325  
   326  		})
   327  
   328  	})
   329  
   330  	Describe("DeleteSpace", func() {
   331  		var (
   332  			jobURL     JobURL
   333  			warnings   Warnings
   334  			executeErr error
   335  		)
   336  
   337  		JustBeforeEach(func() {
   338  			jobURL, warnings, executeErr = client.DeleteSpace("space-guid")
   339  		})
   340  
   341  		When("no errors are encountered", func() {
   342  			BeforeEach(func() {
   343  				server.AppendHandlers(
   344  					CombineHandlers(
   345  						VerifyRequest(http.MethodDelete, "/v3/spaces/space-guid"),
   346  						RespondWith(http.StatusAccepted, nil, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}, "Location": []string{"job-url"}}),
   347  					))
   348  			})
   349  
   350  			It("deletes the Space and returns all warnings", func() {
   351  				Expect(executeErr).NotTo(HaveOccurred())
   352  				Expect(warnings).To(ConsistOf(Warnings{"warning-1", "warning-2"}))
   353  				Expect(jobURL).To(Equal(JobURL("job-url")))
   354  			})
   355  		})
   356  
   357  		When("an error is encountered", func() {
   358  			BeforeEach(func() {
   359  				response := `{
   360     "errors": [
   361        {
   362           "detail": "Space not found",
   363           "title": "CF-ResourceNotFound",
   364           "code": 10010
   365        }
   366     ]
   367  }`
   368  				server.AppendHandlers(
   369  					CombineHandlers(
   370  						VerifyRequest(http.MethodDelete, "/v3/spaces/space-guid"),
   371  						RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}}),
   372  					))
   373  			})
   374  
   375  			It("returns an error and all warnings", func() {
   376  				Expect(executeErr).To(MatchError(ccerror.ResourceNotFoundError{
   377  					Message: "Space not found",
   378  				}))
   379  				Expect(warnings).To(ConsistOf(Warnings{"warning-1", "warning-2"}))
   380  			})
   381  		})
   382  	})
   383  })