Skip to content

Commit f4bc069

Browse files
committed
Merge branch 'chore/room-schema-recreate-598' into dev #598
2 parents ad41241 + b5d2c84 commit f4bc069

2 files changed

Lines changed: 86 additions & 0 deletions

File tree

data/src/main/java/com/project200/data/di/DatabaseModule.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ abstract class DatabaseModule {
3131
return UndabangTypeConverters(moshi)
3232
}
3333

34+
/**
35+
* 출시 전이라 마이그레이션 대신 재생성을 씁니다.
36+
*
37+
* 스키마를 바꿀 때는 version을 올립니다. version을 그대로 두고 스키마만 바꾸면
38+
* identityHash가 어긋나 재생성 없이 크래시합니다
39+
*
40+
* 주의: 재생성은 전송 대기 행까지 지웁니다. 출시 뒤에는 이 설정을 걷고
41+
* 마이그레이션을 씁니다
42+
*/
3443
@Provides
3544
@Singleton
3645
fun provideUndabangDatabase(
@@ -43,6 +52,7 @@ abstract class DatabaseModule {
4352
UndabangDatabase.DATABASE_NAME,
4453
)
4554
.addTypeConverter(typeConverters)
55+
.fallbackToDestructiveMigration()
4656
.build()
4757
}
4858

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.project200.data.di
2+
3+
import android.database.sqlite.SQLiteDatabase
4+
import com.google.common.truth.Truth.assertThat
5+
import com.project200.data.local.UndabangDatabase
6+
import com.project200.data.local.UndabangTypeConverters
7+
import com.project200.data.local.entity.ExerciseCountEntity
8+
import com.squareup.moshi.Moshi
9+
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
10+
import kotlinx.coroutines.test.runTest
11+
import org.junit.Test
12+
import org.junit.runner.RunWith
13+
import org.robolectric.RobolectricTestRunner
14+
import org.robolectric.RuntimeEnvironment
15+
import java.time.LocalDate
16+
17+
/**
18+
* 출시 전 스키마 정책을 검증합니다.
19+
*
20+
* 파일의 version을 낮춰 구버전 DB를 만든 뒤 다시 열어, 마이그레이션 없이도
21+
* 크래시하지 않고 재생성되는지 봅니다
22+
*/
23+
@RunWith(RobolectricTestRunner::class)
24+
class SchemaRecreatePolicyTest {
25+
private val context = RuntimeEnvironment.getApplication()
26+
private val converters = UndabangTypeConverters(Moshi.Builder().add(KotlinJsonAdapterFactory()).build())
27+
28+
private fun openDatabase(): UndabangDatabase = DatabaseModule.provideUndabangDatabase(context, converters)
29+
30+
private val date = LocalDate.parse("2026-09-10")
31+
32+
@Test
33+
fun `파일 버전이 코드와 어긋나면 재생성한다`() =
34+
runTest {
35+
// Given: 캐시가 쌓인 DB
36+
var database = openDatabase()
37+
database.exerciseCountDao().upsertAll(
38+
listOf(ExerciseCountEntity(memberId = "member-a", date = date, count = 2)),
39+
)
40+
assertThat(database.exerciseCountDao().getRange("member-a", date, date)).hasSize(1)
41+
database.close()
42+
43+
// When: 파일 버전을 코드보다 앞선 값으로 바꿔 마이그레이션이 없는 상태를 만든다
44+
val path = context.getDatabasePath(UndabangDatabase.DATABASE_NAME).absolutePath
45+
val mismatched =
46+
SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE).use { raw ->
47+
raw.version = 2
48+
raw.version
49+
}
50+
assertThat(mismatched).isEqualTo(2)
51+
database = openDatabase()
52+
53+
// Then: 예외 없이 열리고 캐시는 비어 있다
54+
assertThat(database.exerciseCountDao().getRange("member-a", date, date)).isEmpty()
55+
database.close()
56+
}
57+
58+
@Test
59+
fun `같은 version이면 저장한 값이 유지된다`() =
60+
runTest {
61+
// Given
62+
var database = openDatabase()
63+
database.exerciseCountDao().upsertAll(
64+
listOf(ExerciseCountEntity(memberId = "member-a", date = date, count = 3)),
65+
)
66+
database.close()
67+
68+
// When
69+
database = openDatabase()
70+
71+
// Then: 재생성 정책이 정상 재열기까지 지우지는 않는다
72+
val counts = database.exerciseCountDao().getRange("member-a", date, date)
73+
assertThat(counts.single().count).isEqualTo(3)
74+
database.close()
75+
}
76+
}

0 commit comments

Comments
 (0)