grpc-go/xds/internal/xdsclient/requests_counter_test.go

163 lines
4.5 KiB
Go

/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package xdsclient
import (
"sync"
"sync/atomic"
"testing"
)
const testService = "test-service-name"
type counterTest struct {
name string
maxRequests uint32
numRequests uint32
expectedSuccesses uint32
expectedErrors uint32
}
var tests = []counterTest{
{
name: "does-not-exceed-max-requests",
maxRequests: 1024,
numRequests: 1024,
expectedSuccesses: 1024,
expectedErrors: 0,
},
{
name: "exceeds-max-requests",
maxRequests: 32,
numRequests: 64,
expectedSuccesses: 32,
expectedErrors: 32,
},
}
func resetClusterRequestsCounter() {
src = &clusterRequestsCounter{
clusters: make(map[clusterNameAndServiceName]*ClusterRequestsCounter),
}
}
func testCounter(t *testing.T, test counterTest) {
requestsStarted := make(chan struct{})
requestsSent := sync.WaitGroup{}
requestsSent.Add(int(test.numRequests))
requestsDone := sync.WaitGroup{}
requestsDone.Add(int(test.numRequests))
var lastError atomic.Value
var successes, errors uint32
for i := 0; i < int(test.numRequests); i++ {
go func() {
counter := GetClusterRequestsCounter(test.name, testService)
defer requestsDone.Done()
err := counter.StartRequest(test.maxRequests)
if err == nil {
atomic.AddUint32(&successes, 1)
} else {
atomic.AddUint32(&errors, 1)
lastError.Store(err)
}
requestsSent.Done()
if err == nil {
<-requestsStarted
counter.EndRequest()
}
}()
}
requestsSent.Wait()
close(requestsStarted)
requestsDone.Wait()
loadedError := lastError.Load()
if test.expectedErrors > 0 && loadedError == nil {
t.Error("no error when error expected")
}
if test.expectedErrors == 0 && loadedError != nil {
t.Errorf("error starting request: %v", loadedError.(error))
}
// We allow the limits to be exceeded during races.
//
// But we should never over-limit, so this test fails if there are less
// successes than expected.
if successes < test.expectedSuccesses || errors > test.expectedErrors {
t.Errorf("unexpected number of (successes, errors), expected (%v, %v), encountered (%v, %v)", test.expectedSuccesses, test.expectedErrors, successes, errors)
}
}
func (s) TestRequestsCounter(t *testing.T) {
defer resetClusterRequestsCounter()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
testCounter(t, test)
})
}
}
func (s) TestGetClusterRequestsCounter(t *testing.T) {
defer resetClusterRequestsCounter()
for _, test := range tests {
counterA := GetClusterRequestsCounter(test.name, testService)
counterB := GetClusterRequestsCounter(test.name, testService)
if counterA != counterB {
t.Errorf("counter %v %v != counter %v %v", counterA, *counterA, counterB, *counterB)
}
}
}
func startRequests(t *testing.T, n uint32, max uint32, counter *ClusterRequestsCounter) {
for i := uint32(0); i < n; i++ {
if err := counter.StartRequest(max); err != nil {
t.Fatalf("error starting initial request: %v", err)
}
}
}
func (s) TestSetMaxRequestsIncreased(t *testing.T) {
defer resetClusterRequestsCounter()
const clusterName string = "set-max-requests-increased"
var initialMax uint32 = 16
counter := GetClusterRequestsCounter(clusterName, testService)
startRequests(t, initialMax, initialMax, counter)
if err := counter.StartRequest(initialMax); err == nil {
t.Fatal("unexpected success on start request after max met")
}
newMax := initialMax + 1
if err := counter.StartRequest(newMax); err != nil {
t.Fatalf("unexpected error on start request after max increased: %v", err)
}
}
func (s) TestSetMaxRequestsDecreased(t *testing.T) {
defer resetClusterRequestsCounter()
const clusterName string = "set-max-requests-decreased"
var initialMax uint32 = 16
counter := GetClusterRequestsCounter(clusterName, testService)
startRequests(t, initialMax-1, initialMax, counter)
newMax := initialMax - 1
if err := counter.StartRequest(newMax); err == nil {
t.Fatalf("unexpected success on start request after max decreased: %v", err)
}
}