Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Fix: Use SqlCipherDeletingErrorHandler in JobDatabase for corruption handling (#13762) #13798

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class JobDatabase(
null,
DATABASE_VERSION,
0,
SqlCipherErrorHandler(DATABASE_NAME),
SqlCipherDeletingErrorHandler(DATABASE_NAME),
SqlCipherDatabaseHook(),
true
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import android.app.Application
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.unmockkObject
import io.mockk.verify
import net.zetetic.database.sqlcipher.SQLiteDatabase
import net.zetetic.database.sqlcipher.SQLiteOpenHelper
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.thoughtcrime.securesms.crypto.DatabaseSecret
import org.thoughtcrime.securesms.database.JobDatabase
import org.thoughtcrime.securesms.database.SqlCipherDeletingErrorHandler
import org.thoughtcrime.securesms.dependencies.AppDependencies

class JobDatabaseTest {

private lateinit var mockApplication: Application
private lateinit var mockDatabase: SQLiteDatabase
private lateinit var sqlCipherDeletingErrorHandler: SqlCipherDeletingErrorHandler
private lateinit var databaseSecret: DatabaseSecret

@Before
fun setUp() {
mockApplication = mockk(relaxed = true)

// Set _application field in AppDependencies using reflection
val applicationField = AppDependencies::class.java.getDeclaredField("_application")
applicationField.isAccessible = true
applicationField.set(null, mockApplication)

databaseSecret = mockk(relaxed = true)
mockDatabase = mockk(relaxed = true)
every { mockDatabase.rawQuery(any(), any()) } returns mockk()
sqlCipherDeletingErrorHandler = spyk(SqlCipherDeletingErrorHandler("signal-jobmanager.db"))
every { mockApplication.deleteDatabase("signal-jobmanager.db") } returns true
}

@After
fun tearDown() {
unmockkObject(AppDependencies)
}

@Test
fun `onCorruption deletes database on corruption event`() {
sqlCipherDeletingErrorHandler.onCorruption(mockDatabase, "Database corrupted!")
verify { mockApplication.deleteDatabase("signal-jobmanager.db") }
}

@Test
fun `JobDatabase initializes with SqlCipherDeletingErrorHandler`() {
val jobDatabase = JobDatabase(mockApplication, databaseSecret)

// Use reflection to access the private errorHandler field
val errorHandlerField = SQLiteOpenHelper::class.java.getDeclaredField("mErrorHandler")
errorHandlerField.isAccessible = true
val errorHandler = errorHandlerField.get(jobDatabase)
assert(errorHandler is SqlCipherDeletingErrorHandler) {
"Expected SqlCipherDeletingErrorHandler, but got ${errorHandler?.javaClass?.name}"
}
}
}