From 7251939107fee1506c005987cc9119e42e3fe8a4 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 13 Mar 2026 22:57:37 +0900 Subject: [PATCH] =?UTF-8?q?fix(fcm):=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20?= =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EC=A0=9C=EC=99=B8=20=EC=A0=95=EC=B1=85?= =?UTF-8?q?=EC=9D=84=20=EC=84=9C=EB=B9=84=EC=8A=A4=EC=97=90=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../can/charge/event/ChargeEventService.kt | 4 +- .../notification/PushNotificationService.kt | 1 + .../PushNotificationServiceTest.kt | 56 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt index 8d71de0d..1b644e5b 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt @@ -79,7 +79,7 @@ class ChargeEventService( applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.INDIVIDUAL, - category = PushNotificationCategory.MESSAGE, + category = PushNotificationCategory.SYSTEM, title = chargeEvent.title, messageKey = "can.charge.event.additional_can_paid", args = listOf(additionalCan), @@ -103,7 +103,7 @@ class ChargeEventService( applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.INDIVIDUAL, - category = PushNotificationCategory.MESSAGE, + category = PushNotificationCategory.SYSTEM, titleKey = "can.charge.event.first_title", messageKey = "can.charge.event.additional_can_paid", args = listOf(additionalCan), diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationService.kt index ba4ce54c..ec34350c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationService.kt @@ -48,6 +48,7 @@ class PushNotificationService( if (recipientMemberIds.isEmpty()) return val category = resolveCategory(fcmEvent) ?: return + if (category == PushNotificationCategory.SYSTEM) return val senderSnapshot = resolveSenderSnapshot(fcmEvent) val deepLink = FcmService.buildDeepLink( serverEnv = serverEnv, diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationServiceTest.kt index 8848711d..9a47c9e6 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/fcm/notification/PushNotificationServiceTest.kt @@ -78,6 +78,62 @@ class PushNotificationServiceTest { Mockito.verify(pushNotificationListRepository, Mockito.never()).save(Mockito.any(PushNotificationList::class.java)) } + @Test + fun shouldNotSaveWhenResolvedCategoryIsSystem() { + // given: 이벤트 category가 null이고 타입 기반 보정 결과가 SYSTEM인 상황을 준비한다. + val event = FcmEvent( + type = FcmEventType.INDIVIDUAL, + category = null, + recipients = listOf(1L) + ) + val pushTokens = listOf(PushTokenInfo(token = "token-1", deviceType = "aos", languageCode = "ko")) + + Mockito.`when`(pushTokenRepository.findMemberIdsByTokenIn(listOf("token-1"))).thenReturn(listOf(1L)) + + // when: 알림 적재를 실행한다. + service.saveNotification( + fcmEvent = event, + languageCode = "ko", + translatedMessage = "시스템 알림", + recipientPushTokens = pushTokens + ) + + // then: SYSTEM 카테고리 보정 결과에 따라 저장이 발생하지 않아야 한다. + Mockito.verify(pushNotificationListRepository, Mockito.never()).save(Mockito.any(PushNotificationList::class.java)) + } + + @Test + fun shouldSaveWhenCategoryIsNullAndResolvedCategoryIsNonSystem() { + // given: 이벤트 category가 null이어도 타입 기반 보정 결과가 LIVE면 저장되어야 한다. + val event = FcmEvent( + type = FcmEventType.START_LIVE, + category = null, + roomId = 11L, + creatorId = 20L, + deepLinkValue = FcmDeepLinkValue.LIVE, + deepLinkId = 11L + ) + val pushTokens = listOf(PushTokenInfo(token = "token-a", deviceType = "aos", languageCode = "ko")) + + Mockito.`when`(pushTokenRepository.findMemberIdsByTokenIn(listOf("token-a"))).thenReturn(listOf(10L)) + Mockito.`when`(pushNotificationListRepository.save(Mockito.any(PushNotificationList::class.java))) + .thenAnswer { invocation -> invocation.getArgument(0) } + + // when: 알림 적재를 실행한다. + service.saveNotification( + fcmEvent = event, + languageCode = "ko", + translatedMessage = "라이브가 시작되었습니다.", + recipientPushTokens = pushTokens + ) + + // then: 보정된 LIVE 카테고리로 저장되어야 한다. + val captor = ArgumentCaptor.forClass(PushNotificationList::class.java) + Mockito.verify(pushNotificationListRepository).save(captor.capture()) + val saved = captor.value + assertEquals(PushNotificationCategory.LIVE, saved.category) + } + @Test fun shouldSaveChunkedRecipientsAndSenderSnapshotWhenEventIsValid() { // given: 1001명의 수신자를 가진 유효 이벤트를 준비한다.