github.com/0chain/gosdk@v1.17.11/core/resty/resty_test.go (about)

     1  package resty
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/0chain/gosdk/core/resty/mocks"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestResty(t *testing.T) {
    18  
    19  	tests := []struct {
    20  		name string
    21  		urls []string
    22  
    23  		statusCode  int
    24  		expectedErr error
    25  		setup       func(a *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty)
    26  	}{
    27  		{
    28  			name:        "Test_Resty_Cancel_With_Timeout",
    29  			expectedErr: context.DeadlineExceeded,
    30  			urls:        []string{"Test_Resty_Timeout_1", "Test_Resty_Timeout_2", "Test_Resty_Timeout_3"},
    31  			setup:       getSetupFuncForCtxDeadlineExtendedTest(),
    32  		},
    33  		{
    34  			name:        "Test_Resty_All_Success",
    35  			statusCode:  200,
    36  			expectedErr: nil,
    37  			urls:        []string{"http://Test_Resty_Success_1", "http://Test_Resty_Success_2"},
    38  			setup:       getSetupFuncForAllSuccessTest(),
    39  		},
    40  		{
    41  			name:        "Test_Resty_Failed_Due_To_Handler_Failing",
    42  			expectedErr: fmt.Errorf("handler returned error"),
    43  			urls:        []string{"http://Test_Resty_Failure_1", "http://Test_Resty_Failure_2"},
    44  			setup:       getSetupFuncForHandlerErrorTest(),
    45  		},
    46  		{
    47  			name:        "Test_Resty_Failed_Due_To_Interceptor_Error",
    48  			expectedErr: fmt.Errorf("interceptor returned with error"),
    49  			urls:        []string{"http://Test_Resty_Failure_1", "http://Test_Resty_Failure_2"},
    50  			setup:       getSetupFuncForInterceptorErrorTest(),
    51  		},
    52  	}
    53  	for _, tt := range tests {
    54  		t.Run(tt.name, func(t *testing.T) {
    55  			r := require.New(t)
    56  			ctx, resty := tt.setup(r, tt.name, tt.statusCode, tt.urls)
    57  			resty.DoGet(ctx, tt.urls...)
    58  			errs := resty.Wait()
    59  			if tt.expectedErr != nil && tt.expectedErr != context.DeadlineExceeded && len(errs) == 0 {
    60  				t.Fatalf("expected err: %v, got: %v", tt.expectedErr, errs)
    61  			}
    62  			for _, err := range errs {
    63  				// test it by predefined error variable instead of error message
    64  				if tt.expectedErr != nil {
    65  					r.Errorf(err, tt.expectedErr.Error())
    66  				} else {
    67  					r.Equal(nil, err)
    68  				}
    69  			}
    70  		})
    71  	}
    72  }
    73  
    74  func getSetupFuncForCtxDeadlineExtendedTest() func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
    75  	return func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
    76  		r := New()
    77  		r.client = &mocks.Timeout{
    78  			Timeout: 1 * time.Second,
    79  		}
    80  		ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second)
    81  		go func() {
    82  			<-ctx.Done()
    83  			cancel()
    84  		}()
    85  		return ctx, r
    86  	}
    87  }
    88  
    89  func getSetupFuncForAllSuccessTest() func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
    90  	return func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
    91  		resty := New().Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
    92  			ra.Equal(200, resp.StatusCode)
    93  			ra.Equal(nil, err)
    94  			ra.Equal(name, string(respBody))
    95  			return nil
    96  		})
    97  
    98  		client := &mocks.Client{}
    99  		setupMockClient(client, urls, statusCode, name)
   100  		resty.client = client
   101  
   102  		ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second)
   103  		go func() {
   104  			<-ctx.Done()
   105  			cancel()
   106  		}()
   107  		return context.TODO(), resty
   108  	}
   109  }
   110  
   111  func getSetupFuncForHandlerErrorTest() func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
   112  	return func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
   113  		resty := New().Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   114  			return fmt.Errorf("handler returned error")
   115  		})
   116  
   117  		client := &mocks.Client{}
   118  		setupMockClient(client, urls, statusCode, name)
   119  		resty.client = client
   120  
   121  		ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second)
   122  		go func() {
   123  			<-ctx.Done()
   124  			cancel()
   125  		}()
   126  		return context.TODO(), resty
   127  	}
   128  }
   129  
   130  func getSetupFuncForInterceptorErrorTest() func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
   131  	return func(ra *require.Assertions, name string, statusCode int, urls []string) (context.Context, *Resty) {
   132  		opts := make([]Option, 0)
   133  		opts = append(opts, WithRequestInterceptor(func(r *http.Request) error {
   134  			return fmt.Errorf("interceptor returned with error") //nolint
   135  		}))
   136  		// create a resty object with an interceptor which returns an error, but the handler doesn't return any error
   137  		resty := New(opts...).Then(func(req *http.Request, resp *http.Response, respBody []byte, cf context.CancelFunc, err error) error {
   138  			return nil
   139  		})
   140  
   141  		client := &mocks.Client{}
   142  		setupMockClient(client, urls, statusCode, name)
   143  		resty.client = client
   144  
   145  		ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second)
   146  		go func() {
   147  			<-ctx.Done()
   148  			cancel()
   149  		}()
   150  		return context.TODO(), resty
   151  	}
   152  }
   153  
   154  func setupMockClient(mck *mocks.Client, urls []string, statusCode int, name string) {
   155  	for _, url := range urls {
   156  		func(u string) {
   157  			mck.On("Do", mock.MatchedBy(func(r *http.Request) bool {
   158  				return r.URL.String() == u
   159  			})).Return(&http.Response{
   160  				StatusCode: statusCode,
   161  				Body:       ioutil.NopCloser(strings.NewReader(name)),
   162  			}, nil)
   163  		}(url)
   164  	}
   165  }