package push import ( "testing" "time" pushv1 "galaxy/backend/proto/push/v1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func mkEvent(cursor uint64, label string) *pushv1.PushEvent { return &pushv1.PushEvent{ Cursor: formatCursor(cursor), Kind: &pushv1.PushEvent_ClientEvent{ ClientEvent: &pushv1.ClientEvent{ Kind: label, Payload: []byte(label), }, }, } } func TestRingAppendAndSinceReturnsTail(t *testing.T) { t.Parallel() now := time.Unix(1_700_000_000, 0) r := newRing(8, time.Minute) for i := uint64(1); i <= 5; i++ { r.append(i, mkEvent(i, "e"), now) } got, stale := r.since(2, now) require.False(t, stale) require.Len(t, got, 3) assert.Equal(t, formatCursor(3), got[0].Cursor) assert.Equal(t, formatCursor(4), got[1].Cursor) assert.Equal(t, formatCursor(5), got[2].Cursor) } func TestRingSinceReturnsEmptyWhenCaughtUp(t *testing.T) { t.Parallel() now := time.Unix(1_700_000_000, 0) r := newRing(8, time.Minute) for i := uint64(1); i <= 3; i++ { r.append(i, mkEvent(i, "e"), now) } got, stale := r.since(3, now) require.False(t, stale) assert.Empty(t, got) got, stale = r.since(99, now) require.False(t, stale) assert.Empty(t, got) } func TestRingSinceFlagsStaleCursorBelowEvictedRange(t *testing.T) { t.Parallel() now := time.Unix(1_700_000_000, 0) r := newRing(3, time.Minute) for i := uint64(1); i <= 5; i++ { r.append(i, mkEvent(i, "e"), now) } // Capacity=3 means cursors 1 and 2 were evicted. require.Equal(t, 3, r.len()) got, stale := r.since(1, now) assert.True(t, stale) assert.Empty(t, got) got, stale = r.since(2, now) assert.False(t, stale) require.Len(t, got, 3) assert.Equal(t, formatCursor(3), got[0].Cursor) } func TestRingEvictsExpiredEntries(t *testing.T) { t.Parallel() t0 := time.Unix(1_700_000_000, 0) r := newRing(8, 10*time.Second) r.append(1, mkEvent(1, "e"), t0) r.append(2, mkEvent(2, "e"), t0.Add(2*time.Second)) r.append(3, mkEvent(3, "e"), t0.Add(15*time.Second)) // At t0+13s the first two entries are past their 10s TTL but the // third (added at t0+15s) is still within the freshness window. got, stale := r.since(0, t0.Add(13*time.Second)) assert.True(t, stale) assert.Empty(t, got) assert.Equal(t, 1, r.len()) } func TestRingEmptyIsNeverStale(t *testing.T) { t.Parallel() r := newRing(4, time.Minute) got, stale := r.since(42, time.Now()) assert.False(t, stale) assert.Empty(t, got) }