snapshot of https://github.com/livekit/livekit.git @ 08c5433449c106943231037d0b892895f6e92d3b (2026-09-15)
This commit is contained in:
361
pkg/sfu/utils/rangemap_test.go
Normal file
361
pkg/sfu/utils/rangemap_test.go
Normal file
@@ -0,0 +1,361 @@
|
||||
// Copyright 2023 LiveKit, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRangeMapUint32(t *testing.T) {
|
||||
r := NewRangeMap[uint32, uint32](2)
|
||||
|
||||
// getting value for any key should be 0 default
|
||||
value, err := r.GetValue(33333)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(0), value)
|
||||
|
||||
expectedRanges := []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 0,
|
||||
end: 0,
|
||||
value: 0,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// add an exclusion, should create a new range
|
||||
err = r.ExcludeRange(10, 11)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 0,
|
||||
end: 9,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
start: 11,
|
||||
end: 0,
|
||||
value: 1,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// getting value in old range should return 0
|
||||
value, err = r.GetValue(6)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(0), value)
|
||||
|
||||
// newer should return 1
|
||||
value, err = r.GetValue(11)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(1), value)
|
||||
|
||||
// excluded range should return error
|
||||
_, err = r.GetValue(10)
|
||||
require.ErrorIs(t, err, errKeyExcluded)
|
||||
|
||||
// out-of-order exclusion should return error
|
||||
err = r.ExcludeRange(9, 10)
|
||||
require.ErrorIs(t, err, errReversedOrder)
|
||||
|
||||
// flipped exclusion should return error
|
||||
err = r.ExcludeRange(12, 11)
|
||||
require.ErrorIs(t, err, errReversedOrder)
|
||||
err = r.ExcludeRange(11, 11)
|
||||
require.ErrorIs(t, err, errReversedOrder)
|
||||
|
||||
// add adjacent exclusion range of length = 1
|
||||
err = r.ExcludeRange(11, 12)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 0,
|
||||
end: 9,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
start: 12,
|
||||
end: 0,
|
||||
value: 2,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// excluded range should return error, now is excluded because exclusion range could be extended
|
||||
_, err = r.GetValue(11)
|
||||
require.ErrorIs(t, err, errKeyExcluded)
|
||||
|
||||
// getting value in old range should return 0
|
||||
_, err = r.GetValue(6)
|
||||
require.NoError(t, err)
|
||||
|
||||
// newer should return 2
|
||||
value, err = r.GetValue(12)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(2), value)
|
||||
|
||||
// add adjacent exclusion range of length = 10
|
||||
err = r.ExcludeRange(12, 22)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 0,
|
||||
end: 9,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
start: 22,
|
||||
end: 0,
|
||||
value: 12,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// excluded range should return error, now is excluded because exclusion range could be extended
|
||||
_, err = r.GetValue(15)
|
||||
require.ErrorIs(t, err, errKeyExcluded)
|
||||
|
||||
// newer should return 12
|
||||
value, err = r.GetValue(25)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(12), value)
|
||||
|
||||
// add a disjoint exclusion of length = 4
|
||||
err = r.ExcludeRange(26, 30)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 0,
|
||||
end: 9,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
start: 22,
|
||||
end: 25,
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
start: 30,
|
||||
end: 0,
|
||||
value: 16,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// get a value from newly closed range [22, 25]
|
||||
value, err = r.GetValue(23)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(12), value)
|
||||
|
||||
// add a disjoint exclusion of length = 1
|
||||
err = r.ExcludeRange(50, 51)
|
||||
require.NoError(t, err)
|
||||
|
||||
// previously first range would have been pruned due to size limitations
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 22,
|
||||
end: 25,
|
||||
value: 12,
|
||||
},
|
||||
{
|
||||
start: 30,
|
||||
end: 49,
|
||||
value: 16,
|
||||
},
|
||||
{
|
||||
start: 51,
|
||||
end: 0,
|
||||
value: 17,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// excluded range should return error
|
||||
_, err = r.GetValue(50)
|
||||
require.ErrorIs(t, err, errKeyExcluded)
|
||||
_, err = r.GetValue(28)
|
||||
require.ErrorIs(t, err, errKeyExcluded)
|
||||
_, err = r.GetValue(17)
|
||||
require.ErrorIs(t, err, errKeyTooOld)
|
||||
|
||||
// previously valid, but aged out key should return error
|
||||
_, err = r.GetValue(5)
|
||||
require.ErrorIs(t, err, errKeyTooOld)
|
||||
|
||||
// valid range access should return values
|
||||
value, err = r.GetValue(24)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(12), value)
|
||||
|
||||
value, err = r.GetValue(34)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(16), value)
|
||||
|
||||
value, err = r.GetValue(49)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(16), value)
|
||||
|
||||
value, err = r.GetValue(55555555)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(17), value)
|
||||
|
||||
// reset
|
||||
r.ClearAndResetValue(24, 23)
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 24,
|
||||
end: 0,
|
||||
value: 23,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
value, err = r.GetValue(55555555)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(23), value)
|
||||
|
||||
// decrement value and ensure that any key after start in ClearAndResetValue above returns that value
|
||||
// (as given end is higher than open range start, open range should be closed and a new range added)
|
||||
r.DecValue(34, 12)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 24,
|
||||
end: 34,
|
||||
value: 23,
|
||||
},
|
||||
{
|
||||
start: 35,
|
||||
end: 0,
|
||||
value: 11,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
value, err = r.GetValue(55555555)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(11), value)
|
||||
|
||||
// add an exclusion and then decrement value
|
||||
err = r.ExcludeRange(40, 45)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 24,
|
||||
end: 34,
|
||||
value: 23,
|
||||
},
|
||||
{
|
||||
start: 35,
|
||||
end: 39,
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
start: 45,
|
||||
end: 0,
|
||||
value: 16,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// before first range access
|
||||
_, err = r.GetValue(5)
|
||||
require.ErrorIs(t, err, errKeyTooOld)
|
||||
|
||||
// first range access
|
||||
value, err = r.GetValue(25)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(23), value)
|
||||
|
||||
// second range access
|
||||
value, err = r.GetValue(35)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(11), value)
|
||||
|
||||
// open range access
|
||||
value, err = r.GetValue(55555555)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(16), value)
|
||||
|
||||
r.DecValue(66, 6)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 35,
|
||||
end: 39,
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
start: 45,
|
||||
end: 66,
|
||||
value: 16,
|
||||
},
|
||||
{
|
||||
start: 67,
|
||||
end: 0,
|
||||
value: 10,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// aged out range access
|
||||
_, err = r.GetValue(25)
|
||||
require.ErrorIs(t, err, errKeyTooOld)
|
||||
|
||||
// access closed range before decrementing value
|
||||
value, err = r.GetValue(66)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(16), value)
|
||||
|
||||
// open range access
|
||||
value, err = r.GetValue(67)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(10), value)
|
||||
|
||||
// decrement with old end and check that open range gets decremented
|
||||
r.DecValue(66, 6)
|
||||
|
||||
expectedRanges = []rangeVal[uint32, uint32]{
|
||||
{
|
||||
start: 35,
|
||||
end: 39,
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
start: 45,
|
||||
end: 66,
|
||||
value: 16,
|
||||
},
|
||||
{
|
||||
start: 67,
|
||||
end: 0,
|
||||
value: 4,
|
||||
},
|
||||
}
|
||||
require.Equal(t, expectedRanges, r.ranges)
|
||||
|
||||
// open range access should get decremented value
|
||||
value, err = r.GetValue(67)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint32(4), value)
|
||||
}
|
||||
Reference in New Issue
Block a user