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 }