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:
Kris 2016-01-04 15:31:01 -08:00
parent 4606171ad0
commit 552e998b1e

View File

@ -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) {