1/*
2Copyright (c) 2017 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 simulator
18
19import (
20	"context"
21	"reflect"
22	"testing"
23
24	"github.com/google/uuid"
25
26	"github.com/vmware/govmomi/find"
27	"github.com/vmware/govmomi/object"
28	"github.com/vmware/govmomi/simulator/esx"
29	"github.com/vmware/govmomi/vim25/mo"
30	"github.com/vmware/govmomi/vim25/soap"
31	"github.com/vmware/govmomi/vim25/types"
32)
33
34func TestResourcePool(t *testing.T) {
35	ctx := context.Background()
36
37	m := &Model{
38		ServiceContent: esx.ServiceContent,
39		RootFolder:     esx.RootFolder,
40	}
41
42	err := m.Create()
43	if err != nil {
44		t.Fatal(err)
45	}
46
47	c := m.Service.client
48
49	finder := find.NewFinder(c, false)
50	finder.SetDatacenter(object.NewDatacenter(c, esx.Datacenter.Reference()))
51
52	spec := types.DefaultResourceConfigSpec()
53
54	parent := object.NewResourcePool(c, esx.ResourcePool.Self)
55
56	spec.CpuAllocation.Reservation = nil
57	// missing required field (Reservation) for create
58	_, err = parent.Create(ctx, "fail", spec)
59	if err == nil {
60		t.Error("expected error")
61	}
62	spec = types.DefaultResourceConfigSpec()
63
64	// can't destroy a root pool
65	task, err := parent.Destroy(ctx)
66	if err != nil {
67		t.Fatal(err)
68	}
69	if err = task.Wait(ctx); err == nil {
70		t.Fatal("expected error destroying a root pool")
71	}
72
73	// create a child pool
74	childName := uuid.New().String()
75
76	child, err := parent.Create(ctx, childName, spec)
77	if err != nil {
78		t.Fatal(err)
79	}
80
81	if child.Reference() == esx.ResourcePool.Self {
82		t.Error("expected new pool Self reference")
83	}
84
85	*spec.CpuAllocation.Reservation = -1
86	// invalid field value (Reservation) for update
87	err = child.UpdateConfig(ctx, "", &spec)
88	if err == nil {
89		t.Error("expected error")
90	}
91
92	// valid config update
93	*spec.CpuAllocation.Reservation = 10
94	err = child.UpdateConfig(ctx, "", &spec)
95	if err != nil {
96		t.Error(err)
97	}
98
99	var p mo.ResourcePool
100	err = child.Properties(ctx, child.Reference(), []string{"config.cpuAllocation"}, &p)
101	if err != nil {
102		t.Error(err)
103	}
104
105	if *p.Config.CpuAllocation.Reservation != 10 {
106		t.Error("config not updated")
107	}
108
109	// duplicate name
110	_, err = parent.Create(ctx, childName, spec)
111	if err == nil {
112		t.Error("expected error")
113	}
114
115	// create a grandchild pool
116	grandChildName := uuid.New().String()
117	_, err = child.Create(ctx, grandChildName, spec)
118	if err != nil {
119		t.Fatal(err)
120	}
121
122	// create sibling (of the grand child) pool
123	siblingName := uuid.New().String()
124	_, err = child.Create(ctx, siblingName, spec)
125	if err != nil {
126		t.Fatal(err)
127	}
128
129	// finder should return the 2 grand children
130	pools, err := finder.ResourcePoolList(ctx, "*/Resources/"+childName+"/*")
131	if err != nil {
132		t.Fatal(err)
133	}
134	if len(pools) != 2 {
135		t.Fatalf("len(pools) == %d", len(pools))
136	}
137
138	// destroy the child
139	task, err = child.Destroy(ctx)
140	if err != nil {
141		t.Fatal(err)
142	}
143	err = task.Wait(ctx)
144	if err != nil {
145		t.Fatal(err)
146	}
147
148	// finder should error not found after destroying the child
149	_, err = finder.ResourcePoolList(ctx, "*/Resources/"+childName+"/*")
150	if err == nil {
151		t.Fatal("expected not found error")
152	}
153
154	// since the child was destroyed, grand child pools should now be children of the root pool
155	pools, err = finder.ResourcePoolList(ctx, "*/Resources/*")
156	if err != nil {
157		t.Fatal(err)
158	}
159
160	if len(pools) != 2 {
161		t.Fatalf("len(pools) == %d", len(pools))
162	}
163}
164
165func TestCreateVAppESX(t *testing.T) {
166	ctx := context.Background()
167
168	m := ESX()
169	m.Datastore = 0
170	m.Machine = 0
171
172	err := m.Create()
173	if err != nil {
174		t.Fatal(err)
175	}
176
177	c := m.Service.client
178
179	parent := object.NewResourcePool(c, esx.ResourcePool.Self)
180
181	rspec := types.DefaultResourceConfigSpec()
182	vspec := NewVAppConfigSpec()
183
184	_, err = parent.CreateVApp(ctx, "myapp", rspec, vspec, nil)
185	if err == nil {
186		t.Fatal("expected error")
187	}
188
189	fault := soap.ToSoapFault(err).Detail.Fault
190
191	if reflect.TypeOf(fault) != reflect.TypeOf(&types.MethodDisabled{}) {
192		t.Errorf("fault=%#v", fault)
193	}
194}
195
196func TestCreateVAppVPX(t *testing.T) {
197	ctx := context.Background()
198
199	m := VPX()
200
201	err := m.Create()
202	if err != nil {
203		t.Fatal(err)
204	}
205
206	defer m.Remove()
207
208	c := m.Service.client
209
210	parent := object.NewResourcePool(c, Map.Any("ResourcePool").Reference())
211
212	rspec := types.DefaultResourceConfigSpec()
213	vspec := NewVAppConfigSpec()
214
215	vapp, err := parent.CreateVApp(ctx, "myapp", rspec, vspec, nil)
216	if err != nil {
217		t.Fatal(err)
218	}
219
220	_, err = parent.CreateVApp(ctx, "myapp", rspec, vspec, nil)
221	if err == nil {
222		t.Error("expected error")
223	}
224
225	spec := types.VirtualMachineConfigSpec{
226		GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest),
227		Files: &types.VirtualMachineFileInfo{
228			VmPathName: "[LocalDS_0]",
229		},
230	}
231
232	for _, fail := range []bool{true, false} {
233		task, cerr := vapp.CreateChildVM(ctx, spec, nil)
234		if cerr != nil {
235			t.Fatal(err)
236		}
237
238		cerr = task.Wait(ctx)
239		if fail {
240			if cerr == nil {
241				t.Error("expected error")
242			}
243		} else {
244			if cerr != nil {
245				t.Error(err)
246			}
247		}
248
249		spec.Name = "test"
250	}
251
252	si := object.NewSearchIndex(c)
253	vm, err := si.FindChild(ctx, vapp, spec.Name)
254	if err != nil {
255		t.Fatal(err)
256	}
257
258	if vm == nil {
259		t.Errorf("FindChild(%s)==nil", spec.Name)
260	}
261
262	task, err := vapp.Destroy(ctx)
263	if err != nil {
264		t.Fatal(err)
265	}
266
267	err = task.Wait(ctx)
268	if err != nil {
269		t.Fatal(err)
270	}
271}
272
273func TestResourcePoolValidation(t *testing.T) {
274	tests := []func() bool{
275		func() bool {
276			return allResourceFieldsSet(&types.ResourceAllocationInfo{})
277		},
278		func() bool {
279			spec := types.DefaultResourceConfigSpec()
280			spec.CpuAllocation.Limit = nil
281			return allResourceFieldsSet(&spec.CpuAllocation)
282		},
283		func() bool {
284			spec := types.DefaultResourceConfigSpec()
285			spec.CpuAllocation.Reservation = nil
286			return allResourceFieldsSet(&spec.CpuAllocation)
287		},
288		func() bool {
289			spec := types.DefaultResourceConfigSpec()
290			spec.CpuAllocation.ExpandableReservation = nil
291			return allResourceFieldsSet(&spec.CpuAllocation)
292		},
293		func() bool {
294			spec := types.DefaultResourceConfigSpec()
295			spec.CpuAllocation.Shares = nil
296			return allResourceFieldsSet(&spec.CpuAllocation)
297		},
298		func() bool {
299			spec := types.DefaultResourceConfigSpec()
300			spec.CpuAllocation.Reservation = types.NewInt64(-1)
301			return allResourceFieldsValid(&spec.CpuAllocation)
302		},
303		func() bool {
304			spec := types.DefaultResourceConfigSpec()
305			spec.CpuAllocation.Limit = types.NewInt64(-100)
306			return allResourceFieldsValid(&spec.CpuAllocation)
307		},
308		func() bool {
309			spec := types.DefaultResourceConfigSpec()
310			shares := spec.CpuAllocation.Shares
311			shares.Level = types.SharesLevelCustom
312			shares.Shares = -1
313			return allResourceFieldsValid(&spec.CpuAllocation)
314		},
315	}
316
317	for i, test := range tests {
318		ok := test()
319		if ok {
320			t.Errorf("%d: expected false", i)
321		}
322	}
323}
324