Switch to private instances of rand for seeding for tests

This commit is contained in:
Jordan Liggitt 2025-02-25 09:56:21 -05:00 committed by cpanato
parent 88300c406b
commit 8090db5dcf
Failed to extract signature
7 changed files with 26 additions and 18 deletions

View File

@ -136,10 +136,14 @@ func (pl *DefaultPreemption) calculateNumCandidates(numNodes int32) int32 {
return n
}
// getOffsetRand is a dedicated random source for GetOffsetAndNumCandidates calls.
// It defaults to rand.Int31n, but is a package variable so it can be overridden to make unit tests deterministic.
var getOffsetRand = rand.Int31n
// GetOffsetAndNumCandidates chooses a random offset and calculates the number
// of candidates that should be shortlisted for dry running preemption.
func (pl *DefaultPreemption) GetOffsetAndNumCandidates(numNodes int32) (int32, int32) {
return rand.Int31n(numNodes), pl.calculateNumCandidates(numNodes)
return getOffsetRand(numNodes), pl.calculateNumCandidates(numNodes)
}
// This function is not applicable for out-of-tree preemption plugins that exercise

View File

@ -1197,7 +1197,7 @@ func TestDryRunPreemption(t *testing.T) {
// Using 4 as a seed source to test getOffsetAndNumCandidates() deterministically.
// However, we need to do it after informerFactory.WaitforCacheSync() which might
// set a seed.
rand.Seed(4)
getOffsetRand = rand.New(rand.NewSource(4)).Int31n
var prevNumFilterCalled int32
for cycle, pod := range tt.testPods {
state := framework.NewCycleState()
@ -1396,7 +1396,7 @@ func TestSelectBestCandidate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rand.Seed(4)
getOffsetRand = rand.New(rand.NewSource(4)).Int31n
nodes := make([]*v1.Node, len(tt.nodeNames))
for i, nodeName := range tt.nodeNames {
nodes[i] = st.MakeNode().Name(nodeName).Capacity(veryLargeRes).Obj()

View File

@ -1237,7 +1237,7 @@ func BenchmarkAuthorization(b *testing.B) {
},
}
podToAdd, _ := generatePod("testwrite", "ns0", "node0", "default", opts)
podToAdd, _ := generatePod("testwrite", "ns0", "node0", "default", opts, rand.Perm)
b.ResetTimer()
for _, testWriteContention := range []bool{false, true} {
@ -1338,11 +1338,11 @@ func populate(graph *Graph, nodes []*corev1.Node, pods []*corev1.Pod, pvs []*cor
}
}
func randomSubset(a, b int) []int {
func randomSubset(a, b int, randPerm func(int) []int) []int {
if b < a {
b = a
}
return rand.Perm(b)[:a]
return randPerm(b)[:a]
}
// generate creates sample pods and persistent volumes based on the provided options.
@ -1356,7 +1356,7 @@ func generate(opts *sampleDataOpts) ([]*corev1.Node, []*corev1.Pod, []*corev1.Pe
attachments := make([]*storagev1.VolumeAttachment, 0, opts.nodes*opts.attachmentsPerNode)
slices := make([]*resourceapi.ResourceSlice, 0, opts.nodes*opts.nodeResourceSlicesPerNode)
rand.Seed(12345)
r := rand.New(rand.NewSource(12345))
for n := 0; n < opts.nodes; n++ {
nodeName := fmt.Sprintf("node%d", n)
@ -1365,7 +1365,7 @@ func generate(opts *sampleDataOpts) ([]*corev1.Node, []*corev1.Pod, []*corev1.Pe
namespace := fmt.Sprintf("ns%d", p%opts.namespaces)
svcAccountName := fmt.Sprintf("svcacct%d-%s", p, nodeName)
pod, podPVs := generatePod(name, namespace, nodeName, svcAccountName, opts)
pod, podPVs := generatePod(name, namespace, nodeName, svcAccountName, opts, r.Perm)
pods = append(pods, pod)
pvs = append(pvs, podPVs...)
}
@ -1395,7 +1395,7 @@ func generate(opts *sampleDataOpts) ([]*corev1.Node, []*corev1.Pod, []*corev1.Pe
return nodes, pods, pvs, attachments, slices
}
func generatePod(name, namespace, nodeName, svcAccountName string, opts *sampleDataOpts) (*corev1.Pod, []*corev1.PersistentVolume) {
func generatePod(name, namespace, nodeName, svcAccountName string, opts *sampleDataOpts, randPerm func(int) []int) (*corev1.Pod, []*corev1.PersistentVolume) {
pvs := make([]*corev1.PersistentVolume, 0, opts.uniquePVCsPerPod+opts.sharedPVCsPerPod)
pod := &corev1.Pod{}
@ -1410,7 +1410,7 @@ func generatePod(name, namespace, nodeName, svcAccountName string, opts *sampleD
}})
}
// Choose shared secrets randomly from shared secrets in a namespace.
subset := randomSubset(opts.sharedSecretsPerPod, opts.sharedSecretsPerNamespace)
subset := randomSubset(opts.sharedSecretsPerPod, opts.sharedSecretsPerNamespace, randPerm)
for _, i := range subset {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{SecretName: fmt.Sprintf("secret%d-shared", i)},
@ -1423,7 +1423,7 @@ func generatePod(name, namespace, nodeName, svcAccountName string, opts *sampleD
}})
}
// Choose shared configmaps randomly from shared configmaps in a namespace.
subset = randomSubset(opts.sharedConfigMapsPerPod, opts.sharedConfigMapsPerNamespace)
subset = randomSubset(opts.sharedConfigMapsPerPod, opts.sharedConfigMapsPerNamespace, randPerm)
for _, i := range subset {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{LocalObjectReference: corev1.LocalObjectReference{Name: fmt.Sprintf("configmap%d-shared", i)}},
@ -1470,7 +1470,7 @@ func generatePod(name, namespace, nodeName, svcAccountName string, opts *sampleD
})
}
// Choose shared pvcs randomly from shared pvcs in a namespace.
subset = randomSubset(opts.sharedPVCsPerPod, opts.sharedPVCsPerNamespace)
subset = randomSubset(opts.sharedPVCsPerPod, opts.sharedPVCsPerNamespace, randPerm)
for _, i := range subset {
pv := &corev1.PersistentVolume{}
pv.Name = fmt.Sprintf("pv%d-shared-%s", i, pod.Namespace)

View File

@ -65,10 +65,10 @@ func TestIntn(t *testing.T) {
func TestPerm(t *testing.T) {
Seed(5)
rand.Seed(5)
r := rand.New(rand.NewSource(5))
for i := 1; i < 20; i++ {
actual := Perm(i)
expected := rand.Perm(i)
expected := r.Perm(i)
for j := 0; j < i; j++ {
if actual[j] != expected[j] {
t.Errorf("Perm call result is unexpected")

View File

@ -80,6 +80,10 @@ func Forever(f func(), period time.Duration) {
Until(f, period, NeverStop)
}
// jitterRand is a dedicated random source for jitter calculations.
// It defaults to rand.Float64, but is a package variable so it can be overridden to make unit tests deterministic.
var jitterRand = rand.Float64
// Jitter returns a time.Duration between duration and duration + maxFactor *
// duration.
//
@ -89,7 +93,7 @@ func Jitter(duration time.Duration, maxFactor float64) time.Duration {
if maxFactor <= 0.0 {
maxFactor = 1.0
}
wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))
wait := duration + time.Duration(jitterRand()*maxFactor*float64(duration))
return wait
}

View File

@ -682,7 +682,7 @@ func TestBackoff_Step(t *testing.T) {
initial = nil
}
t.Run(fmt.Sprintf("%#v seed=%d", initial, seed), func(t *testing.T) {
rand.Seed(seed)
jitterRand = rand.New(rand.NewSource(seed)).Float64
for i := 0; i < len(tt.want); i++ {
got := initial.Step()
t.Logf("[%d]=%s", i, got)

View File

@ -490,9 +490,9 @@ func readFile(content, path string) string {
// genBinDataFromSeed generate binData with random seed
func genBinDataFromSeed(len int, seed int64) []byte {
binData := make([]byte, len)
rand.Seed(seed)
r := rand.New(rand.NewSource(seed))
_, err := rand.Read(binData)
_, err := r.Read(binData)
if err != nil {
fmt.Printf("Error: %v\n", err)
}