admin_group_platform_cache_test.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. //go:build unit
  2. package service
  3. import (
  4. "context"
  5. "testing"
  6. "github.com/stretchr/testify/require"
  7. )
  8. // groupPlatformRepoStub 只实现 UpdateGroup 走到的两个方法,其余靠内嵌接口占位。
  9. type groupPlatformRepoStub struct {
  10. GroupRepository
  11. group *Group
  12. updated *Group
  13. }
  14. func (r *groupPlatformRepoStub) GetByID(_ context.Context, _ int64) (*Group, error) {
  15. cloned := *r.group
  16. return &cloned, nil
  17. }
  18. func (r *groupPlatformRepoStub) Update(_ context.Context, group *Group) error {
  19. r.updated = group
  20. return nil
  21. }
  22. type channelCacheInvalidatorSpy struct {
  23. calls int
  24. }
  25. func (s *channelCacheInvalidatorSpy) InvalidateCache() { s.calls++ }
  26. // 渠道缓存持有 groupID → platform,而渠道定价/模型映射/模型白名单都按平台严格隔离。
  27. // 改了分组平台却不失效缓存,最长 10 分钟内这些查找仍按旧平台匹配(静默走错价)。
  28. func TestUpdateGroupInvalidatesChannelCacheOnPlatformChange(t *testing.T) {
  29. tests := []struct {
  30. name string
  31. fromPlatform string
  32. inputPlatform string
  33. wantCalls int
  34. }{
  35. {
  36. name: "platform changed invalidates",
  37. fromPlatform: PlatformAnthropic,
  38. inputPlatform: PlatformOpenAI,
  39. wantCalls: 1,
  40. },
  41. {
  42. name: "same platform does not invalidate",
  43. fromPlatform: PlatformAnthropic,
  44. inputPlatform: PlatformAnthropic,
  45. wantCalls: 0,
  46. },
  47. {
  48. // 请求里不带 platform 字段时不应该动缓存
  49. name: "platform omitted does not invalidate",
  50. fromPlatform: PlatformAnthropic,
  51. inputPlatform: "",
  52. wantCalls: 0,
  53. },
  54. }
  55. for _, tt := range tests {
  56. t.Run(tt.name, func(t *testing.T) {
  57. repo := &groupPlatformRepoStub{group: &Group{ID: 7, Name: "g", Platform: tt.fromPlatform}}
  58. spy := &channelCacheInvalidatorSpy{}
  59. svc := &adminServiceImpl{groupRepo: repo, channelCacheInvalidator: spy}
  60. got, err := svc.UpdateGroup(context.Background(), 7, &UpdateGroupInput{Platform: tt.inputPlatform})
  61. require.NoError(t, err)
  62. require.NotNil(t, got)
  63. require.Equal(t, tt.wantCalls, spy.calls)
  64. })
  65. }
  66. }
  67. // 依赖可以不注入(例如测试或裁剪构建),此时不应 panic——缓存靠 TTL 自然重建。
  68. func TestUpdateGroupWithoutChannelCacheInvalidator(t *testing.T) {
  69. repo := &groupPlatformRepoStub{group: &Group{ID: 7, Name: "g", Platform: PlatformAnthropic}}
  70. svc := &adminServiceImpl{groupRepo: repo}
  71. got, err := svc.UpdateGroup(context.Background(), 7, &UpdateGroupInput{Platform: PlatformOpenAI})
  72. require.NoError(t, err)
  73. require.Equal(t, PlatformOpenAI, got.Platform)
  74. }