github.com/vmware/govmomi@v0.37.2/vim25/types/json_test.go (about)

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