functional-tester/tester: shuffle failure cases with coprime
Signed-off-by: Gyuho Lee <gyuhox@gmail.com>
This commit is contained in:
@ -19,6 +19,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -234,6 +235,33 @@ func NewCluster(logger *zap.Logger, fpath string) (*Cluster, error) {
|
||||
}
|
||||
go clus.serveTesterServer()
|
||||
|
||||
clus.updateFailures()
|
||||
|
||||
clus.rateLimiter = rate.NewLimiter(
|
||||
rate.Limit(int(clus.Tester.StressQPS)),
|
||||
int(clus.Tester.StressQPS),
|
||||
)
|
||||
clus.updateStresserChecker()
|
||||
return clus, nil
|
||||
}
|
||||
|
||||
func (clus *Cluster) serveTesterServer() {
|
||||
clus.logger.Info(
|
||||
"started tester HTTP server",
|
||||
zap.String("tester-address", clus.Tester.TesterAddr),
|
||||
)
|
||||
err := clus.testerHTTPServer.ListenAndServe()
|
||||
clus.logger.Info(
|
||||
"tester HTTP server returned",
|
||||
zap.String("tester-address", clus.Tester.TesterAddr),
|
||||
zap.Error(err),
|
||||
)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
clus.logger.Fatal("tester HTTP errored", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (clus *Cluster) updateFailures() {
|
||||
for _, cs := range clus.Tester.FailureCases {
|
||||
switch cs {
|
||||
case "KILL_ONE_FOLLOWER":
|
||||
@ -270,33 +298,51 @@ func NewCluster(logger *zap.Logger, fpath string) (*Cluster, error) {
|
||||
clus.failures = append(clus.failures, newFailureNoOp())
|
||||
case "EXTERNAL":
|
||||
clus.failures = append(clus.failures, newFailureExternal(clus.Tester.ExternalExecPath))
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown failure %q", cs)
|
||||
}
|
||||
}
|
||||
|
||||
clus.rateLimiter = rate.NewLimiter(
|
||||
rate.Limit(int(clus.Tester.StressQPS)),
|
||||
int(clus.Tester.StressQPS),
|
||||
)
|
||||
clus.updateStresserChecker()
|
||||
return clus, nil
|
||||
}
|
||||
|
||||
func (clus *Cluster) serveTesterServer() {
|
||||
clus.logger.Info(
|
||||
"started tester HTTP server",
|
||||
zap.String("tester-address", clus.Tester.TesterAddr),
|
||||
)
|
||||
err := clus.testerHTTPServer.ListenAndServe()
|
||||
clus.logger.Info(
|
||||
"tester HTTP server returned",
|
||||
zap.String("tester-address", clus.Tester.TesterAddr),
|
||||
zap.Error(err),
|
||||
)
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
clus.logger.Fatal("tester HTTP errored", zap.Error(err))
|
||||
func (clus *Cluster) shuffleFailures() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
offset := rand.Intn(1000)
|
||||
n := len(clus.failures)
|
||||
cp := coprime(n)
|
||||
|
||||
clus.logger.Info("shuffling test failure cases", zap.Int("total", n))
|
||||
fs := make([]Failure, n)
|
||||
for i := 0; i < n; i++ {
|
||||
fs[i] = clus.failures[(cp*i+offset)%n]
|
||||
}
|
||||
clus.failures = fs
|
||||
clus.logger.Info("shuffled test failure cases", zap.Int("total", n))
|
||||
}
|
||||
|
||||
/*
|
||||
x and y of GCD 1 are coprime to each other
|
||||
|
||||
x1 = ( coprime of n * idx1 + offset ) % n
|
||||
x2 = ( coprime of n * idx2 + offset ) % n
|
||||
(x2 - x1) = coprime of n * (idx2 - idx1) % n
|
||||
= (idx2 - idx1) = 1
|
||||
|
||||
Consecutive x's are guaranteed to be distinct
|
||||
*/
|
||||
func coprime(n int) int {
|
||||
coprime := 1
|
||||
for i := n / 2; i < n; i++ {
|
||||
if gcd(i, n) == 1 {
|
||||
coprime = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return coprime
|
||||
}
|
||||
|
||||
func gcd(x, y int) int {
|
||||
if y == 0 {
|
||||
return x
|
||||
}
|
||||
return gcd(y, x%y)
|
||||
}
|
||||
|
||||
func (clus *Cluster) updateStresserChecker() {
|
||||
|
Reference in New Issue
Block a user