mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Fix a premature server shutdown error
Sometimes the test server would close down the TCP socket before all requests could finish.
This commit is contained in:
parent
4606171ad0
commit
552e998b1e
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package apiserver
|
package apiserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@ -41,15 +42,15 @@ func (fakeRL) Stop() {}
|
|||||||
func (f fakeRL) TryAccept() bool { return bool(f) }
|
func (f fakeRL) TryAccept() bool { return bool(f) }
|
||||||
func (f fakeRL) Accept() {}
|
func (f fakeRL) Accept() {}
|
||||||
|
|
||||||
func expectHTTP(url string, code int, t *testing.T) {
|
func expectHTTP(url string, code int) error {
|
||||||
r, err := http.Get(url)
|
r, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
return fmt.Errorf("unexpected error: %v", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if r.StatusCode != code {
|
if r.StatusCode != code {
|
||||||
t.Errorf("unexpected response: %v", r.StatusCode)
|
return fmt.Errorf("unexpected response: %v", r.StatusCode)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPath(resource, namespace, name string) string {
|
func getPath(resource, namespace, name string) string {
|
||||||
@ -82,6 +83,13 @@ func TestMaxInFlight(t *testing.T) {
|
|||||||
// 'short' accounted ones.
|
// 'short' accounted ones.
|
||||||
calls := &sync.WaitGroup{}
|
calls := &sync.WaitGroup{}
|
||||||
calls.Add(AllowedInflightRequestsNo * 2)
|
calls.Add(AllowedInflightRequestsNo * 2)
|
||||||
|
|
||||||
|
// Responses is used to wait until all responses are
|
||||||
|
// received. This prevents some async requests getting EOF
|
||||||
|
// errors from prematurely closing the server
|
||||||
|
responses := sync.WaitGroup{}
|
||||||
|
responses.Add(AllowedInflightRequestsNo * 2)
|
||||||
|
|
||||||
// Block is used to keep requests in flight for as long as we need to. All requests will
|
// Block is used to keep requests in flight for as long as we need to. All requests will
|
||||||
// be unblocked at the same time.
|
// be unblocked at the same time.
|
||||||
block := sync.WaitGroup{}
|
block := sync.WaitGroup{}
|
||||||
@ -109,21 +117,25 @@ func TestMaxInFlight(t *testing.T) {
|
|||||||
for i := 0; i < AllowedInflightRequestsNo; i++ {
|
for i := 0; i < AllowedInflightRequestsNo; i++ {
|
||||||
// These should hang waiting on block...
|
// These should hang waiting on block...
|
||||||
go func() {
|
go func() {
|
||||||
expectHTTP(server.URL+"/foo/bar/watch", http.StatusOK, t)
|
if err := expectHTTP(server.URL+"/foo/bar/watch", http.StatusOK); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
responses.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
// Check that sever is not saturated by not-accounted calls
|
// Check that sever is not saturated by not-accounted calls
|
||||||
expectHTTP(server.URL+"/dontwait", http.StatusOK, t)
|
if err := expectHTTP(server.URL+"/dontwait", http.StatusOK); err != nil {
|
||||||
oneAccountedFinished := sync.WaitGroup{}
|
t.Error(err)
|
||||||
oneAccountedFinished.Add(1)
|
}
|
||||||
var once sync.Once
|
|
||||||
|
|
||||||
// These should hang and be accounted, i.e. saturate the server
|
// These should hang and be accounted, i.e. saturate the server
|
||||||
for i := 0; i < AllowedInflightRequestsNo; i++ {
|
for i := 0; i < AllowedInflightRequestsNo; i++ {
|
||||||
// These should hang waiting on block...
|
// These should hang waiting on block...
|
||||||
go func() {
|
go func() {
|
||||||
expectHTTP(server.URL, http.StatusOK, t)
|
if err := expectHTTP(server.URL, http.StatusOK); err != nil {
|
||||||
once.Do(oneAccountedFinished.Done)
|
t.Error(err)
|
||||||
|
}
|
||||||
|
responses.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
// We wait for all calls to be received by the server
|
// We wait for all calls to be received by the server
|
||||||
@ -133,18 +145,24 @@ func TestMaxInFlight(t *testing.T) {
|
|||||||
|
|
||||||
// Do this multiple times to show that it rate limit rejected requests don't block.
|
// Do this multiple times to show that it rate limit rejected requests don't block.
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
expectHTTP(server.URL, errors.StatusTooManyRequests, t)
|
if err := expectHTTP(server.URL, errors.StatusTooManyRequests); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Validate that non-accounted URLs still work
|
// Validate that non-accounted URLs still work
|
||||||
expectHTTP(server.URL+"/dontwait/watch", http.StatusOK, t)
|
if err := expectHTTP(server.URL+"/dontwait/watch", http.StatusOK); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Let all hanging requests finish
|
// Let all hanging requests finish
|
||||||
block.Done()
|
block.Done()
|
||||||
|
|
||||||
// Show that we recover from being blocked up.
|
// Show that we recover from being blocked up.
|
||||||
// Too avoid flakyness we need to wait until at least one of the requests really finishes.
|
// Too avoid flakyness we need to wait until at least one of the requests really finishes.
|
||||||
oneAccountedFinished.Wait()
|
responses.Wait()
|
||||||
expectHTTP(server.URL, http.StatusOK, t)
|
if err := expectHTTP(server.URL, http.StatusOK); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadOnly(t *testing.T) {
|
func TestReadOnly(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user