103 lines
2.9 KiB
Go
103 lines
2.9 KiB
Go
package redisstate_test
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"galaxy/lobby/internal/adapters/redisstate"
|
|
|
|
"github.com/alicebob/miniredis/v2"
|
|
"github.com/redis/go-redis/v9"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func newLagTestProbe(t *testing.T, now time.Time) (*redisstate.StreamLagProbe, *miniredis.Miniredis, *redis.Client) {
|
|
t.Helper()
|
|
server := miniredis.RunT(t)
|
|
client := redis.NewClient(&redis.Options{Addr: server.Addr()})
|
|
t.Cleanup(func() {
|
|
_ = client.Close()
|
|
})
|
|
probe, err := redisstate.NewStreamLagProbe(client, func() time.Time { return now })
|
|
require.NoError(t, err)
|
|
return probe, server, client
|
|
}
|
|
|
|
func TestStreamLagProbeReturnsAgeOfNextEntry(t *testing.T) {
|
|
now := time.UnixMilli(2_000_000_000_000).UTC()
|
|
probe, _, client := newLagTestProbe(t, now)
|
|
ctx := context.Background()
|
|
|
|
addEntry := func(ms int64) string {
|
|
id, err := client.XAdd(ctx, &redis.XAddArgs{
|
|
Stream: "demo",
|
|
ID: formatEntryID(ms, 0),
|
|
Values: map[string]any{"k": "v"},
|
|
}).Result()
|
|
require.NoError(t, err)
|
|
return id
|
|
}
|
|
|
|
saved := addEntry(now.UnixMilli() - 5_000) // already processed
|
|
addEntry(now.UnixMilli() - 1_500) // first unprocessed → 1.5s old
|
|
|
|
age, ok, err := probe.OldestUnprocessedAge(ctx, "demo", saved)
|
|
require.NoError(t, err)
|
|
require.True(t, ok)
|
|
assert.InDelta(t, (1_500 * time.Millisecond).Milliseconds(), age.Milliseconds(), 50)
|
|
}
|
|
|
|
func TestStreamLagProbeReturnsFalseWhenAtTail(t *testing.T) {
|
|
now := time.UnixMilli(2_000_000_000_000).UTC()
|
|
probe, _, client := newLagTestProbe(t, now)
|
|
ctx := context.Background()
|
|
|
|
id, err := client.XAdd(ctx, &redis.XAddArgs{
|
|
Stream: "demo",
|
|
ID: formatEntryID(now.UnixMilli()-2_000, 0),
|
|
Values: map[string]any{"k": "v"},
|
|
}).Result()
|
|
require.NoError(t, err)
|
|
|
|
age, ok, err := probe.OldestUnprocessedAge(ctx, "demo", id)
|
|
require.NoError(t, err)
|
|
require.False(t, ok)
|
|
assert.Zero(t, age)
|
|
}
|
|
|
|
func TestStreamLagProbeFallsBackToHeadOnEmptyOffset(t *testing.T) {
|
|
now := time.UnixMilli(2_000_000_000_000).UTC()
|
|
probe, _, client := newLagTestProbe(t, now)
|
|
ctx := context.Background()
|
|
|
|
_, err := client.XAdd(ctx, &redis.XAddArgs{
|
|
Stream: "demo",
|
|
ID: formatEntryID(now.UnixMilli()-3_000, 0),
|
|
Values: map[string]any{"k": "v"},
|
|
}).Result()
|
|
require.NoError(t, err)
|
|
|
|
age, ok, err := probe.OldestUnprocessedAge(ctx, "demo", "")
|
|
require.NoError(t, err)
|
|
require.True(t, ok)
|
|
assert.InDelta(t, (3 * time.Second).Milliseconds(), age.Milliseconds(), 50)
|
|
}
|
|
|
|
func TestStreamLagProbeReturnsFalseOnEmptyStream(t *testing.T) {
|
|
now := time.UnixMilli(2_000_000_000_000).UTC()
|
|
probe, _, _ := newLagTestProbe(t, now)
|
|
ctx := context.Background()
|
|
|
|
age, ok, err := probe.OldestUnprocessedAge(ctx, "demo", "")
|
|
require.NoError(t, err)
|
|
require.False(t, ok)
|
|
assert.Zero(t, age)
|
|
}
|
|
|
|
func formatEntryID(ms int64, seq int64) string {
|
|
return strconv.FormatInt(ms, 10) + "-" + strconv.FormatInt(seq, 10)
|
|
}
|