Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions TEST_STRATEGY.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ verification 모듈의 수동 QA 시나리오는 `VERIFICATION_TEST_PLAN.md` 를
- 미검증: 실기기의 갤러리 URI 접근·실서버 사진 반영·이미지 로딩 결과와 글꼴 크기별 점수 정렬.
실행 조건이 없는 종료·동기화·GPS·Jank·간헐적 오류는 이번 수정 범위에서 제외했다.

### 2026-10-29 무음 동기화 푸시 (#639)

- `RuleUpMessagingServiceTest`: sync 요청 푸시가 알림 없이 catch-up 작업을 예약하는지, 실제 스케줄러를 연결하면 네트워크 조건이 지정된 WorkManager 작업이 등록되는지 검증한다.
- 실제 FCM 전달과 WorkManager 실행은 실기기 및 서버에서 확인해야 한다.

### 2026-09-30 TTI Firebase Performance 연동 (#518)

- `ObservabilityTtiShooterTest` 5건: 저장된 전체·구간 시간(0ms 포함), 미완성 기록 제외,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.google.firebase.messaging.RemoteMessage
import com.ruleup.observability.domain.api.Observability
import com.ruleup.observability.domain.api.d
import com.ruleup.observability.domain.api.w
import com.ruleup.verification.domain.repository.SyncScheduler
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -18,6 +19,7 @@ private const val TAG = "[Push]"
// 페이로드 명세의 type 딱지.
private const val TYPE_SETUP_REQUIRED = "SETUP_REQUIRED"
private const val TYPE_PERMISSION_REQUIRED = "PERMISSION_REQUIRED"
private const val TYPE_SYNC_REQUIRED = "SYNC_REQUIRED"

/** FCM 수신 진입점. */
@AndroidEntryPoint
Expand All @@ -31,6 +33,9 @@ class RuleUpMessagingService : FirebaseMessagingService() {
@Inject
lateinit var notificationPresenter: NotificationPresenter

@Inject
lateinit var syncScheduler: SyncScheduler

private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

override fun onNewToken(token: String) {
Expand All @@ -45,6 +50,7 @@ class RuleUpMessagingService : FirebaseMessagingService() {
when (val type = data["type"]) {
// 무음 쪽지: 알림 없음.
TYPE_SETUP_REQUIRED, TYPE_PERMISSION_REQUIRED -> Unit
TYPE_SYNC_REQUIRED -> syncScheduler.enqueueCatchUp()

else -> {
val push =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.ruleup.android_ruleup.push

import android.app.Application
import androidx.work.Configuration
import androidx.work.NetworkType
import androidx.work.WorkManager
import com.google.firebase.messaging.RemoteMessage
import com.ruleup.observability.domain.test.testObservability
import com.ruleup.verification.data.sync.VerificationSyncSchedulerImpl
import com.ruleup.verification.domain.repository.SyncScheduler
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.annotation.Config
import java.util.concurrent.TimeUnit
import kotlin.test.assertEquals

@RunWith(RobolectricTestRunner::class)
@Config(application = Application::class, sdk = [33])
class RuleUpMessagingServiceTest {
@Test
fun `sync 요청 푸시를 받으면 네트워크가 연결된 경우 실행할 작업이 등록된다`() {
val context = RuntimeEnvironment.getApplication()
WorkManager.initialize(context, Configuration.Builder().build())
val manager = WorkManager.getInstance(context)
val service =
RuleUpMessagingService().apply {
syncScheduler = VerificationSyncSchedulerImpl(context)
observability = testObservability()
}

service.onMessageReceived(RemoteMessage.Builder("test").addData("type", "SYNC_REQUIRED").build())

val work = manager.getWorkInfosForUniqueWork(VerificationSyncSchedulerImpl.CATCH_UP_WORK_NAME).get(10, TimeUnit.SECONDS).single()
assertEquals(NetworkType.CONNECTED, work.constraints.requiredNetworkType)
}

@Test
fun `sync 요청 푸시는 알림 없이 catch-up 동기화를 예약한다`() {
val scheduler = FakeSyncScheduler()
val service =
RuleUpMessagingService().apply {
syncScheduler = scheduler
observability = testObservability()
}
val message = RemoteMessage.Builder("test").addData("type", "SYNC_REQUIRED").build()

service.onMessageReceived(message)

assertEquals(1, scheduler.catchUpCount)
}

private class FakeSyncScheduler : SyncScheduler {
var catchUpCount = 0

override fun enqueueCatchUp() {
catchUpCount++
}

override fun cancel() = Unit

override fun ensureScheduled() = Unit

override fun reschedule(flushIntervalSec: Int) = Unit
}
}
Loading