1
0
mirror of https://github.com/rancher/steve.git synced 2025-04-28 11:14:43 +00:00
steve/pkg/resources/counts/buffer_test.go
Michael Bolot 0e9fde750f Attempting to fix flaky tests
Some tests which relied on timeouts were a bit flaky in CI. This PR
refactors a few of them to work on a more reliable method of receiving
from a channel and raises the timeout of another test.
2024-04-03 15:32:23 -05:00

112 lines
3.4 KiB
Go

package counts
import (
"fmt"
"strconv"
"testing"
"time"
"github.com/rancher/apiserver/pkg/types"
"github.com/stretchr/testify/assert"
)
func Test_countsBuffer(t *testing.T) {
tests := []struct {
name string
numInputEvents int
overrideInput map[int]int // events whose count we should override. Don't include an event >= numInputEvents
}{
{
name: "test basic input",
numInputEvents: 1,
},
{
name: "test basic multiple input",
numInputEvents: 3,
},
{
name: "test basic input which is overriden by later events",
numInputEvents: 3,
overrideInput: map[int]int{
1: 17,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
debounceDuration = 10 * time.Millisecond
countsChannel := make(chan Count, 100)
outputChannel := countsBuffer(countsChannel)
countsChannel <- Count{
ID: "count",
Counts: map[string]ItemCount{"test": createItemCount(1)},
}
// first event is not buffered, so we expect to receive it quicker than the debounce
_, err := receiveWithTimeout(outputChannel, time.Second*1)
assert.NoError(t, err, "Expected first event to be received quickly")
// stream our standard count events
for i := 0; i < test.numInputEvents; i++ {
countsChannel <- Count{
ID: "count",
Counts: map[string]ItemCount{strconv.Itoa(i): createItemCount(1)},
}
}
// stream any overrides, if applicable
for key, value := range test.overrideInput {
countsChannel <- Count{
ID: "count",
Counts: map[string]ItemCount{strconv.Itoa(key): createItemCount(value)},
}
}
// due to complexities of cycle calculation, give a slight delay for the event to actually stream
output, err := receiveWithTimeout(outputChannel, debounceDuration+time.Millisecond*10)
assert.NoError(t, err, "did not expect an error when receiving value from channel")
outputCount := output.Object.Object.(Count)
assert.Len(t, outputCount.Counts, test.numInputEvents)
for outputID, outputItem := range outputCount.Counts {
outputIdx, err := strconv.Atoi(outputID)
assert.NoError(t, err, "couldn't convert output idx")
nsTotal := 0
for _, nsSummary := range outputItem.Namespaces {
nsTotal += nsSummary.Count
}
if outputOverride, ok := test.overrideInput[outputIdx]; ok {
assert.Equal(t, outputOverride, outputItem.Summary.Count, "expected overridden output count to be most recent value")
assert.Equal(t, outputOverride, nsTotal, "expected overridden output namespace count to be most recent value")
} else {
assert.Equal(t, 1, outputItem.Summary.Count, "expected non-overridden output count to be 1")
assert.Equal(t, 1, nsTotal, "expected non-overridden output namespace count to be 1")
}
}
})
}
}
// receiveWithTimeout tries to get a value from input within duration. Returns an error if no input was received during that period
func receiveWithTimeout(input chan types.APIEvent, duration time.Duration) (*types.APIEvent, error) {
select {
case value := <-input:
return &value, nil
case <-time.After(duration):
return nil, fmt.Errorf("timeout error, no value received after %f seconds", duration.Seconds())
}
}
func createItemCount(countTotal int) ItemCount {
return ItemCount{
Summary: Summary{
Count: countTotal,
},
Namespaces: map[string]Summary{
"test": {
Count: countTotal,
},
},
}
}