Files
dudu/server/internal/store/redis_test.go
T
wangjia 40760aa884
ci / server (push) Failing after 14s
ci / design-tokens (push) Failing after 11s
dudu MVP:五端语音输入法初始提交
- server:Go 网关(WS 流式识别中继/计费配额/微信登录支付 mock/反馈/埋点),gummy provider 已真实联调
- desktop:Tauri 2(全局快捷键 push-to-talk/浮层/托盘/设置/登录购买/反馈/首启引导)
- android:Compose 主 App + IME(键盘内录音直传)
- ios:App + 键盘扩展(1A spike 实证键盘内不可录音,走 deep link 听写)
- design/design-pipeline:设计系统 + token 导出 iOS/Android 主题
- doc:前后端设计文档(HTML);web:官网宣传页;todo:任务看板

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 00:38:37 +08:00

81 lines
2.1 KiB
Go

package store
import (
"context"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/redis/go-redis/v9"
)
func rdb(t *testing.T) *redis.Client {
t.Helper()
mr := miniredis.RunT(t)
return redis.NewClient(&redis.Options{Addr: mr.Addr()})
}
func TestAllowSessionWindow(t *testing.T) {
r := rdb(t)
ctx := context.Background()
now := time.Now()
// 30 次放行,第 31 次拒绝
for i := 0; i < 30; i++ {
ok, err := AllowSession(ctx, r, "dev1", now)
if err != nil || !ok {
t.Fatalf("session %d should pass: ok=%v err=%v", i+1, ok, err)
}
}
if ok, _ := AllowSession(ctx, r, "dev1", now); ok {
t.Fatal("31st session should be rejected")
}
// 其他设备不受影响
if ok, _ := AllowSession(ctx, r, "dev2", now); !ok {
t.Fatal("other device should pass")
}
}
func TestAllowAudioSecondsWindow(t *testing.T) {
r := rdb(t)
ctx := context.Background()
now := time.Now()
// 1700s 放行
if ok, _ := AllowAudioSeconds(ctx, r, "dev1", 1700, now); !ok {
t.Fatal("1700s should pass")
}
// 再 100s(累计 1800)放行
if ok, _ := AllowAudioSeconds(ctx, r, "dev1", 100, now.Add(time.Second)); !ok {
t.Fatal("cumulative 1800s should pass")
}
// 再 1s 超限拒绝
if ok, _ := AllowAudioSeconds(ctx, r, "dev1", 1, now.Add(2*time.Second)); ok {
t.Fatal("1801s should be rejected")
}
}
func TestDeviceSlot(t *testing.T) {
r := rdb(t)
ctx := context.Background()
ok, err := AcquireDeviceSlot(ctx, r, "dev1", "s1")
if err != nil || !ok {
t.Fatalf("first acquire should pass: %v", err)
}
if ok, _ := AcquireDeviceSlot(ctx, r, "dev1", "s2"); ok {
t.Fatal("second concurrent acquire should fail")
}
// 非持有者释放无效
if err := ReleaseDeviceSlot(ctx, r, "dev1", "s2"); err != nil {
t.Fatal(err)
}
if ok, _ := AcquireDeviceSlot(ctx, r, "dev1", "s3"); ok {
t.Fatal("slot should still be held by s1")
}
// 持有者释放后可再获取
if err := ReleaseDeviceSlot(ctx, r, "dev1", "s1"); err != nil {
t.Fatal(err)
}
if ok, _ := AcquireDeviceSlot(ctx, r, "dev1", "s3"); !ok {
t.Fatal("acquire after release should pass")
}
}