🎉 live server seems to be working now
This commit is contained in:
157
third_party/sendspin-go/pkg/sendspin/buffer_tracker_test.go
vendored
Normal file
157
third_party/sendspin-go/pkg/sendspin/buffer_tracker_test.go
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
// ABOUTME: Tests for the per-client BufferTracker
|
||||
// ABOUTME: Verifies capacity gating, duration cap, prune, and ring growth
|
||||
package sendspin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBufferTracker_BasicFlow(t *testing.T) {
|
||||
tracker := NewBufferTracker(1000) // 1000 bytes capacity
|
||||
|
||||
// Should be able to send when empty
|
||||
if !tracker.CanSend(100, 20000) {
|
||||
t.Error("should be able to send when empty")
|
||||
}
|
||||
|
||||
// Register a chunk
|
||||
tracker.Register(100000, 100, 20000) // ends at 100ms, 100 bytes, 20ms duration
|
||||
|
||||
if tracker.BufferedBytes() != 100 {
|
||||
t.Errorf("buffered bytes = %d, want 100", tracker.BufferedBytes())
|
||||
}
|
||||
|
||||
// Should still be able to send more
|
||||
if !tracker.CanSend(100, 20000) {
|
||||
t.Error("should be able to send with capacity remaining")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferTracker_ByteCapacity(t *testing.T) {
|
||||
tracker := NewBufferTracker(200)
|
||||
|
||||
// Fill to capacity
|
||||
tracker.Register(100000, 100, 20000)
|
||||
tracker.Register(200000, 100, 20000)
|
||||
|
||||
// Should NOT be able to send — at capacity
|
||||
if tracker.CanSend(100, 20000) {
|
||||
t.Error("should not be able to send at byte capacity")
|
||||
}
|
||||
|
||||
// Even a 1-byte chunk should be rejected
|
||||
if tracker.CanSend(1, 20000) {
|
||||
t.Error("should not be able to send when over byte capacity")
|
||||
}
|
||||
|
||||
// Prune the first chunk (simulate time passing)
|
||||
tracker.PruneConsumed(100000) // now = 100ms, first chunk ends at 100ms
|
||||
|
||||
// Should be able to send again
|
||||
if !tracker.CanSend(100, 20000) {
|
||||
t.Error("should be able to send after pruning")
|
||||
}
|
||||
if tracker.BufferedBytes() != 100 {
|
||||
t.Errorf("buffered bytes after prune = %d, want 100", tracker.BufferedBytes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferTracker_DurationCap(t *testing.T) {
|
||||
tracker := NewBufferTracker(1000000) // large byte capacity
|
||||
|
||||
// Fill 30 seconds of 20ms chunks (1500 chunks × 20000μs = 30s)
|
||||
endTime := int64(0)
|
||||
for i := 0; i < 1500; i++ {
|
||||
endTime += 20000
|
||||
tracker.Register(endTime, 100, 20000)
|
||||
}
|
||||
|
||||
// At exactly 30s — should NOT be able to send more
|
||||
if tracker.CanSend(100, 20000) {
|
||||
t.Error("should not be able to send at 30s duration cap")
|
||||
}
|
||||
|
||||
// Prune 1 chunk — should free up space
|
||||
tracker.PruneConsumed(20000)
|
||||
if !tracker.CanSend(100, 20000) {
|
||||
t.Error("should be able to send after pruning one chunk")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferTracker_PruneMultiple(t *testing.T) {
|
||||
tracker := NewBufferTracker(10000)
|
||||
|
||||
tracker.Register(100000, 50, 20000)
|
||||
tracker.Register(200000, 60, 20000)
|
||||
tracker.Register(300000, 70, 20000)
|
||||
|
||||
if tracker.BufferedBytes() != 180 {
|
||||
t.Errorf("bytes = %d, want 180", tracker.BufferedBytes())
|
||||
}
|
||||
|
||||
// Prune first two
|
||||
tracker.PruneConsumed(200000)
|
||||
if tracker.BufferedBytes() != 70 {
|
||||
t.Errorf("after prune bytes = %d, want 70", tracker.BufferedBytes())
|
||||
}
|
||||
if tracker.BufferedDurationUs() != 20000 {
|
||||
t.Errorf("after prune duration = %d, want 20000", tracker.BufferedDurationUs())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferTracker_PruneAll(t *testing.T) {
|
||||
tracker := NewBufferTracker(10000)
|
||||
|
||||
tracker.Register(100000, 50, 20000)
|
||||
tracker.Register(200000, 60, 20000)
|
||||
|
||||
tracker.PruneConsumed(300000) // past both
|
||||
|
||||
if tracker.BufferedBytes() != 0 {
|
||||
t.Errorf("bytes after full prune = %d, want 0", tracker.BufferedBytes())
|
||||
}
|
||||
if tracker.BufferedDurationUs() != 0 {
|
||||
t.Errorf("duration after full prune = %d, want 0", tracker.BufferedDurationUs())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferTracker_RingGrowth(t *testing.T) {
|
||||
tracker := NewBufferTracker(1000000)
|
||||
|
||||
// Fill beyond the initial ring capacity (1500)
|
||||
for i := 0; i < 2000; i++ {
|
||||
endTime := int64((i + 1) * 20000)
|
||||
tracker.Register(endTime, 10, 20000)
|
||||
}
|
||||
|
||||
// Prune half
|
||||
tracker.PruneConsumed(1000 * 20000) // prune first 1000
|
||||
|
||||
if tracker.BufferedBytes() != 10000 {
|
||||
t.Errorf("bytes after partial prune = %d, want 10000", tracker.BufferedBytes())
|
||||
}
|
||||
|
||||
// Should still work correctly after growth
|
||||
if !tracker.CanSend(10, 20000) {
|
||||
t.Error("should be able to send after partial prune")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferTracker_EmptyPrune(t *testing.T) {
|
||||
tracker := NewBufferTracker(1000)
|
||||
|
||||
// Prune on empty tracker should not panic
|
||||
tracker.PruneConsumed(999999)
|
||||
|
||||
if tracker.BufferedBytes() != 0 {
|
||||
t.Error("empty tracker should have 0 bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufferTracker_ZeroCapacity(t *testing.T) {
|
||||
tracker := NewBufferTracker(0) // should default to 1MB
|
||||
|
||||
if !tracker.CanSend(1000, 20000) {
|
||||
t.Error("zero capacity should default to 1MB")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user