github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/api/cloudcontroller/ccv3/role_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"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/ghttp"
    13  )
    14  
    15  var _ = Describe("Role", func() {
    16  	var client *Client
    17  
    18  	BeforeEach(func() {
    19  		client, _ = NewTestClient()
    20  	})
    21  
    22  	Describe("CreateRole", func() {
    23  		var (
    24  			roleType  constant.RoleType
    25  			userGUID  string
    26  			userName  string
    27  			origin    string
    28  			orgGUID   string
    29  			spaceGUID string
    30  
    31  			createdRole Role
    32  			warnings    Warnings
    33  			executeErr  error
    34  		)
    35  
    36  		BeforeEach(func() {
    37  			userGUID = ""
    38  			userName = ""
    39  			origin = "uaa"
    40  			orgGUID = ""
    41  			spaceGUID = ""
    42  		})
    43  
    44  		JustBeforeEach(func() {
    45  			createdRole, warnings, executeErr = client.CreateRole(Role{
    46  				Type:      roleType,
    47  				UserGUID:  userGUID,
    48  				Username:  userName,
    49  				Origin:    origin,
    50  				OrgGUID:   orgGUID,
    51  				SpaceGUID: spaceGUID,
    52  			})
    53  		})
    54  
    55  		Describe("create org role by username/origin", func() {
    56  			BeforeEach(func() {
    57  				roleType = constant.OrgAuditorRole
    58  				userName = "user-name"
    59  				origin = "uaa"
    60  				orgGUID = "org-guid"
    61  			})
    62  
    63  			When("the request succeeds", func() {
    64  				When("no additional flags", func() {
    65  					BeforeEach(func() {
    66  						response := `{
    67  							"guid": "some-role-guid",
    68  							"type": "organization_auditor",
    69  							"relationships": {
    70  								"organization": {
    71  									"data": { "guid": "org-guid" }
    72  								},
    73  								"user": {
    74  									"data": { "guid": "user-guid" }
    75  								}
    76  							}
    77  						}`
    78  
    79  						expectedBody := `{
    80  							"type": "organization_auditor",
    81  							"relationships": {
    82  								"organization": {
    83  									"data": { "guid": "org-guid" }
    84  								},
    85  								"user": {
    86  									"data": { "username": "user-name", "origin": "uaa" }
    87  								}
    88  							}
    89  						}`
    90  
    91  						server.AppendHandlers(
    92  							CombineHandlers(
    93  								VerifyRequest(http.MethodPost, "/v3/roles"),
    94  								VerifyJSON(expectedBody),
    95  								RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}),
    96  							),
    97  						)
    98  					})
    99  
   100  					It("returns the given role and all warnings", func() {
   101  						Expect(executeErr).ToNot(HaveOccurred())
   102  						Expect(warnings).To(ConsistOf("warning-1"))
   103  
   104  						Expect(createdRole).To(Equal(Role{
   105  							GUID:     "some-role-guid",
   106  							Type:     constant.OrgAuditorRole,
   107  							UserGUID: "user-guid",
   108  							OrgGUID:  "org-guid",
   109  						}))
   110  					})
   111  				})
   112  			})
   113  
   114  			When("the cloud controller returns errors and warnings", func() {
   115  				BeforeEach(func() {
   116  					response := `{
   117  		"errors": [
   118  			{
   119  				"code": 10008,
   120  				"detail": "The request is semantically invalid: command presence",
   121  				"title": "CF-UnprocessableEntity"
   122  			},
   123  			{
   124  				"code": 10010,
   125  				"detail": "Isolation segment not found",
   126  				"title": "CF-ResourceNotFound"
   127  			}
   128  		]
   129  	}`
   130  					server.AppendHandlers(
   131  						CombineHandlers(
   132  							VerifyRequest(http.MethodPost, "/v3/roles"),
   133  							RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   134  						),
   135  					)
   136  				})
   137  
   138  				It("returns the error and all warnings", func() {
   139  					Expect(executeErr).To(MatchError(ccerror.MultiError{
   140  						ResponseCode: http.StatusTeapot,
   141  						Errors: []ccerror.V3Error{
   142  							{
   143  								Code:   10008,
   144  								Detail: "The request is semantically invalid: command presence",
   145  								Title:  "CF-UnprocessableEntity",
   146  							},
   147  							{
   148  								Code:   10010,
   149  								Detail: "Isolation segment not found",
   150  								Title:  "CF-ResourceNotFound",
   151  							},
   152  						},
   153  					}))
   154  					Expect(warnings).To(ConsistOf("this is a warning"))
   155  				})
   156  			})
   157  		})
   158  
   159  		Describe("create space role by username/origin", func() {
   160  			BeforeEach(func() {
   161  				roleType = constant.SpaceAuditorRole
   162  				userName = "user-name"
   163  				spaceGUID = "space-guid"
   164  			})
   165  
   166  			When("the request succeeds", func() {
   167  				When("no additional flags", func() {
   168  					BeforeEach(func() {
   169  						response := `{
   170  							"guid": "some-role-guid",
   171  							"type": "space_auditor",
   172  							"relationships": {
   173  								"space": {
   174  									"data": { "guid": "space-guid" }
   175  								},
   176  								"user": {
   177  									"data": { "guid": "user-guid" }
   178  								}
   179  							}
   180  						}`
   181  
   182  						expectedBody := `{
   183  							"type": "space_auditor",
   184  							"relationships": {
   185  								"space": {
   186  									"data": { "guid": "space-guid" }
   187  								},
   188  								"user": {
   189  									"data": { "username": "user-name", "origin": "uaa" }
   190  								}
   191  							}
   192  						}`
   193  
   194  						server.AppendHandlers(
   195  							CombineHandlers(
   196  								VerifyRequest(http.MethodPost, "/v3/roles"),
   197  								VerifyJSON(expectedBody),
   198  								RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   199  							),
   200  						)
   201  					})
   202  
   203  					It("returns the given route and all warnings", func() {
   204  						Expect(executeErr).ToNot(HaveOccurred())
   205  						Expect(warnings).To(ConsistOf("warning-1"))
   206  
   207  						Expect(createdRole).To(Equal(Role{
   208  							GUID:      "some-role-guid",
   209  							Type:      constant.SpaceAuditorRole,
   210  							UserGUID:  "user-guid",
   211  							SpaceGUID: "space-guid",
   212  						}))
   213  					})
   214  				})
   215  			})
   216  		})
   217  
   218  		Describe("create org role by guid", func() {
   219  			BeforeEach(func() {
   220  				roleType = constant.OrgAuditorRole
   221  				userGUID = "user-guid"
   222  				orgGUID = "org-guid"
   223  			})
   224  
   225  			When("the request succeeds", func() {
   226  				When("no additional flags", func() {
   227  					BeforeEach(func() {
   228  						response := `{
   229  							"guid": "some-role-guid",
   230  							"type": "organization_auditor",
   231  							"relationships": {
   232  								"organization": {
   233  									"data": { "guid": "org-guid" }
   234  								},
   235  								"user": {
   236  									"data": { "guid": "user-guid" }
   237  								}
   238  							}
   239  						}`
   240  
   241  						expectedBody := `{
   242  							"type": "organization_auditor",
   243  							"relationships": {
   244  								"organization": {
   245  									"data": { "guid": "org-guid" }
   246  								},
   247  								"user": {
   248  									"data": { "guid": "user-guid" }
   249  								}
   250  							}
   251  						}`
   252  
   253  						server.AppendHandlers(
   254  							CombineHandlers(
   255  								VerifyRequest(http.MethodPost, "/v3/roles"),
   256  								VerifyJSON(expectedBody),
   257  								RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   258  							),
   259  						)
   260  					})
   261  
   262  					It("returns the given route and all warnings", func() {
   263  						Expect(executeErr).ToNot(HaveOccurred())
   264  						Expect(warnings).To(ConsistOf("warning-1"))
   265  
   266  						Expect(createdRole).To(Equal(Role{
   267  							GUID:     "some-role-guid",
   268  							Type:     constant.OrgAuditorRole,
   269  							UserGUID: "user-guid",
   270  							OrgGUID:  "org-guid",
   271  						}))
   272  					})
   273  				})
   274  			})
   275  
   276  			When("the cloud controller returns errors and warnings", func() {
   277  				BeforeEach(func() {
   278  					response := `{
   279  		"errors": [
   280  			{
   281  				"code": 10008,
   282  				"detail": "Something was not processable",
   283  				"title": "CF-UnprocessableEntity"
   284  			},
   285  			{
   286  				"code": 10010,
   287  				"detail": "Something was not found",
   288  				"title": "CF-ResourceNotFound"
   289  			}
   290  		]
   291  	}`
   292  					server.AppendHandlers(
   293  						CombineHandlers(
   294  							VerifyRequest(http.MethodPost, "/v3/roles"),
   295  							RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   296  						),
   297  					)
   298  				})
   299  
   300  				It("returns the error and all warnings", func() {
   301  					Expect(executeErr).To(MatchError(ccerror.MultiError{
   302  						ResponseCode: http.StatusTeapot,
   303  						Errors: []ccerror.V3Error{
   304  							{
   305  								Code:   10008,
   306  								Detail: "Something was not processable",
   307  								Title:  "CF-UnprocessableEntity",
   308  							},
   309  							{
   310  								Code:   10010,
   311  								Detail: "Something was not found",
   312  								Title:  "CF-ResourceNotFound",
   313  							},
   314  						},
   315  					}))
   316  					Expect(warnings).To(ConsistOf("this is a warning"))
   317  				})
   318  			})
   319  		})
   320  
   321  		Describe("create space role by guid", func() {
   322  			BeforeEach(func() {
   323  				roleType = constant.SpaceAuditorRole
   324  				userGUID = "user-guid"
   325  				spaceGUID = "space-guid"
   326  			})
   327  
   328  			When("the request succeeds", func() {
   329  				When("no additional flags", func() {
   330  					BeforeEach(func() {
   331  						response := `{
   332  							"guid": "some-role-guid",
   333  							"type": "space_auditor",
   334  							"relationships": {
   335  								"space": {
   336  									"data": { "guid": "space-guid" }
   337  								},
   338  								"user": {
   339  									"data": { "guid": "user-guid" }
   340  								}
   341  							}
   342  						}`
   343  
   344  						expectedBody := `{
   345  							"type": "space_auditor",
   346  							"relationships": {
   347  								"space": {
   348  									"data": { "guid": "space-guid" }
   349  								},
   350  								"user": {
   351  									"data": { "guid": "user-guid" }
   352  								}
   353  							}
   354  						}`
   355  
   356  						server.AppendHandlers(
   357  							CombineHandlers(
   358  								VerifyRequest(http.MethodPost, "/v3/roles"),
   359  								VerifyJSON(expectedBody),
   360  								RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   361  							),
   362  						)
   363  					})
   364  
   365  					It("returns the given route and all warnings", func() {
   366  						Expect(executeErr).ToNot(HaveOccurred())
   367  						Expect(warnings).To(ConsistOf("warning-1"))
   368  
   369  						Expect(createdRole).To(Equal(Role{
   370  							GUID:      "some-role-guid",
   371  							Type:      constant.SpaceAuditorRole,
   372  							UserGUID:  "user-guid",
   373  							SpaceGUID: "space-guid",
   374  						}))
   375  					})
   376  				})
   377  			})
   378  		})
   379  	})
   380  
   381  	Describe("GetRoles", func() {
   382  		var (
   383  			roles      []Role
   384  			includes   IncludedResources
   385  			warnings   Warnings
   386  			executeErr error
   387  			query      []Query
   388  		)
   389  
   390  		BeforeEach(func() {
   391  			query = []Query{
   392  				{
   393  					Key:    OrganizationGUIDFilter,
   394  					Values: []string{"some-org-name"},
   395  				},
   396  				{
   397  					Key:    Include,
   398  					Values: []string{"users"},
   399  				},
   400  			}
   401  		})
   402  		JustBeforeEach(func() {
   403  			roles, includes, warnings, executeErr = client.GetRoles(query...)
   404  		})
   405  
   406  		Describe("listing roles", func() {
   407  			When("the request succeeds", func() {
   408  				BeforeEach(func() {
   409  					response1 := fmt.Sprintf(`{
   410  	"pagination": {
   411  		"next": {
   412  			"href": "%s/v3/roles?organization_guids=some-org-name&page=2&per_page=1&include=users"
   413  		}
   414  	},
   415    "resources": [
   416      {
   417        "guid": "role-guid-1",
   418        "type": "organization_user"
   419      }
   420    ]
   421  }`, server.URL())
   422  					response2 := `{
   423  							"pagination": {
   424  								"next": null
   425  							},
   426  						 "resources": [
   427  						   {
   428  						     "guid": "role-guid-2",
   429  						     "type": "organization_manager"
   430  						   }
   431  						 ]
   432  						}`
   433  
   434  					server.AppendHandlers(
   435  						CombineHandlers(
   436  							VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&include=users"),
   437  							RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   438  						),
   439  					)
   440  					server.AppendHandlers(
   441  						CombineHandlers(
   442  							VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&page=2&per_page=1&include=users"),
   443  							RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}),
   444  						),
   445  					)
   446  				})
   447  
   448  				It("returns the given route and all warnings", func() {
   449  					Expect(executeErr).ToNot(HaveOccurred())
   450  					Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   451  
   452  					Expect(roles).To(Equal([]Role{{
   453  						GUID: "role-guid-1",
   454  						Type: constant.OrgUserRole,
   455  					}, {
   456  						GUID: "role-guid-2",
   457  						Type: constant.OrgManagerRole,
   458  					}}))
   459  				})
   460  			})
   461  
   462  			When("the request uses the `include` query key", func() {
   463  				BeforeEach(func() {
   464  					response1 := fmt.Sprintf(`{
   465  						"pagination": {
   466  							"next": {
   467  								"href": "%s/v3/roles?organization_guids=some-org-name&page=2&per_page=1&include=users"
   468  							}
   469  						},
   470  						"resources": [
   471  							{
   472  							  "guid": "role-guid-1",
   473  							  "type": "organization_user",
   474  							  "relationships": {
   475  								"user": {
   476  								  "data": {"guid": "user-guid-1"}
   477  								}
   478  							  }
   479  							}
   480  						],
   481  						"included": {
   482  							"users": [
   483  								{
   484  									"guid": "user-guid-1",
   485  									"username": "user-name-1",
   486  									"origin": "uaa"
   487  							  	}
   488  							]
   489  						}
   490  }`, server.URL())
   491  					response2 := `{
   492  							"pagination": {
   493  								"next": null
   494  							},
   495  						 "resources": [
   496  						   {
   497  						     "guid": "role-guid-2",
   498  						     "type": "organization_manager",
   499  							  "relationships": {
   500  								"user": {
   501  								  "data": {"guid": "user-guid-2"}
   502  								}
   503  							  }
   504  						   }
   505  						 ],
   506  						"included": {
   507  							"users": [
   508  							  {
   509  								"guid": "user-guid-2",
   510  								"username": "user-name-2",
   511  								"origin": "uaa"
   512  							  }
   513  							]
   514  						  }
   515  						}`
   516  
   517  					server.AppendHandlers(
   518  						CombineHandlers(
   519  							VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&include=users"),
   520  							RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}),
   521  						),
   522  					)
   523  					server.AppendHandlers(
   524  						CombineHandlers(
   525  							VerifyRequest(http.MethodGet, "/v3/roles", "organization_guids=some-org-name&page=2&per_page=1&include=users"),
   526  							RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"warning-2"}}),
   527  						),
   528  					)
   529  				})
   530  
   531  				It("returns the given route and all warnings", func() {
   532  					Expect(executeErr).ToNot(HaveOccurred())
   533  					Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   534  
   535  					Expect(roles).To(Equal([]Role{{
   536  						GUID:     "role-guid-1",
   537  						Type:     constant.OrgUserRole,
   538  						UserGUID: "user-guid-1",
   539  					}, {
   540  						GUID:     "role-guid-2",
   541  						Type:     constant.OrgManagerRole,
   542  						UserGUID: "user-guid-2",
   543  					}}))
   544  
   545  					Expect(includes).To(Equal(IncludedResources{
   546  						Users: []User{
   547  							{GUID: "user-guid-1", Username: "user-name-1", Origin: "uaa"},
   548  							{GUID: "user-guid-2", Username: "user-name-2", Origin: "uaa"},
   549  						},
   550  					}))
   551  				})
   552  			})
   553  
   554  			When("the cloud controller returns errors and warnings", func() {
   555  				BeforeEach(func() {
   556  					response := `{
   557    "errors": [
   558      {
   559        "code": 10008,
   560        "detail": "The request is semantically invalid: command presence",
   561        "title": "CF-UnprocessableEntity"
   562      },
   563      {
   564        "code": 10010,
   565        "detail": "Org not found",
   566        "title": "CF-ResourceNotFound"
   567      }
   568    ]
   569  }`
   570  					server.AppendHandlers(
   571  						CombineHandlers(
   572  							VerifyRequest(http.MethodGet, "/v3/roles"),
   573  							RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   574  						),
   575  					)
   576  				})
   577  
   578  				It("returns the error and all warnings", func() {
   579  					Expect(executeErr).To(MatchError(ccerror.MultiError{
   580  						ResponseCode: http.StatusTeapot,
   581  						Errors: []ccerror.V3Error{
   582  							{
   583  								Code:   10008,
   584  								Detail: "The request is semantically invalid: command presence",
   585  								Title:  "CF-UnprocessableEntity",
   586  							},
   587  							{
   588  								Code:   10010,
   589  								Detail: "Org not found",
   590  								Title:  "CF-ResourceNotFound",
   591  							},
   592  						},
   593  					}))
   594  					Expect(warnings).To(ConsistOf("this is a warning"))
   595  				})
   596  			})
   597  		})
   598  	})
   599  
   600  	Describe("DeleteRoles", func() {
   601  		var (
   602  			roleGUID     string
   603  			jobURL       JobURL
   604  			jobURLString string
   605  			warnings     Warnings
   606  			executeErr   error
   607  		)
   608  
   609  		BeforeEach(func() {
   610  			roleGUID = "role-guid"
   611  		})
   612  
   613  		JustBeforeEach(func() {
   614  			jobURL, warnings, executeErr = client.DeleteRole(roleGUID)
   615  		})
   616  
   617  		When("role exists", func() {
   618  			roleGUID = "role-guid"
   619  			jobURLString = "https://api.test.com/v3/jobs/job-guid"
   620  
   621  			BeforeEach(func() {
   622  				server.AppendHandlers(
   623  					CombineHandlers(
   624  						VerifyRequest(http.MethodDelete, "/v3/roles/role-guid"),
   625  						RespondWith(http.StatusAccepted, nil, http.Header{
   626  							"X-Cf-Warnings": {"this is a warning"},
   627  							"Location":      {jobURLString},
   628  						}),
   629  					),
   630  				)
   631  			})
   632  
   633  			It("returns all warnings", func() {
   634  				Expect(executeErr).NotTo(HaveOccurred())
   635  				Expect(jobURL).To(Equal(JobURL(jobURLString)))
   636  				Expect(warnings).To(ConsistOf("this is a warning"))
   637  			})
   638  		})
   639  
   640  		When("the cloud controller returns errors and warnings", func() {
   641  			BeforeEach(func() {
   642  				response := `{
   643  								  "errors": [
   644  										{
   645  										  "code": 10008,
   646  										  "detail": "The request is semantically invalid: command presence",
   647  										  "title": "CF-UnprocessableEntity"
   648  										},
   649  										{
   650  										  "code": 10010,
   651  										  "detail": "Isolation segment not found",
   652  										  "title": "CF-ResourceNotFound"
   653  										}
   654  									  ]
   655  									}`
   656  				server.AppendHandlers(
   657  					CombineHandlers(
   658  						VerifyRequest(http.MethodDelete, "/v3/roles/role-guid"),
   659  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   660  					),
   661  				)
   662  			})
   663  
   664  			It("returns the error and all warnings", func() {
   665  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   666  					ResponseCode: http.StatusTeapot,
   667  					Errors: []ccerror.V3Error{
   668  						{
   669  							Code:   10008,
   670  							Detail: "The request is semantically invalid: command presence",
   671  							Title:  "CF-UnprocessableEntity",
   672  						},
   673  						{
   674  							Code:   10010,
   675  							Detail: "Isolation segment not found",
   676  							Title:  "CF-ResourceNotFound",
   677  						},
   678  					},
   679  				}))
   680  				Expect(warnings).To(ConsistOf("this is a warning"))
   681  			})
   682  		})
   683  	})
   684  })