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 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 // GetOffsetAndNumCandidates chooses a random offset and calculates the number
// of candidates that should be shortlisted for dry running preemption. // of candidates that should be shortlisted for dry running preemption.
func (pl *DefaultPreemption) GetOffsetAndNumCandidates(numNodes int32) (int32, int32) { 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 // 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. // Using 4 as a seed source to test getOffsetAndNumCandidates() deterministically.
// However, we need to do it after informerFactory.WaitforCacheSync() which might // However, we need to do it after informerFactory.WaitforCacheSync() which might
// set a seed. // set a seed.
rand.Seed(4) getOffsetRand = rand.New(rand.NewSource(4)).Int31n
var prevNumFilterCalled int32 var prevNumFilterCalled int32
for cycle, pod := range tt.testPods { for cycle, pod := range tt.testPods {
state := framework.NewCycleState() state := framework.NewCycleState()
@ -1396,7 +1396,7 @@ func TestSelectBestCandidate(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { 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)) nodes := make([]*v1.Node, len(tt.nodeNames))
for i, nodeName := range tt.nodeNames { for i, nodeName := range tt.nodeNames {
nodes[i] = st.MakeNode().Name(nodeName).Capacity(veryLargeRes).Obj() 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() b.ResetTimer()
for _, testWriteContention := range []bool{false, true} { 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 { if b < a {
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. // 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) attachments := make([]*storagev1.VolumeAttachment, 0, opts.nodes*opts.attachmentsPerNode)
slices := make([]*resourceapi.ResourceSlice, 0, opts.nodes*opts.nodeResourceSlicesPerNode) 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++ { for n := 0; n < opts.nodes; n++ {
nodeName := fmt.Sprintf("node%d", 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) namespace := fmt.Sprintf("ns%d", p%opts.namespaces)
svcAccountName := fmt.Sprintf("svcacct%d-%s", p, nodeName) 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) pods = append(pods, pod)
pvs = append(pvs, podPVs...) pvs = append(pvs, podPVs...)
} }
@ -1395,7 +1395,7 @@ func generate(opts *sampleDataOpts) ([]*corev1.Node, []*corev1.Pod, []*corev1.Pe
return nodes, pods, pvs, attachments, slices 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) pvs := make([]*corev1.PersistentVolume, 0, opts.uniquePVCsPerPod+opts.sharedPVCsPerPod)
pod := &corev1.Pod{} 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. // 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 { for _, i := range subset {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{VolumeSource: corev1.VolumeSource{ pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{SecretName: fmt.Sprintf("secret%d-shared", i)}, 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. // 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 { for _, i := range subset {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{VolumeSource: corev1.VolumeSource{ 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)}}, 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. // 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 { for _, i := range subset {
pv := &corev1.PersistentVolume{} pv := &corev1.PersistentVolume{}
pv.Name = fmt.Sprintf("pv%d-shared-%s", i, pod.Namespace) 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) { func TestPerm(t *testing.T) {
Seed(5) Seed(5)
rand.Seed(5) r := rand.New(rand.NewSource(5))
for i := 1; i < 20; i++ { for i := 1; i < 20; i++ {
actual := Perm(i) actual := Perm(i)
expected := rand.Perm(i) expected := r.Perm(i)
for j := 0; j < i; j++ { for j := 0; j < i; j++ {
if actual[j] != expected[j] { if actual[j] != expected[j] {
t.Errorf("Perm call result is unexpected") t.Errorf("Perm call result is unexpected")

View File

@ -80,6 +80,10 @@ func Forever(f func(), period time.Duration) {
Until(f, period, NeverStop) 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 * // Jitter returns a time.Duration between duration and duration + maxFactor *
// duration. // duration.
// //
@ -89,7 +93,7 @@ func Jitter(duration time.Duration, maxFactor float64) time.Duration {
if maxFactor <= 0.0 { if maxFactor <= 0.0 {
maxFactor = 1.0 maxFactor = 1.0
} }
wait := duration + time.Duration(rand.Float64()*maxFactor*float64(duration)) wait := duration + time.Duration(jitterRand()*maxFactor*float64(duration))
return wait return wait
} }

View File

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

View File

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