mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-16 10:56:50 -04:00
Added KiwixRoomDatabaseTest, ObjectBoxToRoomMigratorTest, RecentSearchRoomDaoTest for testing all the scenarios of migration and saving the recent searches in room database.
* Improved the SaveSearchToRecentsTest. * Removed unused code from project.
This commit is contained in:
parent
106e83c704
commit
0613d36ab9
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2024 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile
|
||||
|
||||
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.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity
|
||||
import org.kiwix.kiwixmobile.core.data.KiwixRoomDatabase
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class KiwixRoomDatabaseTest {
|
||||
private lateinit var recentSearchRoomDao: RecentSearchRoomDao
|
||||
private lateinit var db: KiwixRoomDatabase
|
||||
|
||||
@After
|
||||
fun teardown() {
|
||||
db.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRecentSearchRoomDao() = runBlocking {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
db = Room.inMemoryDatabaseBuilder(context, KiwixRoomDatabase::class.java)
|
||||
.allowMainThreadQueries()
|
||||
.build()
|
||||
val zimId = "34388L"
|
||||
val searchTerm = "title 1"
|
||||
val searchTerm2 = "title 2"
|
||||
val url = ""
|
||||
recentSearchRoomDao = db.recentSearchRoomDao()
|
||||
val recentSearch = RecentSearchRoomEntity(zimId = zimId, searchTerm = searchTerm, url = url)
|
||||
val recentSearch1 = RecentSearchRoomEntity(zimId = zimId, searchTerm = searchTerm2, url = url)
|
||||
|
||||
// test inserting into recent search database
|
||||
recentSearchRoomDao.saveSearch(recentSearch.searchTerm, recentSearch.zimId, url = url)
|
||||
var recentSearches = recentSearchRoomDao.search(zimId).first()
|
||||
assertEquals(recentSearches.size, 1)
|
||||
assertEquals(recentSearch.searchTerm, recentSearches.first().searchTerm)
|
||||
assertEquals(recentSearch.zimId, recentSearches.first().zimId)
|
||||
|
||||
// test deleting recent search
|
||||
recentSearchRoomDao.deleteSearchString(searchTerm)
|
||||
recentSearches = recentSearchRoomDao.search(searchTerm).first()
|
||||
assertEquals(recentSearches.size, 0)
|
||||
|
||||
// test deleting all recent search history
|
||||
recentSearchRoomDao.saveSearch(recentSearch.searchTerm, recentSearch.zimId, url = url)
|
||||
recentSearchRoomDao.saveSearch(recentSearch1.searchTerm, recentSearch1.zimId, url = url)
|
||||
recentSearches = recentSearchRoomDao.search(zimId).first()
|
||||
assertEquals(recentSearches.size, 2)
|
||||
recentSearchRoomDao.deleteSearchHistory()
|
||||
recentSearches = recentSearchRoomDao.search(searchTerm).first()
|
||||
assertEquals(recentSearches.size, 0)
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2024 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.objectbox.Box
|
||||
import io.objectbox.BoxStore
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
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.utils.SharedPreferenceUtil
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ObjectBoxToRoomMigratorTest {
|
||||
private lateinit var context: Context
|
||||
private lateinit var kiwixRoomDatabase: KiwixRoomDatabase
|
||||
private lateinit var boxStore: BoxStore
|
||||
private lateinit var objectBoxToRoomMigrator: ObjectBoxToRoomMigrator
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
context = ApplicationProvider.getApplicationContext()
|
||||
kiwixRoomDatabase = Room.inMemoryDatabaseBuilder(context, KiwixRoomDatabase::class.java)
|
||||
.allowMainThreadQueries()
|
||||
.build()
|
||||
boxStore = DatabaseModule.boxStore!!
|
||||
objectBoxToRoomMigrator = ObjectBoxToRoomMigrator()
|
||||
objectBoxToRoomMigrator.kiwixRoomDatabase = kiwixRoomDatabase
|
||||
objectBoxToRoomMigrator.boxStore = boxStore
|
||||
objectBoxToRoomMigrator.sharedPreferenceUtil = SharedPreferenceUtil(context)
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanup() {
|
||||
kiwixRoomDatabase.close()
|
||||
boxStore.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrateRecentSearch_shouldInsertDataIntoRoomDatabase() = runBlocking {
|
||||
val box = boxStore.boxFor(RecentSearchEntity::class.java)
|
||||
// clear both databases for recent searches to test more edge cases
|
||||
clearRecentSearchDatabases(box)
|
||||
val expectedSearchTerm = "test search"
|
||||
val expectedZimId = "8812214350305159407L"
|
||||
val expectedUrl = "http://kiwix.app/mainPage"
|
||||
val recentSearchEntity =
|
||||
RecentSearchEntity(searchTerm = expectedSearchTerm, zimId = expectedZimId, url = expectedUrl)
|
||||
// insert into object box
|
||||
box.put(recentSearchEntity)
|
||||
// migrate data into room database
|
||||
objectBoxToRoomMigrator.migrateRecentSearch(box)
|
||||
// check if data successfully migrated to room
|
||||
val actual = kiwixRoomDatabase.recentSearchRoomDao().search(expectedZimId).first()
|
||||
assertEquals(actual.size, 1)
|
||||
assertEquals(actual[0].searchTerm, expectedSearchTerm)
|
||||
assertEquals(actual[0].zimId, expectedZimId)
|
||||
|
||||
// clear both databases for recent searches to test more edge cases
|
||||
clearRecentSearchDatabases(box)
|
||||
|
||||
// Migrate data from empty ObjectBox database
|
||||
objectBoxToRoomMigrator.migrateRecentSearch(box)
|
||||
val actualData = kiwixRoomDatabase.recentSearchRoomDao().fullSearch().first()
|
||||
assertTrue(actualData.isEmpty())
|
||||
|
||||
// Test if data successfully migrated to Room and existing data is preserved
|
||||
val existingSearchTerm = "existing search"
|
||||
val existingZimId = "8812214350305159407L"
|
||||
kiwixRoomDatabase.recentSearchRoomDao()
|
||||
.saveSearch(existingSearchTerm, existingZimId, "$expectedUrl/1")
|
||||
box.put(recentSearchEntity)
|
||||
// Migrate data into Room database
|
||||
objectBoxToRoomMigrator.migrateRecentSearch(box)
|
||||
val actualDataAfterMigration = kiwixRoomDatabase.recentSearchRoomDao().fullSearch().first()
|
||||
assertEquals(1, actual.size)
|
||||
val existingItem =
|
||||
actualDataAfterMigration.find {
|
||||
it.searchTerm == existingSearchTerm && it.zimId == existingZimId
|
||||
}
|
||||
assertNotNull(existingItem)
|
||||
val newItem =
|
||||
actualDataAfterMigration.find {
|
||||
it.searchTerm == expectedSearchTerm && it.zimId == expectedZimId
|
||||
}
|
||||
assertNotNull(newItem)
|
||||
|
||||
clearRecentSearchDatabases(box)
|
||||
|
||||
// Test migration if ObjectBox has null values
|
||||
lateinit var undefinedSearchTerm: String
|
||||
lateinit var undefinedZimId: String
|
||||
lateinit var undefinedUrl: String
|
||||
try {
|
||||
val invalidSearchEntity =
|
||||
RecentSearchEntity(
|
||||
searchTerm = undefinedSearchTerm,
|
||||
zimId = undefinedZimId,
|
||||
url = undefinedUrl
|
||||
)
|
||||
box.put(invalidSearchEntity)
|
||||
// Migrate data into Room database
|
||||
objectBoxToRoomMigrator.migrateRecentSearch(box)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
// Ensure Room database remains empty or unaffected by the invalid data
|
||||
val actualDataAfterInvalidMigration =
|
||||
kiwixRoomDatabase.recentSearchRoomDao().fullSearch().first()
|
||||
assertTrue(actualDataAfterInvalidMigration.isEmpty())
|
||||
|
||||
// Test large data migration for recent searches
|
||||
val numEntities = 1000
|
||||
// Insert a large number of recent search entities into ObjectBox
|
||||
for (i in 1..numEntities) {
|
||||
val searchTerm = "search_$i"
|
||||
val zimId = "$i"
|
||||
val recentSearchEntity =
|
||||
RecentSearchEntity(searchTerm = searchTerm, zimId = zimId, url = "$expectedUrl$i")
|
||||
box.put(recentSearchEntity)
|
||||
}
|
||||
val startTime = System.currentTimeMillis()
|
||||
// Migrate data into Room database
|
||||
objectBoxToRoomMigrator.migrateRecentSearch(box)
|
||||
val endTime = System.currentTimeMillis()
|
||||
val migrationTime = endTime - startTime
|
||||
// Check if data successfully migrated to Room
|
||||
val actualDataAfterLargeMigration =
|
||||
kiwixRoomDatabase.recentSearchRoomDao().fullSearch().first()
|
||||
assertEquals(numEntities, actualDataAfterLargeMigration.size)
|
||||
// Assert that the migration completes within a reasonable time frame
|
||||
assertTrue("Migration took too long: $migrationTime ms", migrationTime < 5000)
|
||||
}
|
||||
|
||||
private fun clearRecentSearchDatabases(box: Box<RecentSearchEntity>) {
|
||||
// delete history for testing other edge cases
|
||||
kiwixRoomDatabase.recentSearchRoomDao().deleteSearchHistory()
|
||||
box.removeAll()
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2024 Kiwix <android.kiwix.org>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile
|
||||
|
||||
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
|
||||
import org.junit.After
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.kiwix.kiwixmobile.core.dao.RecentSearchRoomDao
|
||||
import org.kiwix.kiwixmobile.core.data.KiwixRoomDatabase
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class RecentSearchRoomDaoTest {
|
||||
|
||||
private lateinit var kiwixRoomDatabase: KiwixRoomDatabase
|
||||
private lateinit var recentSearchRoomDao: RecentSearchRoomDao
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
kiwixRoomDatabase.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRecentSearchRoomDao() = runBlocking {
|
||||
val zimId = "8812214350305159407L"
|
||||
val url = "http://kiwix.app/mainPage"
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
kiwixRoomDatabase = Room.inMemoryDatabaseBuilder(context, KiwixRoomDatabase::class.java).build()
|
||||
recentSearchRoomDao = kiwixRoomDatabase.recentSearchRoomDao()
|
||||
// Save a recent search entity
|
||||
val query =
|
||||
"This is a long search term to test whether it will be saved into the room database."
|
||||
recentSearchRoomDao.saveSearch(query, zimId, url)
|
||||
// Search for recent search entities with a matching zimId
|
||||
val result = getRecentSearchByZimId(zimId)
|
||||
// Verify that the result contains the saved entity
|
||||
assertThat(result.size, equalTo(1))
|
||||
assertThat(result[0].searchTerm, equalTo(query))
|
||||
assertThat(result[0].zimId, equalTo(zimId))
|
||||
|
||||
// Delete the saved entity by search term
|
||||
recentSearchRoomDao.deleteSearchString(query)
|
||||
// Verify that the result does not contain the deleted entity
|
||||
assertThat(getRecentSearchByZimId(zimId).size, equalTo(0))
|
||||
|
||||
// Testing deleting all recent searched history
|
||||
// Save two recent search entities
|
||||
recentSearchRoomDao.saveSearch(query, zimId, url)
|
||||
recentSearchRoomDao.saveSearch("query 2", zimId, url)
|
||||
// Delete all recent search entities
|
||||
recentSearchRoomDao.deleteSearchHistory()
|
||||
// Verify that the result is empty
|
||||
assertThat(getRecentSearchByZimId(zimId).size, equalTo(0))
|
||||
|
||||
// test to save empty values for recent search
|
||||
val emptyQuery = ""
|
||||
recentSearchRoomDao.saveSearch(emptyQuery, zimId, url)
|
||||
// verify that the result is not empty
|
||||
assertThat(getRecentSearchByZimId(zimId).size, equalTo(1))
|
||||
|
||||
// we are not saving undefined or null values into database.
|
||||
// test to save undefined value for recent search.
|
||||
lateinit var undefinedQuery: String
|
||||
try {
|
||||
recentSearchRoomDao.saveSearch(undefinedQuery, zimId, url)
|
||||
assertThat(
|
||||
"Undefined value was saved into database",
|
||||
false
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
assertThat("Undefined value was not saved, as expected.", true)
|
||||
}
|
||||
|
||||
// Delete all recent search entities for testing unicodes values
|
||||
recentSearchRoomDao.deleteSearchHistory()
|
||||
|
||||
// save unicode values into database
|
||||
val unicodeQuery = "title \u03A3" // Unicode character for Greek capital letter Sigma
|
||||
recentSearchRoomDao.saveSearch(unicodeQuery, zimId, url)
|
||||
assertThat(getRecentSearchByZimId(zimId)[0].searchTerm, equalTo("title Σ"))
|
||||
}
|
||||
|
||||
private suspend fun getRecentSearchByZimId(zimId: String) =
|
||||
recentSearchRoomDao.search(zimId).first()
|
||||
}
|
@ -20,13 +20,8 @@ package org.kiwix.kiwixmobile.core.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import io.objectbox.Box
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchEntity
|
||||
import org.kiwix.kiwixmobile.core.dao.entities.RecentSearchRoomEntity
|
||||
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem
|
||||
|
||||
@ -80,18 +75,6 @@ abstract class RecentSearchRoomDao {
|
||||
@Query("DELETE FROM RecentSearchRoomEntity")
|
||||
abstract fun deleteSearchHistory()
|
||||
|
||||
fun migrationToRoomInsert(
|
||||
box: Box<RecentSearchEntity>
|
||||
) {
|
||||
val searchRoomEntityList = box.all
|
||||
searchRoomEntityList.forEachIndexed { _, recentSearchEntity ->
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
saveSearch(recentSearchEntity.searchTerm, recentSearchEntity.zimId, recentSearchEntity.url)
|
||||
// Todo Should we remove object store data now?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NUM_RECENT_RESULTS = 100
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ internal class SaveSearchToRecentsTest {
|
||||
|
||||
@Test
|
||||
fun `invoke with non null Id saves search`() = runBlocking {
|
||||
val id = "id"
|
||||
val id = "8812214350305159407L"
|
||||
SaveSearchToRecents(
|
||||
newRecentSearchDao,
|
||||
searchListItem,
|
||||
|
Loading…
x
Reference in New Issue
Block a user