github.com/xmidt-org/webpa-common@v1.11.9/xhttp/xtimeout/constructor_test.go (about)

     1  package xtimeout
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"github.com/xmidt-org/webpa-common/xhttp"
    13  )
    14  
    15  func testTimeoutHandlerPanic(t *testing.T) {
    16  	var (
    17  		assert  = assert.New(t)
    18  		require = require.New(t)
    19  
    20  		panicDelegate = http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
    21  			panic("expected")
    22  		})
    23  
    24  		handler = NewConstructor(Options{Timeout: time.Minute})(panicDelegate)
    25  
    26  		request  = httptest.NewRequest("GET", "/", nil)
    27  		response = httptest.NewRecorder()
    28  	)
    29  
    30  	require.NotNil(handler)
    31  
    32  	defer func() {
    33  		assert.Equal("expected", recover())
    34  	}()
    35  
    36  	handler.ServeHTTP(response, request)
    37  	assert.Fail("ServeHTTP should have panicked")
    38  }
    39  
    40  func testTimeoutHandlerSuccess(t *testing.T) {
    41  	const body = "success!"
    42  
    43  	var (
    44  		assert = assert.New(t)
    45  
    46  		delegate = xhttp.Constant{
    47  			Code: 299,
    48  			Header: http.Header{
    49  				"X-Custom": {"value"},
    50  				"X-Multi":  {"1", "2"},
    51  			},
    52  			Body: []byte(body),
    53  		}
    54  
    55  		handler = NewConstructor(Options{Timeout: time.Minute})(delegate)
    56  
    57  		request  = httptest.NewRequest("GET", "/", nil)
    58  		response = httptest.NewRecorder()
    59  	)
    60  
    61  	handler.ServeHTTP(response, request)
    62  	assert.Equal(299, response.Code)
    63  	assert.Equal([]string{"value"}, response.HeaderMap["X-Custom"])
    64  	assert.Equal([]string{"1", "2"}, response.HeaderMap["X-Multi"])
    65  	assert.Equal(body, response.Body.String())
    66  }
    67  
    68  func testTimeoutHandlerTimeout(t *testing.T) {
    69  	const body = "timeout!"
    70  
    71  	var (
    72  		assert = assert.New(t)
    73  
    74  		delegateReady = make(chan struct{})
    75  		delegateBlock = make(chan struct{})
    76  		delegate      = http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
    77  			response.WriteHeader(599)
    78  			response.Write([]byte("the delegate's write should have been discarded"))
    79  			close(delegateReady)
    80  			<-delegateBlock
    81  		})
    82  
    83  		timedOut = xhttp.Constant{
    84  			Code: 499,
    85  			Header: http.Header{
    86  				"X-Custom": {"value"},
    87  				"X-Multi":  {"1", "2"},
    88  			},
    89  			Body: []byte(body),
    90  		}
    91  
    92  		handlerDone = make(chan struct{})
    93  		handler     = NewConstructor(Options{Timeout: time.Hour, TimedOut: timedOut})(delegate)
    94  
    95  		parentCtx, parentCancel = context.WithCancel(context.Background())
    96  		request                 = httptest.NewRequest("GET", "/", nil).WithContext(parentCtx)
    97  		response                = httptest.NewRecorder()
    98  	)
    99  
   100  	go func() {
   101  		defer close(handlerDone)
   102  		handler.ServeHTTP(response, request)
   103  	}()
   104  
   105  	select {
   106  	case <-delegateReady:
   107  		// passing
   108  	case <-time.After(10 * time.Second):
   109  		assert.Fail("Delegate was not called")
   110  	}
   111  
   112  	parentCancel() // simulate a timeout
   113  
   114  	select {
   115  	case <-handlerDone:
   116  		// passing
   117  	case <-time.After(10 * time.Second):
   118  		assert.Fail("Handler did not complete")
   119  	}
   120  
   121  	assert.Equal(499, response.Code)
   122  	assert.Equal([]string{"value"}, response.HeaderMap["X-Custom"])
   123  	assert.Equal([]string{"1", "2"}, response.HeaderMap["X-Multi"])
   124  	assert.Equal(body, response.Body.String())
   125  }
   126  
   127  func TestTimeoutHandler(t *testing.T) {
   128  	t.Run("Panic", testTimeoutHandlerPanic)
   129  	t.Run("Success", testTimeoutHandlerSuccess)
   130  	t.Run("Timeout", testTimeoutHandlerTimeout)
   131  }
   132  
   133  func testNewConstructorNoTimeout(t *testing.T) {
   134  	var (
   135  		assert  = assert.New(t)
   136  		require = require.New(t)
   137  
   138  		delegate    = xhttp.Constant{Code: 388}
   139  		constructor = NewConstructor(Options{})
   140  	)
   141  
   142  	require.NotNil(constructor)
   143  	assert.Equal(delegate, constructor(delegate))
   144  }
   145  
   146  func testNewConstructorDefaultTimedOut(t *testing.T) {
   147  	var (
   148  		assert  = assert.New(t)
   149  		require = require.New(t)
   150  
   151  		delegate = xhttp.Constant{Code: 123}
   152  		handler  = NewConstructor(Options{Timeout: time.Hour})(delegate)
   153  	)
   154  
   155  	th, ok := handler.(*timeoutHandler)
   156  	require.True(ok)
   157  
   158  	assert.Equal(time.Hour, th.timeout)
   159  	assert.Equal(defaultTimedOut, th.timedOut)
   160  	assert.Equal(delegate, th.next)
   161  }
   162  
   163  func TestNewConstructor(t *testing.T) {
   164  	t.Run("NoTimeout", testNewConstructorNoTimeout)
   165  	t.Run("DefaultTimedOut", testNewConstructorDefaultTimedOut)
   166  }