mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Add more comments to TestMaxInflight
This commit is contained in:
		@@ -57,22 +57,39 @@ func pathWithPrefix(prefix, resource, namespace, name string) string {
 | 
			
		||||
	return testapi.Default.ResourcePathWithPrefix(prefix, resource, namespace, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tests that MaxInFlightLimit works, i.e.
 | 
			
		||||
// - "long" requests such as proxy or watch, identified by regexp are not accounted despite
 | 
			
		||||
//   hanging for the long time,
 | 
			
		||||
// - "short" requests are correctly accounted, i.e. there can be only size of channel passed to the
 | 
			
		||||
//   constructor in flight at any given moment,
 | 
			
		||||
// - subsequent "short" requests are rejected instantly with apropriate error,
 | 
			
		||||
// - subsequent "long" requests are handled normally,
 | 
			
		||||
// - we correctly recover after some "short" requests finish, i.e. we can process new ones.
 | 
			
		||||
func TestMaxInFlight(t *testing.T) {
 | 
			
		||||
	const Iterations = 3
 | 
			
		||||
	const AllowedInflightRequestsNo = 3
 | 
			
		||||
	// Size of inflightRequestsChannel determines how many concurent inflight requests
 | 
			
		||||
	// are allowed.
 | 
			
		||||
	inflightRequestsChannel := make(chan bool, AllowedInflightRequestsNo)
 | 
			
		||||
	// notAccountedPathsRegexp specifies paths requests to which we don't account into
 | 
			
		||||
	// requests in flight.
 | 
			
		||||
	notAccountedPathsRegexp := regexp.MustCompile(".*\\/watch")
 | 
			
		||||
 | 
			
		||||
	// Calls is used to wait until all server calls are received. We are sending
 | 
			
		||||
	// AllowedInflightRequestsNo of 'long' not-accounted requests and the same number of
 | 
			
		||||
	// 'short' accounted ones.
 | 
			
		||||
	calls := &sync.WaitGroup{}
 | 
			
		||||
	calls.Add(AllowedInflightRequestsNo * 2)
 | 
			
		||||
	// Block is used to keep requests in flight for as long as we need to. All requests will
 | 
			
		||||
	// be unblocked at the same time.
 | 
			
		||||
	block := sync.WaitGroup{}
 | 
			
		||||
	block.Add(1)
 | 
			
		||||
	oneAccountedFinished := sync.WaitGroup{}
 | 
			
		||||
	oneAccountedFinished.Add(1)
 | 
			
		||||
	var once sync.Once
 | 
			
		||||
	sem := make(chan bool, Iterations)
 | 
			
		||||
 | 
			
		||||
	re := regexp.MustCompile("[.*\\/watch][^\\/proxy.*]")
 | 
			
		||||
 | 
			
		||||
	// Calls verifies that the server is actually blocked up before running the rest of the test
 | 
			
		||||
	calls := &sync.WaitGroup{}
 | 
			
		||||
	calls.Add(Iterations * 3)
 | 
			
		||||
 | 
			
		||||
	server := httptest.NewServer(MaxInFlightLimit(sem, re, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	server := httptest.NewServer(
 | 
			
		||||
		MaxInFlightLimit(
 | 
			
		||||
			inflightRequestsChannel,
 | 
			
		||||
			notAccountedPathsRegexp,
 | 
			
		||||
			http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
				// A short, accounted request that does not wait for block WaitGroup.
 | 
			
		||||
				if strings.Contains(r.URL.Path, "dontwait") {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
@@ -80,48 +97,49 @@ func TestMaxInFlight(t *testing.T) {
 | 
			
		||||
					calls.Done()
 | 
			
		||||
				}
 | 
			
		||||
				block.Wait()
 | 
			
		||||
	})))
 | 
			
		||||
			}),
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	defer server.Close()
 | 
			
		||||
 | 
			
		||||
	// These should hang, but not affect accounting.
 | 
			
		||||
	for i := 0; i < Iterations; i++ {
 | 
			
		||||
	for i := 0; i < AllowedInflightRequestsNo; i++ {
 | 
			
		||||
		// These should hang waiting on block...
 | 
			
		||||
		go func() {
 | 
			
		||||
			expectHTTP(server.URL+"/foo/bar/watch", http.StatusOK, t)
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// These should hang, but not affect accounting.
 | 
			
		||||
	for i := 0; i < Iterations; i++ {
 | 
			
		||||
		// These should hang waiting on block...
 | 
			
		||||
		go func() {
 | 
			
		||||
			expectHTTP(server.URL+"/proxy/foo/bar", http.StatusOK, t)
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
	// Check that sever is not saturated by not-accounted calls
 | 
			
		||||
	expectHTTP(server.URL+"/dontwait", http.StatusOK, t)
 | 
			
		||||
	oneAccountedFinished := sync.WaitGroup{}
 | 
			
		||||
	oneAccountedFinished.Add(1)
 | 
			
		||||
	var once sync.Once
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < Iterations; i++ {
 | 
			
		||||
	// These should hang and be accounted, i.e. saturate the server
 | 
			
		||||
	for i := 0; i < AllowedInflightRequestsNo; i++ {
 | 
			
		||||
		// These should hang waiting on block...
 | 
			
		||||
		go func() {
 | 
			
		||||
			expectHTTP(server.URL, http.StatusOK, t)
 | 
			
		||||
			once.Do(oneAccountedFinished.Done)
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
	// We wait for all calls to be received by the server
 | 
			
		||||
	calls.Wait()
 | 
			
		||||
	// Disable calls notifications in the server
 | 
			
		||||
	calls = nil
 | 
			
		||||
 | 
			
		||||
	// Do this multiple times to show that it rate limit rejected requests don't block.
 | 
			
		||||
	for i := 0; i < 2; i++ {
 | 
			
		||||
		expectHTTP(server.URL, errors.StatusTooManyRequests, t)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate that non-accounted URLs still work
 | 
			
		||||
	expectHTTP(server.URL+"/dontwait/watch", http.StatusOK, t)
 | 
			
		||||
 | 
			
		||||
	// Let all hanging requests finish
 | 
			
		||||
	block.Done()
 | 
			
		||||
 | 
			
		||||
	// Show that we recover from being blocked up.
 | 
			
		||||
	// However, we should 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()
 | 
			
		||||
	expectHTTP(server.URL, http.StatusOK, t)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user