github.com/vmware/govmomi@v0.51.0/vim25/retry_test.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package vim25_test 6 7 import ( 8 "context" 9 "net/http" 10 "testing" 11 "time" 12 13 "github.com/vmware/govmomi/find" 14 "github.com/vmware/govmomi/simulator" 15 "github.com/vmware/govmomi/vim25" 16 "github.com/vmware/govmomi/vim25/soap" 17 "github.com/vmware/govmomi/vim25/types" 18 ) 19 20 type tempError struct{} 21 22 func (tempError) Error() string { return "tempError" } 23 func (tempError) Timeout() bool { return true } 24 func (tempError) Temporary() bool { return true } 25 26 type nonTempError struct{} 27 28 func (nonTempError) Error() string { return "nonTempError" } 29 func (nonTempError) Timeout() bool { return false } 30 func (nonTempError) Temporary() bool { return false } 31 32 type fakeRoundTripper struct { 33 errs []error 34 } 35 36 func (f *fakeRoundTripper) RoundTrip(ctx context.Context, req, res soap.HasFault) error { 37 err := f.errs[0] 38 f.errs = f.errs[1:] 39 return err 40 } 41 42 func TestRetry(t *testing.T) { 43 var tcs = []struct { 44 errs []error 45 expected error 46 }{ 47 { 48 errs: []error{nil}, 49 expected: nil, 50 }, 51 { 52 errs: []error{tempError{}, nil}, 53 expected: nil, 54 }, 55 { 56 errs: []error{tempError{}, tempError{}}, 57 expected: tempError{}, 58 }, 59 { 60 errs: []error{nonTempError{}}, 61 expected: nonTempError{}, 62 }, 63 { 64 errs: []error{tempError{}, nonTempError{}}, 65 expected: nonTempError{}, 66 }, 67 } 68 69 for _, tc := range tcs { 70 var rt soap.RoundTripper = &fakeRoundTripper{errs: tc.errs} 71 rt = vim25.Retry(rt, vim25.RetryTemporaryNetworkError, 2) 72 73 err := rt.RoundTrip(context.TODO(), nil, nil) 74 if err != tc.expected { 75 t.Errorf("Expected: %s, got: %s", tc.expected, err) 76 } 77 } 78 } 79 80 func TestRetryNetworkError(t *testing.T) { 81 simulator.Test(func(ctx context.Context, c *vim25.Client) { 82 c.RoundTripper = vim25.Retry(c.Client, vim25.RetryTemporaryNetworkError, 2) 83 84 vm, err := find.NewFinder(c).VirtualMachine(ctx, "DC0_H0_VM0") 85 if err != nil { 86 t.Fatal(err) 87 } 88 89 // Tell vcsim to respond with 502 on the 1st request 90 simulator.StatusSDK = http.StatusBadGateway 91 92 state, err := vm.PowerState(ctx) 93 if err != nil { 94 t.Fatal(err) 95 } 96 97 if state != types.VirtualMachinePowerStatePoweredOn { 98 t.Errorf("state=%s", state) 99 } 100 101 retry := func(err error) (bool, time.Duration) { 102 simulator.StatusSDK = http.StatusBadGateway // Tell vcsim to respond with 502 on every request 103 return vim25.IsTemporaryNetworkError(err), 0 104 } 105 c.RoundTripper = vim25.Retry(c.Client, retry, 2) 106 107 simulator.StatusSDK = http.StatusBadGateway 108 // beyond max retry attempts, should result in an erro 109 for i := 0; i < 3; i++ { 110 _, err = vm.PowerState(ctx) 111 } 112 113 if err == nil { 114 t.Error("expected error") 115 } 116 117 if !vim25.IsTemporaryNetworkError(err) { 118 t.Errorf("unexpected error=%s", err) 119 } 120 simulator.StatusSDK = http.StatusOK 121 }) 122 }