Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

240 строки
6.0 KiB

  1. package user_migration
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/QuantumNous/new-api/model"
  6. "github.com/glebarez/sqlite"
  7. "github.com/stretchr/testify/require"
  8. "gorm.io/gorm"
  9. )
  10. type fakeClient struct {
  11. listPages map[int][]RemoteUserSnapshot
  12. getUserResp *RemoteUserSnapshot
  13. getUserByID map[int]*RemoteUserSnapshot
  14. hasCopyResult bool
  15. hasCopyByID map[int]bool
  16. convertCalls []int
  17. convertReqs map[int]*ConvertRemoteUserRequest
  18. }
  19. func (f *fakeClient) ListUsers(page, pageSize int) (*ListRemoteUsersResponse, error) {
  20. users := f.listPages[page]
  21. return &ListRemoteUsersResponse{
  22. Success: true,
  23. Data: users,
  24. Total: len(users),
  25. }, nil
  26. }
  27. func (f *fakeClient) GetUser(userId int) (*RemoteUserSnapshot, error) {
  28. if snapshot, ok := f.getUserByID[userId]; ok {
  29. return snapshot, nil
  30. }
  31. if f.getUserResp != nil {
  32. return f.getUserResp, nil
  33. }
  34. return nil, fmt.Errorf("user %d not found", userId)
  35. }
  36. func (f *fakeClient) ConvertToSynced(userId int, req *ConvertRemoteUserRequest) error {
  37. f.convertCalls = append(f.convertCalls, userId)
  38. if f.convertReqs == nil {
  39. f.convertReqs = make(map[int]*ConvertRemoteUserRequest)
  40. }
  41. if req != nil {
  42. copyReq := *req
  43. f.convertReqs[userId] = &copyReq
  44. }
  45. return nil
  46. }
  47. func (f *fakeClient) HasSyncedCopy(cnUserId int) (bool, error) {
  48. if value, ok := f.hasCopyByID[cnUserId]; ok {
  49. return value, nil
  50. }
  51. return f.hasCopyResult, nil
  52. }
  53. func setupMigrationServiceDB(t *testing.T) *gorm.DB {
  54. t.Helper()
  55. db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
  56. require.NoError(t, err)
  57. sqlDB, err := db.DB()
  58. require.NoError(t, err)
  59. sqlDB.SetMaxOpenConns(1)
  60. require.NoError(t, db.AutoMigrate(
  61. &model.User{},
  62. &model.CustomOAuthProvider{},
  63. &model.UserOAuthBinding{},
  64. &model.UserMigrationBatch{},
  65. &model.UserMigrationItem{},
  66. &model.MigrationQuotaGrant{},
  67. ))
  68. return db
  69. }
  70. func TestScanBatch_NoConflict_MarksReady(t *testing.T) {
  71. db := setupMigrationServiceDB(t)
  72. orig := model.DB
  73. model.DB = db
  74. defer func() {
  75. model.DB = orig
  76. }()
  77. batch := &model.UserMigrationBatch{Name: "wave-1", SourceRegion: "ov", TargetRegion: "cn", OperatorId: 1}
  78. require.NoError(t, model.CreateUserMigrationBatch(batch))
  79. client := &fakeClient{
  80. listPages: map[int][]RemoteUserSnapshot{
  81. 0: {{
  82. Id: 10000001,
  83. Username: "ov-bob",
  84. Email: "bob@example.com",
  85. Quota: 456,
  86. AffCode: "A002",
  87. }},
  88. },
  89. }
  90. svc := &Service{client: client}
  91. require.NoError(t, svc.ScanBatch(batch.Id))
  92. items, err := model.ListUserMigrationItemsByBatch(batch.Id)
  93. require.NoError(t, err)
  94. require.Len(t, items, 1)
  95. require.Equal(t, model.UserMigrationStrategyCreateNew, items[0].ResolutionStrategy)
  96. require.Equal(t, model.UserMigrationItemStatusReady, items[0].Status)
  97. var savedBatch model.UserMigrationBatch
  98. require.NoError(t, db.First(&savedBatch, batch.Id).Error)
  99. require.Equal(t, model.UserMigrationBatchStatusReady, savedBatch.Status)
  100. }
  101. func TestScanBatch_EmailConflict_NoCNSyncedCopy_RecommendsMerge(t *testing.T) {
  102. db := setupMigrationServiceDB(t)
  103. orig := model.DB
  104. model.DB = db
  105. defer func() {
  106. model.DB = orig
  107. }()
  108. require.NoError(t, db.Create(&model.User{
  109. Id: 1,
  110. Username: "cn-alice",
  111. Password: "hash",
  112. Email: "alice@example.com",
  113. AffCode: "C001",
  114. }).Error)
  115. batch := &model.UserMigrationBatch{Name: "wave-2", SourceRegion: "ov", TargetRegion: "cn", OperatorId: 1}
  116. require.NoError(t, model.CreateUserMigrationBatch(batch))
  117. client := &fakeClient{
  118. listPages: map[int][]RemoteUserSnapshot{
  119. 0: {{
  120. Id: 10000001,
  121. Username: "ov-alice",
  122. Email: "alice@example.com",
  123. Quota: 123,
  124. AffCode: "A001",
  125. }},
  126. },
  127. hasCopyResult: false,
  128. }
  129. svc := &Service{client: client}
  130. require.NoError(t, svc.ScanBatch(batch.Id))
  131. items, err := model.ListUserMigrationItemsByBatch(batch.Id)
  132. require.NoError(t, err)
  133. require.Len(t, items, 1)
  134. require.Equal(t, model.UserMigrationStrategyMergeExisting, items[0].ResolutionStrategy)
  135. require.Equal(t, model.UserMigrationItemStatusReady, items[0].Status)
  136. require.Equal(t, 1, items[0].TargetUserId)
  137. }
  138. func TestScanBatch_EmailConflict_CNHasSyncedCopy_MarksHardConflict(t *testing.T) {
  139. db := setupMigrationServiceDB(t)
  140. orig := model.DB
  141. model.DB = db
  142. defer func() {
  143. model.DB = orig
  144. }()
  145. require.NoError(t, db.Create(&model.User{
  146. Id: 456,
  147. Username: "cn-user456",
  148. Password: "hash",
  149. Email: "shared@example.com",
  150. AffCode: "C456",
  151. }).Error)
  152. batch := &model.UserMigrationBatch{Name: "wave-3", SourceRegion: "ov", TargetRegion: "cn", OperatorId: 1}
  153. require.NoError(t, model.CreateUserMigrationBatch(batch))
  154. client := &fakeClient{
  155. listPages: map[int][]RemoteUserSnapshot{
  156. 0: {{
  157. Id: 10000003,
  158. Username: "ov-x",
  159. Email: "shared@example.com",
  160. Quota: 50,
  161. AffCode: "OVX",
  162. }},
  163. },
  164. hasCopyResult: true,
  165. }
  166. svc := &Service{client: client}
  167. require.NoError(t, svc.ScanBatch(batch.Id))
  168. items, err := model.ListUserMigrationItemsByBatch(batch.Id)
  169. require.NoError(t, err)
  170. require.Len(t, items, 1)
  171. require.Equal(t, model.UserMigrationItemStatusConflict, items[0].Status)
  172. require.Contains(t, items[0].ConflictFlags, "cn_already_synced_to_ov")
  173. }
  174. func TestScanBatch_Paginated(t *testing.T) {
  175. db := setupMigrationServiceDB(t)
  176. orig := model.DB
  177. model.DB = db
  178. defer func() {
  179. model.DB = orig
  180. }()
  181. batch := &model.UserMigrationBatch{Name: "wave-big", SourceRegion: "ov", TargetRegion: "cn", OperatorId: 1}
  182. require.NoError(t, model.CreateUserMigrationBatch(batch))
  183. page0 := make([]RemoteUserSnapshot, scanPageSize)
  184. for i := range page0 {
  185. page0[i] = RemoteUserSnapshot{
  186. Id: 10000001 + i,
  187. Username: fmt.Sprintf("u%d", i),
  188. AffCode: fmt.Sprintf("A%d", i),
  189. }
  190. }
  191. page1 := []RemoteUserSnapshot{{
  192. Id: 10000001 + scanPageSize,
  193. Username: "last",
  194. AffCode: "LAST",
  195. }}
  196. client := &fakeClient{
  197. listPages: map[int][]RemoteUserSnapshot{
  198. 0: page0,
  199. 1: page1,
  200. },
  201. }
  202. svc := &Service{client: client}
  203. require.NoError(t, svc.ScanBatch(batch.Id))
  204. items, err := model.ListUserMigrationItemsByBatch(batch.Id)
  205. require.NoError(t, err)
  206. require.Len(t, items, scanPageSize+1)
  207. }