github.com/vmware/govmomi@v0.43.0/simulator/race_test.go (about) 1 /* 2 Copyright (c) 2018 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 simulator 18 19 import ( 20 "context" 21 "fmt" 22 "sync" 23 "testing" 24 "time" 25 26 "github.com/vmware/govmomi" 27 "github.com/vmware/govmomi/event" 28 "github.com/vmware/govmomi/find" 29 "github.com/vmware/govmomi/property" 30 "github.com/vmware/govmomi/task" 31 "github.com/vmware/govmomi/view" 32 "github.com/vmware/govmomi/vim25/types" 33 ) 34 35 func TestRace(t *testing.T) { 36 ctx := context.Background() 37 38 m := VPX() 39 40 defer m.Remove() 41 42 err := m.Create() 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 s := m.Service.NewServer() 48 defer s.Close() 49 50 c, err := govmomi.NewClient(ctx, s.URL, true) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 content := c.Client.ServiceContent 56 57 wctx, cancel := context.WithCancel(ctx) 58 var wg, collectors sync.WaitGroup 59 60 nevents := -1 61 em := event.NewManager(c.Client) 62 63 wg.Add(1) 64 collectors.Add(1) 65 go func() { 66 defer collectors.Done() 67 68 werr := em.Events(wctx, []types.ManagedObjectReference{content.RootFolder}, 50, true, false, 69 func(_ types.ManagedObjectReference, e []types.BaseEvent) error { 70 if nevents == -1 { 71 wg.Done() // make sure we are called at least once before cancel() below 72 nevents = 0 73 } 74 75 nevents += len(e) 76 return nil 77 }) 78 if werr != nil { 79 t.Error(werr) 80 } 81 }() 82 83 collectors.Add(1) 84 go func() { 85 defer collectors.Done() 86 87 ec, werr := em.CreateCollectorForEvents(ctx, types.EventFilterSpec{}) 88 if werr != nil { 89 t.Error(werr) 90 } 91 92 n := 0 93 for { 94 events, werr := ec.ReadNextEvents(ctx, 10) 95 if werr != nil { 96 t.Error(werr) 97 } 98 99 n += len(events) 100 if len(events) != 0 { 101 continue 102 } 103 104 select { 105 case <-wctx.Done(): 106 logf := t.Logf 107 if n == 0 { 108 logf = t.Errorf 109 } 110 logf("ReadNextEvents=%d", n) 111 return 112 case <-time.After(time.Millisecond * 100): 113 } 114 } 115 }() 116 117 ntasks := -1 118 tv, err := view.NewManager(c.Client).CreateTaskView(ctx, content.TaskManager) 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 lv, err := view.NewManager(c.Client).CreateListView(ctx, nil) 124 if err != nil { 125 t.Fatal(err) 126 } 127 128 wg.Add(1) 129 collectors.Add(1) 130 go func() { 131 defer collectors.Done() 132 133 werr := tv.Collect(ctx, func(tasks []types.TaskInfo) { 134 if ntasks == -1 { 135 wg.Done() // make sure we are called at least once before cancel() below 136 ntasks = 0 137 } 138 ntasks += len(tasks) 139 }) 140 if werr != nil { 141 t.Error(werr) 142 } 143 }() 144 145 for i := 0; i < 2; i++ { 146 spec := types.VirtualMachineConfigSpec{ 147 Name: fmt.Sprintf("race-test-%d", i), 148 GuestId: string(types.VirtualMachineGuestOsIdentifierOtherGuest), 149 Files: &types.VirtualMachineFileInfo{ 150 VmPathName: "[LocalDS_0]", 151 }, 152 } 153 154 wg.Add(1) 155 go func() { 156 defer wg.Done() 157 158 finder := find.NewFinder(c.Client, false) 159 pc := property.DefaultCollector(c.Client) 160 dc, err := finder.DefaultDatacenter(ctx) 161 if err != nil { 162 t.Error(err) 163 } 164 165 finder.SetDatacenter(dc) 166 167 f, err := dc.Folders(ctx) 168 if err != nil { 169 t.Error(err) 170 } 171 172 pool, err := finder.ResourcePool(ctx, "DC0_C0/Resources") 173 if err != nil { 174 t.Error(err) 175 } 176 177 for j := 0; j < 2; j++ { 178 cspec := spec // copy spec and give it a unique name 179 cspec.Name += fmt.Sprintf("-%d", j) 180 181 wg.Add(1) 182 go func() { 183 defer wg.Done() 184 185 task, _ := f.VmFolder.CreateVM(ctx, cspec, pool, nil) 186 r, terr := task.WaitForResult(ctx, nil) 187 if terr != nil { 188 t.Error(terr) 189 } 190 _, terr = lv.Add(ctx, []types.ManagedObjectReference{r.Result.(types.ManagedObjectReference)}) 191 if terr != nil { 192 t.Error(terr) 193 } 194 }() 195 } 196 197 vms, err := finder.VirtualMachineList(ctx, "*") 198 if err != nil { 199 t.Error(err) 200 } 201 202 for i := range vms { 203 props := []string{"runtime.powerState"} 204 vm := vms[i] 205 206 wg.Add(1) 207 go func() { 208 defer wg.Done() 209 210 werr := property.Wait(ctx, pc, vm.Reference(), props, func(changes []types.PropertyChange) bool { 211 for _, change := range changes { 212 if change.Name != props[0] { 213 t.Errorf("unexpected property: %s", change.Name) 214 } 215 if change.Val == types.VirtualMachinePowerStatePoweredOff { 216 return true 217 } 218 } 219 220 wg.Add(1) 221 time.AfterFunc(100*time.Millisecond, func() { 222 defer wg.Done() 223 224 _, _ = lv.Remove(ctx, []types.ManagedObjectReference{vm.Reference()}) 225 task, _ := vm.PowerOff(ctx) 226 _ = task.Wait(ctx) 227 }) 228 229 return false 230 231 }) 232 if werr != nil { 233 if werr != context.Canceled { 234 t.Error(werr) 235 } 236 } 237 }() 238 } 239 }() 240 } 241 242 wg.Wait() 243 244 // cancel event and tasks collectors, waiting for them to complete 245 cancel() 246 collectors.Wait() 247 248 t.Logf("collected %d events, %d tasks", nevents, ntasks) 249 if nevents == 0 { 250 t.Error("no events collected") 251 } 252 if ntasks == 0 { 253 t.Error("no tasks collected") 254 } 255 } 256 257 func isManagedObjectNotFound(err error) bool { 258 _, ok := err.(task.Error).Fault().(*types.ManagedObjectNotFound) 259 return ok 260 } 261 262 // Race VirtualMachine.Destroy vs Folder.Destroy; the latter removes the VM parent and the former should not panic in that case 263 func TestRaceDestroy(t *testing.T) { 264 ctx := context.Background() 265 266 m := VPX() 267 m.Folder = 1 268 m.Autostart = false 269 defer m.Remove() 270 271 err := m.Create() 272 if err != nil { 273 t.Fatal(err) 274 } 275 276 s := m.Service.NewServer() 277 defer s.Close() 278 279 c, err := govmomi.NewClient(ctx, s.URL, true) 280 if err != nil { 281 t.Fatal(err) 282 } 283 284 finder := find.NewFinder(c.Client) 285 vms, err := finder.VirtualMachineList(ctx, "*") 286 if err != nil { 287 t.Fatal(err) 288 } 289 290 folder, err := finder.Folder(ctx, "vm/F0") 291 if err != nil { 292 t.Fatal(err) 293 } 294 295 notFound := false 296 var wg sync.WaitGroup 297 298 wg.Add(1) 299 go func() { 300 defer wg.Done() 301 for _, vm := range vms { 302 task, err := vm.Destroy(ctx) 303 if err != nil { 304 t.Error(err) 305 } 306 err = task.Wait(ctx) 307 if err != nil { 308 if isManagedObjectNotFound(err) { 309 notFound = true 310 } else { 311 t.Error(err) 312 } 313 } 314 } 315 }() 316 317 wg.Add(1) 318 go func() { 319 defer wg.Done() 320 task, err := folder.Destroy(ctx) 321 if err != nil { 322 t.Error(err) 323 } 324 err = task.Wait(ctx) 325 if err != nil { 326 t.Error(err) 327 } 328 }() 329 330 wg.Wait() 331 332 if !notFound { 333 t.Error("expected ManagedObjectNotFound") 334 } 335 }