@@ -137,8 +137,8 @@ struct FCMTokenSyncHandlerTests {
137137 _ = handler
138138 }
139139
140- @Test ( " 같은 사용자와 같은 FCM token도 매번 저장한다 " )
141- func 같은_사용자와_같은_FCM_token도_매번_저장한다 ( ) async throws {
140+ @Test ( " 같은 사용자와 같은 FCM token은 한 번만 저장한다 " )
141+ func 같은_사용자와_같은_FCM_token은_한_번만_저장한다 ( ) async throws {
142142 let notificationCenter = NotificationCenter ( )
143143 let messagingService = PushMessagingServiceSpy ( currentFCMToken: " current-token " )
144144 let userService = UserServiceSpy ( )
@@ -156,9 +156,8 @@ struct FCMTokenSyncHandlerTests {
156156 }
157157
158158 notificationCenter. post ( name: . didRequestFCMTokenSync, object: nil )
159- try await waitUntil {
160- await userService. updatedFCMTokens == [ " current-token " , " current-token " ]
161- }
159+ try await Task . sleep ( for: . milliseconds( 100 ) )
160+ #expect( await userService. updatedFCMTokens == [ " current-token " ] )
162161
163162 _ = handler
164163 }
@@ -189,6 +188,72 @@ struct FCMTokenSyncHandlerTests {
189188 _ = handler
190189 }
191190
191+ @Test ( " FCM token이 바뀌면 같은 사용자도 다시 저장한다 " )
192+ func FCM_token이_바뀌면_같은_사용자도_다시_저장한다( ) async throws {
193+ let notificationCenter = NotificationCenter ( )
194+ let messagingService = PushMessagingServiceSpy ( currentFCMToken: " first-token " )
195+ let userService = UserServiceSpy ( )
196+ let authService = AuthServiceSpy ( )
197+ let handler = FCMTokenSyncHandler (
198+ authService: authService,
199+ messagingService: messagingService,
200+ userService: userService,
201+ notificationCenter: notificationCenter
202+ )
203+
204+ notificationCenter. post ( name: . didRequestFCMTokenSync, object: nil )
205+ try await waitUntil { await userService. updatedFCMTokens == [ " first-token " ] }
206+
207+ messagingService. currentFCMToken = " second-token "
208+ notificationCenter. post ( name: . didRequestFCMTokenSync, object: nil )
209+ try await waitUntil { await userService. updatedFCMTokens == [ " first-token " , " second-token " ] }
210+ _ = handler
211+ }
212+
213+ @Test ( " 로그아웃 후 같은 사용자로 다시 로그인하면 같은 FCM token도 다시 저장한다 " )
214+ func 로그아웃_후_같은_사용자로_다시_로그인하면_같은_FCM_token도_다시_저장한다( ) async throws {
215+ let notificationCenter = NotificationCenter ( )
216+ let messagingService = PushMessagingServiceSpy ( currentFCMToken: " current-token " )
217+ let userService = UserServiceSpy ( )
218+ let authService = AuthServiceSpy ( uid: " user-id " )
219+ let handler = FCMTokenSyncHandler (
220+ authService: authService,
221+ messagingService: messagingService,
222+ userService: userService,
223+ notificationCenter: notificationCenter
224+ )
225+
226+ notificationCenter. post ( name: . didRequestFCMTokenSync, object: nil )
227+ try await waitUntil { await userService. updatedFCMTokens == [ " current-token " ] }
228+
229+ authService. updateSession ( uid: nil )
230+ authService. updateSession ( uid: " user-id " )
231+ try await waitUntil { await userService. updatedFCMTokens == [ " current-token " , " current-token " ] }
232+ _ = handler
233+ }
234+
235+ @Test ( " FCM token 저장에 실패하면 같은 요청을 다시 저장한다 " )
236+ func FCM_token_저장에_실패하면_같은_요청을_다시_저장한다( ) async throws {
237+ let notificationCenter = NotificationCenter ( )
238+ let messagingService = PushMessagingServiceSpy ( currentFCMToken: " current-token " )
239+ let userService = UserServiceSpy ( updateError: FCMTokenSyncTestError ( ) )
240+ let authService = AuthServiceSpy ( )
241+ let handler = FCMTokenSyncHandler (
242+ authService: authService,
243+ messagingService: messagingService,
244+ userService: userService,
245+ notificationCenter: notificationCenter
246+ )
247+
248+ notificationCenter. post ( name: . didRequestFCMTokenSync, object: nil )
249+ try await waitUntil { await userService. updatedFCMTokens == [ " current-token " ] }
250+
251+ await userService. setUpdateError ( nil )
252+ notificationCenter. post ( name: . didRequestFCMTokenSync, object: nil )
253+ try await waitUntil { await userService. updatedFCMTokens == [ " current-token " , " current-token " ] }
254+ _ = handler
255+ }
256+
192257 @Test ( " 로그인 세션 전이 시 현재 FCM token을 저장한다 " )
193258 func 로그인_세션_전이_시_현재_FCM_token을_저장한다( ) async throws {
194259 let notificationCenter = NotificationCenter ( )
@@ -214,16 +279,28 @@ struct FCMTokenSyncHandlerTests {
214279
215280private actor UserServiceSpy : UserService {
216281 private( set) var updatedFCMTokens = [ String] ( )
282+ private var updateError : Error ?
283+
284+ init ( updateError: Error ? = nil ) {
285+ self . updateError = updateError
286+ }
217287
218288 func upsertUser( _ response: AuthDataResponse ) async throws { }
219289 func fetchUserProfile( ) async throws -> UserProfileResponse { fatalError ( ) }
220290 func upsertStatusMessage( _ message: String ) async throws { }
221291
222292 func updateFCMToken( _ fcmToken: String ) async throws {
223293 updatedFCMTokens. append ( fcmToken)
294+ if let updateError {
295+ throw updateError
296+ }
224297 }
225298
226299 func updateUserTimeZone( ) async throws { }
300+
301+ func setUpdateError( _ error: Error ? ) {
302+ updateError = error
303+ }
227304}
228305
229306private final class AuthServiceSpy : AuthService {
@@ -255,7 +332,7 @@ private final class AuthServiceSpy: AuthService {
255332}
256333
257334private final class PushMessagingServiceSpy : PushMessagingService {
258- private let currentFCMToken : String ?
335+ var currentFCMToken : String ?
259336 private( set) var apnsTokens = [ Data] ( )
260337
261338 init ( currentFCMToken: String ? ) {
@@ -273,6 +350,8 @@ private final class PushMessagingServiceSpy: PushMessagingService {
273350 }
274351}
275352
353+ private struct FCMTokenSyncTestError : Error { }
354+
276355private final class NotificationObserver {
277356 private( set) var didReceiveNotification = false
278357 private var token : NSObjectProtocol ?
0 commit comments