118 lines
3.7 KiB
Go
118 lines
3.7 KiB
Go
package redisstore
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"telesrv/internal/domain"
|
|
)
|
|
|
|
func TestUserCacheRoundTrip(t *testing.T) {
|
|
addr := os.Getenv("TELESRV_TEST_REDIS_ADDR")
|
|
if addr == "" {
|
|
t.Skip("set TELESRV_TEST_REDIS_ADDR to run redis integration test")
|
|
}
|
|
ctx := context.Background()
|
|
c, err := Open(ctx, addr, "", 0)
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = c.Close() })
|
|
|
|
const userID int64 = 77000001
|
|
cache := NewUserCache(c, time.Minute)
|
|
t.Cleanup(func() { _ = c.Del(ctx, userBaseKey(userID), userBaseKey(userID+1)).Err() })
|
|
|
|
want := domain.User{
|
|
ID: userID,
|
|
AccessHash: 12345,
|
|
Phone: "15550000001",
|
|
FirstName: "Alice",
|
|
LastName: "Base",
|
|
About: "about",
|
|
Username: "alice_base",
|
|
CountryCode: "US",
|
|
Verified: true,
|
|
Support: true,
|
|
LastSeenAt: 99,
|
|
Contact: true,
|
|
PhotoID: 42,
|
|
Birthday: domain.Birthday{Day: 14, Month: 2, Year: 1990},
|
|
PersonalChannelID: 555,
|
|
}
|
|
if err := cache.PutMany(ctx, []domain.User{want, want}); err != nil {
|
|
t.Fatalf("put: %v", err)
|
|
}
|
|
got, err := cache.GetByIDs(ctx, []int64{userID, userID + 1, userID})
|
|
if err != nil {
|
|
t.Fatalf("get: %v", err)
|
|
}
|
|
u, ok := got[userID]
|
|
if !ok {
|
|
t.Fatalf("cached user %d not found", userID)
|
|
}
|
|
if u.ID != want.ID || u.AccessHash != want.AccessHash || u.FirstName != want.FirstName || u.Username != want.Username || u.LastSeenAt != want.LastSeenAt {
|
|
t.Fatalf("cached base mismatch: got %+v want %+v", u, want)
|
|
}
|
|
if u.Contact || u.PhotoID != 0 {
|
|
t.Fatalf("viewer overlay leaked into base cache: %+v", u)
|
|
}
|
|
// birthday / personal channel 必须随缓存往返(缓存命中路径丢失会让刚保存的值归零)。
|
|
if u.Birthday != want.Birthday || u.PersonalChannelID != want.PersonalChannelID {
|
|
t.Fatalf("birthday/personal channel lost in base cache round-trip: got birthday=%+v personal=%d", u.Birthday, u.PersonalChannelID)
|
|
}
|
|
if _, ok := got[userID+1]; ok {
|
|
t.Fatalf("unexpected missing user hit: %+v", got[userID+1])
|
|
}
|
|
|
|
if err := c.Set(ctx, userBaseKey(userID+1), "{bad json", time.Minute).Err(); err != nil {
|
|
t.Fatalf("set corrupt: %v", err)
|
|
}
|
|
got, err = cache.GetByIDs(ctx, []int64{userID + 1})
|
|
if err != nil {
|
|
t.Fatalf("get corrupt: %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Fatalf("corrupt cache returned users: %+v", got)
|
|
}
|
|
if n, err := c.Exists(ctx, userBaseKey(userID+1)).Result(); err != nil || n != 0 {
|
|
t.Fatalf("corrupt key exists=%d err=%v, want deleted", n, err)
|
|
}
|
|
|
|
if err := cache.PutMany(ctx, []domain.User{{ID: userID + 1, AccessHash: 6789, FirstName: "WrongKey"}}); err != nil {
|
|
t.Fatalf("put mismatched payload source: %v", err)
|
|
}
|
|
raw, err := c.Get(ctx, userBaseKey(userID+1)).Result()
|
|
if err != nil {
|
|
t.Fatalf("get raw mismatched source: %v", err)
|
|
}
|
|
if err := c.Set(ctx, userBaseKey(userID), raw, time.Minute).Err(); err != nil {
|
|
t.Fatalf("set mismatched payload: %v", err)
|
|
}
|
|
got, err = cache.GetByIDs(ctx, []int64{userID})
|
|
if err != nil {
|
|
t.Fatalf("get mismatched payload: %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Fatalf("mismatched payload returned users: %+v", got)
|
|
}
|
|
if n, err := c.Exists(ctx, userBaseKey(userID)).Result(); err != nil || n != 0 {
|
|
t.Fatalf("mismatched key exists=%d err=%v, want deleted", n, err)
|
|
}
|
|
|
|
if err := cache.PutMany(ctx, []domain.User{want}); err != nil {
|
|
t.Fatalf("restore user: %v", err)
|
|
}
|
|
if err := cache.Delete(ctx, []int64{userID}); err != nil {
|
|
t.Fatalf("delete: %v", err)
|
|
}
|
|
got, err = cache.GetByIDs(ctx, []int64{userID})
|
|
if err != nil {
|
|
t.Fatalf("get after delete: %v", err)
|
|
}
|
|
if len(got) != 0 {
|
|
t.Fatalf("cache hit after delete: %+v", got)
|
|
}
|
|
}
|