Skip to content
Snippets Groups Projects
Commit 46a3aa77 authored by Benjamin Wenger's avatar Benjamin Wenger
Browse files

Merge branch 'XX-4284/attemptsTests' into 'project/Channels'

XX-4284 / Add tests to histogram.go

See merge request !425
parents 660365ed fe33d5e6
No related branches found
No related tags found
3 merge requests!510Release,!425XX-4284 / Add tests to histogram.go,!340Project/channels
......@@ -18,11 +18,19 @@ const (
optimalAttemptsInitValue = -1
)
// SendAttemptTracker tracks the number of attempts it took to send a cMix
// message in order to predict how many attempt are needed.
type SendAttemptTracker interface {
// SubmitProbeAttempt feeds the number of attempts it took to send a cMix
// message into the tracker and updates the optimal number of attempts.
SubmitProbeAttempt(numAttemptsUntilSuccessful int)
// GetOptimalNumAttempts returns the number of optimal sends. If there is
// insufficient data to calculate, then ready is false.
GetOptimalNumAttempts() (attempts int, ready bool)
}
// sendAttempts tracks the number of attempts to send a cMix message.
type sendAttempts struct {
optimalAttempts *int32
isFull bool
......@@ -31,6 +39,7 @@ type sendAttempts struct {
lock sync.Mutex
}
// NewSendAttempts initialises a new SendAttemptTracker.
func NewSendAttempts() SendAttemptTracker {
optimalAttempts := int32(optimalAttemptsInitValue)
sa := &sendAttempts{
......@@ -43,6 +52,8 @@ func NewSendAttempts() SendAttemptTracker {
return sa
}
// SubmitProbeAttempt feeds the number of attempts it took to send a cMix
// message into the tracker and updates the optimal number of attempts.
func (sa *sendAttempts) SubmitProbeAttempt(numAttemptsUntilSuccessful int) {
sa.lock.Lock()
defer sa.lock.Unlock()
......@@ -58,6 +69,8 @@ func (sa *sendAttempts) SubmitProbeAttempt(numAttemptsUntilSuccessful int) {
sa.computeOptimalUnsafe()
}
// GetOptimalNumAttempts returns the number of optimal sends. If there is
// insufficient data to calculate, then ready is false.
func (sa *sendAttempts) GetOptimalNumAttempts() (attempts int, ready bool) {
optimalAttempts := atomic.LoadInt32(sa.optimalAttempts)
......@@ -68,6 +81,7 @@ func (sa *sendAttempts) GetOptimalNumAttempts() (attempts int, ready bool) {
return int(optimalAttempts), true
}
// computeOptimalUnsafe updates the optimal send attempts.
func (sa *sendAttempts) computeOptimalUnsafe() {
toCopy := maxHistogramSize
if !sa.isFull {
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2022 xx foundation //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file. //
////////////////////////////////////////////////////////////////////////////////
package attempts
import (
"math/rand"
"reflect"
"testing"
)
// Tests that NewSendAttempts returns a new sendAttempts with the expected
// fields.
func TestNewSendAttempts(t *testing.T) {
optimalAttempts := int32(optimalAttemptsInitValue)
expected := &sendAttempts{
optimalAttempts: &optimalAttempts,
isFull: false,
currentIndex: 0,
numAttempts: make([]int, maxHistogramSize),
}
sa := NewSendAttempts()
if !reflect.DeepEqual(expected, sa) {
t.Errorf("New SendAttemptTracker does not match expected."+
"\nexpected: %+v\nreceivedL %+v", expected, sa)
}
}
// Tests that sendAttempts.SubmitProbeAttempt properly increments and stores the
// attempts.
func Test_sendAttempts_SubmitProbeAttempt(t *testing.T) {
sa := NewSendAttempts().(*sendAttempts)
for i := 0; i < maxHistogramSize+20; i++ {
sa.SubmitProbeAttempt(i)
if sa.currentIndex != (i+1)%maxHistogramSize {
t.Errorf("Incorrect currentIndex (%d).\nexpected: %d\nreceived: %d",
i, (i+1)%maxHistogramSize, sa.currentIndex)
} else if sa.numAttempts[i%maxHistogramSize] != i {
t.Errorf("Incorrect numAttempts at %d.\nexpected: %d\nreceived: %d",
i, i, sa.numAttempts[i%maxHistogramSize])
} else if i > maxHistogramSize && !sa.isFull {
t.Errorf("Should be marked full when numAttempts > %d.",
maxHistogramSize)
}
}
}
// Tests sendAttempts.GetOptimalNumAttempts returns numbers close to 70% of the
// average of attempts feeding in.
func Test_sendAttempts_GetOptimalNumAttempts(t *testing.T) {
prng := rand.New(rand.NewSource(42))
sa := NewSendAttempts().(*sendAttempts)
attempts, ready := sa.GetOptimalNumAttempts()
if ready {
t.Errorf("Marked ready when no attempts have been made.")
} else if attempts != 0 {
t.Errorf("Incorrect number of attempt.\nexpected: %d\nreceived: %d",
0, attempts)
}
const n = 100
factor := (n * 7) / 10
for i := 0; i < 500; i++ {
sa.SubmitProbeAttempt(prng.Intn(n))
attempts, ready = sa.GetOptimalNumAttempts()
if (sa.currentIndex < minElements && !sa.isFull) && ready {
t.Errorf("Ready when less than %d attempts made (%d).",
minElements, i)
} else if sa.currentIndex >= minElements {
if !ready {
t.Errorf("Not ready when more than %d attempts made (%d).",
minElements, i)
} else if attempts < factor-25 || attempts > factor+25 {
t.Errorf("Attempts is not close to average (%d)."+
"\naverage: %d\nattempts: %d", i, factor, attempts)
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment