@@ -18,6 +18,7 @@ package filters
18
18
19
19
import (
20
20
"context"
21
+ "errors"
21
22
"fmt"
22
23
"net/http"
23
24
"net/http/httptest"
@@ -26,6 +27,7 @@ import (
26
27
"reflect"
27
28
"strings"
28
29
"sync"
30
+ "sync/atomic"
29
31
"testing"
30
32
"time"
31
33
@@ -128,20 +130,20 @@ func newApfServerWithSingleRequest(t *testing.T, decision mockDecision) *httptes
128
130
t .Errorf ("execute should not be invoked" )
129
131
}
130
132
// atomicReadOnlyExecuting can be either 0 or 1 as we test one request at a time.
131
- if decision != decisionSkipFilter && atomicReadOnlyExecuting != 1 {
132
- t .Errorf ("Wanted %d requests executing, got %d" , 1 , atomicReadOnlyExecuting )
133
+ if want , got := int32 ( 1 ), atomic . LoadInt32 ( & atomicReadOnlyExecuting ); decision != decisionSkipFilter && want != got {
134
+ t .Errorf ("Wanted %d requests executing, got %d" , want , got )
133
135
}
134
136
}
135
137
postExecuteFunc := func () {}
136
138
// atomicReadOnlyWaiting can be either 0 or 1 as we test one request at a time.
137
139
postEnqueueFunc := func () {
138
- if atomicReadOnlyWaiting != 1 {
139
- t .Errorf ("Wanted %d requests in queue, got %d" , 1 , atomicReadOnlyWaiting )
140
+ if want , got := int32 ( 1 ), atomic . LoadInt32 ( & atomicReadOnlyWaiting ); want != got {
141
+ t .Errorf ("Wanted %d requests in queue, got %d" , want , got )
140
142
}
141
143
}
142
144
postDequeueFunc := func () {
143
- if atomicReadOnlyWaiting != 0 {
144
- t .Errorf ("Wanted %d requests in queue, got %d" , 0 , atomicReadOnlyWaiting )
145
+ if want , got := int32 ( 0 ), atomic . LoadInt32 ( & atomicReadOnlyWaiting ); want != got {
146
+ t .Errorf ("Wanted %d requests in queue, got %d" , want , got )
145
147
}
146
148
}
147
149
return newApfServerWithHooks (t , decision , onExecuteFunc , postExecuteFunc , postEnqueueFunc , postDequeueFunc )
@@ -177,11 +179,19 @@ func newApfHandlerWithFilter(t *testing.T, flowControlFilter utilflowcontrol.Int
177
179
r = r .WithContext (apirequest .WithUser (r .Context (), & user.DefaultInfo {
178
180
Groups : []string {user .AllUnauthenticated },
179
181
}))
180
- apfHandler .ServeHTTP (w , r )
181
- postExecute ()
182
- if atomicReadOnlyExecuting != 0 {
183
- t .Errorf ("Wanted %d requests executing, got %d" , 0 , atomicReadOnlyExecuting )
184
- }
182
+ func () {
183
+ // the defer ensures that the following assertion is
184
+ // executed, even if the APF handler panics
185
+ // TODO: all test(s) using this filter must run serially to each other
186
+ defer func () {
187
+ t .Logf ("the APF handler has finished, checking atomicReadOnlyExecuting" )
188
+ if want , got := int32 (0 ), atomic .LoadInt32 (& atomicReadOnlyExecuting ); want != got {
189
+ t .Errorf ("Wanted %d requests executing, got %d" , want , got )
190
+ }
191
+ }()
192
+ apfHandler .ServeHTTP (w , r )
193
+ postExecute ()
194
+ }()
185
195
}), requestInfoFactory )
186
196
187
197
return handler
@@ -270,8 +280,8 @@ func TestApfExecuteMultipleRequests(t *testing.T) {
270
280
onExecuteFunc := func () {
271
281
preStartExecute .Done ()
272
282
preStartExecute .Wait ()
273
- if int ( atomicReadOnlyExecuting ) != concurrentRequests {
274
- t .Errorf ("Wanted %d requests executing, got %d" , concurrentRequests , atomicReadOnlyExecuting )
283
+ if want , got := int32 ( concurrentRequests ), atomic . LoadInt32 ( & atomicReadOnlyExecuting ); want != got {
284
+ t .Errorf ("Wanted %d requests executing, got %d" , want , got )
275
285
}
276
286
postStartExecute .Done ()
277
287
postStartExecute .Wait ()
@@ -280,8 +290,8 @@ func TestApfExecuteMultipleRequests(t *testing.T) {
280
290
postEnqueueFunc := func () {
281
291
preEnqueue .Done ()
282
292
preEnqueue .Wait ()
283
- if int ( atomicReadOnlyWaiting ) != concurrentRequests {
284
- t .Errorf ("Wanted %d requests in queue, got %d" , 1 , atomicReadOnlyWaiting )
293
+ if want , got := int32 ( concurrentRequests ), atomic . LoadInt32 ( & atomicReadOnlyWaiting ); want != got {
294
+ t .Errorf ("Wanted %d requests in queue, got %d" , want , got )
285
295
286
296
}
287
297
postEnqueue .Done ()
@@ -291,8 +301,8 @@ func TestApfExecuteMultipleRequests(t *testing.T) {
291
301
postDequeueFunc := func () {
292
302
preDequeue .Done ()
293
303
preDequeue .Wait ()
294
- if atomicReadOnlyWaiting != 0 {
295
- t .Errorf ("Wanted %d requests in queue, got %d" , 0 , atomicReadOnlyWaiting )
304
+ if want , got := int32 ( 0 ), atomic . LoadInt32 ( & atomicReadOnlyWaiting ); want != got {
305
+ t .Errorf ("Wanted %d requests in queue, got %d" , want , got )
296
306
}
297
307
postDequeue .Done ()
298
308
postDequeue .Wait ()
@@ -345,19 +355,21 @@ func TestApfCancelWaitRequest(t *testing.T) {
345
355
}
346
356
347
357
type fakeWatchApfFilter struct {
358
+ t * testing.T
348
359
lock sync.Mutex
349
360
inflight int
350
361
capacity int
351
362
352
- postExecutePanic bool
353
- preExecutePanic bool
363
+ postExecutePanic error
364
+ preExecutePanic error
354
365
355
366
utilflowcontrol.WatchTracker
356
367
utilflowcontrol.MaxSeatsTracker
357
368
}
358
369
359
- func newFakeWatchApfFilter (capacity int ) * fakeWatchApfFilter {
370
+ func newFakeWatchApfFilter (t * testing. T , capacity int ) * fakeWatchApfFilter {
360
371
return & fakeWatchApfFilter {
372
+ t : t ,
361
373
capacity : capacity ,
362
374
WatchTracker : utilflowcontrol .NewWatchTracker (),
363
375
MaxSeatsTracker : utilflowcontrol .NewMaxSeatsTracker (),
@@ -385,17 +397,23 @@ func (f *fakeWatchApfFilter) Handle(ctx context.Context,
385
397
return
386
398
}
387
399
388
- if f .preExecutePanic {
389
- panic ("pre-exec-panic" )
390
- }
391
- execFn ()
392
- if f .postExecutePanic {
393
- panic ("post-exec-panic" )
394
- }
400
+ func () {
401
+ defer func () {
402
+ f .lock .Lock ()
403
+ defer f .lock .Unlock ()
404
+ f .inflight --
405
+ }()
395
406
396
- f .lock .Lock ()
397
- defer f .lock .Unlock ()
398
- f .inflight --
407
+ if f .preExecutePanic != nil {
408
+ f .t .Logf ("going to panic (pre-exec) as expected with error: %v, fakeWatchApfFilter: %#v" , f .preExecutePanic , f )
409
+ panic (f .preExecutePanic )
410
+ }
411
+ execFn ()
412
+ if f .postExecutePanic != nil {
413
+ f .t .Logf ("going to panic (post-exec) as expected with error: %v, fakeWatchApfFilter: %#v" , f .postExecutePanic , f )
414
+ panic (f .postExecutePanic )
415
+ }
416
+ }()
399
417
}
400
418
401
419
func (f * fakeWatchApfFilter ) Run (stopCh <- chan struct {}) error {
@@ -447,7 +465,7 @@ func TestApfExecuteWatchRequestsWithInitializationSignal(t *testing.T) {
447
465
allRunning := sync.WaitGroup {}
448
466
allRunning .Add (2 * concurrentRequests )
449
467
450
- fakeFilter := newFakeWatchApfFilter (concurrentRequests )
468
+ fakeFilter := newFakeWatchApfFilter (t , concurrentRequests )
451
469
452
470
onExecuteFunc := func () {
453
471
firstRunning .Done ()
@@ -493,7 +511,7 @@ func TestApfExecuteWatchRequestsWithInitializationSignal(t *testing.T) {
493
511
}
494
512
495
513
func TestApfRejectWatchRequestsWithInitializationSignal (t * testing.T ) {
496
- fakeFilter := newFakeWatchApfFilter (0 )
514
+ fakeFilter := newFakeWatchApfFilter (t , 0 )
497
515
498
516
onExecuteFunc := func () {
499
517
t .Errorf ("Request unexepectedly executing" )
@@ -512,7 +530,7 @@ func TestApfWatchPanic(t *testing.T) {
512
530
epmetrics .Register ()
513
531
fcmetrics .Register ()
514
532
515
- fakeFilter := newFakeWatchApfFilter (1 )
533
+ fakeFilter := newFakeWatchApfFilter (t , 1 )
516
534
517
535
onExecuteFunc := func () {
518
536
panic ("test panic" )
@@ -539,11 +557,11 @@ func TestApfWatchPanic(t *testing.T) {
539
557
func TestApfWatchHandlePanic (t * testing.T ) {
540
558
epmetrics .Register ()
541
559
fcmetrics .Register ()
542
- preExecutePanicingFilter := newFakeWatchApfFilter (1 )
543
- preExecutePanicingFilter .preExecutePanic = true
560
+ preExecutePanicingFilter := newFakeWatchApfFilter (t , 1 )
561
+ preExecutePanicingFilter .preExecutePanic = http . ErrAbortHandler
544
562
545
- postExecutePanicingFilter := newFakeWatchApfFilter (1 )
546
- postExecutePanicingFilter .postExecutePanic = true
563
+ postExecutePanicingFilter := newFakeWatchApfFilter (t , 1 )
564
+ postExecutePanicingFilter .postExecutePanic = http . ErrAbortHandler
547
565
548
566
testCases := []struct {
549
567
name string
@@ -559,18 +577,31 @@ func TestApfWatchHandlePanic(t *testing.T) {
559
577
},
560
578
}
561
579
562
- onExecuteFunc := func () {
563
- time .Sleep (5 * time .Second )
564
- }
565
- postExecuteFunc := func () {}
566
-
567
580
for _ , test := range testCases {
568
581
t .Run (test .name , func (t * testing.T ) {
582
+ onExecuteFunc := func () {
583
+ time .Sleep (5 * time .Second )
584
+
585
+ // this function should not be executed if
586
+ // pre-execute panic is set
587
+ if test .filter .preExecutePanic != nil {
588
+ t .Errorf ("did not expect the execute function to be executed" )
589
+ }
590
+ t .Logf ("on-execute function invoked" )
591
+ }
592
+
593
+ // we either panic before the execute function, or after,
594
+ // so the following function should never be executed.
595
+ postExecuteFunc := func () {
596
+ t .Errorf ("did not expect the post-execute function to be invoked" )
597
+ }
598
+
569
599
apfHandler := newApfHandlerWithFilter (t , test .filter , time .Minute / 4 , onExecuteFunc , postExecuteFunc )
570
600
handler := func (w http.ResponseWriter , r * http.Request ) {
571
601
defer func () {
572
- if err := recover (); err == nil {
573
- t .Errorf ("expected panic, got %v" , err )
602
+ recovered := recover ()
603
+ if err , ok := recovered .(error ); ! ok || ! errors .Is (err , http .ErrAbortHandler ) {
604
+ t .Errorf ("expected panic with error: %v, but got: %v" , http .ErrAbortHandler , err )
574
605
}
575
606
}()
576
607
apfHandler .ServeHTTP (w , r )
0 commit comments