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  }