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