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