@@ -19,7 +19,8 @@ import (
1919)
2020
2121type delayedInitSandbox struct {
22- delay time.Duration
22+ initDelay time.Duration
23+ invokeDelay time.Duration
2324 invokeCalled bool
2425 initCompletedAt time.Time
2526 invokeErr error
@@ -36,8 +37,9 @@ func (s *delayedInitSandbox) AwaitInitCompletion() time.Time {
3637
3738func (s * delayedInitSandbox ) Invoke (http.ResponseWriter , * interop.Invoke ) error {
3839 s .invokeCalled = true
39- time .Sleep (s .delay )
40+ time .Sleep (s .initDelay )
4041 s .initCompletedAt = time .Now ()
42+ time .Sleep (s .invokeDelay )
4143 return s .invokeErr
4244}
4345
@@ -88,7 +90,7 @@ func TestInvokeHandlerReportsRuntimeInitDuration(t *testing.T) {
8890
8991 request := httptest .NewRequest (http .MethodPost , "/2015-03-31/functions/function/invocations" , nil )
9092 response := httptest .NewRecorder ()
91- sandbox := & delayedInitSandbox {delay : 50 * time .Millisecond }
93+ sandbox := & delayedInitSandbox {initDelay : 50 * time .Millisecond }
9294
9395 reader , writer , err := os .Pipe ()
9496 require .NoError (t , err )
@@ -129,7 +131,7 @@ func TestInvokeHandlerReportsInitDurationWhenInitTimesOut(t *testing.T) {
129131 request := httptest .NewRequest (http .MethodPost , "/2015-03-31/functions/function/invocations" , nil )
130132 response := httptest .NewRecorder ()
131133 sandbox := & delayedInitSandbox {
132- delay : 10 * time .Millisecond ,
134+ initDelay : 50 * time .Millisecond ,
133135 invokeErr : rapidcore .ErrInvokeTimeout ,
134136 }
135137
@@ -155,4 +157,94 @@ func TestInvokeHandlerReportsInitDurationWhenInitTimesOut(t *testing.T) {
155157
156158 matches = regexp .MustCompile (`\tDuration: ([0-9.]+) ms` ).FindStringSubmatch (string (output ))
157159 require .Len (t , matches , 2 )
160+ durationMilliseconds , err := strconv .ParseFloat (matches [1 ], 64 )
161+ require .NoError (t , err )
162+ require .Less (t , durationMilliseconds , float64 (40 ))
163+ require .LessOrEqual (t , initDurationMilliseconds + durationMilliseconds , float64 (1020 ))
164+ }
165+
166+ func TestInvokeHandlerSeparatesInitFromTimedOutInvocation (t * testing.T ) {
167+ initMutex .Lock ()
168+ initDone = false
169+ initMutex .Unlock ()
170+ t .Cleanup (func () {
171+ initMutex .Lock ()
172+ initDone = false
173+ initMutex .Unlock ()
174+ })
175+ t .Setenv ("AWS_LAMBDA_FUNCTION_TIMEOUT" , "1" )
176+
177+ request := httptest .NewRequest (http .MethodPost , "/2015-03-31/functions/function/invocations" , nil )
178+ response := httptest .NewRecorder ()
179+ sandbox := & delayedInitSandbox {
180+ initDelay : 50 * time .Millisecond ,
181+ invokeDelay : 50 * time .Millisecond ,
182+ invokeErr : rapidcore .ErrInvokeTimeout ,
183+ }
184+
185+ reader , writer , err := os .Pipe ()
186+ require .NoError (t , err )
187+ originalStdout := os .Stdout
188+ os .Stdout = writer
189+ t .Cleanup (func () { os .Stdout = originalStdout })
190+
191+ InvokeHandler (response , request , sandbox , nil )
192+ require .NoError (t , writer .Close ())
193+ output , err := io .ReadAll (reader )
194+ require .NoError (t , err )
195+ require .NoError (t , reader .Close ())
196+
197+ require .Equal (t , "Task timed out after 1.00 seconds" , response .Body .String ())
198+ initMatches := regexp .MustCompile (`Init Duration: ([0-9.]+) ms` ).FindStringSubmatch (string (output ))
199+ require .Len (t , initMatches , 2 )
200+ initDurationMilliseconds , err := strconv .ParseFloat (initMatches [1 ], 64 )
201+ require .NoError (t , err )
202+ require .GreaterOrEqual (t , initDurationMilliseconds , float64 (40 ))
203+
204+ durationMatches := regexp .MustCompile (`\tDuration: ([0-9.]+) ms` ).FindStringSubmatch (string (output ))
205+ require .Len (t , durationMatches , 2 )
206+ durationMilliseconds , err := strconv .ParseFloat (durationMatches [1 ], 64 )
207+ require .NoError (t , err )
208+ require .GreaterOrEqual (t , durationMilliseconds , float64 (40 ))
209+ require .Less (t , durationMilliseconds , float64 (90 ))
210+ require .LessOrEqual (t , initDurationMilliseconds + durationMilliseconds , float64 (1020 ))
211+ }
212+
213+ func TestInvokeHandlerReportsWarmTimeoutWithoutInitDuration (t * testing.T ) {
214+ initMutex .Lock ()
215+ initDone = true
216+ initMutex .Unlock ()
217+ t .Cleanup (func () {
218+ initMutex .Lock ()
219+ initDone = false
220+ initMutex .Unlock ()
221+ })
222+ t .Setenv ("AWS_LAMBDA_FUNCTION_TIMEOUT" , "1" )
223+
224+ request := httptest .NewRequest (http .MethodPost , "/2015-03-31/functions/function/invocations" , nil )
225+ response := httptest .NewRecorder ()
226+ sandbox := & delayedInitSandbox {
227+ invokeDelay : 50 * time .Millisecond ,
228+ invokeErr : rapidcore .ErrInvokeTimeout ,
229+ }
230+
231+ reader , writer , err := os .Pipe ()
232+ require .NoError (t , err )
233+ originalStdout := os .Stdout
234+ os .Stdout = writer
235+ t .Cleanup (func () { os .Stdout = originalStdout })
236+
237+ InvokeHandler (response , request , sandbox , nil )
238+ require .NoError (t , writer .Close ())
239+ output , err := io .ReadAll (reader )
240+ require .NoError (t , err )
241+ require .NoError (t , reader .Close ())
242+
243+ require .Equal (t , "Task timed out after 1.00 seconds" , response .Body .String ())
244+ require .NotContains (t , string (output ), "Init Duration:" )
245+ durationMatches := regexp .MustCompile (`\tDuration: ([0-9.]+) ms` ).FindStringSubmatch (string (output ))
246+ require .Len (t , durationMatches , 2 )
247+ durationMilliseconds , err := strconv .ParseFloat (durationMatches [1 ], 64 )
248+ require .NoError (t , err )
249+ require .GreaterOrEqual (t , durationMilliseconds , float64 (40 ))
158250}
0 commit comments