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 }