github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/metadata_v2_test.go (about) 1 //go:build (vapp || vdc || metadata || functional || ALL) && !skipLong 2 3 /* 4 * Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 5 */ 6 7 package govcd 8 9 import ( 10 "fmt" 11 "github.com/vmware/go-vcloud-director/v2/types/v56" 12 . "gopkg.in/check.v1" 13 "regexp" 14 "strings" 15 ) 16 17 func init() { 18 testingTags["metadata"] = "metadata_v2_test.go" 19 } 20 21 func (vcd *TestVCD) TestVmMetadata(check *C) { 22 fmt.Printf("Running: %s\n", check.TestName()) 23 24 if vcd.skipVappTests { 25 check.Skip("Skipping test because vApp was not successfully created at setup") 26 } 27 28 if vcd.vapp.VApp == nil { 29 check.Skip("skipping test because no vApp is found in configuration") 30 } 31 32 vApp := vcd.findFirstVapp() 33 vmType, vmName := vcd.findFirstVm(vApp) 34 if vmName == "" { 35 check.Skip("skipping test because no VM is found") 36 } 37 38 vm := NewVM(&vcd.client.Client) 39 vm.VM = &vmType 40 41 vcd.testMetadataCRUDActions(vm, check, nil) 42 vcd.testMetadataIgnore(vm, "vApp", vm.VM.Name, check) 43 } 44 45 func (vcd *TestVCD) TestAdminVdcMetadata(check *C) { 46 fmt.Printf("Running: %s\n", check.TestName()) 47 vcd.skipIfNotSysAdmin(check) 48 if vcd.config.VCD.Nsxt.Vdc == "" { 49 check.Skip("skipping test because VDC name is empty") 50 } 51 52 org, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) 53 check.Assert(err, IsNil) 54 check.Assert(org, NotNil) 55 56 adminVdc, err := org.GetAdminVDCByName(vcd.config.VCD.Nsxt.Vdc, false) 57 check.Assert(err, IsNil) 58 check.Assert(adminVdc, NotNil) 59 60 vcd.testMetadataCRUDActions(adminVdc, check, func(testCase metadataTest) { 61 testVdcMetadata(vcd, check, testCase) 62 }) 63 vcd.testMetadataIgnore(adminVdc, "vdc", adminVdc.AdminVdc.Name, check) 64 } 65 66 func testVdcMetadata(vcd *TestVCD, check *C, testCase metadataTest) { 67 org, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) 68 check.Assert(err, IsNil) 69 check.Assert(org, NotNil) 70 71 vdc, err := org.GetVDCByName(vcd.config.VCD.Nsxt.Vdc, false) 72 check.Assert(err, IsNil) 73 check.Assert(vdc, NotNil) 74 check.Assert(vdc.Vdc.Name, Equals, vcd.config.VCD.Nsxt.Vdc) 75 76 metadata, err := vdc.GetMetadata() 77 check.Assert(err, IsNil) 78 assertMetadata(check, metadata, testCase, 1) 79 } 80 81 func (vcd *TestVCD) TestProviderVdcMetadata(check *C) { 82 fmt.Printf("Running: %s\n", check.TestName()) 83 vcd.skipIfNotSysAdmin(check) 84 providerVdc, err := vcd.client.GetProviderVdcByName(vcd.config.VCD.NsxtProviderVdc.Name) 85 if err != nil { 86 check.Skip(fmt.Sprintf("%s: Provider VDC %s not found. Test can't proceed", check.TestName(), vcd.config.VCD.NsxtProviderVdc.Name)) 87 return 88 } 89 vcd.testMetadataCRUDActions(providerVdc, check, nil) 90 vcd.testMetadataIgnore(providerVdc, "providervdc", providerVdc.ProviderVdc.Name, check) 91 } 92 93 func (vcd *TestVCD) TestVAppMetadata(check *C) { 94 fmt.Printf("Running: %s\n", check.TestName()) 95 if vcd.skipVappTests { 96 check.Skip("Skipping test because vApp was not successfully created at setup") 97 } 98 vcd.testMetadataCRUDActions(vcd.vapp, check, nil) 99 vcd.testMetadataIgnore(vcd.vapp, "vApp", vcd.vapp.VApp.Name, check) 100 } 101 102 func (vcd *TestVCD) TestVAppTemplateMetadata(check *C) { 103 fmt.Printf("Running: %s\n", check.TestName()) 104 vAppTemplate, err := vcd.nsxtVdc.GetVAppTemplateByName(vcd.config.VCD.Catalog.NsxtCatalogItem) 105 if err != nil { 106 check.Skip("Skipping test because vApp Template was not found. Test can't proceed") 107 return 108 } 109 check.Assert(vAppTemplate, NotNil) 110 check.Assert(vAppTemplate.VAppTemplate.Name, Equals, vcd.config.VCD.Catalog.NsxtCatalogItem) 111 112 vcd.testMetadataCRUDActions(vAppTemplate, check, nil) 113 vcd.testMetadataIgnore(vAppTemplate, "vAppTemplate", vAppTemplate.VAppTemplate.Name, check) 114 } 115 116 func (vcd *TestVCD) TestMediaRecordMetadata(check *C) { 117 fmt.Printf("Running: %s\n", check.TestName()) 118 119 skipWhenMediaPathMissing(vcd, check) 120 121 org, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) 122 check.Assert(err, IsNil) 123 check.Assert(org, NotNil) 124 125 catalog, err := org.GetCatalogByName(vcd.config.VCD.Catalog.Name, false) 126 check.Assert(err, IsNil) 127 check.Assert(catalog, NotNil) 128 check.Assert(catalog.Catalog.Name, Equals, vcd.config.VCD.Catalog.Name) 129 130 uploadTask, err := catalog.UploadMediaImage(check.TestName(), check.TestName(), vcd.config.Media.MediaPath, 1024) 131 check.Assert(err, IsNil) 132 check.Assert(uploadTask, NotNil) 133 err = uploadTask.WaitTaskCompletion() 134 check.Assert(err, IsNil) 135 // cleanup uploaded media so that other tests don't fail 136 defer func() { 137 media, err := catalog.GetMediaByName(check.TestName(), true) 138 check.Assert(err, IsNil) 139 check.Assert(media, NotNil) 140 141 deleteTask, err := media.Delete() 142 check.Assert(err, IsNil) 143 check.Assert(deleteTask, NotNil) 144 err = deleteTask.WaitTaskCompletion() 145 check.Assert(err, IsNil) 146 }() 147 148 AddToCleanupList(check.TestName(), "mediaCatalogImage", vcd.org.Org.Name+"|"+vcd.config.VCD.Catalog.Name, "Test_AddMetadataOnMediaRecord") 149 150 err = vcd.org.Refresh() 151 check.Assert(err, IsNil) 152 153 mediaRecord, err := catalog.QueryMedia(check.TestName()) 154 check.Assert(err, IsNil) 155 check.Assert(mediaRecord, NotNil) 156 check.Assert(mediaRecord.MediaRecord.Name, Equals, check.TestName()) 157 158 vcd.testMetadataCRUDActions(mediaRecord, check, nil) 159 vcd.testMetadataIgnore(mediaRecord, "media", mediaRecord.MediaRecord.Name, check) 160 } 161 162 func (vcd *TestVCD) TestMediaMetadata(check *C) { 163 fmt.Printf("Running: %s\n", check.TestName()) 164 165 skipWhenMediaPathMissing(vcd, check) 166 167 org, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) 168 check.Assert(err, IsNil) 169 check.Assert(org, NotNil) 170 171 catalog, err := org.GetCatalogByName(vcd.config.VCD.Catalog.Name, false) 172 check.Assert(err, IsNil) 173 check.Assert(catalog, NotNil) 174 check.Assert(catalog.Catalog.Name, Equals, vcd.config.VCD.Catalog.Name) 175 176 media, err := catalog.GetMediaByName(vcd.config.Media.Media, false) 177 check.Assert(err, IsNil) 178 179 vcd.testMetadataCRUDActions(media, check, nil) 180 vcd.testMetadataIgnore(media, "media", media.Media.Name, check) 181 } 182 183 func (vcd *TestVCD) TestAdminCatalogMetadata(check *C) { 184 fmt.Printf("Running: %s\n", check.TestName()) 185 186 org, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) 187 check.Assert(err, IsNil) 188 check.Assert(org, NotNil) 189 190 adminCatalog, err := org.GetAdminCatalogByName(vcd.config.VCD.Catalog.NsxtBackedCatalogName, false) 191 check.Assert(err, IsNil) 192 check.Assert(adminCatalog, NotNil) 193 check.Assert(adminCatalog.AdminCatalog.Name, Equals, vcd.config.VCD.Catalog.NsxtBackedCatalogName) 194 195 vcd.testMetadataCRUDActions(adminCatalog, check, func(testCase metadataTest) { 196 testCatalogMetadata(vcd, check, testCase) 197 }) 198 vcd.testMetadataIgnore(adminCatalog, "catalog", adminCatalog.AdminCatalog.Name, check) 199 } 200 201 func testCatalogMetadata(vcd *TestVCD, check *C, testCase metadataTest) { 202 org, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) 203 check.Assert(err, IsNil) 204 check.Assert(org, NotNil) 205 206 catalog, err := org.GetCatalogByName(vcd.config.VCD.Catalog.NsxtBackedCatalogName, false) 207 check.Assert(err, IsNil) 208 check.Assert(catalog, NotNil) 209 check.Assert(catalog.Catalog.Name, Equals, vcd.config.VCD.Catalog.NsxtBackedCatalogName) 210 211 metadata, err := catalog.GetMetadata() 212 check.Assert(err, IsNil) 213 assertMetadata(check, metadata, testCase, 1) 214 } 215 216 func (vcd *TestVCD) TestAdminOrgMetadata(check *C) { 217 fmt.Printf("Running: %s\n", check.TestName()) 218 219 adminOrg, err := vcd.client.GetAdminOrgByName(vcd.org.Org.Name) 220 check.Assert(err, IsNil) 221 check.Assert(adminOrg, NotNil) 222 223 vcd.testMetadataCRUDActions(adminOrg, check, func(testCase metadataTest) { 224 testOrgMetadata(vcd, check, testCase) 225 }) 226 vcd.testMetadataIgnore(adminOrg, "org", adminOrg.AdminOrg.Name, check) 227 } 228 229 func testOrgMetadata(vcd *TestVCD, check *C, testCase metadataTest) { 230 org, err := vcd.client.GetOrgByName(vcd.org.Org.Name) 231 check.Assert(err, IsNil) 232 check.Assert(org, NotNil) 233 234 metadata, err := org.GetMetadata() 235 check.Assert(err, IsNil) 236 assertMetadata(check, metadata, testCase, 1) 237 } 238 239 func (vcd *TestVCD) TestDiskMetadata(check *C) { 240 fmt.Printf("Running: %s\n", check.TestName()) 241 242 diskCreateParams := &types.DiskCreateParams{ 243 Disk: &types.Disk{ 244 Name: TestCreateDisk, 245 SizeMb: 11, 246 Description: TestCreateDisk, 247 }, 248 } 249 250 task, err := vcd.vdc.CreateDisk(diskCreateParams) 251 check.Assert(err, IsNil) 252 253 diskHREF := task.Task.Owner.HREF 254 PrependToCleanupList(diskHREF, "disk", "", check.TestName()) 255 256 err = task.WaitTaskCompletion() 257 check.Assert(err, IsNil) 258 259 disk, err := vcd.vdc.GetDiskByHref(diskHREF) 260 check.Assert(err, IsNil) 261 262 vcd.testMetadataCRUDActions(disk, check, nil) 263 vcd.testMetadataIgnore(disk, "disk", disk.Disk.Name, check) 264 265 task, err = disk.Delete() 266 check.Assert(err, IsNil) 267 err = task.WaitTaskCompletion() 268 check.Assert(err, IsNil) 269 } 270 271 func (vcd *TestVCD) TestOrgVDCNetworkMetadata(check *C) { 272 fmt.Printf("Running: %s\n", check.TestName()) 273 net, err := vcd.vdc.GetOrgVdcNetworkByName(vcd.config.VCD.Network.Net1, false) 274 if err != nil { 275 check.Skip(fmt.Sprintf("network %s not found. Test can't proceed", vcd.config.VCD.Network.Net1)) 276 return 277 } 278 vcd.testMetadataCRUDActions(net, check, nil) 279 vcd.testMetadataIgnore(net, "network", net.OrgVDCNetwork.Name, check) 280 } 281 282 func (vcd *TestVCD) TestCatalogItemMetadata(check *C) { 283 fmt.Printf("Running: %s\n", check.TestName()) 284 catalog, err := vcd.org.GetCatalogByName(vcd.config.VCD.Catalog.Name, false) 285 if err != nil { 286 check.Skip(fmt.Sprintf("Catalog %s not found. Test can't proceed", vcd.config.VCD.Catalog.Name)) 287 return 288 } 289 290 catalogItem, err := catalog.GetCatalogItemByName(vcd.config.VCD.Catalog.CatalogItem, false) 291 if err != nil { 292 check.Skip(fmt.Sprintf("Catalog item %s not found. Test can't proceed", vcd.config.VCD.Catalog.CatalogItem)) 293 return 294 } 295 296 vcd.testMetadataCRUDActions(catalogItem, check, nil) 297 vcd.testMetadataIgnore(catalogItem, "catalogItem", catalogItem.CatalogItem.Name, check) 298 } 299 300 func (vcd *TestVCD) testMetadataIgnore(resource metadataCompatible, objectType, objectName string, check *C) { 301 existingMetadata, err := resource.GetMetadata() 302 check.Assert(err, IsNil) 303 304 err = resource.AddMetadataEntryWithVisibility("foo", "bar", types.MetadataStringValue, types.MetadataReadWriteVisibility, false) 305 check.Assert(err, IsNil) 306 307 // Add a new entry that won't be filtered out 308 err = resource.AddMetadataEntryWithVisibility("not_ignored", "bar2", types.MetadataStringValue, types.MetadataReadWriteVisibility, false) 309 check.Assert(err, IsNil) 310 311 cleanup := func() { 312 vcd.client.Client.IgnoredMetadata = nil 313 metadata, err := resource.GetMetadata() 314 check.Assert(err, IsNil) 315 for _, entry := range metadata.MetadataEntry { 316 itWasAlreadyPresent := false 317 for _, existingEntry := range existingMetadata.MetadataEntry { 318 if existingEntry.Key == entry.Key && existingEntry.TypedValue.Value == entry.TypedValue.Value && 319 existingEntry.Type == entry.Type { 320 itWasAlreadyPresent = true 321 } 322 } 323 if !itWasAlreadyPresent { 324 err = resource.DeleteMetadataEntryWithDomain(entry.Key, entry.Domain != nil && entry.Domain.Domain == "SYSTEM") 325 check.Assert(err, IsNil) 326 } 327 } 328 metadata, err = resource.GetMetadata() 329 check.Assert(err, IsNil) 330 check.Assert(metadata, NotNil) 331 check.Assert(len(metadata.MetadataEntry), Equals, len(existingMetadata.MetadataEntry)) 332 } 333 defer cleanup() 334 335 tests := []struct { 336 ignoredMetadata []IgnoredMetadata 337 metadataIsIgnored bool 338 }{ 339 { 340 ignoredMetadata: []IgnoredMetadata{{ObjectType: &objectType, KeyRegex: regexp.MustCompile(`^foo$`)}}, 341 metadataIsIgnored: true, 342 }, 343 { 344 ignoredMetadata: []IgnoredMetadata{{ObjectType: &objectType, ValueRegex: regexp.MustCompile(`^bar$`)}}, 345 metadataIsIgnored: true, 346 }, 347 { 348 ignoredMetadata: []IgnoredMetadata{{ObjectType: &objectType, KeyRegex: regexp.MustCompile(`^fizz$`)}}, 349 metadataIsIgnored: false, 350 }, 351 { 352 ignoredMetadata: []IgnoredMetadata{{ObjectType: &objectType, ValueRegex: regexp.MustCompile(`^buzz$`)}}, 353 metadataIsIgnored: false, 354 }, 355 { 356 ignoredMetadata: []IgnoredMetadata{{ObjectName: &objectName, KeyRegex: regexp.MustCompile(`^foo$`)}}, 357 metadataIsIgnored: true, 358 }, 359 { 360 ignoredMetadata: []IgnoredMetadata{{ObjectName: &objectName, ValueRegex: regexp.MustCompile(`^bar$`)}}, 361 metadataIsIgnored: true, 362 }, 363 { 364 ignoredMetadata: []IgnoredMetadata{{ObjectName: &objectName, KeyRegex: regexp.MustCompile(`^fizz$`)}}, 365 metadataIsIgnored: false, 366 }, 367 { 368 ignoredMetadata: []IgnoredMetadata{{ObjectName: &objectName, ValueRegex: regexp.MustCompile(`^buzz$`)}}, 369 metadataIsIgnored: false, 370 }, 371 { 372 ignoredMetadata: []IgnoredMetadata{{ObjectType: &objectType, ObjectName: &objectName, KeyRegex: regexp.MustCompile(`foo`), ValueRegex: regexp.MustCompile(`bar`)}}, 373 metadataIsIgnored: true, 374 }, 375 } 376 377 // Tests that the ignored metadata setter works as expected 378 vcd.client.Client.IgnoredMetadata = []IgnoredMetadata{{ObjectType: &objectType, ValueRegex: regexp.MustCompile(`dummy`)}} 379 previousIgnoredMetadata := vcd.client.SetMetadataToIgnore(nil) 380 check.Assert(vcd.client.Client.IgnoredMetadata, IsNil) 381 check.Assert(len(previousIgnoredMetadata) > 0, Equals, true) 382 previousIgnoredMetadata = vcd.client.SetMetadataToIgnore(previousIgnoredMetadata) 383 check.Assert(previousIgnoredMetadata, IsNil) 384 check.Assert(len(vcd.client.Client.IgnoredMetadata) > 0, Equals, true) 385 386 for _, tt := range tests { 387 vcd.client.Client.IgnoredMetadata = tt.ignoredMetadata 388 389 // Tests getting a simple metadata entry by its key 390 singleMetadata, err := resource.GetMetadataByKey("foo", false) 391 if tt.metadataIsIgnored { 392 check.Assert(err, NotNil) 393 check.Assert(true, Equals, strings.Contains(err.Error(), "ignored")) 394 } else { 395 check.Assert(err, IsNil) 396 check.Assert(singleMetadata, NotNil) 397 check.Assert(singleMetadata.TypedValue.Value, Equals, "bar") 398 } 399 400 // Retrieve all metadata 401 allMetadata, err := resource.GetMetadata() 402 check.Assert(err, IsNil) 403 check.Assert(allMetadata, NotNil) 404 if tt.metadataIsIgnored { 405 // If metadata is ignored, there should be an offset of 1 entry (with key "test") 406 check.Assert(len(allMetadata.MetadataEntry), Equals, len(existingMetadata.MetadataEntry)+1) 407 for _, entry := range allMetadata.MetadataEntry { 408 if tt.metadataIsIgnored { 409 check.Assert(entry.Key, Not(Equals), "foo") 410 check.Assert(entry.TypedValue.Value, Not(Equals), "bar") 411 } 412 } 413 } else { 414 // If metadata is NOT ignored, there should be an offset of 2 entries (with key "foo" and "test") 415 check.Assert(len(allMetadata.MetadataEntry), Equals, len(existingMetadata.MetadataEntry)+2) 416 } 417 } 418 419 // Tries to delete a metadata entry that is ignored, it should hence fail 420 err = resource.DeleteMetadataEntryWithDomain("foo", false) 421 check.Assert(err, NotNil) 422 check.Assert(true, Equals, strings.Contains(err.Error(), "ignored")) 423 424 // Tries to merge metadata that is filtered out, hence it should fail 425 err = resource.MergeMetadataWithMetadataValues(map[string]types.MetadataValue{ 426 "foo": { 427 TypedValue: &types.MetadataTypedValue{ 428 XsiType: types.MetadataStringValue, 429 Value: "bar3", 430 }, 431 }, 432 }) 433 check.Assert(err, NotNil) 434 check.Assert(true, Equals, strings.Contains(err.Error(), "after filtering metadata, there is no metadata to merge")) 435 436 // Tries to merge metadata, one entry is filtered out, another is not 437 err = resource.MergeMetadataWithMetadataValues(map[string]types.MetadataValue{ 438 "foo": { 439 TypedValue: &types.MetadataTypedValue{ 440 XsiType: types.MetadataStringValue, 441 Value: "bar3", 442 }, 443 }, 444 "not_ignored": { 445 TypedValue: &types.MetadataTypedValue{ 446 XsiType: types.MetadataStringValue, 447 Value: "bar", 448 }, 449 }, 450 }) 451 check.Assert(err, IsNil) 452 } 453 454 // metadataCompatible allows centralizing and generalizing the tests for metadata compatible resources. 455 type metadataCompatible interface { 456 GetMetadata() (*types.Metadata, error) 457 GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) 458 AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error 459 MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error 460 DeleteMetadataEntryWithDomain(key string, isSystem bool) error 461 } 462 463 type metadataTest struct { 464 Key string 465 Value string 466 UpdatedValue string 467 Type string 468 Visibility string 469 IsSystem bool 470 ExpectErrorOnFirstAdd bool 471 } 472 473 // testMetadataCRUDActions performs a complete test of all use cases that metadata can have, for a metadata compatible resource. 474 // The function parameter extraReadStep performs an extra read step that can be passed as a function. Useful to perform a test 475 // on "admin+not admin" resource combinations, where the "not admin" only has a GetMetadata function. 476 // For example, AdminOrg and Org, where Org only has GetMetadata. 477 func (vcd *TestVCD) testMetadataCRUDActions(resource metadataCompatible, check *C, extraReadStep func(testCase metadataTest)) { 478 // Check how much metadata exists 479 metadata, err := resource.GetMetadata() 480 check.Assert(err, IsNil) 481 check.Assert(metadata, NotNil) 482 existingMetaDataCount := len(metadata.MetadataEntry) 483 484 var testCases = []metadataTest{ 485 { 486 Key: "stringKey", 487 Value: "stringValue", 488 UpdatedValue: "stringValueUpdated", 489 Type: types.MetadataStringValue, 490 Visibility: types.MetadataReadWriteVisibility, 491 IsSystem: false, 492 ExpectErrorOnFirstAdd: false, 493 }, 494 { 495 Key: "numberKey", 496 Value: "notANumber", 497 Type: types.MetadataNumberValue, 498 Visibility: types.MetadataReadWriteVisibility, 499 IsSystem: false, 500 ExpectErrorOnFirstAdd: true, 501 }, 502 { 503 Key: "numberKey", 504 Value: "1", 505 UpdatedValue: "99", 506 Type: types.MetadataNumberValue, 507 Visibility: types.MetadataReadWriteVisibility, 508 IsSystem: false, 509 ExpectErrorOnFirstAdd: false, 510 }, 511 { 512 Key: "boolKey", 513 Value: "notABool", 514 Type: types.MetadataBooleanValue, 515 Visibility: types.MetadataReadWriteVisibility, 516 IsSystem: false, 517 ExpectErrorOnFirstAdd: true, 518 }, 519 { 520 Key: "boolKey", 521 Value: "true", 522 UpdatedValue: "false", 523 Type: types.MetadataBooleanValue, 524 Visibility: types.MetadataReadWriteVisibility, 525 IsSystem: false, 526 ExpectErrorOnFirstAdd: false, 527 }, 528 { 529 Key: "dateKey", 530 Value: "notADate", 531 Type: types.MetadataDateTimeValue, 532 Visibility: types.MetadataReadWriteVisibility, 533 IsSystem: false, 534 ExpectErrorOnFirstAdd: true, 535 }, 536 { 537 Key: "dateKey", 538 Value: "2022-10-05T13:44:00.000Z", 539 UpdatedValue: "2022-12-05T13:44:00.000Z", 540 Type: types.MetadataDateTimeValue, 541 Visibility: types.MetadataReadWriteVisibility, 542 IsSystem: false, 543 ExpectErrorOnFirstAdd: false, 544 }, 545 { 546 Key: "hidden", 547 Value: "hiddenValue", 548 UpdatedValue: "hiddenValueUpdated", 549 Type: types.MetadataStringValue, 550 Visibility: types.MetadataHiddenVisibility, 551 IsSystem: true, 552 ExpectErrorOnFirstAdd: false, 553 }, 554 { 555 Key: "readOnly", 556 Value: "readOnlyValue", 557 UpdatedValue: "readOnlyValueUpdated", 558 Type: types.MetadataStringValue, 559 Visibility: types.MetadataReadOnlyVisibility, 560 IsSystem: true, 561 ExpectErrorOnFirstAdd: false, 562 }, 563 { 564 Key: "readWriteKey", 565 Value: "butPlacedInSystem", 566 Type: types.MetadataStringValue, 567 Visibility: types.MetadataReadWriteVisibility, 568 IsSystem: true, 569 ExpectErrorOnFirstAdd: true, // types.MetadataReadWriteVisibility can't have isSystem=true 570 }, 571 } 572 573 for _, testCase := range testCases { 574 575 // The SYSTEM domain can only be set by a system administrator. 576 // If this test runs as org user, we skip the cases containing 'IsSystem' constraints 577 if !vcd.client.Client.IsSysAdmin && testCase.IsSystem { 578 continue 579 } 580 581 err = resource.AddMetadataEntryWithVisibility(testCase.Key, testCase.Value, testCase.Type, testCase.Visibility, testCase.IsSystem) 582 if testCase.ExpectErrorOnFirstAdd { 583 check.Assert(err, NotNil) 584 continue 585 } 586 check.Assert(err, IsNil) 587 588 // Check if metadata was added correctly 589 metadata, err = resource.GetMetadata() 590 check.Assert(err, IsNil) 591 assertMetadata(check, metadata, testCase, existingMetaDataCount+1) 592 593 metadataValue, err := resource.GetMetadataByKey(testCase.Key, testCase.IsSystem) 594 check.Assert(err, IsNil) 595 check.Assert(metadataValue.TypedValue.Value, Equals, testCase.Value) 596 check.Assert(metadataValue.TypedValue.XsiType, Equals, testCase.Type) 597 598 // Perform an extra read step that can be passed as a function. Useful to perform a test 599 // on resources that only have a GetMetadata function. For example, AdminOrg and Org, where Org only has GetMetadata. 600 if extraReadStep != nil { 601 extraReadStep(testCase) 602 } 603 604 domain := "GENERAL" 605 if testCase.IsSystem { 606 domain = "SYSTEM" 607 } 608 // Merge updated metadata with a new entry 609 err = resource.MergeMetadataWithMetadataValues(map[string]types.MetadataValue{ 610 "mergedKey": { 611 TypedValue: &types.MetadataTypedValue{ 612 Value: "mergedValue", 613 XsiType: types.MetadataStringValue, 614 }, 615 }, 616 testCase.Key: { 617 Domain: &types.MetadataDomainTag{ 618 Visibility: testCase.Visibility, 619 Domain: domain, 620 }, 621 TypedValue: &types.MetadataTypedValue{ 622 Value: testCase.UpdatedValue, 623 XsiType: testCase.Type, 624 }, 625 }, 626 }) 627 check.Assert(err, IsNil) 628 629 // Check that the first key was updated and the second, created 630 metadata, err = resource.GetMetadata() 631 check.Assert(err, IsNil) 632 check.Assert(metadata, NotNil) 633 check.Assert(len(metadata.MetadataEntry), Equals, existingMetaDataCount+2) 634 for _, entry := range metadata.MetadataEntry { 635 switch entry.Key { 636 case "mergedKey": 637 check.Assert(entry.TypedValue.Value, Equals, "mergedValue") 638 case testCase.Key: 639 check.Assert(entry.TypedValue.Value, Equals, testCase.UpdatedValue) 640 } 641 } 642 643 err = resource.DeleteMetadataEntryWithDomain("mergedKey", false) 644 check.Assert(err, IsNil) 645 err = resource.DeleteMetadataEntryWithDomain(testCase.Key, testCase.IsSystem) 646 check.Assert(err, IsNil) 647 648 // Check if metadata was deleted correctly 649 metadata, err = resource.GetMetadata() 650 check.Assert(err, IsNil) 651 check.Assert(metadata, NotNil) 652 check.Assert(len(metadata.MetadataEntry), Equals, existingMetaDataCount) 653 } 654 } 655 656 // assertMetadata performs a common set of assertions on the given metadata 657 func assertMetadata(check *C, given *types.Metadata, expected metadataTest, expectedMetadataEntries int) { 658 check.Assert(given, NotNil) 659 check.Assert(len(given.MetadataEntry), Equals, expectedMetadataEntries) 660 var foundEntry *types.MetadataEntry 661 for _, entry := range given.MetadataEntry { 662 if entry.Key == expected.Key { 663 foundEntry = entry 664 } 665 } 666 check.Assert(foundEntry, NotNil) 667 check.Assert(foundEntry.Key, Equals, expected.Key) 668 check.Assert(foundEntry.TypedValue.Value, Equals, expected.Value) 669 check.Assert(foundEntry.TypedValue.XsiType, Equals, expected.Type) 670 if expected.IsSystem { 671 // If it's on SYSTEM domain, VCD should return the Domain subtype always populated 672 check.Assert(foundEntry.Domain, NotNil) 673 check.Assert(foundEntry.Domain.Domain, Equals, "SYSTEM") 674 check.Assert(foundEntry.Domain.Visibility, Equals, expected.Visibility) 675 } else { 676 if expected.Visibility == types.MetadataReadWriteVisibility { 677 // If it's on GENERAL domain, and the entry is Read/Write, VCD doesn't return the Domain subtype. 678 check.Assert(foundEntry.Domain, IsNil) 679 } else { 680 check.Assert(foundEntry.Domain.Domain, Equals, "GENERAL") 681 check.Assert(foundEntry.Domain.Visibility, Equals, expected.Visibility) 682 } 683 } 684 }