github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/defined_entity_test.go (about) 1 //go:build functional || openapi || rde || ALL 2 3 /* 4 * Copyright 2023 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 5 */ 6 7 package govcd 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "github.com/vmware/go-vcloud-director/v2/types/v56" 13 . "gopkg.in/check.v1" 14 "io" 15 "os" 16 "path/filepath" 17 "strings" 18 ) 19 20 // Test_RdeAndRdeType tests the CRUD operations for the RDE Type with both System administrator and a tenant user. 21 func (vcd *TestVCD) Test_RdeAndRdeType(check *C) { 22 if vcd.skipAdminTests { 23 check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) 24 } 25 26 for _, endpoint := range []string{ 27 types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeEntityTypes, 28 types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeEntitiesResolve, 29 types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointRdeEntities, 30 } { 31 skipOpenApiEndpointTest(vcd, check, endpoint) 32 } 33 34 if len(vcd.config.Tenants) == 0 { 35 check.Skip("skipping as there is no configured tenant users") 36 } 37 38 // Creates the clients for the System admin and the Tenant user 39 systemAdministratorClient := vcd.client 40 tenantUserClient := NewVCDClient(vcd.client.Client.VCDHREF, true) 41 err := tenantUserClient.Authenticate(vcd.config.Tenants[0].User, vcd.config.Tenants[0].Password, vcd.config.Tenants[0].SysOrg) 42 check.Assert(err, IsNil) 43 44 unmarshaledRdeTypeSchema, err := loadRdeTypeSchemaFromTestResources() 45 check.Assert(err, IsNil) 46 check.Assert(true, Equals, len(unmarshaledRdeTypeSchema) > 0) 47 48 // First, it checks how many exist already, as VCD contains some pre-defined ones. 49 allRdeTypesBySystemAdmin, err := systemAdministratorClient.GetAllRdeTypes(nil) 50 check.Assert(err, IsNil) 51 alreadyPresentRdes := len(allRdeTypesBySystemAdmin) 52 53 // For the tenant, it returns 0 RDE Types, but no error. 54 allRdeTypesByTenant, err := tenantUserClient.GetAllRdeTypes(nil) 55 check.Assert(err, IsNil) 56 check.Assert(len(allRdeTypesByTenant), Equals, 0) 57 58 // Then we create a new RDE Type with System administrator. 59 // Can't put check.TestName() in nss due to a bug in VCD 10.4.1 that causes RDEs to fail on GET once created with special characters like "." 60 vendor := "vmware" 61 nss := strings.ReplaceAll(check.TestName()+"name", ".", "") 62 version := "1.2.3" 63 rdeTypeToCreate := &types.DefinedEntityType{ 64 Name: check.TestName(), 65 Nss: nss, 66 Version: version, 67 Description: "Description of " + check.TestName(), 68 Schema: unmarshaledRdeTypeSchema, 69 Vendor: vendor, 70 Interfaces: []string{"urn:vcloud:interface:vmware:k8s:1.0.0"}, 71 } 72 createdRdeType, err := systemAdministratorClient.CreateRdeType(rdeTypeToCreate) 73 check.Assert(err, IsNil) 74 check.Assert(createdRdeType, NotNil) 75 check.Assert(createdRdeType.DefinedEntityType.Name, Equals, rdeTypeToCreate.Name) 76 check.Assert(createdRdeType.DefinedEntityType.Nss, Equals, rdeTypeToCreate.Nss) 77 check.Assert(createdRdeType.DefinedEntityType.Version, Equals, rdeTypeToCreate.Version) 78 check.Assert(createdRdeType.DefinedEntityType.Schema, NotNil) 79 check.Assert(createdRdeType.DefinedEntityType.Schema["type"], Equals, "object") 80 check.Assert(createdRdeType.DefinedEntityType.Schema["definitions"], NotNil) 81 check.Assert(createdRdeType.DefinedEntityType.Schema["required"], NotNil) 82 check.Assert(createdRdeType.DefinedEntityType.Schema["properties"], NotNil) 83 AddToCleanupListOpenApi(createdRdeType.DefinedEntityType.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeEntityTypes+createdRdeType.DefinedEntityType.ID) 84 85 // Tenants can't create RDE Types 86 nilRdeType, err := tenantUserClient.CreateRdeType(&types.DefinedEntityType{ 87 Name: check.TestName(), 88 Nss: "notworking", 89 Version: "4.5.6", 90 Schema: unmarshaledRdeTypeSchema, 91 Vendor: "willfail", 92 }) 93 check.Assert(err, NotNil) 94 check.Assert(nilRdeType, IsNil) 95 check.Assert(strings.Contains(err.Error(), "ACCESS_TO_RESOURCE_IS_FORBIDDEN"), Equals, true) 96 97 // Assign rights to the tenant user, so it can perform following operations. 98 // We don't need to clean the rights afterwards as deleting the RDE Type deletes the associated bundle 99 // with its rights. 100 role, err := systemAdministratorClient.Client.GetGlobalRoleByName("Organization Administrator") 101 check.Assert(err, IsNil) 102 check.Assert(role, NotNil) 103 104 rightsBundleName := fmt.Sprintf("%s:%s Entitlement", vendor, nss) 105 rightsBundle, err := systemAdministratorClient.Client.GetRightsBundleByName(rightsBundleName) 106 check.Assert(err, IsNil) 107 check.Assert(rightsBundle, NotNil) 108 109 err = rightsBundle.PublishAllTenants() 110 check.Assert(err, IsNil) 111 112 rights, err := rightsBundle.GetRights(nil) 113 check.Assert(err, IsNil) 114 check.Assert(len(rights), Not(Equals), 0) 115 116 var rightsToAdd []types.OpenApiReference 117 for _, right := range rights { 118 if strings.Contains(right.Name, fmt.Sprintf("%s:%s", vendor, nss)) { 119 rightsToAdd = append(rightsToAdd, types.OpenApiReference{ 120 Name: right.Name, 121 ID: right.ID, 122 }) 123 } 124 } 125 check.Assert(rightsToAdd, NotNil) 126 check.Assert(len(rightsToAdd), Not(Equals), 0) 127 128 err = role.AddRights(rightsToAdd) 129 check.Assert(err, IsNil) 130 131 // As we created a new RDE Type, we check the new count is correct in both System admin and Tenant user 132 allRdeTypesBySystemAdmin, err = systemAdministratorClient.GetAllRdeTypes(nil) 133 check.Assert(err, IsNil) 134 check.Assert(len(allRdeTypesBySystemAdmin), Equals, alreadyPresentRdes+1) 135 136 // Count is 1 for tenant user as it can only retrieve the created type as per the assigned rights above. 137 allRdeTypesByTenant, err = tenantUserClient.GetAllRdeTypes(nil) 138 check.Assert(err, IsNil) 139 check.Assert(len(allRdeTypesByTenant), Equals, 1) 140 141 // Test the multiple ways of getting a RDE Types in both users. 142 obtainedRdeTypeBySysAdmin, err := systemAdministratorClient.GetRdeTypeById(createdRdeType.DefinedEntityType.ID) 143 check.Assert(err, IsNil) 144 check.Assert(*obtainedRdeTypeBySysAdmin.DefinedEntityType, DeepEquals, *createdRdeType.DefinedEntityType) 145 146 // The RDE Type retrieved by the tenant should be the same as the retrieved by Sysadmin 147 obtainedRdeTypeByTenant, err := tenantUserClient.GetRdeTypeById(createdRdeType.DefinedEntityType.ID) 148 check.Assert(err, IsNil) 149 check.Assert(*obtainedRdeTypeByTenant.DefinedEntityType, DeepEquals, *obtainedRdeTypeBySysAdmin.DefinedEntityType) 150 151 obtainedRdeTypeBySysAdmin, err = systemAdministratorClient.GetRdeType(createdRdeType.DefinedEntityType.Vendor, createdRdeType.DefinedEntityType.Nss, createdRdeType.DefinedEntityType.Version) 152 check.Assert(err, IsNil) 153 check.Assert(*obtainedRdeTypeBySysAdmin.DefinedEntityType, DeepEquals, *obtainedRdeTypeBySysAdmin.DefinedEntityType) 154 155 // The RDE Type retrieved by the tenant should be the same as the retrieved by Sysadmin 156 obtainedRdeTypeByTenant, err = tenantUserClient.GetRdeType(createdRdeType.DefinedEntityType.Vendor, createdRdeType.DefinedEntityType.Nss, createdRdeType.DefinedEntityType.Version) 157 check.Assert(err, IsNil) 158 check.Assert(*obtainedRdeTypeByTenant.DefinedEntityType, DeepEquals, *obtainedRdeTypeBySysAdmin.DefinedEntityType) 159 160 // We don't want to update the name nor the schema. It should populate them from the receiver object automatically 161 err = obtainedRdeTypeBySysAdmin.Update(types.DefinedEntityType{ 162 Description: rdeTypeToCreate.Description + "UpdatedByAdmin", 163 }) 164 check.Assert(err, IsNil) 165 check.Assert(obtainedRdeTypeBySysAdmin.DefinedEntityType.Description, Equals, rdeTypeToCreate.Description+"UpdatedByAdmin") 166 167 testRdeCrudWithGivenType(check, obtainedRdeTypeBySysAdmin) 168 testRdeCrudAsTenant(check, obtainedRdeTypeByTenant.DefinedEntityType.Vendor, obtainedRdeTypeByTenant.DefinedEntityType.Nss, obtainedRdeTypeByTenant.DefinedEntityType.Version, vcd.client) 169 170 // We delete it with Sysadmin 171 deletedId := createdRdeType.DefinedEntityType.ID 172 err = createdRdeType.Delete() 173 check.Assert(err, IsNil) 174 check.Assert(*createdRdeType.DefinedEntityType, DeepEquals, types.DefinedEntityType{}) 175 176 _, err = systemAdministratorClient.GetRdeTypeById(deletedId) 177 check.Assert(err, NotNil) 178 check.Assert(strings.Contains(err.Error(), ErrorEntityNotFound.Error()), Equals, true) 179 } 180 181 // testRdeCrudWithGivenType is a sub-section of Test_Rde that is focused on testing all RDE instances casuistics. 182 // This would be the viewpoint of a System admin as they can retrieve and manipulate RDE types. 183 func testRdeCrudWithGivenType(check *C, rdeType *DefinedEntityType) { 184 185 // We are missing the mandatory field "foo" on purpose 186 rdeEntityJson := []byte(` 187 { 188 "bar": "stringValue1", 189 "prop2": { 190 "subprop1": "stringValue2", 191 "subprop2": [ 192 "stringValue3", 193 "stringValue4" 194 ] 195 } 196 }`) 197 198 var unmarshaledRdeEntityJson map[string]interface{} 199 err := json.Unmarshal(rdeEntityJson, &unmarshaledRdeEntityJson) 200 check.Assert(err, IsNil) 201 202 rde, err := rdeType.CreateRde(types.DefinedEntity{ 203 Name: check.TestName(), 204 ExternalId: "123", 205 Entity: unmarshaledRdeEntityJson, 206 }, nil) 207 check.Assert(err, IsNil) 208 check.Assert(rde.DefinedEntity.Name, Equals, check.TestName()) 209 check.Assert(*rde.DefinedEntity.State, Equals, "PRE_CREATED") 210 211 // If we don't resolve the RDE, we cannot delete it 212 err = rde.Delete() 213 check.Assert(err, NotNil) 214 check.Assert(true, Equals, strings.Contains(err.Error(), "RDE_ENTITY_NOT_RESOLVED")) 215 216 // Resolution should fail as we missed to add a mandatory field 217 err = rde.Resolve() 218 eTag := rde.Etag 219 check.Assert(err, IsNil) 220 // The RDE can be automatically deleted now as rde.Resolve() was called successfully 221 AddToCleanupListOpenApi(rde.DefinedEntity.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeEntities+rde.DefinedEntity.ID) 222 223 check.Assert(*rde.DefinedEntity.State, Equals, "RESOLUTION_ERROR") 224 check.Assert(eTag, Not(Equals), "") 225 226 // We amend it 227 unmarshaledRdeEntityJson["foo"] = map[string]interface{}{"key": "stringValue5"} 228 err = rde.Update(types.DefinedEntity{ 229 Entity: unmarshaledRdeEntityJson, 230 }) 231 check.Assert(err, IsNil) 232 check.Assert(*rde.DefinedEntity.State, Equals, "RESOLUTION_ERROR") 233 check.Assert(rde.Etag, Not(Equals), "") 234 check.Assert(rde.Etag, Not(Equals), eTag) 235 eTag = rde.Etag 236 237 // This time it should resolve 238 err = rde.Resolve() 239 check.Assert(err, IsNil) 240 check.Assert(*rde.DefinedEntity.State, Equals, "RESOLVED") 241 check.Assert(rde.Etag, Not(Equals), "") 242 check.Assert(rde.Etag, Not(Equals), eTag) 243 244 // Delete the RDE instance now that it's resolved 245 deletedId := rde.DefinedEntity.ID 246 err = rde.Delete() 247 check.Assert(err, IsNil) 248 check.Assert(*rde.DefinedEntity, DeepEquals, types.DefinedEntity{}) 249 250 // RDE should not exist anymore 251 _, err = rdeType.GetRdeById(deletedId) 252 check.Assert(err, NotNil) 253 check.Assert(strings.Contains(err.Error(), ErrorEntityNotFound.Error()), Equals, true) 254 } 255 256 // testRdeCrudAsTenant is a sub-section of Test_Rde that is focused on testing all RDE instances casuistics without specifying the 257 // RDE type. This would be the viewpoint of a tenant as they can't get RDE types. 258 func testRdeCrudAsTenant(check *C, vendor string, namespace string, version string, vcdClient *VCDClient) { 259 // We are missing the mandatory field "foo" on purpose 260 rdeEntityJson := []byte(` 261 { 262 "bar": "stringValue1", 263 "prop2": { 264 "subprop1": "stringValue2", 265 "subprop2": [ 266 "stringValue3", 267 "stringValue4" 268 ] 269 } 270 }`) 271 272 var unmarshaledRdeEntityJson map[string]interface{} 273 err := json.Unmarshal(rdeEntityJson, &unmarshaledRdeEntityJson) 274 check.Assert(err, IsNil) 275 276 rde, err := vcdClient.CreateRde(vendor, namespace, version, types.DefinedEntity{ 277 Name: check.TestName(), 278 ExternalId: "123", 279 Entity: unmarshaledRdeEntityJson, 280 }, nil) 281 check.Assert(err, IsNil) 282 check.Assert(rde.DefinedEntity.Name, Equals, check.TestName()) 283 check.Assert(*rde.DefinedEntity.State, Equals, "PRE_CREATED") 284 285 // If we don't resolve the RDE, we cannot delete it 286 err = rde.Delete() 287 check.Assert(err, NotNil) 288 check.Assert(true, Equals, strings.Contains(err.Error(), "RDE_ENTITY_NOT_RESOLVED")) 289 290 // Resolution should fail as we missed to add a mandatory field 291 err = rde.Resolve() 292 eTag := rde.Etag 293 check.Assert(err, IsNil) 294 check.Assert(*rde.DefinedEntity.State, Equals, "RESOLUTION_ERROR") 295 check.Assert(eTag, Not(Equals), "") 296 297 // We amend it 298 unmarshaledRdeEntityJson["foo"] = map[string]interface{}{"key": "stringValue5"} 299 err = rde.Update(types.DefinedEntity{ 300 Entity: unmarshaledRdeEntityJson, 301 }) 302 check.Assert(err, IsNil) 303 check.Assert(*rde.DefinedEntity.State, Equals, "RESOLUTION_ERROR") 304 check.Assert(rde.Etag, Not(Equals), "") 305 check.Assert(rde.Etag, Not(Equals), eTag) 306 eTag = rde.Etag 307 308 // This time it should resolve 309 err = rde.Resolve() 310 check.Assert(err, IsNil) 311 check.Assert(*rde.DefinedEntity.State, Equals, "RESOLVED") 312 check.Assert(rde.Etag, Not(Equals), "") 313 check.Assert(rde.Etag, Not(Equals), eTag) 314 315 // The RDE can't be deleted until rde.Resolve() is called 316 AddToCleanupListOpenApi(rde.DefinedEntity.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeEntities+rde.DefinedEntity.ID) 317 318 // Delete the RDE instance now that it's resolved 319 deletedId := rde.DefinedEntity.ID 320 err = rde.Delete() 321 check.Assert(err, IsNil) 322 check.Assert(*rde.DefinedEntity, DeepEquals, types.DefinedEntity{}) 323 check.Assert(rde.Etag, Equals, "") 324 325 // RDE should not exist anymore 326 _, err = vcdClient.GetRdeById(deletedId) 327 check.Assert(err, NotNil) 328 check.Assert(strings.Contains(err.Error(), ErrorEntityNotFound.Error()), Equals, true) 329 } 330 331 // loadRdeTypeSchemaFromTestResources loads the RDE schema present in the test-resources folder and unmarshals it 332 // into a map. Returns an error if something fails along the way. 333 func loadRdeTypeSchemaFromTestResources() (map[string]interface{}, error) { 334 // Load the RDE type schema 335 rdeFilePath := "../test-resources/rde_type.json" 336 _, err := os.Stat(rdeFilePath) 337 if os.IsNotExist(err) { 338 return nil, fmt.Errorf("unable to find RDE type file '%s': %s", rdeFilePath, err) 339 } 340 341 rdeFile, err := os.OpenFile(filepath.Clean(rdeFilePath), os.O_RDONLY, 0400) 342 if err != nil { 343 return nil, fmt.Errorf("unable to open RDE type file '%s': %s", rdeFilePath, err) 344 } 345 defer safeClose(rdeFile) 346 347 rdeSchema, err := io.ReadAll(rdeFile) 348 if err != nil { 349 return nil, fmt.Errorf("error reading RDE type file %s: %s", rdeFilePath, err) 350 } 351 352 var unmarshaledJson map[string]interface{} 353 err = json.Unmarshal(rdeSchema, &unmarshaledJson) 354 if err != nil { 355 return nil, fmt.Errorf("could not unmarshal RDE type file %s: %s", rdeFilePath, err) 356 } 357 358 return unmarshaledJson, nil 359 } 360 361 // Test_RdeTypeBehavior tests the CRUD methods of RDE Types to create Behaviors, as a System administrator and tenant user. 362 // This test can be run with GOVCD_SKIP_VAPP_CREATION option enabled. 363 func (vcd *TestVCD) Test_RdeTypeBehavior(check *C) { 364 if vcd.skipAdminTests { 365 check.Skip(fmt.Sprintf(TestRequiresSysAdminPrivileges, check.TestName())) 366 } 367 skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeTypeBehaviors) 368 369 // Create a new RDE Type from scratch 370 unmarshaledRdeTypeSchema, err := loadRdeTypeSchemaFromTestResources() 371 check.Assert(err, IsNil) 372 check.Assert(true, Equals, len(unmarshaledRdeTypeSchema) > 0) 373 sanizitedTestName := strings.NewReplacer("_", "", ".", "").Replace(check.TestName()) 374 rdeType, err := vcd.client.CreateRdeType(&types.DefinedEntityType{ 375 Name: sanizitedTestName, 376 Description: "Created by " + check.TestName(), 377 Nss: "nss", 378 Version: "1.0.0", 379 Vendor: "vmware", 380 Schema: unmarshaledRdeTypeSchema, 381 Interfaces: []string{"urn:vcloud:interface:vmware:k8s:1.0.0"}, 382 }) 383 check.Assert(err, IsNil) 384 AddToCleanupListOpenApi(rdeType.DefinedEntityType.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeEntityTypes+rdeType.DefinedEntityType.ID) 385 defer func() { 386 err := rdeType.Delete() 387 check.Assert(err, IsNil) 388 }() 389 390 // Get all the behaviors of the RDE Type. As it referenced the K8s Interface, it inherits its Behaviors, so it 391 // has one Behavior without anyone creating it. 392 originalBehaviors, err := rdeType.GetAllBehaviors(nil) 393 check.Assert(err, IsNil) 394 check.Assert(len(originalBehaviors), Equals, 1) 395 check.Assert(originalBehaviors[0].Name, Equals, "createKubeConfig") 396 check.Assert(originalBehaviors[0].Description, Equals, "Creates and returns a kubeconfig") 397 check.Assert(len(originalBehaviors[0].Execution), Equals, 2) 398 check.Assert(originalBehaviors[0].Execution["id"], Equals, "CreateKubeConfigActivity") 399 check.Assert(originalBehaviors[0].Execution["type"], Equals, "Activity") 400 401 // Error getting non-existing Behaviors 402 _, err = rdeType.GetBehaviorById("urn:vcloud:behavior-type:notexist:notexist:notexist:9.9.9") 403 check.Assert(err, NotNil) 404 check.Assert(strings.Contains(err.Error(), "RDE_INVALID_BEHAVIOR_SCOPE"), Equals, true) 405 406 _, err = rdeType.GetBehaviorByName("DoesNotExist") 407 check.Assert(err, NotNil) 408 check.Assert(strings.Contains(err.Error(), ErrorEntityNotFound.Error()), Equals, true) 409 410 // Getting behaviors correctly 411 originalBehavior, err := rdeType.GetBehaviorById(originalBehaviors[0].ID) 412 check.Assert(err, IsNil) 413 check.Assert(originalBehavior, NotNil) 414 check.Assert(originalBehavior.Name, Equals, originalBehaviors[0].Name) 415 check.Assert(originalBehavior.Description, Equals, originalBehaviors[0].Description) 416 check.Assert(originalBehavior.Execution, DeepEquals, originalBehaviors[0].Execution) 417 418 behavior2, err := rdeType.GetBehaviorByName(originalBehaviors[0].Name) 419 check.Assert(err, IsNil) 420 check.Assert(originalBehavior, NotNil) 421 check.Assert(originalBehavior, DeepEquals, behavior2) 422 423 // Override the behavior 424 rdeTypeBehavior, err := rdeType.UpdateBehaviorOverride(types.Behavior{ 425 ID: originalBehavior.ID, 426 Description: originalBehavior.Description + "Overridden", 427 Execution: map[string]interface{}{ 428 "id": originalBehavior.Execution["id"].(string) + "Overridden", 429 "type": "noop", 430 }, 431 Name: "WillNotBeOverridden", 432 }) 433 check.Assert(err, IsNil) 434 check.Assert(rdeTypeBehavior.ID, Not(Equals), originalBehavior.ID) // Now that it is overridden, ID changes to behavior-type 435 check.Assert(rdeTypeBehavior.Ref, Equals, originalBehavior.ID) 436 check.Assert(rdeTypeBehavior.Description, Equals, originalBehavior.Description+"Overridden") 437 check.Assert(rdeTypeBehavior.Execution["id"], Equals, originalBehavior.Execution["id"].(string)+"Overridden") 438 check.Assert(rdeTypeBehavior.Execution["type"], Equals, "noop") 439 check.Assert(rdeTypeBehavior.Name, Equals, originalBehavior.Name) // Name can't be overridden 440 441 // Check that it can be retrieved with new Behavior ID (generated by the override) and old one 442 retrOverridden, err := rdeType.GetBehaviorById(rdeTypeBehavior.ID) 443 check.Assert(err, IsNil) 444 check.Assert(retrOverridden, DeepEquals, rdeTypeBehavior) 445 446 retrOverridden, err = rdeType.GetBehaviorById(rdeTypeBehavior.Ref) // Ref is the Interface Behavior ID 447 check.Assert(err, IsNil) 448 check.Assert(retrOverridden, DeepEquals, rdeTypeBehavior) 449 450 testRdeTypeAccessControls(check, rdeType, retrOverridden) 451 452 // We test Behavior invocation. Note that we invoke the overridden Behavior 453 // instead of the one from the Interface as the overridden is a dummy No-op that will finish OK all the time, 454 // as opposed as the original Activity. 455 testRdeBehaviorInvocation(check, rdeType, retrOverridden) 456 457 // Delete the Behavior with original RDE Interface Behavior ID. It doesn't care if we use the original or the overridden ID, 458 // it is smart enough to delete the Behavior from the receiver Type. 459 err = rdeType.DeleteBehaviorOverride(originalBehavior.ID) 460 check.Assert(err, IsNil) 461 462 // Check that the deletion was done correctly 463 originalBehaviors, err = rdeType.GetAllBehaviors(nil) 464 check.Assert(err, IsNil) 465 check.Assert(len(originalBehaviors), Equals, 1) // We still have 1: The original RDE Interface Behavior 466 check.Assert(originalBehaviors[0].ID, Not(Equals), retrOverridden.ID) // The ID should not be the overridden one as we deleted it 467 check.Assert(originalBehaviors[0].ID, Equals, originalBehavior.ID) // The ID should not be the overridden one as we deleted it 468 } 469 470 // testRdeBehaviorInvocation tests that a Behavior can be invoked in a RDE of a given Type. 471 func testRdeBehaviorInvocation(check *C, rdeType *DefinedEntityType, behavior *types.Behavior) { 472 rdeEntityJson := []byte(` 473 { 474 "bar": "stringValue1", 475 "prop2": { 476 "subprop1": "stringValue2", 477 "subprop2": [ 478 "stringValue3", 479 "stringValue4" 480 ] 481 }, 482 "foo": { 483 "key": "stringValue5" 484 } 485 }`) 486 var unmarshaledRdeEntityJson map[string]interface{} 487 err := json.Unmarshal(rdeEntityJson, &unmarshaledRdeEntityJson) 488 check.Assert(err, IsNil) 489 490 rde, err := rdeType.CreateRde(types.DefinedEntity{ 491 Name: check.TestName(), 492 Entity: unmarshaledRdeEntityJson, 493 }, nil) 494 check.Assert(err, IsNil) 495 496 // RDE needs to be Resolved to ve invoked or deleted 497 err = rde.Resolve() 498 check.Assert(err, IsNil) 499 AddToCleanupListOpenApi(rde.DefinedEntity.ID, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointRdeEntities+rde.DefinedEntity.ID) 500 defer func() { 501 err := rde.Delete() 502 check.Assert(err, IsNil) 503 }() 504 505 // We need to grant access to the Behavior to invoke it 506 err = rdeType.SetBehaviorAccessControls([]*types.BehaviorAccess{ 507 { 508 AccessLevelId: "urn:vcloud:accessLevel:FullControl", 509 BehaviorId: behavior.Ref, 510 }, 511 }) 512 check.Assert(err, IsNil) 513 514 var invocation map[string]interface{} 515 err = rde.InvokeBehaviorAndMarshal(behavior.ID, types.BehaviorInvocation{ 516 Arguments: map[string]interface{}{}, 517 Metadata: map[string]interface{}{}, 518 }, &invocation) 519 check.Assert(err, IsNil) 520 check.Assert(len(invocation) > 0, Equals, true) 521 check.Assert(invocation["entityId"], Equals, rde.DefinedEntity.ID) 522 } 523 524 func testRdeTypeAccessControls(check *C, rdeType *DefinedEntityType, behavior *types.Behavior) { 525 allAccCtrl, err := rdeType.GetAllBehaviorsAccessControls(nil) 526 check.Assert(err, IsNil) 527 check.Assert(len(allAccCtrl), Equals, 0) 528 529 // Add the behavior access controls 530 behaviorAccess := &types.BehaviorAccess{ 531 AccessLevelId: "urn:vcloud:accessLevel:ReadOnly", 532 BehaviorId: behavior.ID, 533 } 534 err = rdeType.SetBehaviorAccessControls([]*types.BehaviorAccess{behaviorAccess}) 535 check.Assert(err, IsNil) 536 537 allAccCtrl, err = rdeType.GetAllBehaviorsAccessControls(nil) 538 check.Assert(err, IsNil) 539 check.Assert(len(allAccCtrl), Equals, 1) 540 check.Assert(*allAccCtrl[0], DeepEquals, *behaviorAccess) 541 542 // Update the behavior access controls 543 behaviorAccess = &types.BehaviorAccess{ 544 AccessLevelId: "urn:vcloud:accessLevel:ReadWrite", 545 BehaviorId: behavior.ID, 546 } 547 err = rdeType.SetBehaviorAccessControls([]*types.BehaviorAccess{behaviorAccess}) 548 check.Assert(err, IsNil) 549 550 allAccCtrl, err = rdeType.GetAllBehaviorsAccessControls(nil) 551 check.Assert(err, IsNil) 552 check.Assert(len(allAccCtrl), Equals, 1) 553 check.Assert(*allAccCtrl[0], DeepEquals, *behaviorAccess) 554 555 // Delete the behavior access controls 556 err = rdeType.SetBehaviorAccessControls([]*types.BehaviorAccess{}) 557 check.Assert(err, IsNil) 558 559 var payload []*types.BehaviorAccess 560 // This one simulates a filtering that goes wrong and leaves "payload" nil 561 for _, acl := range allAccCtrl { 562 if acl.BehaviorId == "notExist" { 563 payload = append(payload, acl) 564 } 565 } 566 567 err = rdeType.SetBehaviorAccessControls(payload) // payload is nil, it should be equivalent to set an empty slice of access controls 568 check.Assert(err, IsNil) 569 570 allAccCtrl, err = rdeType.GetAllBehaviorsAccessControls(nil) 571 check.Assert(err, IsNil) 572 check.Assert(len(allAccCtrl), Equals, 0) 573 }