// ObjectContentToType loads an ObjectContent value into the value it // represents. If the ObjectContent value has a non-empty 'MissingSet' field, // it returns the first fault it finds there as error. If the 'MissingSet' // field is empty, it returns a pointer to a reflect.Value. It handles contain // nested properties, such as 'guest.ipAddress' or 'config.hardware'. func ObjectContentToType(o types.ObjectContent) (interface{}, error) { // Expect no properties in the missing set for _, p := range o.MissingSet { if ignoreMissingProperty(o.Obj, p) { continue } return nil, soap.WrapVimFault(p.Fault.Fault) } ti := typeInfoForType(o.Obj.Type) v, err := ti.LoadFromObjectContent(o) if err != nil { return nil, err } return v.Elem().Interface(), nil }
// TestSoapFaults covers the various soap fault checking paths func TestSoapFaults(t *testing.T) { ctx := context.Background() // Nothing VC specific in this test, so we use the simpler ESX model model := simulator.ESX() defer model.Remove() err := model.Create() if err != nil { t.Fatal(err) } server := model.Service.NewServer() defer server.Close() client, err := govmomi.NewClient(ctx, server.URL, true) if err != nil { t.Fatal(err) } // Any VM will do finder := find.NewFinder(client.Client, false) vm, err := finder.VirtualMachine(ctx, "/ha-datacenter/vm/*_VM0") if err != nil { t.Fatal(err) } // Test the success path err = Wait(ctx, func(ctx context.Context) (Task, error) { return vm.PowerOn(ctx) }) if err != nil { t.Fatal(err) } // Wrap existing vm MO with faultyVirtualMachine ref := simulator.Map.Get(vm.Reference()) fvm := &faultyVirtualMachine{*ref.(*simulator.VirtualMachine), nil} simulator.Map.Put(fvm) // Inject TaskInProgress fault fvm.fault = new(types.TaskInProgress) task, err := vm.PowerOff(ctx) if err != nil { t.Fatal(err) } // Test the task.Error path res, err := task.WaitForResult(ctx, nil) if !isTaskInProgress(err) { t.Error(err) } // Test the soap.IsVimFault() path if !isTaskInProgress(soap.WrapVimFault(res.Error.Fault)) { t.Errorf("fault=%#v", res.Error.Fault) } // Test the soap.IsSoapFault() path err = vm.MarkAsTemplate(ctx) if !isTaskInProgress(err) { t.Error(err) } // Test a fault other than TaskInProgress fvm.fault = &types.QuestionPending{ Text: "now why would you want to do such a thing?", } err = Wait(ctx, func(ctx context.Context) (Task, error) { return vm.PowerOff(ctx) }) if err == nil { t.Error("expected error") } if isTaskInProgress(err) { t.Error(err) } // Test with retry fvm.fault = new(types.TaskInProgress) called := 0 err = Wait(ctx, func(ctx context.Context) (Task, error) { called++ if called > 1 { simulator.Map.Put(ref) // remove fault injection } return vm.PowerOff(ctx) }) if err != nil { t.Error(err) } if called != 2 { t.Errorf("called=%d", called) } }