1/*
2Copyright (c) 2015 VMware, Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package object
18
19import (
20	"math/rand"
21	"reflect"
22	"testing"
23
24	"github.com/vmware/govmomi/vim25/types"
25)
26
27func intPtrValue(val int32) *int32 {
28	return &val
29}
30
31var devices = VirtualDeviceList([]types.BaseVirtualDevice{
32	&types.VirtualIDEController{
33		VirtualController: types.VirtualController{
34			VirtualDevice: types.VirtualDevice{
35				DynamicData: types.DynamicData{},
36				Key:         200,
37				DeviceInfo: &types.Description{
38					DynamicData: types.DynamicData{},
39					Label:       "IDE 0",
40					Summary:     "IDE 0",
41				},
42				Backing:       nil,
43				Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
44				SlotInfo:      nil,
45				ControllerKey: 0,
46				UnitNumber:    intPtrValue(0),
47			},
48			BusNumber: 0,
49			Device:    []int32{3001, 3000},
50		},
51	},
52	&types.VirtualIDEController{
53		VirtualController: types.VirtualController{
54			VirtualDevice: types.VirtualDevice{
55				DynamicData: types.DynamicData{},
56				Key:         201,
57				DeviceInfo: &types.Description{
58					DynamicData: types.DynamicData{},
59					Label:       "IDE 1",
60					Summary:     "IDE 1",
61				},
62				Backing:       nil,
63				Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
64				SlotInfo:      nil,
65				ControllerKey: 0,
66				UnitNumber:    intPtrValue(0),
67			},
68			BusNumber: 1,
69			Device:    []int32{3002},
70		},
71	},
72	&types.VirtualPS2Controller{
73		VirtualController: types.VirtualController{
74			VirtualDevice: types.VirtualDevice{
75				DynamicData: types.DynamicData{},
76				Key:         300,
77				DeviceInfo: &types.Description{
78					DynamicData: types.DynamicData{},
79					Label:       "PS2 controller 0",
80					Summary:     "PS2 controller 0",
81				},
82				Backing:       nil,
83				Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
84				SlotInfo:      nil,
85				ControllerKey: 0,
86				UnitNumber:    intPtrValue(0),
87			},
88			BusNumber: 0,
89			Device:    []int32{600, 700},
90		},
91	},
92	&types.VirtualPCIController{
93		VirtualController: types.VirtualController{
94			VirtualDevice: types.VirtualDevice{
95				DynamicData: types.DynamicData{},
96				Key:         100,
97				DeviceInfo: &types.Description{
98					DynamicData: types.DynamicData{},
99					Label:       "PCI controller 0",
100					Summary:     "PCI controller 0",
101				},
102				Backing:       nil,
103				Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
104				SlotInfo:      nil,
105				ControllerKey: 0,
106				UnitNumber:    intPtrValue(0),
107			},
108			BusNumber: 0,
109			Device:    []int32{500, 12000, 1000, 4000},
110		},
111	},
112	&types.VirtualSIOController{
113		VirtualController: types.VirtualController{
114			VirtualDevice: types.VirtualDevice{
115				DynamicData: types.DynamicData{},
116				Key:         400,
117				DeviceInfo: &types.Description{
118					DynamicData: types.DynamicData{},
119					Label:       "SIO controller 0",
120					Summary:     "SIO controller 0",
121				},
122				Backing:       nil,
123				Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
124				SlotInfo:      nil,
125				ControllerKey: 0,
126				UnitNumber:    intPtrValue(0),
127			},
128			BusNumber: 0,
129			Device:    []int32{9000},
130		},
131	},
132	&types.VirtualKeyboard{
133		VirtualDevice: types.VirtualDevice{
134			DynamicData: types.DynamicData{},
135			Key:         600,
136			DeviceInfo: &types.Description{
137				DynamicData: types.DynamicData{},
138				Label:       "Keyboard ",
139				Summary:     "Keyboard",
140			},
141			Backing:       nil,
142			Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
143			SlotInfo:      nil,
144			ControllerKey: 300,
145			UnitNumber:    intPtrValue(0),
146		},
147	},
148	&types.VirtualPointingDevice{
149		VirtualDevice: types.VirtualDevice{
150			DynamicData: types.DynamicData{},
151			Key:         700,
152			DeviceInfo: &types.Description{
153				DynamicData: types.DynamicData{},
154				Label:       "Pointing device",
155				Summary:     "Pointing device; Device",
156			},
157			Backing: &types.VirtualPointingDeviceDeviceBackingInfo{
158				VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{},
159				HostPointingDevice:             "autodetect",
160			},
161			Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
162			SlotInfo:      nil,
163			ControllerKey: 300,
164			UnitNumber:    intPtrValue(1),
165		},
166	},
167	&types.VirtualMachineVideoCard{
168		VirtualDevice: types.VirtualDevice{
169			DynamicData: types.DynamicData{},
170			Key:         500,
171			DeviceInfo: &types.Description{
172				DynamicData: types.DynamicData{},
173				Label:       "Video card ",
174				Summary:     "Video card",
175			},
176			Backing:       nil,
177			Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
178			SlotInfo:      nil,
179			ControllerKey: 100,
180			UnitNumber:    intPtrValue(0),
181		},
182		VideoRamSizeInKB: 4096,
183		NumDisplays:      1,
184		UseAutoDetect:    types.NewBool(false),
185		Enable3DSupport:  types.NewBool(false),
186		Use3dRenderer:    "automatic",
187	},
188	&types.VirtualMachineVMCIDevice{
189		VirtualDevice: types.VirtualDevice{
190			DynamicData: types.DynamicData{},
191			Key:         12000,
192			DeviceInfo: &types.Description{
193				DynamicData: types.DynamicData{},
194				Label:       "VMCI device",
195				Summary:     "Device on the virtual machine PCI bus that provides support for the virtual machine communication interface",
196			},
197			Backing:     nil,
198			Connectable: (*types.VirtualDeviceConnectInfo)(nil),
199			SlotInfo: &types.VirtualDevicePciBusSlotInfo{
200				VirtualDeviceBusSlotInfo: types.VirtualDeviceBusSlotInfo{},
201				PciSlotNumber:            33,
202			},
203			ControllerKey: 100,
204			UnitNumber:    intPtrValue(17),
205		},
206		Id: 1754519335,
207		AllowUnrestrictedCommunication: types.NewBool(false),
208	},
209	&types.VirtualLsiLogicController{
210		VirtualSCSIController: types.VirtualSCSIController{
211			VirtualController: types.VirtualController{
212				VirtualDevice: types.VirtualDevice{
213					DynamicData: types.DynamicData{},
214					Key:         1000,
215					DeviceInfo: &types.Description{
216						DynamicData: types.DynamicData{},
217						Label:       "SCSI controller 0",
218						Summary:     "LSI Logic",
219					},
220					Backing:       nil,
221					Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
222					SlotInfo:      nil,
223					ControllerKey: 100,
224					UnitNumber:    intPtrValue(3),
225				},
226				BusNumber: 0,
227				Device:    nil,
228			},
229			HotAddRemove:       types.NewBool(true),
230			SharedBus:          "noSharing",
231			ScsiCtlrUnitNumber: 7,
232		},
233	},
234	&types.VirtualCdrom{
235		VirtualDevice: types.VirtualDevice{
236			DynamicData: types.DynamicData{},
237			Key:         3001,
238			DeviceInfo: &types.Description{
239				DynamicData: types.DynamicData{},
240				Label:       "CD/DVD drive 1",
241				Summary:     "ISO [datastore1] ttylinux-pc_i486-16.1.iso",
242			},
243			Backing: &types.VirtualCdromIsoBackingInfo{
244				VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
245					VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
246					FileName:                 "[datastore1] foo.iso",
247					Datastore:                &types.ManagedObjectReference{Type: "Datastore", Value: "53fe43cc-75dc5110-3643-000c2918dc41"},
248					BackingObjectId:          "",
249				},
250			},
251			Connectable: &types.VirtualDeviceConnectInfo{
252				DynamicData:       types.DynamicData{},
253				StartConnected:    true,
254				AllowGuestControl: true,
255				Connected:         false,
256				Status:            "untried",
257			},
258			SlotInfo:      nil,
259			ControllerKey: 200,
260			UnitNumber:    intPtrValue(1),
261		},
262	},
263	&types.VirtualDisk{
264		VirtualDevice: types.VirtualDevice{
265			DynamicData: types.DynamicData{},
266			Key:         3000,
267			DeviceInfo: &types.Description{
268				DynamicData: types.DynamicData{},
269				Label:       "Hard disk 1",
270				Summary:     "30,720 KB",
271			},
272			Backing: &types.VirtualDiskFlatVer2BackingInfo{
273				VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
274					VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
275					FileName:                 "[datastore1] bar/bar.vmdk",
276					Datastore:                &types.ManagedObjectReference{Type: "Datastore", Value: "53fe43cc-75dc5110-3643-000c2918dc41"},
277					BackingObjectId:          "3-3000-0",
278				},
279				DiskMode:        "persistent",
280				Split:           types.NewBool(false),
281				WriteThrough:    types.NewBool(false),
282				ThinProvisioned: types.NewBool(false),
283				EagerlyScrub:    types.NewBool(true),
284				Uuid:            "6000C296-d0af-1209-1975-10c98eae10e4",
285				ContentId:       "d46395062e2d1b1790985bdec573b211",
286				ChangeId:        "",
287				Parent: &types.VirtualDiskFlatVer2BackingInfo{
288					VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
289						VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
290						FileName:                 "[datastore1] ttylinux.vmdk",
291						Datastore:                &types.ManagedObjectReference{Type: "Datastore", Value: "53fe43cc-75dc5110-3643-000c2918dc41"},
292						BackingObjectId:          "3-3000-1",
293					},
294					DiskMode:        "persistent",
295					Split:           types.NewBool(false),
296					WriteThrough:    types.NewBool(false),
297					ThinProvisioned: types.NewBool(false),
298					EagerlyScrub:    types.NewBool(true),
299					Uuid:            "6000C296-d0af-1209-1975-10c98eae10e4",
300					ContentId:       "1c2dad9e1662219e962a620c6d238a7c",
301					ChangeId:        "",
302					Parent:          (*types.VirtualDiskFlatVer2BackingInfo)(nil),
303					DeltaDiskFormat: "",
304					DigestEnabled:   types.NewBool(false),
305					DeltaGrainSize:  0,
306				},
307				DeltaDiskFormat: "redoLogFormat",
308				DigestEnabled:   types.NewBool(false),
309				DeltaGrainSize:  0,
310			},
311			Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
312			SlotInfo:      nil,
313			ControllerKey: 200,
314			UnitNumber:    intPtrValue(0),
315		},
316		CapacityInKB:    30720,
317		CapacityInBytes: 31457280,
318		Shares: &types.SharesInfo{
319			DynamicData: types.DynamicData{},
320			Shares:      1000,
321			Level:       "normal",
322		},
323		StorageIOAllocation: &types.StorageIOAllocationInfo{
324			DynamicData: types.DynamicData{},
325			Limit:       types.NewInt64(-1),
326			Shares: &types.SharesInfo{
327				DynamicData: types.DynamicData{},
328				Shares:      1000,
329				Level:       "normal",
330			},
331			Reservation: types.NewInt32(0),
332		},
333		DiskObjectId:          "3-3000",
334		VFlashCacheConfigInfo: (*types.VirtualDiskVFlashCacheConfigInfo)(nil),
335	},
336	&types.VirtualDisk{
337		VirtualDevice: types.VirtualDevice{
338			DynamicData: types.DynamicData{},
339			Key:         3002,
340			DeviceInfo: &types.Description{
341				DynamicData: types.DynamicData{},
342				Label:       "Hard disk 2",
343				Summary:     "10,000,000 KB",
344			},
345			Backing: &types.VirtualDiskFlatVer2BackingInfo{
346				VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
347					VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
348					FileName:                 "[datastore1] bar/disk-201-0.vmdk",
349					Datastore:                &types.ManagedObjectReference{Type: "Datastore", Value: "53fe43cc-75dc5110-3643-000c2918dc41"},
350					BackingObjectId:          "3-3002-0",
351				},
352				DiskMode:        "persistent",
353				Split:           types.NewBool(false),
354				WriteThrough:    types.NewBool(false),
355				ThinProvisioned: types.NewBool(true),
356				EagerlyScrub:    types.NewBool(false),
357				Uuid:            "6000C293-fde5-4457-5118-dd267ea992a7",
358				ContentId:       "90399989b9d520eed6793ab0fffffffe",
359				ChangeId:        "",
360				Parent:          (*types.VirtualDiskFlatVer2BackingInfo)(nil),
361				DeltaDiskFormat: "",
362				DigestEnabled:   types.NewBool(false),
363				DeltaGrainSize:  0,
364			},
365			Connectable:   (*types.VirtualDeviceConnectInfo)(nil),
366			SlotInfo:      nil,
367			ControllerKey: 201,
368			UnitNumber:    intPtrValue(0),
369		},
370		CapacityInKB:    10000000,
371		CapacityInBytes: 10240000000,
372		Shares: &types.SharesInfo{
373			DynamicData: types.DynamicData{},
374			Shares:      1000,
375			Level:       "normal",
376		},
377		StorageIOAllocation: &types.StorageIOAllocationInfo{
378			DynamicData: types.DynamicData{},
379			Limit:       types.NewInt64(-1),
380			Shares: &types.SharesInfo{
381				DynamicData: types.DynamicData{},
382				Shares:      1000,
383				Level:       "normal",
384			},
385			Reservation: types.NewInt32(0),
386		},
387		DiskObjectId:          "3-3002",
388		VFlashCacheConfigInfo: (*types.VirtualDiskVFlashCacheConfigInfo)(nil),
389	},
390	&types.VirtualE1000{
391		VirtualEthernetCard: types.VirtualEthernetCard{
392			VirtualDevice: types.VirtualDevice{
393				DynamicData: types.DynamicData{},
394				Key:         4000,
395				DeviceInfo: &types.Description{
396					DynamicData: types.DynamicData{},
397					Label:       "Network adapter 1",
398					Summary:     "VM Network",
399				},
400				Backing: &types.VirtualEthernetCardNetworkBackingInfo{
401					VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
402						VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
403						DeviceName:               "VM Network",
404						UseAutoDetect:            types.NewBool(false),
405					},
406					Network:           &types.ManagedObjectReference{Type: "Network", Value: "HaNetwork-VM Network"},
407					InPassthroughMode: types.NewBool(false),
408				},
409				Connectable: &types.VirtualDeviceConnectInfo{
410					DynamicData:       types.DynamicData{},
411					StartConnected:    true,
412					AllowGuestControl: true,
413					Connected:         false,
414					Status:            "untried",
415				},
416				SlotInfo: &types.VirtualDevicePciBusSlotInfo{
417					VirtualDeviceBusSlotInfo: types.VirtualDeviceBusSlotInfo{},
418					PciSlotNumber:            32,
419				},
420				ControllerKey: 100,
421				UnitNumber:    intPtrValue(7),
422			},
423			AddressType:      "generated",
424			MacAddress:       "00:0c:29:93:d7:27",
425			WakeOnLanEnabled: types.NewBool(true),
426		},
427	},
428	&types.VirtualSerialPort{
429		VirtualDevice: types.VirtualDevice{
430			DynamicData: types.DynamicData{},
431			Key:         9000,
432			DeviceInfo: &types.Description{
433				DynamicData: types.DynamicData{},
434				Label:       "Serial port 1",
435				Summary:     "Remote localhost:0",
436			},
437			Backing: &types.VirtualSerialPortURIBackingInfo{
438				VirtualDeviceURIBackingInfo: types.VirtualDeviceURIBackingInfo{
439					VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
440					ServiceURI:               "localhost:0",
441					Direction:                "client",
442					ProxyURI:                 "",
443				},
444			},
445			Connectable: &types.VirtualDeviceConnectInfo{
446				DynamicData:       types.DynamicData{},
447				StartConnected:    true,
448				AllowGuestControl: true,
449				Connected:         false,
450				Status:            "untried",
451			},
452			SlotInfo:      nil,
453			ControllerKey: 400,
454			UnitNumber:    intPtrValue(0),
455		},
456		YieldOnPoll: true,
457	},
458})
459
460func TestSelectByType(t *testing.T) {
461	tests := []struct {
462		dtype  types.BaseVirtualDevice
463		expect int
464	}{
465		{
466			(*types.VirtualCdrom)(nil),
467			1,
468		},
469		{
470			(*types.VirtualEthernetCard)(nil),
471			1,
472		},
473		{
474			(*types.VirtualDisk)(nil),
475			2,
476		},
477		{
478			(*types.VirtualController)(nil),
479			6,
480		},
481		{
482			(*types.VirtualIDEController)(nil),
483			2,
484		},
485		{
486			(*types.VirtualSCSIController)(nil),
487			1,
488		},
489		{
490			(*types.VirtualLsiLogicController)(nil),
491			1,
492		},
493		{
494			(*types.ParaVirtualSCSIController)(nil),
495			0,
496		},
497	}
498
499	for _, test := range tests {
500		d := devices.SelectByType(test.dtype)
501
502		if len(d) != test.expect {
503			t.Errorf("%#v has %d", test.dtype, len(devices))
504		}
505	}
506}
507
508func TestSelectByBackingInfo(t *testing.T) {
509	tests := []types.BaseVirtualDeviceBackingInfo{
510		&types.VirtualEthernetCardNetworkBackingInfo{
511			VirtualDeviceDeviceBackingInfo: types.VirtualDeviceDeviceBackingInfo{
512				DeviceName: "VM Network",
513			},
514		},
515		&types.VirtualDiskFlatVer2BackingInfo{
516			VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
517				FileName: "[datastore1] bar/bar.vmdk",
518			},
519		},
520		&types.VirtualDiskFlatVer2BackingInfo{
521			Parent: &types.VirtualDiskFlatVer2BackingInfo{
522				VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
523					FileName: "[datastore1] ttylinux.vmdk",
524				},
525			},
526		},
527		&types.VirtualCdromIsoBackingInfo{
528			VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
529				VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
530				FileName:                 "[datastore1] foo.iso",
531			},
532		},
533		(*types.VirtualCdromIsoBackingInfo)(nil),
534		&types.VirtualSerialPortURIBackingInfo{
535			VirtualDeviceURIBackingInfo: types.VirtualDeviceURIBackingInfo{
536				VirtualDeviceBackingInfo: types.VirtualDeviceBackingInfo{},
537				ServiceURI:               "localhost:0",
538				Direction:                "client",
539				ProxyURI:                 "",
540			},
541		},
542		(*types.VirtualSerialPortURIBackingInfo)(nil),
543	}
544
545	for _, test := range tests {
546		l := devices.SelectByBackingInfo(test)
547
548		if len(l) != 1 {
549			t.Errorf("Expected 1, got %d: %#v", len(l), test)
550		}
551	}
552
553	// test selecting by backing type
554	tests = []types.BaseVirtualDeviceBackingInfo{
555		(*types.VirtualDiskFlatVer2BackingInfo)(nil),
556	}
557
558	for _, test := range tests {
559		l := devices.SelectByBackingInfo(test)
560
561		if len(l) != 2 {
562			t.Errorf("Expected 2, got %d: %#v", len(l), test)
563		}
564	}
565}
566
567func TestFind(t *testing.T) {
568	for _, device := range devices {
569		name := devices.Name(device)
570		d := devices.Find(name)
571		if name != devices.Name(d) {
572			t.Errorf("expected name: %s, got: %s", name, devices.Name(d))
573		}
574	}
575
576	d := devices.Find("enoent")
577	if d != nil {
578		t.Errorf("unexpected: %#v", d)
579	}
580}
581
582func TestFindController(t *testing.T) {
583	for _, name := range []string{"", "ide-200"} {
584		_, err := devices.FindIDEController(name)
585		if err != nil {
586			t.Error(err)
587		}
588	}
589
590	for _, name := range []string{"", "lsilogic-1000"} {
591		_, err := devices.FindSCSIController(name)
592		if err != nil {
593			t.Error(err)
594		}
595	}
596
597	fns := []func() error{
598		func() error {
599			_, err := devices.FindIDEController("lsilogic-1000")
600			return err
601		},
602		func() error {
603			_, err := devices.FindSCSIController("ide-200")
604			return err
605		},
606	}
607
608	for _, f := range fns {
609		err := f()
610		if err == nil {
611			t.Error("should fail")
612		}
613	}
614}
615
616func TestPickController(t *testing.T) {
617	list := devices
618
619	tests := []struct {
620		ctype types.BaseVirtualController
621		key   int32
622		unit  int32
623	}{
624		{
625			(*types.VirtualIDEController)(nil), 201, 1,
626		},
627		{
628			(*types.VirtualSCSIController)(nil), 1000, 0,
629		},
630		{
631			(*types.VirtualSCSIController)(nil), 1000, 1,
632		},
633	}
634
635	for _, test := range tests {
636		c := list.PickController(test.ctype).GetVirtualController()
637
638		key := c.Key
639		if key != test.key {
640			t.Errorf("expected controller key: %d, got: %d\n", test.key, key)
641		}
642
643		unit := list.newUnitNumber(c)
644		if unit != test.unit {
645			t.Errorf("expected unit number: %d, got: %d\n", test.unit, unit)
646		}
647
648		dev := &types.VirtualDevice{
649			Key:           int32(rand.Int()),
650			UnitNumber:    new(int32),
651			ControllerKey: key,
652		}
653		*dev.UnitNumber = unit
654
655		list = append(list, dev)
656		c.Device = append(c.Device, dev.Key)
657	}
658
659	if list.PickController((*types.VirtualIDEController)(nil)) != nil {
660		t.Error("should be nil")
661	}
662
663	if list.PickController((*types.VirtualSCSIController)(nil)) == nil {
664		t.Errorf("should not be nil")
665	}
666}
667
668func TestCreateSCSIController(t *testing.T) {
669	for _, l := range []VirtualDeviceList{SCSIControllerTypes(), devices} {
670		_, err := l.CreateSCSIController("enoent")
671		if err == nil {
672			t.Error("should fail")
673		}
674
675		for _, name := range []string{"", "scsi", "pvscsi", "buslogic", "lsilogic", "lsilogic-sas"} {
676			_, err = l.CreateSCSIController(name)
677			if err != nil {
678				t.Error(err)
679			}
680		}
681	}
682}
683
684func TestCreateEthernetCard(t *testing.T) {
685	_, err := EthernetCardTypes().CreateEthernetCard("enoent", nil)
686	if err == nil {
687		t.Error("should fail")
688	}
689
690	for _, name := range []string{"", "e1000", "e1000e", "vmxnet3"} {
691		_, err := EthernetCardTypes().CreateEthernetCard(name, nil)
692		if err != nil {
693			t.Error(err)
694		}
695	}
696}
697
698func TestCdrom(t *testing.T) {
699	c, err := devices.FindCdrom("")
700	if err != nil {
701		t.Error(err)
702	}
703
704	d := devices.Find(devices.Name(c))
705
706	if c.Key != d.GetVirtualDevice().Key {
707		t.Error("device key mismatch")
708	}
709
710	for _, name := range []string{"enoent", "ide-200"} {
711		c, err = devices.FindCdrom(name)
712		if err == nil {
713			t.Errorf("FindCdrom(%s) should fail", name)
714		}
715	}
716
717	c, err = devices.Select(func(device types.BaseVirtualDevice) bool {
718		if _, ok := device.(*types.VirtualCdrom); ok {
719			return false
720		}
721		return true
722	}).FindCdrom("")
723
724	if err == nil {
725		t.Error("FindCdrom('') should fail")
726	}
727}
728
729func TestSerialPort(t *testing.T) {
730	device, err := devices.CreateSerialPort()
731	if err != nil {
732		t.Error(err)
733	}
734	devices.ConnectSerialPort(device, "telnet://:33233", false, "")
735}
736
737func TestPrimaryMacAddress(t *testing.T) {
738	expect := "00:0c:29:93:d7:27"
739	mac := devices.PrimaryMacAddress()
740	if expect != mac {
741		t.Errorf("expected: %s, got: %s", expect, mac)
742	}
743}
744
745func TestBootOrder(t *testing.T) {
746	o := []string{DeviceTypeEthernet, DeviceTypeCdrom, DeviceTypeFloppy, DeviceTypeDisk}
747	list := devices
748
749	n := 4 // 1 ethernet, 1 cdrom, 2 disk
750	order := list.BootOrder(o)
751	if len(order) != n {
752		t.Errorf("expected %d boot devices, got: %d", n, len(order))
753	}
754
755	list = list.SelectBootOrder(order)
756	if len(list) != n {
757		t.Errorf("expected %d boot devices, got: %d", n, len(list))
758	}
759
760	// test lookup by name
761	var names []string
762	for _, x := range list {
763		names = append(names, list.Name(x))
764	}
765
766	order = list.BootOrder(names)
767	if len(order) != n {
768		t.Errorf("expected %d boot devices, got: %d", n, len(order))
769	}
770
771	if !reflect.DeepEqual(list, list.SelectBootOrder(order)) {
772		t.Error("boot order mismatch")
773	}
774
775	// remove disks
776	list = list.Select(func(device types.BaseVirtualDevice) bool {
777		if _, ok := device.(*types.VirtualDisk); ok {
778			return false
779		}
780		return true
781	})
782
783	n = 2 // 1 ethernet, 1 cdrom
784	order = list.BootOrder(o)
785	if len(order) != n {
786		t.Errorf("expected %d boot devices, got: %d", n, len(order))
787	}
788
789	if !reflect.DeepEqual(list, list.SelectBootOrder(order)) {
790		t.Error("boot order mismatch")
791	}
792
793	if len(list.BootOrder([]string{DeviceTypeDisk})) != 0 {
794		t.Error("expected 0 disks")
795	}
796
797	if len(list.BootOrder([]string{DeviceTypeNone})) != 1 {
798		t.Error("expected 1")
799	}
800}
801
802func TestName(t *testing.T) {
803	tests := []struct {
804		device types.BaseVirtualDevice
805		expect string
806	}{
807		{
808			&types.VirtualCdrom{},
809			"cdrom-0",
810		},
811		{
812			&types.VirtualDisk{},
813			"disk-0-0",
814		},
815		{
816			&types.VirtualFloppy{},
817			"floppy-0",
818		},
819		{
820			&types.VirtualIDEController{},
821			"ide-0",
822		},
823		{
824			&types.VirtualMachineVideoCard{},
825			"video-0",
826		},
827		{
828			&types.VirtualPointingDevice{},
829			"pointing-0",
830		},
831		{
832			&types.ParaVirtualSCSIController{},
833			"pvscsi-0",
834		},
835		{
836			&types.VirtualSerialPort{},
837			"serialport-0",
838		},
839		{
840			&types.VirtualE1000{
841				VirtualEthernetCard: types.VirtualEthernetCard{
842					VirtualDevice: types.VirtualDevice{
843						UnitNumber: intPtrValue(7),
844					},
845				},
846			},
847			"ethernet-0",
848		},
849	}
850
851	for _, test := range tests {
852		name := devices.Name(test.device)
853		if name != test.expect {
854			t.Errorf("expected: %s, got: %s", test.expect, name)
855		}
856	}
857}
858
859func TestChildDisk(t *testing.T) {
860	disks := devices.SelectByType((*types.VirtualDisk)(nil))
861
862	for _, disk := range disks {
863		child := disks.ChildDisk(disk.(*types.VirtualDisk))
864		name := child.Backing.(*types.VirtualDiskFlatVer2BackingInfo).VirtualDeviceFileBackingInfo.FileName
865
866		p := new(DatastorePath)
867		p.FromString(name)
868
869		if p.Datastore != "datastore1" {
870			t.Fatal(p.Datastore)
871		}
872
873		if p.Path != "" {
874			t.Fatal(p.Path)
875		}
876	}
877}
878