github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/resty/context_test.go (about)

     1  // Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com)
     2  // 2016 Andrew Grigorev (https://github.com/ei-grad)
     3  // All rights reserved.
     4  // resty source code and usage is governed by a MIT style
     5  // license that can be found in the LICENSE file.
     6  
     7  package resty
     8  
     9  import (
    10  	"context"
    11  	"net/http"
    12  	"net/url"
    13  	"strings"
    14  	"sync/atomic"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/stretchr/testify/assert"
    19  )
    20  
    21  func TestSetContext(t *testing.T) {
    22  	ts := createGetServer(t)
    23  	defer ts.Close()
    24  
    25  	resp, err := dc().R().
    26  		SetContext(context.Background()).
    27  		Get(ts.URL + "/")
    28  
    29  	assert.Nil(t, err)
    30  	assert.Equal(t, http.StatusOK, resp.StatusCode())
    31  	assert.Equal(t, "200 OK", resp.Status())
    32  	assert.Equal(t, true, resp.Body() != nil)
    33  	assert.Equal(t, "TestGet: text response", resp.String())
    34  
    35  	logResponse(t, resp)
    36  }
    37  
    38  func TestSetContextWithError(t *testing.T) {
    39  	ts := createGetServer(t)
    40  	defer ts.Close()
    41  
    42  	resp, err := dcr().
    43  		SetContext(context.Background()).
    44  		Get(ts.URL + "/mypage")
    45  
    46  	assert.Nil(t, err)
    47  	assert.Equal(t, http.StatusBadRequest, resp.StatusCode())
    48  	assert.Equal(t, "", resp.String())
    49  
    50  	logResponse(t, resp)
    51  }
    52  
    53  func TestSetContextCancel(t *testing.T) {
    54  	ch := make(chan struct{})
    55  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
    56  		defer func() {
    57  			ch <- struct{}{} // tell test request is finished
    58  		}()
    59  		t.Logf("Server: %v %v", r.Method, r.URL.Path)
    60  		ch <- struct{}{}
    61  		<-ch // wait for client to finish request
    62  		n, err := w.Write([]byte("TestSetContextCancel: response"))
    63  		// FIXME? test server doesn't handle request cancellation
    64  		t.Logf("Server: wrote %d bytes", n)
    65  		t.Logf("Server: err is %v ", err)
    66  	})
    67  	defer ts.Close()
    68  
    69  	ctx, cancel := context.WithCancel(context.Background())
    70  
    71  	go func() {
    72  		<-ch // wait for server to start request handling
    73  		cancel()
    74  	}()
    75  
    76  	_, err := dc().R().
    77  		SetContext(ctx).
    78  		Get(ts.URL + "/")
    79  
    80  	ch <- struct{}{} // tell server to continue request handling
    81  
    82  	<-ch // wait for server to finish request handling
    83  
    84  	t.Logf("Error: %v", err)
    85  	if !errIsContextCanceled(err) {
    86  		t.Errorf("Got unexpected error: %v", err)
    87  	}
    88  }
    89  
    90  func TestSetContextCancelRetry(t *testing.T) {
    91  	reqCount := 0
    92  	ch := make(chan struct{})
    93  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
    94  		reqCount++
    95  		defer func() {
    96  			ch <- struct{}{} // tell test request is finished
    97  		}()
    98  		t.Logf("Server: %v %v", r.Method, r.URL.Path)
    99  		ch <- struct{}{}
   100  		<-ch // wait for client to finish request
   101  		n, err := w.Write([]byte("TestSetContextCancel: response"))
   102  		// FIXME? test server doesn't handle request cancellation
   103  		t.Logf("Server: wrote %d bytes", n)
   104  		t.Logf("Server: err is %v ", err)
   105  	})
   106  	defer ts.Close()
   107  
   108  	ctx, cancel := context.WithCancel(context.Background())
   109  
   110  	go func() {
   111  		<-ch // wait for server to start request handling
   112  		cancel()
   113  	}()
   114  
   115  	c := dc().
   116  		SetTimeout(time.Second * 3).
   117  		SetRetryCount(3)
   118  
   119  	_, err := c.R().
   120  		SetContext(ctx).
   121  		Get(ts.URL + "/")
   122  
   123  	ch <- struct{}{} // tell server to continue request handling
   124  
   125  	<-ch // wait for server to finish request handling
   126  
   127  	t.Logf("Error: %v", err)
   128  	if !errIsContextCanceled(err) {
   129  		t.Errorf("Got unexpected error: %v", err)
   130  	}
   131  
   132  	if reqCount != 1 {
   133  		t.Errorf("Request was retried %d times instead of 1", reqCount)
   134  	}
   135  }
   136  
   137  func TestSetContextCancelWithError(t *testing.T) {
   138  	ch := make(chan struct{})
   139  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   140  		defer func() {
   141  			ch <- struct{}{} // tell test request is finished
   142  		}()
   143  		t.Logf("Server: %v %v", r.Method, r.URL.Path)
   144  		t.Log("Server: sending StatusBadRequest response")
   145  		w.WriteHeader(http.StatusBadRequest)
   146  		ch <- struct{}{}
   147  		<-ch // wait for client to finish request
   148  		n, err := w.Write([]byte("TestSetContextCancelWithError: response"))
   149  		// FIXME? test server doesn't handle request cancellation
   150  		t.Logf("Server: wrote %d bytes", n)
   151  		t.Logf("Server: err is %v ", err)
   152  	})
   153  	defer ts.Close()
   154  
   155  	ctx, cancel := context.WithCancel(context.Background())
   156  
   157  	go func() {
   158  		<-ch // wait for server to start request handling
   159  		cancel()
   160  	}()
   161  
   162  	_, err := dc().R().
   163  		SetContext(ctx).
   164  		Get(ts.URL + "/")
   165  
   166  	ch <- struct{}{} // tell server to continue request handling
   167  
   168  	<-ch // wait for server to finish request handling
   169  
   170  	t.Logf("Error: %v", err)
   171  	if !errIsContextCanceled(err) {
   172  		t.Errorf("Got unexpected error: %v", err)
   173  	}
   174  }
   175  
   176  func TestClientRetryWithSetContext(t *testing.T) {
   177  	var attemptctx int32
   178  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   179  		t.Logf("Method: %v", r.Method)
   180  		t.Logf("Path: %v", r.URL.Path)
   181  		attp := atomic.AddInt32(&attemptctx, 1)
   182  		if attp <= 4 {
   183  			time.Sleep(time.Second * 2)
   184  		}
   185  		_, _ = w.Write([]byte("TestClientRetry page"))
   186  	})
   187  	defer ts.Close()
   188  
   189  	c := dc().
   190  		SetTimeout(time.Second * 1).
   191  		SetRetryCount(3)
   192  
   193  	_, err := c.R().
   194  		SetContext(context.Background()).
   195  		Get(ts.URL + "/")
   196  
   197  	assert.Equal(t, true, (strings.HasPrefix(err.Error(), "Get "+ts.URL+"/") ||
   198  		strings.HasPrefix(err.Error(), "Get \""+ts.URL+"/\"")))
   199  }
   200  
   201  func TestRequestContext(t *testing.T) {
   202  	client := dc()
   203  	r := client.NewRequest()
   204  	assert.NotNil(t, r.Context())
   205  
   206  	r.SetContext(context.Background())
   207  	assert.NotNil(t, r.Context())
   208  }
   209  
   210  func errIsContextCanceled(err error) bool {
   211  	ue, ok := err.(*url.Error)
   212  	if !ok {
   213  		return false
   214  	}
   215  	return ue.Err == context.Canceled
   216  }