admin_service_credentials_merge_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. //go:build unit
  2. package service
  3. import (
  4. "context"
  5. "testing"
  6. "github.com/stretchr/testify/require"
  7. )
  8. type updateAccountCredsRepoStub struct {
  9. mockAccountRepoForGemini
  10. account *Account
  11. updateCalls int
  12. }
  13. func (r *updateAccountCredsRepoStub) GetByID(ctx context.Context, id int64) (*Account, error) {
  14. return r.account, nil
  15. }
  16. func (r *updateAccountCredsRepoStub) Update(ctx context.Context, account *Account) error {
  17. r.updateCalls++
  18. r.account = account
  19. return nil
  20. }
  21. func TestUpdateAccount_PreservesSensitiveCredsWhenIncomingOmits(t *testing.T) {
  22. accountID := int64(202)
  23. repo := &updateAccountCredsRepoStub{
  24. account: &Account{
  25. ID: accountID,
  26. Platform: PlatformAnthropic,
  27. Type: AccountTypeOAuth,
  28. Status: StatusActive,
  29. Credentials: map[string]any{
  30. "refresh_token": "rt-existing",
  31. "access_token": "at-existing",
  32. "id_token": "id-existing",
  33. "base_url": "https://old.example.com",
  34. },
  35. },
  36. }
  37. svc := &adminServiceImpl{accountRepo: repo}
  38. // 模拟前端编辑:仅修改 base_url,没有传 token(脱敏后前端 spread 拿不到敏感键)
  39. updated, err := svc.UpdateAccount(context.Background(), accountID, &UpdateAccountInput{
  40. Credentials: map[string]any{
  41. "base_url": "https://new.example.com",
  42. },
  43. })
  44. require.NoError(t, err)
  45. require.NotNil(t, updated)
  46. require.Equal(t, 1, repo.updateCalls)
  47. // 敏感键应保留
  48. require.Equal(t, "rt-existing", repo.account.Credentials["refresh_token"])
  49. require.Equal(t, "at-existing", repo.account.Credentials["access_token"])
  50. require.Equal(t, "id-existing", repo.account.Credentials["id_token"])
  51. // 非敏感键被替换
  52. require.Equal(t, "https://new.example.com", repo.account.Credentials["base_url"])
  53. }
  54. func TestUpdateAccount_ExplicitNewTokenOverwrites(t *testing.T) {
  55. accountID := int64(203)
  56. repo := &updateAccountCredsRepoStub{
  57. account: &Account{
  58. ID: accountID,
  59. Platform: PlatformAnthropic,
  60. Type: AccountTypeOAuth,
  61. Status: StatusActive,
  62. Credentials: map[string]any{
  63. "refresh_token": "rt-old",
  64. "api_key": "sk-old",
  65. },
  66. },
  67. }
  68. svc := &adminServiceImpl{accountRepo: repo}
  69. updated, err := svc.UpdateAccount(context.Background(), accountID, &UpdateAccountInput{
  70. Credentials: map[string]any{
  71. "refresh_token": "rt-new",
  72. // api_key 没传 → 应保留旧值
  73. },
  74. })
  75. require.NoError(t, err)
  76. require.NotNil(t, updated)
  77. require.Equal(t, "rt-new", repo.account.Credentials["refresh_token"])
  78. require.Equal(t, "sk-old", repo.account.Credentials["api_key"])
  79. }
  80. func TestUpdateAccount_EmptyCredentialsSkipsUpdate(t *testing.T) {
  81. accountID := int64(204)
  82. repo := &updateAccountCredsRepoStub{
  83. account: &Account{
  84. ID: accountID,
  85. Platform: PlatformAnthropic,
  86. Type: AccountTypeOAuth,
  87. Status: StatusActive,
  88. Credentials: map[string]any{
  89. "refresh_token": "rt-existing",
  90. },
  91. },
  92. }
  93. svc := &adminServiceImpl{accountRepo: repo}
  94. _, err := svc.UpdateAccount(context.Background(), accountID, &UpdateAccountInput{
  95. Credentials: map[string]any{}, // len == 0 → 闸门跳过
  96. Name: "renamed",
  97. })
  98. require.NoError(t, err)
  99. require.Equal(t, "rt-existing", repo.account.Credentials["refresh_token"], "空 credentials 不应触碰已有 token")
  100. require.Equal(t, "renamed", repo.account.Name)
  101. }