github.com/vmware/govmomi@v0.37.2/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  }