github.com/vmware/govmomi@v0.51.0/vim25/types/json_test.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package types 6 7 import ( 8 "bytes" 9 "os" 10 "reflect" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/google/go-cmp/cmp" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 var serializationTests = []struct { 20 name string 21 file string 22 data any 23 goType reflect.Type 24 expDecErr string 25 }{ 26 { 27 name: "vminfo", 28 file: "./testdata/vminfo.json", 29 data: &vmInfoObjForTests, 30 goType: reflect.TypeOf(VirtualMachineConfigInfo{}), 31 }, 32 { 33 name: "retrieveResult", 34 file: "./testdata/retrieveResult.json", 35 data: &retrieveResultForTests, 36 goType: reflect.TypeOf(RetrieveResult{}), 37 }, 38 { 39 name: "vminfo-invalid-type-name-value", 40 file: "./testdata/vminfo-invalid-type-name-value.json", 41 data: &vmInfoObjForTests, 42 goType: reflect.TypeOf(VirtualMachineConfigInfo{}), 43 expDecErr: `json: cannot unmarshal bool into Go struct field VirtualMachineConfigInfo.extraConfig of type string`, 44 }, 45 } 46 47 func TestSerialization(t *testing.T) { 48 for _, test := range serializationTests { 49 t.Run(test.name+" Decode", func(t *testing.T) { 50 f, err := os.Open(test.file) 51 if err != nil { 52 t.Fatal(err) 53 } 54 defer f.Close() 55 56 dec := NewJSONDecoder(f) 57 58 ee := test.expDecErr 59 data := reflect.New(test.goType).Interface() 60 if err := dec.Decode(data); err != nil { 61 if ee != err.Error() { 62 t.Errorf("expected error mismatch: e=%v, a=%v", ee, err) 63 } else if ee == "" { 64 t.Errorf("unexpected error: %v", err) 65 } 66 } else if ee != "" { 67 t.Errorf("expected error did not occur: %v", ee) 68 } else { 69 a, e := data, test.data 70 if diff := cmp.Diff(a, e); diff != "" { 71 t.Errorf("mismatched %v: %s", test.name, diff) 72 } 73 } 74 }) 75 76 t.Run(test.name+" Encode", func(t *testing.T) { 77 if test.expDecErr != "" { 78 t.Skip("skipping due to expected decode error") 79 } 80 81 expJSON, err := os.ReadFile(test.file) 82 if err != nil { 83 t.Fatal(err) 84 } 85 86 var w bytes.Buffer 87 _ = w 88 enc := NewJSONEncoder(&w) 89 90 if err := enc.Encode(test.data); err != nil { 91 t.Fatal(err) 92 } 93 94 expected, actual := string(expJSON), w.String() 95 assert.JSONEq(t, expected, actual) 96 }) 97 } 98 99 t.Run("ConfigSpec", func(t *testing.T) { 100 t.Run("Encode", func(t *testing.T) { 101 102 var testCases = []struct { 103 name string 104 data any 105 expected string 106 expectPanic bool 107 }{ 108 { 109 name: "nil ConfigSpec", 110 data: (*VirtualMachineConfigSpec)(nil), 111 expected: "null", 112 }, 113 { 114 name: "ConfigSpec with nil OptionValue value", 115 data: &VirtualMachineConfigSpec{ 116 ExtraConfig: []BaseOptionValue{ 117 &OptionValue{ 118 Key: "key1", 119 Value: nil, 120 }, 121 }, 122 }, 123 expected: `{"_typeName":"VirtualMachineConfigSpec","extraConfig":[{"_typeName":"OptionValue","key":"key1","value":null}]}`, 124 }, 125 { 126 name: "ConfigSpec with nil OptionValue interface value", 127 data: &VirtualMachineConfigSpec{ 128 ExtraConfig: []BaseOptionValue{ 129 &OptionValue{ 130 Key: "key1", 131 Value: (any)(nil), 132 }, 133 }, 134 }, 135 expected: `{"_typeName":"VirtualMachineConfigSpec","extraConfig":[{"_typeName":"OptionValue","key":"key1","value":null}]}`, 136 }, 137 { 138 name: "ConfigSpec with nil element in OptionValues", 139 data: &VirtualMachineConfigSpec{ 140 ExtraConfig: []BaseOptionValue{ 141 (*OptionValue)(nil), 142 }, 143 }, 144 expected: `{"_typeName":"VirtualMachineConfigSpec","extraConfig":[null]}`, 145 }, 146 { 147 name: "ConfigSpec with nil ToolsConfigInfo", 148 data: &VirtualMachineConfigSpec{ 149 Tools: (*ToolsConfigInfo)(nil), 150 }, 151 expected: `{"_typeName":"VirtualMachineConfigSpec"}`, 152 }, 153 { 154 name: "ConfigSpec with nil vAppConfig", 155 data: &VirtualMachineConfigSpec{ 156 VAppConfig: nil, 157 }, 158 expected: `{"_typeName":"VirtualMachineConfigSpec"}`, 159 }, 160 { 161 name: "ConfigSpec with nil pointer vAppConfig ", 162 data: &VirtualMachineConfigSpec{ 163 VAppConfig: (*VmConfigSpec)(nil), 164 }, 165 expected: `{"_typeName":"VirtualMachineConfigSpec","vAppConfig":null}`, 166 }, 167 } 168 169 for i := range testCases { 170 tc := testCases[i] 171 t.Run(tc.name, func(t *testing.T) { 172 var w bytes.Buffer 173 enc := NewJSONEncoder(&w) 174 175 var panicErr any 176 177 func() { 178 defer func() { 179 panicErr = recover() 180 }() 181 if err := enc.Encode(tc.data); err != nil { 182 t.Fatal(err) 183 } 184 }() 185 186 if tc.expectPanic && panicErr == nil { 187 t.Fatalf("did not panic, w=%v", w.String()) 188 } else if tc.expectPanic && panicErr != nil { 189 t.Logf("expected panic occurred: %v\n", panicErr) 190 } else if !tc.expectPanic && panicErr != nil { 191 t.Fatalf("unexpected panic occurred: %v\n", panicErr) 192 } else if a, e := w.String(), tc.expected+"\n"; a != e { 193 t.Fatalf("act=%s != exp=%s", a, e) 194 } else { 195 t.Log(a) 196 } 197 }) 198 } 199 }) 200 }) 201 } 202 203 func TestOptionValueSerialization(t *testing.T) { 204 tv, e := time.Parse(time.RFC3339Nano, "2022-12-12T11:48:35.473645Z") 205 if e != nil { 206 t.Log("Cannot parse test timestamp. This is coding error.") 207 t.Fail() 208 return 209 } 210 options := []struct { 211 name string 212 wire string 213 binding OptionValue 214 }{ 215 { 216 name: "boolean", 217 wire: `{"_typeName": "OptionValue","key": "option1", 218 "value": {"_typeName": "boolean","_value": true} 219 }`, 220 binding: OptionValue{Key: "option1", Value: true}, 221 }, 222 { 223 name: "byte", 224 wire: `{"_typeName": "OptionValue","key": "option1", 225 "value": {"_typeName": "byte","_value": 16} 226 }`, 227 binding: OptionValue{Key: "option1", Value: uint8(16)}, 228 }, 229 { 230 name: "short", 231 wire: `{"_typeName": "OptionValue","key": "option1", 232 "value": {"_typeName": "short","_value": 300} 233 }`, 234 binding: OptionValue{Key: "option1", Value: int16(300)}, 235 }, 236 { 237 name: "int", 238 wire: `{"_typeName": "OptionValue","key": "option1", 239 "value": {"_typeName": "int","_value": 300}}`, 240 binding: OptionValue{Key: "option1", Value: int32(300)}, 241 }, 242 { 243 name: "long", 244 wire: `{"_typeName": "OptionValue","key": "option1", 245 "value": {"_typeName": "long","_value": 300}}`, 246 binding: OptionValue{Key: "option1", Value: int64(300)}, 247 }, 248 { 249 name: "float", 250 wire: `{"_typeName": "OptionValue","key": "option1", 251 "value": {"_typeName": "float","_value": 30.5}}`, 252 binding: OptionValue{Key: "option1", Value: float32(30.5)}, 253 }, 254 { 255 name: "double", 256 wire: `{"_typeName": "OptionValue","key": "option1", 257 "value": {"_typeName": "double","_value": 12.2}}`, 258 binding: OptionValue{Key: "option1", Value: float64(12.2)}, 259 }, 260 { 261 name: "string", 262 wire: `{"_typeName": "OptionValue","key": "option1", 263 "value": {"_typeName": "string","_value": "test"}}`, 264 binding: OptionValue{Key: "option1", Value: "test"}, 265 }, 266 { 267 name: "dateTime", // time.Time 268 wire: `{"_typeName": "OptionValue","key": "option1", 269 "value": {"_typeName": "dateTime","_value": "2022-12-12T11:48:35.473645Z"}}`, 270 binding: OptionValue{Key: "option1", Value: tv}, 271 }, 272 { 273 name: "binary", // []byte 274 wire: `{"_typeName": "OptionValue","key": "option1", 275 "value": {"_typeName": "binary","_value": "SGVsbG8="}}`, 276 binding: OptionValue{Key: "option1", Value: []byte("Hello")}, 277 }, 278 // during serialization we have no way to guess that a string is to be 279 // converted to uri. Using net.URL solves this. It is a breaking change. 280 // See https://github.com/vmware/govmomi/pull/3123 281 // { 282 // name: "anyURI", // string 283 // wire: `{"_typeName": "OptionValue","key": "option1", 284 // "value": {"_typeName": "anyURI","_value": "http://hello"}}`, 285 // binding: OptionValue{Key: "option1", Value: "test"}, 286 // }, 287 { 288 name: "enum", 289 wire: `{"_typeName": "OptionValue","key": "option1", 290 "value": {"_typeName": "CustomizationNetBIOSMode","_value": "enableNetBIOS"}}`, 291 binding: OptionValue{Key: "option1", Value: CustomizationNetBIOSModeEnableNetBIOS}, 292 }, 293 // There is no ArrayOfCustomizationNetBIOSMode type emitted i.e. no enum 294 // array types are emitted in govmomi. 295 // We can process these in the serialization logic i.e. discover or 296 // prepend the "ArrayOf" prefix 297 // { 298 // name: "array of enum", 299 // wire: `{ 300 // "_typeName": "OptionValue", 301 // "key": "option1", 302 // "value": {"_typeName": "ArrayOfCustomizationNetBIOSMode", 303 // "_value": ["enableNetBIOS"]}}`, 304 // binding: OptionValue{Key: "option1", 305 // Value: []CustomizationNetBIOSMode{ 306 // CustomizationNetBIOSModeEnableNetBIOS 307 // }}, 308 // }, 309 310 // array of struct is weird. Do we want to unmarshal this as 311 // []ClusterHostRecommendation directly? Why do we want to use 312 // ArrayOfClusterHostRecommendation wrapper? 313 // if SOAP does it then I guess back compat is a big reason. 314 { 315 name: "array of struct", 316 wire: `{"_typeName": "OptionValue","key": "option1", 317 "value": {"_typeName": "ArrayOfClusterHostRecommendation","_value": [ 318 { 319 "_typeName":"ClusterHostRecommendation", 320 "host": { 321 "_typeName": "ManagedObjectReference", 322 "type": "HostSystem", 323 "value": "host-42" 324 }, 325 "rating":42 326 }]}}`, 327 binding: OptionValue{ 328 Key: "option1", 329 Value: ArrayOfClusterHostRecommendation{ 330 ClusterHostRecommendation: []ClusterHostRecommendation{ 331 { 332 Host: ManagedObjectReference{ 333 Type: "HostSystem", 334 Value: "host-42", 335 }, 336 Rating: 42, 337 }, 338 }, 339 }, 340 }, 341 }, 342 } 343 344 for _, opt := range options { 345 t.Run("Serialize "+opt.name, func(t *testing.T) { 346 r := strings.NewReader(opt.wire) 347 dec := NewJSONDecoder(r) 348 v := OptionValue{} 349 e := dec.Decode(&v) 350 if e != nil { 351 assert.Fail(t, "Cannot read json", "json %v err %v", opt.wire, e) 352 return 353 } 354 assert.Equal(t, opt.binding, v) 355 }) 356 357 t.Run("De-serialize "+opt.name, func(t *testing.T) { 358 var w bytes.Buffer 359 enc := NewJSONEncoder(&w) 360 enc.Encode(opt.binding) 361 s := w.String() 362 assert.JSONEq(t, opt.wire, s) 363 }) 364 } 365 } 366 367 var vmInfoObjForTests = VirtualMachineConfigInfo{ 368 ChangeVersion: "2022-12-12T11:48:35.473645Z", 369 Modified: mustParseTime(time.RFC3339, "1970-01-01T00:00:00Z"), 370 Name: "test", 371 GuestFullName: "VMware Photon OS (64-bit)", 372 Version: "vmx-20", 373 Uuid: "422ca90b-853b-1101-3350-759f747730cc", 374 CreateDate: addrOfMustParseTime(time.RFC3339, "2022-12-12T11:47:24.685785Z"), 375 InstanceUuid: "502cc2a5-1f06-2890-6d70-ba2c55c5c2b7", 376 NpivTemporaryDisabled: NewBool(true), 377 LocationId: "Earth", 378 Template: false, 379 GuestId: "vmwarePhoton64Guest", 380 AlternateGuestName: "", 381 Annotation: "Hello, world.", 382 Files: VirtualMachineFileInfo{ 383 VmPathName: "[datastore1] test/test.vmx", 384 SnapshotDirectory: "[datastore1] test/", 385 SuspendDirectory: "[datastore1] test/", 386 LogDirectory: "[datastore1] test/", 387 }, 388 Tools: &ToolsConfigInfo{ 389 ToolsVersion: 1, 390 AfterPowerOn: NewBool(true), 391 AfterResume: NewBool(true), 392 BeforeGuestStandby: NewBool(true), 393 BeforeGuestShutdown: NewBool(true), 394 BeforeGuestReboot: nil, 395 ToolsUpgradePolicy: "manual", 396 SyncTimeWithHostAllowed: NewBool(true), 397 SyncTimeWithHost: NewBool(false), 398 LastInstallInfo: &ToolsConfigInfoToolsLastInstallInfo{ 399 Counter: 0, 400 }, 401 }, 402 Flags: VirtualMachineFlagInfo{ 403 EnableLogging: NewBool(true), 404 UseToe: NewBool(false), 405 RunWithDebugInfo: NewBool(false), 406 MonitorType: "release", 407 HtSharing: "any", 408 SnapshotDisabled: NewBool(false), 409 SnapshotLocked: NewBool(false), 410 DiskUuidEnabled: NewBool(false), 411 SnapshotPowerOffBehavior: "powerOff", 412 RecordReplayEnabled: NewBool(false), 413 FaultToleranceType: "unset", 414 CbrcCacheEnabled: NewBool(false), 415 VvtdEnabled: NewBool(false), 416 VbsEnabled: NewBool(false), 417 }, 418 DefaultPowerOps: VirtualMachineDefaultPowerOpInfo{ 419 PowerOffType: "soft", 420 SuspendType: "hard", 421 ResetType: "soft", 422 DefaultPowerOffType: "soft", 423 DefaultSuspendType: "hard", 424 DefaultResetType: "soft", 425 StandbyAction: "checkpoint", 426 }, 427 RebootPowerOff: NewBool(false), 428 Hardware: VirtualHardware{ 429 NumCPU: 1, 430 NumCoresPerSocket: 1, 431 AutoCoresPerSocket: NewBool(true), 432 MemoryMB: 2048, 433 VirtualICH7MPresent: NewBool(false), 434 VirtualSMCPresent: NewBool(false), 435 Device: []BaseVirtualDevice{ 436 &VirtualIDEController{ 437 VirtualController: VirtualController{ 438 VirtualDevice: VirtualDevice{ 439 Key: 200, 440 DeviceInfo: &Description{ 441 Label: "IDE 0", 442 Summary: "IDE 0", 443 }, 444 }, 445 BusNumber: 0, 446 }, 447 }, 448 &VirtualIDEController{ 449 VirtualController: VirtualController{ 450 VirtualDevice: VirtualDevice{ 451 Key: 201, 452 DeviceInfo: &Description{ 453 Label: "IDE 1", 454 Summary: "IDE 1", 455 }, 456 }, 457 BusNumber: 1, 458 }, 459 }, 460 &VirtualPS2Controller{ 461 VirtualController: VirtualController{ 462 VirtualDevice: VirtualDevice{ 463 Key: 300, 464 DeviceInfo: &Description{ 465 Label: "PS2 controller 0", 466 Summary: "PS2 controller 0", 467 }, 468 }, 469 BusNumber: 0, 470 Device: []int32{600, 700}, 471 }, 472 }, 473 &VirtualPCIController{ 474 VirtualController: VirtualController{ 475 VirtualDevice: VirtualDevice{ 476 Key: 100, 477 DeviceInfo: &Description{ 478 Label: "PCI controller 0", 479 Summary: "PCI controller 0", 480 }, 481 }, 482 BusNumber: 0, 483 Device: []int32{500, 12000, 14000, 1000, 15000, 4000}, 484 }, 485 }, 486 &VirtualSIOController{ 487 VirtualController: VirtualController{ 488 VirtualDevice: VirtualDevice{ 489 Key: 400, 490 DeviceInfo: &Description{ 491 Label: "SIO controller 0", 492 Summary: "SIO controller 0", 493 }, 494 }, 495 BusNumber: 0, 496 }, 497 }, 498 &VirtualKeyboard{ 499 VirtualDevice: VirtualDevice{ 500 Key: 600, 501 DeviceInfo: &Description{ 502 Label: "Keyboard", 503 Summary: "Keyboard", 504 }, 505 ControllerKey: 300, 506 UnitNumber: NewInt32(0), 507 }, 508 }, 509 &VirtualPointingDevice{ 510 VirtualDevice: VirtualDevice{ 511 Key: 700, 512 DeviceInfo: &Description{Label: "Pointing device", Summary: "Pointing device; Device"}, 513 Backing: &VirtualPointingDeviceDeviceBackingInfo{ 514 VirtualDeviceDeviceBackingInfo: VirtualDeviceDeviceBackingInfo{ 515 UseAutoDetect: NewBool(false), 516 }, 517 HostPointingDevice: "autodetect", 518 }, 519 ControllerKey: 300, 520 UnitNumber: NewInt32(1), 521 }, 522 }, 523 &VirtualMachineVideoCard{ 524 VirtualDevice: VirtualDevice{ 525 Key: 500, 526 DeviceInfo: &Description{Label: "Video card ", Summary: "Video card"}, 527 ControllerKey: 100, 528 UnitNumber: NewInt32(0), 529 }, 530 VideoRamSizeInKB: 4096, 531 NumDisplays: 1, 532 UseAutoDetect: NewBool(false), 533 Enable3DSupport: NewBool(false), 534 Use3dRenderer: "automatic", 535 GraphicsMemorySizeInKB: 262144, 536 }, 537 &VirtualMachineVMCIDevice{ 538 VirtualDevice: VirtualDevice{ 539 Key: 12000, 540 DeviceInfo: &Description{ 541 Label: "VMCI device", 542 Summary: "Device on the virtual machine PCI " + 543 "bus that provides support for the " + 544 "virtual machine communication interface", 545 }, 546 ControllerKey: 100, 547 UnitNumber: NewInt32(17), 548 }, 549 Id: -1, 550 AllowUnrestrictedCommunication: NewBool(false), 551 FilterEnable: NewBool(true), 552 }, 553 &ParaVirtualSCSIController{ 554 VirtualSCSIController: VirtualSCSIController{ 555 VirtualController: VirtualController{ 556 VirtualDevice: VirtualDevice{ 557 Key: 1000, 558 DeviceInfo: &Description{ 559 Label: "SCSI controller 0", 560 Summary: "VMware paravirtual SCSI", 561 }, 562 ControllerKey: 100, 563 UnitNumber: NewInt32(3), 564 }, 565 Device: []int32{2000}, 566 }, 567 HotAddRemove: NewBool(true), 568 SharedBus: "noSharing", 569 ScsiCtlrUnitNumber: 7, 570 }, 571 }, 572 &VirtualAHCIController{ 573 VirtualSATAController: VirtualSATAController{ 574 VirtualController: VirtualController{ 575 VirtualDevice: VirtualDevice{ 576 Key: 15000, 577 DeviceInfo: &Description{ 578 Label: "SATA controller 0", 579 Summary: "AHCI", 580 }, 581 ControllerKey: 100, 582 UnitNumber: NewInt32(24), 583 }, 584 Device: []int32{16000}, 585 }, 586 }, 587 }, 588 &VirtualCdrom{ 589 VirtualDevice: VirtualDevice{ 590 Key: 16000, 591 DeviceInfo: &Description{ 592 Label: "CD/DVD drive 1", 593 Summary: "Remote device", 594 }, 595 Backing: &VirtualCdromRemotePassthroughBackingInfo{ 596 VirtualDeviceRemoteDeviceBackingInfo: VirtualDeviceRemoteDeviceBackingInfo{ 597 UseAutoDetect: NewBool(false), 598 }, 599 }, 600 Connectable: &VirtualDeviceConnectInfo{AllowGuestControl: true, Status: "untried"}, 601 ControllerKey: 15000, 602 UnitNumber: NewInt32(0), 603 }, 604 }, 605 &VirtualDisk{ 606 VirtualDevice: VirtualDevice{ 607 Key: 2000, 608 DeviceInfo: &Description{ 609 Label: "Hard disk 1", 610 Summary: "4,194,304 KB", 611 }, 612 Backing: &VirtualDiskFlatVer2BackingInfo{ 613 VirtualDeviceFileBackingInfo: VirtualDeviceFileBackingInfo{ 614 BackingObjectId: "1", 615 FileName: "[datastore1] test/test.vmdk", 616 Datastore: &ManagedObjectReference{ 617 Type: "Datastore", 618 Value: "datastore-21", 619 }, 620 }, 621 DiskMode: "persistent", 622 Split: NewBool(false), 623 WriteThrough: NewBool(false), 624 ThinProvisioned: NewBool(false), 625 EagerlyScrub: NewBool(false), 626 Uuid: "6000C298-df15-fe89-ddcb-8ea33329595d", 627 ContentId: "e4e1a794c6307ce7906a3973fffffffe", 628 ChangeId: "", 629 Parent: nil, 630 DeltaDiskFormat: "", 631 DigestEnabled: NewBool(false), 632 DeltaGrainSize: 0, 633 DeltaDiskFormatVariant: "", 634 Sharing: "sharingNone", 635 KeyId: nil, 636 }, 637 ControllerKey: 1000, 638 UnitNumber: NewInt32(0), 639 }, 640 CapacityInKB: 4194304, 641 CapacityInBytes: 4294967296, 642 Shares: &SharesInfo{Shares: 1000, Level: "normal"}, 643 StorageIOAllocation: &StorageIOAllocationInfo{ 644 Limit: NewInt64(-1), 645 Shares: &SharesInfo{Shares: 1000, Level: "normal"}, 646 Reservation: NewInt32(0), 647 }, 648 DiskObjectId: "1-2000", 649 NativeUnmanagedLinkedClone: NewBool(false), 650 }, 651 &VirtualVmxnet3{ 652 VirtualVmxnet: VirtualVmxnet{ 653 VirtualEthernetCard: VirtualEthernetCard{ 654 VirtualDevice: VirtualDevice{ 655 Key: 4000, 656 DeviceInfo: &Description{ 657 Label: "Network adapter 1", 658 Summary: "VM Network", 659 }, 660 Backing: &VirtualEthernetCardNetworkBackingInfo{ 661 VirtualDeviceDeviceBackingInfo: VirtualDeviceDeviceBackingInfo{ 662 DeviceName: "VM Network", 663 UseAutoDetect: NewBool(false), 664 }, 665 Network: &ManagedObjectReference{ 666 Type: "Network", 667 Value: "network-27", 668 }, 669 }, 670 Connectable: &VirtualDeviceConnectInfo{ 671 MigrateConnect: "unset", 672 StartConnected: true, 673 Status: "untried", 674 }, 675 ControllerKey: 100, 676 UnitNumber: NewInt32(7), 677 }, 678 AddressType: "assigned", 679 MacAddress: "00:50:56:ac:4d:ed", 680 WakeOnLanEnabled: NewBool(true), 681 ResourceAllocation: &VirtualEthernetCardResourceAllocation{ 682 Reservation: NewInt64(0), 683 Share: SharesInfo{ 684 Shares: 50, 685 Level: "normal", 686 }, 687 Limit: NewInt64(-1), 688 }, 689 UptCompatibilityEnabled: NewBool(true), 690 }, 691 }, 692 Uptv2Enabled: NewBool(false), 693 }, 694 &VirtualUSBXHCIController{ 695 VirtualController: VirtualController{ 696 VirtualDevice: VirtualDevice{ 697 Key: 14000, 698 DeviceInfo: &Description{ 699 Label: "USB xHCI controller ", 700 Summary: "USB xHCI controller", 701 }, 702 SlotInfo: &VirtualDevicePciBusSlotInfo{ 703 PciSlotNumber: -1, 704 }, 705 ControllerKey: 100, 706 UnitNumber: NewInt32(23), 707 }, 708 }, 709 710 AutoConnectDevices: NewBool(false), 711 }, 712 }, 713 MotherboardLayout: "i440bxHostBridge", 714 SimultaneousThreads: 1, 715 }, 716 CpuAllocation: &ResourceAllocationInfo{ 717 Reservation: NewInt64(0), 718 ExpandableReservation: NewBool(false), 719 Limit: NewInt64(-1), 720 Shares: &SharesInfo{ 721 Shares: 1000, 722 Level: SharesLevelNormal, 723 }, 724 }, 725 MemoryAllocation: &ResourceAllocationInfo{ 726 Reservation: NewInt64(0), 727 ExpandableReservation: NewBool(false), 728 Limit: NewInt64(-1), 729 Shares: &SharesInfo{ 730 Shares: 20480, 731 Level: SharesLevelNormal, 732 }, 733 }, 734 LatencySensitivity: &LatencySensitivity{ 735 Level: LatencySensitivitySensitivityLevelNormal, 736 }, 737 MemoryHotAddEnabled: NewBool(false), 738 CpuHotAddEnabled: NewBool(false), 739 CpuHotRemoveEnabled: NewBool(false), 740 ExtraConfig: []BaseOptionValue{ 741 &OptionValue{Key: "nvram", Value: "test.nvram"}, 742 &OptionValue{Key: "svga.present", Value: "TRUE"}, 743 &OptionValue{Key: "pciBridge0.present", Value: "TRUE"}, 744 &OptionValue{Key: "pciBridge4.present", Value: "TRUE"}, 745 &OptionValue{Key: "pciBridge4.virtualDev", Value: "pcieRootPort"}, 746 &OptionValue{Key: "pciBridge4.functions", Value: "8"}, 747 &OptionValue{Key: "pciBridge5.present", Value: "TRUE"}, 748 &OptionValue{Key: "pciBridge5.virtualDev", Value: "pcieRootPort"}, 749 &OptionValue{Key: "pciBridge5.functions", Value: "8"}, 750 &OptionValue{Key: "pciBridge6.present", Value: "TRUE"}, 751 &OptionValue{Key: "pciBridge6.virtualDev", Value: "pcieRootPort"}, 752 &OptionValue{Key: "pciBridge6.functions", Value: "8"}, 753 &OptionValue{Key: "pciBridge7.present", Value: "TRUE"}, 754 &OptionValue{Key: "pciBridge7.virtualDev", Value: "pcieRootPort"}, 755 &OptionValue{Key: "pciBridge7.functions", Value: "8"}, 756 &OptionValue{Key: "hpet0.present", Value: "TRUE"}, 757 &OptionValue{Key: "RemoteDisplay.maxConnections", Value: "-1"}, 758 &OptionValue{Key: "sched.cpu.latencySensitivity", Value: "normal"}, 759 &OptionValue{Key: "vmware.tools.internalversion", Value: "0"}, 760 &OptionValue{Key: "vmware.tools.requiredversion", Value: "12352"}, 761 &OptionValue{Key: "migrate.hostLogState", Value: "none"}, 762 &OptionValue{Key: "migrate.migrationId", Value: "0"}, 763 &OptionValue{Key: "migrate.hostLog", Value: "test-36f94569.hlog"}, 764 &OptionValue{ 765 Key: "viv.moid", 766 Value: "c5b34aa9-d962-4a74-b7d2-b83ec683ba1b:vm-28:lIgQ2t7v24n2nl3N7K3m6IHW2OoPF4CFrJd5N+Tdfio=", 767 }, 768 }, 769 DatastoreUrl: []VirtualMachineConfigInfoDatastoreUrlPair{ 770 { 771 Name: "datastore1", 772 Url: "/vmfs/volumes/63970ed8-4abddd2a-62d7-02003f49c37d", 773 }, 774 }, 775 SwapPlacement: "inherit", 776 BootOptions: &VirtualMachineBootOptions{ 777 EnterBIOSSetup: NewBool(false), 778 EfiSecureBootEnabled: NewBool(false), 779 BootDelay: 1, 780 BootRetryEnabled: NewBool(false), 781 BootRetryDelay: 10000, 782 NetworkBootProtocol: "ipv4", 783 }, 784 FtInfo: nil, 785 RepConfig: nil, 786 VAppConfig: nil, 787 VAssertsEnabled: NewBool(false), 788 ChangeTrackingEnabled: NewBool(false), 789 Firmware: "bios", 790 MaxMksConnections: -1, 791 GuestAutoLockEnabled: NewBool(true), 792 ManagedBy: nil, 793 MemoryReservationLockedToMax: NewBool(false), 794 InitialOverhead: &VirtualMachineConfigInfoOverheadInfo{ 795 InitialMemoryReservation: 214446080, 796 InitialSwapReservation: 2541883392, 797 }, 798 NestedHVEnabled: NewBool(false), 799 VPMCEnabled: NewBool(false), 800 ScheduledHardwareUpgradeInfo: &ScheduledHardwareUpgradeInfo{ 801 UpgradePolicy: "never", 802 ScheduledHardwareUpgradeStatus: "none", 803 }, 804 ForkConfigInfo: nil, 805 VFlashCacheReservation: 0, 806 VmxConfigChecksum: []uint8{ 807 0x69, 0xf7, 0xa7, 0x9e, 808 0xd1, 0xc2, 0x21, 0x4b, 809 0x6c, 0x20, 0x77, 0x0a, 810 0x94, 0x94, 0x99, 0xee, 811 0x17, 0x5d, 0xdd, 0xa3, 812 }, 813 MessageBusTunnelEnabled: NewBool(false), 814 GuestIntegrityInfo: &VirtualMachineGuestIntegrityInfo{ 815 Enabled: NewBool(false), 816 }, 817 MigrateEncryption: "opportunistic", 818 SgxInfo: &VirtualMachineSgxInfo{ 819 FlcMode: "unlocked", 820 RequireAttestation: NewBool(false), 821 }, 822 ContentLibItemInfo: nil, 823 FtEncryptionMode: "ftEncryptionOpportunistic", 824 GuestMonitoringModeInfo: &VirtualMachineGuestMonitoringModeInfo{}, 825 SevEnabled: NewBool(false), 826 NumaInfo: &VirtualMachineVirtualNumaInfo{ 827 AutoCoresPerNumaNode: NewBool(true), 828 VnumaOnCpuHotaddExposed: NewBool(false), 829 }, 830 PmemFailoverEnabled: NewBool(false), 831 VmxStatsCollectionEnabled: NewBool(true), 832 VmOpNotificationToAppEnabled: NewBool(false), 833 VmOpNotificationTimeout: -1, 834 DeviceSwap: &VirtualMachineVirtualDeviceSwap{ 835 LsiToPvscsi: &VirtualMachineVirtualDeviceSwapDeviceSwapInfo{ 836 Enabled: NewBool(true), 837 Applicable: NewBool(false), 838 Status: "none", 839 }, 840 }, 841 Pmem: nil, 842 DeviceGroups: &VirtualMachineVirtualDeviceGroups{}, 843 } 844 845 var retrieveResultForTests = RetrieveResult{ 846 Token: "", 847 Objects: []ObjectContent{ 848 849 { 850 851 DynamicData: DynamicData{}, 852 Obj: ManagedObjectReference{ 853 854 Type: "Folder", 855 Value: "group-d1", 856 }, 857 PropSet: []DynamicProperty{ 858 { 859 860 Name: "alarmActionsEnabled", 861 Val: true, 862 }, 863 { 864 865 Name: "availableField", 866 Val: ArrayOfCustomFieldDef{ 867 868 CustomFieldDef: []CustomFieldDef{}, 869 }, 870 }, 871 872 { 873 874 Name: "childEntity", 875 Val: ArrayOfManagedObjectReference{ 876 ManagedObjectReference: []ManagedObjectReference{}, 877 }, 878 }, 879 { 880 Name: "childType", 881 Val: ArrayOfString{ 882 String: []string{ 883 "Folder", 884 "Datacenter"}, 885 }, 886 }, 887 { 888 Name: "configIssue", 889 Val: ArrayOfEvent{ 890 Event: []BaseEvent{}, 891 }, 892 }, 893 { 894 Name: "configStatus", 895 Val: ManagedEntityStatusGray}, 896 { 897 Name: "customValue", 898 Val: ArrayOfCustomFieldValue{ 899 CustomFieldValue: []BaseCustomFieldValue{}, 900 }, 901 }, 902 { 903 Name: "declaredAlarmState", 904 Val: ArrayOfAlarmState{ 905 AlarmState: []AlarmState{ 906 { 907 Key: "alarm-328.group-d1", 908 Entity: ManagedObjectReference{ 909 Type: "Folder", 910 Value: "group-d1"}, 911 Alarm: ManagedObjectReference{ 912 Type: "Alarm", 913 Value: "alarm-328"}, 914 OverallStatus: "gray", 915 Time: time.Date(2023, time.January, 14, 8, 57, 35, 279575000, time.UTC), 916 Acknowledged: NewBool(false), 917 }, 918 { 919 Key: "alarm-327.group-d1", 920 Entity: ManagedObjectReference{ 921 Type: "Folder", 922 Value: "group-d1"}, 923 Alarm: ManagedObjectReference{ 924 Type: "Alarm", 925 Value: "alarm-327"}, 926 OverallStatus: "green", 927 Time: time.Date(2023, time.January, 14, 8, 56, 40, 83607000, time.UTC), 928 Acknowledged: NewBool(false), 929 EventKey: 756, 930 }, 931 { 932 DynamicData: DynamicData{}, 933 Key: "alarm-326.group-d1", 934 Entity: ManagedObjectReference{ 935 Type: "Folder", 936 Value: "group-d1"}, 937 Alarm: ManagedObjectReference{ 938 Type: "Alarm", 939 Value: "alarm-326"}, 940 OverallStatus: "green", 941 Time: time.Date(2023, 942 time.January, 943 14, 944 8, 945 56, 946 35, 947 82616000, 948 time.UTC), 949 Acknowledged: NewBool(false), 950 EventKey: 751, 951 }, 952 }, 953 }, 954 }, 955 { 956 Name: "disabledMethod", 957 Val: ArrayOfString{ 958 String: []string{}, 959 }, 960 }, 961 { 962 Name: "effectiveRole", 963 Val: ArrayOfInt{ 964 Int: []int32{-1}, 965 }, 966 }, 967 { 968 Name: "name", 969 Val: "Datacenters"}, 970 { 971 Name: "overallStatus", 972 Val: ManagedEntityStatusGray}, 973 { 974 Name: "permission", 975 Val: ArrayOfPermission{ 976 Permission: []Permission{ 977 { 978 Entity: &ManagedObjectReference{ 979 Value: "group-d1", 980 Type: "Folder", 981 }, 982 Principal: "VSPHERE.LOCAL\\vmware-vsm-2bd917c6-e084-4d1f-988d-a68f7525cc94", 983 Group: false, 984 RoleId: 1034, 985 Propagate: true}, 986 { 987 Entity: &ManagedObjectReference{ 988 Value: "group-d1", 989 Type: "Folder", 990 }, 991 Principal: "VSPHERE.LOCAL\\topologysvc-2bd917c6-e084-4d1f-988d-a68f7525cc94", 992 Group: false, 993 RoleId: 1024, 994 Propagate: true}, 995 { 996 Entity: &ManagedObjectReference{ 997 Value: "group-d1", 998 Type: "Folder", 999 }, 1000 Principal: "VSPHERE.LOCAL\\vpxd-extension-2bd917c6-e084-4d1f-988d-a68f7525cc94", 1001 Group: false, 1002 RoleId: -1, 1003 Propagate: true}, 1004 }, 1005 }, 1006 }, 1007 { 1008 Name: "recentTask", 1009 Val: ArrayOfManagedObjectReference{ 1010 ManagedObjectReference: []ManagedObjectReference{ 1011 { 1012 Type: "Task", 1013 Value: "task-186"}, 1014 { 1015 Type: "Task", 1016 Value: "task-187"}, 1017 { 1018 Type: "Task", 1019 Value: "task-188"}, 1020 }, 1021 }, 1022 }, 1023 { 1024 Name: "tag", 1025 Val: ArrayOfTag{ 1026 Tag: []Tag{}, 1027 }, 1028 }, 1029 { 1030 Name: "triggeredAlarmState", 1031 Val: ArrayOfAlarmState{ 1032 AlarmState: []AlarmState{}, 1033 }, 1034 }, 1035 { 1036 Name: "value", 1037 Val: ArrayOfCustomFieldValue{ 1038 CustomFieldValue: []BaseCustomFieldValue{}, 1039 }, 1040 }, 1041 }, 1042 MissingSet: nil, 1043 }, 1044 }, 1045 } 1046 1047 func mustParseTime(layout, value string) time.Time { 1048 t, err := time.Parse(layout, value) 1049 if err != nil { 1050 panic(err) 1051 } 1052 return t 1053 } 1054 1055 func addrOfMustParseTime(layout, value string) *time.Time { 1056 t := mustParseTime(layout, value) 1057 return &t 1058 }