Skip to content

Commit

Permalink
Merge pull request #3863 from kiwix/Fixes#3113
Browse files Browse the repository at this point in the history
Migrated Notes to room database.
  • Loading branch information
kelson42 authored Jun 7, 2024
2 parents 9b1bb3d + cf58340 commit 3bd5380
Show file tree
Hide file tree
Showing 28 changed files with 558 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,19 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
import org.kiwix.kiwixmobile.core.dao.NotesRoomDao
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity
import org.kiwix.kiwixmobile.core.data.KiwixRoomDatabase
import org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem

@RunWith(AndroidJUnit4::class)
class KiwixRoomDatabaseTest {
private lateinit var recentSearchRoomDao: RecentSearchRoomDao
private lateinit var db: KiwixRoomDatabase
private lateinit var historyRoomDao: HistoryRoomDao
private lateinit var notesRoomDao: NotesRoomDao

@Before
fun setUpDatabase() {
Expand Down Expand Up @@ -103,7 +106,7 @@ class KiwixRoomDatabaseTest {

// test inserting into history database
historyRoomDao.saveHistory(historyItem)
var historyList = historyRoomDao.historyRoomEntity().first()
var historyList = historyRoomDao.historyRoomEntity().blockingFirst()
with(historyList.first()) {
assertThat(historyTitle, equalTo(historyItem.title))
assertThat(zimId, equalTo(historyItem.zimId))
Expand All @@ -117,21 +120,64 @@ class KiwixRoomDatabaseTest {

// test deleting the history
historyRoomDao.deleteHistory(listOf(historyItem))
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertEquals(historyList.size, 0)

// test deleting all history
historyRoomDao.saveHistory(historyItem)
historyRoomDao.saveHistory(
getHistoryItem(databaseId = 2)
)
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertEquals(historyList.size, 2)
historyRoomDao.deleteAllHistory()
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertEquals(historyList.size, 0)
}

@Test
fun testNoteRoomDao() = runBlocking {
notesRoomDao = db.notesRoomDao()
// delete all the notes from database to properly run the test cases.
notesRoomDao.deleteNotes(notesRoomDao.notes().blockingFirst() as List<NoteListItem>)
val noteItem = getNoteListItem(
zimUrl = "http://kiwix.app/MainPage",
noteFilePath = "/storage/emulated/0/Download/Notes/Alpine linux/MainPage.txt"
)

// Save and retrieve a notes item
notesRoomDao.saveNote(noteItem)
var notesList = notesRoomDao.notes().blockingFirst() as List<NoteListItem>
with(notesList.first()) {
assertThat(zimId, equalTo(noteItem.zimId))
assertThat(zimUrl, equalTo(noteItem.zimUrl))
assertThat(title, equalTo(noteItem.title))
assertThat(zimFilePath, equalTo(noteItem.zimFilePath))
assertThat(noteFilePath, equalTo(noteItem.noteFilePath))
assertThat(favicon, equalTo(noteItem.favicon))
}
assertEquals(notesList.size, 1)

// test deleting the history
notesRoomDao.deleteNotes(listOf(noteItem))
notesList = notesRoomDao.notes().blockingFirst() as List<NoteListItem>
assertEquals(notesList.size, 0)

// test deleting all notes
notesRoomDao.saveNote(noteItem)
notesRoomDao.saveNote(
getNoteListItem(
title = "Installing",
zimUrl = "http://kiwix.app/Installing"
)
)
notesList = notesRoomDao.notes().blockingFirst() as List<NoteListItem>
assertEquals(notesList.size, 2)
notesRoomDao.deletePages(notesRoomDao.notes().blockingFirst())
notesList = notesRoomDao.notes().blockingFirst() as List<NoteListItem>
assertEquals(notesList.size, 0)
}

companion object {
fun getHistoryItem(
title: String = "Installation",
Expand All @@ -154,5 +200,23 @@ class KiwixRoomDatabaseTest {
dateString = dateString,
timeStamp = timeStamp
)

fun getNoteListItem(
databaseId: Long = 0L,
zimId: String = "1f88ab6f-c265-b-3ff-8f49-b7f4429503800",
title: String = "Alpine Wiki",
zimFilePath: String = "/storage/emulated/0/Download/alpinelinux_en_all_maxi_2023-01.zim",
zimUrl: String,
noteFilePath: String = "/storage/emulated/0/Download/Notes/Alpine linux/AlpineNote.txt"
): NoteListItem = NoteListItem(
databaseId = databaseId,
zimId = zimId,
title = title,
zimFilePath = zimFilePath,
zimUrl = zimUrl,
noteFilePath = noteFilePath,
null,
false
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.kiwix.kiwixmobile.KiwixRoomDatabaseTest.Companion.getHistoryItem
import org.kiwix.kiwixmobile.KiwixRoomDatabaseTest.Companion.getNoteListItem
import org.kiwix.kiwixmobile.core.dao.entities.HistoryEntity
import org.kiwix.kiwixmobile.core.dao.entities.NotesEntity
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchEntity
import org.kiwix.kiwixmobile.core.data.KiwixRoomDatabase
import org.kiwix.kiwixmobile.core.data.remote.ObjectBoxToRoomMigrator
import org.kiwix.kiwixmobile.core.di.modules.DatabaseModule
import org.kiwix.kiwixmobile.core.page.notes.adapter.NoteListItem
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil

@RunWith(AndroidJUnit4::class)
Expand Down Expand Up @@ -162,10 +165,12 @@ class ObjectBoxToRoomMigratorTest {
assertTrue("Migration took too long: $migrationTime ms", migrationTime < 20000)
}

private fun <T> clearRoomAndBoxStoreDatabases(box: Box<T>) {
private suspend fun <T> clearRoomAndBoxStoreDatabases(box: Box<T>) {
// delete history for testing other edge cases
kiwixRoomDatabase.recentSearchRoomDao().deleteSearchHistory()
kiwixRoomDatabase.historyRoomDao().deleteAllHistory()
kiwixRoomDatabase.notesRoomDao()
.deletePages(kiwixRoomDatabase.notesRoomDao().notes().blockingFirst())
box.removeAll()
}

Expand All @@ -186,7 +191,7 @@ class ObjectBoxToRoomMigratorTest {
// migrate data into room database
objectBoxToRoomMigrator.migrateHistory(box)
// check if data successfully migrated to room
val actual = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().first()
val actual = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().blockingFirst()
with(actual.first()) {
assertThat(historyTitle, equalTo(historyItem.title))
assertThat(zimId, equalTo(historyItem.zimId))
Expand All @@ -202,15 +207,15 @@ class ObjectBoxToRoomMigratorTest {

// Migrate data from empty ObjectBox database
objectBoxToRoomMigrator.migrateHistory(box)
var actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().first()
var actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().blockingFirst()
assertTrue(actualData.isEmpty())

// Test if data successfully migrated to Room and existing data is preserved
kiwixRoomDatabase.historyRoomDao().saveHistory(historyItem3)
box.put(HistoryEntity(historyItem2))
// Migrate data into Room database
objectBoxToRoomMigrator.migrateHistory(box)
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().first()
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().blockingFirst()
assertEquals(2, actualData.size)
val existingItem =
actualData.find {
Expand All @@ -229,7 +234,7 @@ class ObjectBoxToRoomMigratorTest {
kiwixRoomDatabase.historyRoomDao().saveHistory(historyItem)
box.put(HistoryEntity(historyItem))
objectBoxToRoomMigrator.migrateHistory(box)
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().first()
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().blockingFirst()
assertEquals(1, actualData.size)

clearRoomAndBoxStoreDatabases(box)
Expand All @@ -243,7 +248,7 @@ class ObjectBoxToRoomMigratorTest {
} catch (_: Exception) {
}
// Ensure Room database remains empty or unaffected by the invalid data
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().first()
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().blockingFirst()
assertTrue(actualData.isEmpty())

// Test large data migration for recent searches
Expand All @@ -265,9 +270,118 @@ class ObjectBoxToRoomMigratorTest {
val endTime = System.currentTimeMillis()
val migrationTime = endTime - startTime
// Check if data successfully migrated to Room
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().first()
actualData = kiwixRoomDatabase.historyRoomDao().historyRoomEntity().blockingFirst()
assertEquals(numEntities, actualData.size)
// Assert that the migration completes within a reasonable time frame
assertTrue("Migration took too long: $migrationTime ms", migrationTime < 20000)
}

@Test
fun migrateNotes_shouldInsertDataIntoRoomDatabase() = runBlocking {
val box = boxStore.boxFor(NotesEntity::class.java)
// clear both databases for history to test more edge cases
clearRoomAndBoxStoreDatabases(box)

val noteItem = getNoteListItem(
zimUrl = "http://kiwix.app/MainPage",
noteFilePath = "/storage/emulated/0/Download/Notes/Alpine linux/MainPage.txt"
)

val noteItem1 = getNoteListItem(
databaseId = 1,
title = "Installing",
zimUrl = "http://kiwix.app/Installing",
noteFilePath = "/storage/emulated/0/Download/Notes/Alpine linux/Installing.txt"
)

// insert into object box
box.put(NotesEntity(noteItem))
// migrate data into room database
objectBoxToRoomMigrator.migrateNotes(box)
// check if data successfully migrated to room
var notesList = kiwixRoomDatabase.notesRoomDao().notes().blockingFirst() as List<NoteListItem>
with(notesList.first()) {
assertThat(zimId, equalTo(noteItem.zimId))
assertThat(zimUrl, equalTo(noteItem.zimUrl))
assertThat(title, equalTo(noteItem.title))
assertThat(zimFilePath, equalTo(noteItem.zimFilePath))
assertThat(noteFilePath, equalTo(noteItem.noteFilePath))
assertThat(favicon, equalTo(noteItem.favicon))
}
assertEquals(notesList.size, 1)

clearRoomAndBoxStoreDatabases(box)

// Migrate data from empty ObjectBox database
objectBoxToRoomMigrator.migrateNotes(box)
notesList = kiwixRoomDatabase.notesRoomDao().notes().blockingFirst() as List<NoteListItem>
assertTrue(notesList.isEmpty())

// Test if data successfully migrated to Room and existing data is preserved
kiwixRoomDatabase.notesRoomDao().saveNote(noteItem1)
box.put(NotesEntity(noteItem))
// Migrate data into Room database
objectBoxToRoomMigrator.migrateNotes(box)
notesList = kiwixRoomDatabase.notesRoomDao().notes().blockingFirst() as List<NoteListItem>
assertEquals(noteItem.title, notesList.first().title)
assertEquals(2, notesList.size)
val existingItem =
notesList.find {
it.zimUrl == noteItem.zimUrl && it.title == noteItem.title
}
assertNotNull(existingItem)
val newItem =
notesList.find {
it.zimUrl == noteItem1.zimUrl && it.title == noteItem1.title
}
assertNotNull(newItem)

clearRoomAndBoxStoreDatabases(box)

// Test room will update the already exiting data in the database while migration.
kiwixRoomDatabase.notesRoomDao().saveNote(noteItem1)
box.put(NotesEntity(noteItem1))
// Migrate data into Room database
objectBoxToRoomMigrator.migrateNotes(box)
notesList = kiwixRoomDatabase.notesRoomDao().notes().blockingFirst() as List<NoteListItem>
assertEquals(1, notesList.size)

clearRoomAndBoxStoreDatabases(box)

// Test migration if ObjectBox has null values
try {
lateinit var invalidNotesEntity: NotesEntity
box.put(invalidNotesEntity)
// Migrate data into Room database
objectBoxToRoomMigrator.migrateNotes(box)
} catch (_: Exception) {
}
// Ensure Room database remains empty or unaffected by the invalid data
notesList = kiwixRoomDatabase.notesRoomDao().notes().blockingFirst() as List<NoteListItem>
assertTrue(notesList.isEmpty())

// Test large data migration for recent searches
val numEntities = 5000
// Insert a large number of recent search entities into ObjectBox
for (i in 1..numEntities) {
box.put(
NotesEntity(
getNoteListItem(
title = "Installation$i",
zimUrl = "https://kiwix.app/A/Installation$i"
)
)
)
}
val startTime = System.currentTimeMillis()
// Migrate data into Room database
objectBoxToRoomMigrator.migrateNotes(box)
val endTime = System.currentTimeMillis()
val migrationTime = endTime - startTime
// Check if data successfully migrated to Room
notesList = kiwixRoomDatabase.notesRoomDao().notes().blockingFirst() as List<NoteListItem>
assertEquals(numEntities, notesList.size)
// Assert that the migration completes within a reasonable time frame
assertTrue("Migration took too long: $migrationTime ms", migrationTime < 20000)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual.equalTo
Expand Down Expand Up @@ -65,7 +64,7 @@ class HistoryRoomDaoTest {

// Save and retrieve a history item
historyRoomDao.saveHistory(historyItem)
var historyList = historyRoomDao.historyRoomEntity().first()
var historyList = historyRoomDao.historyRoomEntity().blockingFirst()
with(historyList.first()) {
assertThat(historyTitle, equalTo(historyItem.title))
assertThat(zimId, equalTo(historyItem.zimId))
Expand All @@ -79,26 +78,26 @@ class HistoryRoomDaoTest {

// Test to update the same day history for url
historyRoomDao.saveHistory(historyItem)
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertEquals(historyList.size, 1)

// Delete the saved history item
historyRoomDao.deleteHistory(listOf(historyItem))
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertEquals(historyList.size, 0)

// Save and delete all history items
historyRoomDao.saveHistory(historyItem)
historyRoomDao.saveHistory(getHistoryItem(databaseId = 2, dateString = "31 May 2024"))
historyRoomDao.deleteAllHistory()
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertThat(historyList.size, equalTo(0))

// Save history item with empty fields
val emptyHistoryUrl = ""
val emptyTitle = ""
historyRoomDao.saveHistory(getHistoryItem(emptyTitle, emptyHistoryUrl, databaseId = 1))
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertThat(historyList.size, equalTo(1))
historyRoomDao.deleteAllHistory()

Expand All @@ -118,13 +117,13 @@ class HistoryRoomDaoTest {
val unicodeTitle = "title \u03A3" // Unicode character for Greek capital letter Sigma
val historyItem2 = getHistoryItem(title = unicodeTitle, databaseId = 2)
historyRoomDao.saveHistory(historyItem2)
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertThat(historyList.first().historyTitle, equalTo("title Σ"))

// Test deletePages function
historyRoomDao.saveHistory(historyItem)
historyRoomDao.deletePages(listOf(historyItem, historyItem2))
historyList = historyRoomDao.historyRoomEntity().first()
historyList = historyRoomDao.historyRoomEntity().blockingFirst()
assertThat(historyList.size, equalTo(0))
}
}
Loading

0 comments on commit 3bd5380

Please sign in to comment.