@@ -43,6 +43,7 @@ import (
43
43
"k8s.io/apimachinery/pkg/watch"
44
44
example "k8s.io/apiserver/pkg/apis/example"
45
45
"k8s.io/apiserver/pkg/endpoints/handlers"
46
+ "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
46
47
apitesting "k8s.io/apiserver/pkg/endpoints/testing"
47
48
"k8s.io/apiserver/pkg/registry/rest"
48
49
"k8s.io/client-go/dynamic"
@@ -607,6 +608,21 @@ func (t *fakeTimeoutFactory) TimeoutCh() (<-chan time.Time, func() bool) {
607
608
}
608
609
}
609
610
611
+ // serveWatch will serve a watch response according to the watcher and watchServer.
612
+ // Before watchServer.ServeHTTP, an error may occur like k8s.io/apiserver/pkg/endpoints/handlers/watch.go#serveWatch does.
613
+ func serveWatch (watcher watch.Interface , watchServer * handlers.WatchServer , preServeErr error ) http.HandlerFunc {
614
+ return func (w http.ResponseWriter , req * http.Request ) {
615
+ defer watcher .Stop ()
616
+
617
+ if preServeErr != nil {
618
+ responsewriters .ErrorNegotiated (preServeErr , watchServer .Scope .Serializer , watchServer .Scope .Kind .GroupVersion (), w , req )
619
+ return
620
+ }
621
+
622
+ watchServer .ServeHTTP (w , req )
623
+ }
624
+ }
625
+
610
626
func TestWatchHTTPErrors (t * testing.T ) {
611
627
watcher := watch .NewFake ()
612
628
timeoutCh := make (chan time.Time )
@@ -632,9 +648,7 @@ func TestWatchHTTPErrors(t *testing.T) {
632
648
TimeoutFactory : & fakeTimeoutFactory {timeoutCh , done },
633
649
}
634
650
635
- s := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
636
- watchServer .ServeHTTP (w , req )
637
- }))
651
+ s := httptest .NewServer (serveWatch (watcher , watchServer , nil ))
638
652
defer s .Close ()
639
653
640
654
// Setup a client
@@ -671,6 +685,68 @@ func TestWatchHTTPErrors(t *testing.T) {
671
685
}
672
686
}
673
687
688
+ func TestWatchHTTPErrorsBeforeServe (t * testing.T ) {
689
+ watcher := watch .NewFake ()
690
+ timeoutCh := make (chan time.Time )
691
+ done := make (chan struct {})
692
+
693
+ info , ok := runtime .SerializerInfoForMediaType (codecs .SupportedMediaTypes (), runtime .ContentTypeJSON )
694
+ if ! ok || info .StreamSerializer == nil {
695
+ t .Fatal (info )
696
+ }
697
+ serializer := info .StreamSerializer
698
+
699
+ // Setup a new watchserver
700
+ watchServer := & handlers.WatchServer {
701
+ Scope : & handlers.RequestScope {
702
+ Serializer : runtime .NewSimpleNegotiatedSerializer (info ),
703
+ Kind : testGroupVersion .WithKind ("test" ),
704
+ },
705
+ Watching : watcher ,
706
+
707
+ MediaType : "testcase/json" ,
708
+ Framer : serializer .Framer ,
709
+ Encoder : newCodec ,
710
+ EmbeddedEncoder : newCodec ,
711
+
712
+ Fixup : func (obj runtime.Object ) runtime.Object { return obj },
713
+ TimeoutFactory : & fakeTimeoutFactory {timeoutCh , done },
714
+ }
715
+
716
+ errStatus := errors .NewInternalError (fmt .Errorf ("we got an error" ))
717
+
718
+ s := httptest .NewServer (serveWatch (watcher , watchServer , errStatus ))
719
+ defer s .Close ()
720
+
721
+ // Setup a client
722
+ dest , _ := url .Parse (s .URL )
723
+ dest .Path = "/" + prefix + "/" + newGroupVersion .Group + "/" + newGroupVersion .Version + "/simple"
724
+ dest .RawQuery = "watch=true"
725
+
726
+ req , _ := http .NewRequest ("GET" , dest .String (), nil )
727
+ client := http.Client {}
728
+ resp , err := client .Do (req )
729
+ if err != nil {
730
+ t .Fatalf ("Unexpected error: %v" , err )
731
+ }
732
+
733
+ // We had already got an error before watch serve started
734
+ decoder := json .NewDecoder (resp .Body )
735
+ var status * metav1.Status
736
+ err = decoder .Decode (& status )
737
+ if err != nil {
738
+ t .Fatalf ("Unexpected error: %v" , err )
739
+ }
740
+ if status .Kind != "Status" || status .APIVersion != "v1" || status .Code != 500 || status .Status != "Failure" || ! strings .Contains (status .Message , "we got an error" ) {
741
+ t .Fatalf ("error: %#v" , status )
742
+ }
743
+
744
+ // check for leaks
745
+ if ! watcher .IsStopped () {
746
+ t .Errorf ("Leaked watcher goruntine after request done" )
747
+ }
748
+ }
749
+
674
750
func TestWatchHTTPDynamicClientErrors (t * testing.T ) {
675
751
watcher := watch .NewFake ()
676
752
timeoutCh := make (chan time.Time )
@@ -696,9 +772,7 @@ func TestWatchHTTPDynamicClientErrors(t *testing.T) {
696
772
TimeoutFactory : & fakeTimeoutFactory {timeoutCh , done },
697
773
}
698
774
699
- s := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
700
- watchServer .ServeHTTP (w , req )
701
- }))
775
+ s := httptest .NewServer (serveWatch (watcher , watchServer , nil ))
702
776
defer s .Close ()
703
777
defer s .CloseClientConnections ()
704
778
@@ -741,9 +815,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
741
815
TimeoutFactory : & fakeTimeoutFactory {timeoutCh , done },
742
816
}
743
817
744
- s := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
745
- watchServer .ServeHTTP (w , req )
746
- }))
818
+ s := httptest .NewServer (serveWatch (watcher , watchServer , nil ))
747
819
defer s .Close ()
748
820
749
821
// Setup a client
@@ -771,7 +843,7 @@ func TestWatchHTTPTimeout(t *testing.T) {
771
843
close (timeoutCh )
772
844
select {
773
845
case <- done :
774
- if ! watcher .Stopped {
846
+ if ! watcher .IsStopped () {
775
847
t .Errorf ("Leaked watch on timeout" )
776
848
}
777
849
case <- time .After (wait .ForeverTestTimeout ):
0 commit comments