mirror of
https://github.com/f-droid/fdroidclient.git
synced 2026-04-20 06:47:06 -04:00
[db] clean up RepositoryDao and add more tests
This commit is contained in:
@@ -127,4 +127,19 @@ internal class AppDaoTest : AppTest() {
|
||||
assertEquals(0, appDao.getNumberOfAppsInCategory("C"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetNumberOfAppsInRepository() {
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
assertEquals(0, appDao.getNumberOfAppsInRepository(repoId))
|
||||
|
||||
appDao.insert(repoId, packageName1, app1, locales)
|
||||
assertEquals(1, appDao.getNumberOfAppsInRepository(repoId))
|
||||
|
||||
appDao.insert(repoId, packageName2, app2, locales)
|
||||
assertEquals(2, appDao.getNumberOfAppsInRepository(repoId))
|
||||
|
||||
appDao.insert(repoId, packageName3, app3, locales)
|
||||
assertEquals(3, appDao.getNumberOfAppsInRepository(repoId))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
package org.fdroid.database
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.fdroid.database.TestUtils.assertRepoEquals
|
||||
import org.fdroid.database.TestUtils.getOrFail
|
||||
import org.fdroid.test.TestAppUtils.getRandomMetadataV2
|
||||
import org.fdroid.test.TestRepoUtils.getRandomRepo
|
||||
import org.fdroid.test.TestUtils.getRandomString
|
||||
import org.fdroid.test.TestUtils.orNull
|
||||
import org.fdroid.test.TestVersionUtils.getRandomPackageVersionV2
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class RepositoryDaoTest : DbTest() {
|
||||
|
||||
@get:Rule
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
@Test
|
||||
fun testInsertInitialRepository() {
|
||||
val repo = InitialRepository(
|
||||
name = getRandomString(),
|
||||
address = getRandomString(),
|
||||
description = getRandomString(),
|
||||
certificate = getRandomString(),
|
||||
version = Random.nextLong(),
|
||||
enabled = Random.nextBoolean(),
|
||||
weight = Random.nextInt(),
|
||||
)
|
||||
val repoId = repoDao.insert(repo)
|
||||
|
||||
val actualRepo = repoDao.getRepository(repoId) ?: fail()
|
||||
assertEquals(repo.name, actualRepo.getName(locales))
|
||||
assertEquals(repo.address, actualRepo.address)
|
||||
assertEquals(repo.description, actualRepo.getDescription(locales))
|
||||
assertEquals(repo.certificate, actualRepo.certificate)
|
||||
assertEquals(repo.version, actualRepo.version)
|
||||
assertEquals(repo.enabled, actualRepo.enabled)
|
||||
assertEquals(repo.weight, actualRepo.weight)
|
||||
assertEquals(-1, actualRepo.timestamp)
|
||||
assertEquals(emptyList(), actualRepo.mirrors)
|
||||
assertEquals(emptyList(), actualRepo.userMirrors)
|
||||
assertEquals(emptyList(), actualRepo.disabledMirrors)
|
||||
assertEquals(emptyList(), actualRepo.getMirrors())
|
||||
assertEquals(emptyList(), actualRepo.antiFeatures)
|
||||
assertEquals(emptyList(), actualRepo.categories)
|
||||
assertEquals(emptyList(), actualRepo.releaseChannels)
|
||||
assertNull(actualRepo.formatVersion)
|
||||
assertNull(actualRepo.icon)
|
||||
assertNull(actualRepo.lastUpdated)
|
||||
assertNull(actualRepo.webBaseUrl)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInsertEmptyRepo() {
|
||||
// insert empty repo
|
||||
val address = getRandomString()
|
||||
val username = getRandomString().orNull()
|
||||
val password = getRandomString().orNull()
|
||||
val repoId = repoDao.insertEmptyRepo(address, username, password)
|
||||
|
||||
// check that repo got inserted as expected
|
||||
val actualRepo = repoDao.getRepository(repoId) ?: fail()
|
||||
assertEquals(address, actualRepo.address)
|
||||
assertEquals(username, actualRepo.username)
|
||||
assertEquals(password, actualRepo.password)
|
||||
assertEquals(-1, actualRepo.timestamp)
|
||||
assertEquals(emptyList(), actualRepo.getMirrors())
|
||||
assertEquals(emptyList(), actualRepo.antiFeatures)
|
||||
assertEquals(emptyList(), actualRepo.categories)
|
||||
assertEquals(emptyList(), actualRepo.releaseChannels)
|
||||
assertNull(actualRepo.formatVersion)
|
||||
assertNull(actualRepo.icon)
|
||||
assertNull(actualRepo.lastUpdated)
|
||||
assertNull(actualRepo.webBaseUrl)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertAndDeleteTwoRepos() {
|
||||
// insert first repo
|
||||
val repo1 = getRandomRepo()
|
||||
val repoId1 = repoDao.insertOrReplace(repo1)
|
||||
|
||||
// check that first repo got added and retrieved as expected
|
||||
repoDao.getRepositories().let { repos ->
|
||||
assertEquals(1, repos.size)
|
||||
assertRepoEquals(repo1, repos[0])
|
||||
}
|
||||
val repositoryPreferences1 = repoDao.getRepositoryPreferences(repoId1)
|
||||
assertEquals(repoId1, repositoryPreferences1?.repoId)
|
||||
|
||||
// insert second repo
|
||||
val repo2 = getRandomRepo()
|
||||
val repoId2 = repoDao.insertOrReplace(repo2)
|
||||
|
||||
// check that both repos got added and retrieved as expected
|
||||
listOf(
|
||||
repoDao.getRepositories().sortedBy { it.repoId },
|
||||
repoDao.getLiveRepositories().getOrFail().sortedBy { it.repoId },
|
||||
).forEach { repos ->
|
||||
assertEquals(2, repos.size)
|
||||
assertRepoEquals(repo1, repos[0])
|
||||
assertRepoEquals(repo2, repos[1])
|
||||
}
|
||||
val repositoryPreferences2 = repoDao.getRepositoryPreferences(repoId2)
|
||||
assertEquals(repoId2, repositoryPreferences2?.repoId)
|
||||
// second repo has one weight point more than first repo
|
||||
assertEquals(repositoryPreferences1?.weight?.plus(1), repositoryPreferences2?.weight)
|
||||
|
||||
// remove first repo and check that the database only returns one
|
||||
repoDao.deleteRepository(repoId1)
|
||||
listOf(
|
||||
repoDao.getRepositories(),
|
||||
repoDao.getLiveRepositories().getOrFail(),
|
||||
).forEach { repos ->
|
||||
assertEquals(1, repos.size)
|
||||
assertRepoEquals(repo2, repos[0])
|
||||
}
|
||||
assertNull(repoDao.getRepositoryPreferences(repoId1))
|
||||
|
||||
// remove second repo and check that all associated data got removed as well
|
||||
repoDao.deleteRepository(repoId2)
|
||||
assertEquals(0, repoDao.getRepositories().size)
|
||||
assertEquals(0, repoDao.countMirrors())
|
||||
assertEquals(0, repoDao.countAntiFeatures())
|
||||
assertEquals(0, repoDao.countCategories())
|
||||
assertEquals(0, repoDao.countReleaseChannels())
|
||||
assertNull(repoDao.getRepositoryPreferences(repoId2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertTwoReposAndClearAll() {
|
||||
val repo1 = getRandomRepo()
|
||||
val repo2 = getRandomRepo()
|
||||
repoDao.insertOrReplace(repo1)
|
||||
repoDao.insertOrReplace(repo2)
|
||||
assertEquals(2, repoDao.getRepositories().size)
|
||||
assertEquals(2, repoDao.getLiveRepositories().getOrFail().size)
|
||||
|
||||
repoDao.clearAll()
|
||||
assertEquals(0, repoDao.getRepositories().size)
|
||||
assertEquals(0, repoDao.getLiveRepositories().getOrFail().size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetRepositoryEnabled() {
|
||||
// repo is enabled by default
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
assertTrue(repoDao.getRepository(repoId)?.enabled ?: fail())
|
||||
|
||||
// disabled repo is disabled
|
||||
repoDao.setRepositoryEnabled(repoId, false)
|
||||
assertFalse(repoDao.getRepository(repoId)?.enabled ?: fail())
|
||||
|
||||
// enabling again works
|
||||
repoDao.setRepositoryEnabled(repoId, true)
|
||||
assertTrue(repoDao.getRepository(repoId)?.enabled ?: fail())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateUserMirrors() {
|
||||
// repo is enabled by default
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
assertEquals(emptyList(), repoDao.getRepository(repoId)?.userMirrors)
|
||||
|
||||
// add user mirrors
|
||||
val userMirrors = listOf(getRandomString(), getRandomString(), getRandomString())
|
||||
repoDao.updateUserMirrors(repoId, userMirrors)
|
||||
val repo = repoDao.getRepository(repoId) ?: fail()
|
||||
assertEquals(userMirrors, repo.userMirrors)
|
||||
|
||||
// user mirrors are part of all mirrors
|
||||
val userDownloadMirrors = userMirrors.map { org.fdroid.download.Mirror(it) }
|
||||
assertTrue(repo.getMirrors().containsAll(userDownloadMirrors))
|
||||
|
||||
// remove user mirrors
|
||||
repoDao.updateUserMirrors(repoId, emptyList())
|
||||
assertEquals(emptyList(), repoDao.getRepository(repoId)?.userMirrors)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateUsernameAndPassword() {
|
||||
// repo has no username or password initially
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
repoDao.getRepository(repoId)?.let { repo ->
|
||||
assertEquals(null, repo.username)
|
||||
assertEquals(null, repo.password)
|
||||
} ?: fail()
|
||||
|
||||
// add user name and password
|
||||
val username = getRandomString().orNull()
|
||||
val password = getRandomString().orNull()
|
||||
repoDao.updateUsernameAndPassword(repoId, username, password)
|
||||
repoDao.getRepository(repoId)?.let { repo ->
|
||||
assertEquals(username, repo.username)
|
||||
assertEquals(password, repo.password)
|
||||
} ?: fail()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateDisabledMirrors() {
|
||||
// repo has no username or password initially
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
repoDao.getRepository(repoId)?.let { repo ->
|
||||
assertEquals(null, repo.username)
|
||||
assertEquals(null, repo.password)
|
||||
} ?: fail()
|
||||
|
||||
// add user name and password
|
||||
val username = getRandomString().orNull()
|
||||
val password = getRandomString().orNull()
|
||||
repoDao.updateUsernameAndPassword(repoId, username, password)
|
||||
repoDao.getRepository(repoId)?.let { repo ->
|
||||
assertEquals(username, repo.username)
|
||||
assertEquals(password, repo.password)
|
||||
} ?: fail()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clearingRepoRemovesAllAssociatedData() {
|
||||
// insert one repo with one app with one version
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
val repositoryPreferences = repoDao.getRepositoryPreferences(repoId)
|
||||
val packageId = getRandomString()
|
||||
val versionId = getRandomString()
|
||||
appDao.insert(repoId, packageId, getRandomMetadataV2())
|
||||
val packageVersion = getRandomPackageVersionV2()
|
||||
versionDao.insert(repoId, packageId, versionId, packageVersion, Random.nextBoolean())
|
||||
|
||||
// data is there as expected
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(1, appDao.getAppMetadata().size)
|
||||
assertEquals(1, versionDao.getAppVersions(repoId, packageId).size)
|
||||
assertTrue(versionDao.getVersionedStrings(repoId, packageId).isNotEmpty())
|
||||
|
||||
// clearing the repo removes apps and versions
|
||||
repoDao.clear(repoId)
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(0, appDao.countApps())
|
||||
assertEquals(0, appDao.countLocalizedFiles())
|
||||
assertEquals(0, appDao.countLocalizedFileLists())
|
||||
assertEquals(0, versionDao.getAppVersions(repoId, packageId).size)
|
||||
assertEquals(0, versionDao.getVersionedStrings(repoId, packageId).size)
|
||||
// preferences are not touched by clearing
|
||||
assertEquals(repositoryPreferences, repoDao.getRepositoryPreferences(repoId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun certGetsUpdated() {
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(null, repoDao.getRepositories()[0].certificate)
|
||||
|
||||
val cert = getRandomString()
|
||||
repoDao.updateRepository(repoId, cert)
|
||||
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(cert, repoDao.getRepositories()[0].certificate)
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package org.fdroid.database
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.fdroid.database.TestUtils.assertRepoEquals
|
||||
import org.fdroid.test.TestAppUtils.getRandomMetadataV2
|
||||
import org.fdroid.test.TestRepoUtils.getRandomRepo
|
||||
import org.fdroid.test.TestUtils.getRandomString
|
||||
import org.fdroid.test.TestVersionUtils.getRandomPackageVersionV2
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class RepositoryTest : DbTest() {
|
||||
|
||||
@Test
|
||||
fun insertAndDeleteTwoRepos() {
|
||||
// insert first repo
|
||||
val repo1 = getRandomRepo()
|
||||
val repoId1 = repoDao.insertOrReplace(repo1)
|
||||
|
||||
// check that first repo got added and retrieved as expected
|
||||
var repos = repoDao.getRepositories()
|
||||
assertEquals(1, repos.size)
|
||||
assertRepoEquals(repo1, repos[0])
|
||||
val repositoryPreferences1 = repoDao.getRepositoryPreferences(repoId1)
|
||||
assertEquals(repoId1, repositoryPreferences1?.repoId)
|
||||
|
||||
// insert second repo
|
||||
val repo2 = getRandomRepo()
|
||||
val repoId2 = repoDao.insertOrReplace(repo2)
|
||||
|
||||
// check that both repos got added and retrieved as expected
|
||||
repos = repoDao.getRepositories().sortedBy { it.repoId }
|
||||
assertEquals(2, repos.size)
|
||||
assertRepoEquals(repo1, repos[0])
|
||||
assertRepoEquals(repo2, repos[1])
|
||||
val repositoryPreferences2 = repoDao.getRepositoryPreferences(repoId2)
|
||||
assertEquals(repoId2, repositoryPreferences2?.repoId)
|
||||
assertEquals(repositoryPreferences1?.weight?.plus(1), repositoryPreferences2?.weight)
|
||||
|
||||
// remove first repo and check that the database only returns one
|
||||
repoDao.deleteRepository(repos[0].repository.repoId)
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
|
||||
// remove second repo as well and check that all associated data got removed as well
|
||||
repoDao.deleteRepository(repos[1].repository.repoId)
|
||||
assertEquals(0, repoDao.getRepositories().size)
|
||||
assertEquals(0, repoDao.getMirrors().size)
|
||||
assertEquals(0, repoDao.getAntiFeatures().size)
|
||||
assertEquals(0, repoDao.getCategories().size)
|
||||
assertEquals(0, repoDao.getReleaseChannels().size)
|
||||
assertNull(repoDao.getRepositoryPreferences(repoId1))
|
||||
assertNull(repoDao.getRepositoryPreferences(repoId2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun insertTwoReposAndClearAll() {
|
||||
val repo1 = getRandomRepo()
|
||||
val repo2 = getRandomRepo()
|
||||
repoDao.insertOrReplace(repo1)
|
||||
repoDao.insertOrReplace(repo2)
|
||||
assertEquals(2, repoDao.getRepositories().size)
|
||||
|
||||
repoDao.clearAll()
|
||||
assertEquals(0, repoDao.getRepositories().size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clearingRepoRemovesAllAssociatedData() {
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
val repositoryPreferences = repoDao.getRepositoryPreferences(repoId)
|
||||
val packageId = getRandomString()
|
||||
val versionId = getRandomString()
|
||||
appDao.insert(repoId, packageId, getRandomMetadataV2())
|
||||
val packageVersion = getRandomPackageVersionV2()
|
||||
versionDao.insert(repoId, packageId, versionId, packageVersion, Random.nextBoolean())
|
||||
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(1, appDao.getAppMetadata().size)
|
||||
assertEquals(1, versionDao.getAppVersions(repoId, packageId).size)
|
||||
assertTrue(versionDao.getVersionedStrings(repoId, packageId).isNotEmpty())
|
||||
|
||||
repoDao.clear(repoId)
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(0, appDao.countApps())
|
||||
assertEquals(0, appDao.countLocalizedFiles())
|
||||
assertEquals(0, appDao.countLocalizedFileLists())
|
||||
assertEquals(0, versionDao.getAppVersions(repoId, packageId).size)
|
||||
assertEquals(0, versionDao.getVersionedStrings(repoId, packageId).size)
|
||||
// preferences are not touched by clearing
|
||||
assertEquals(repositoryPreferences, repoDao.getRepositoryPreferences(repoId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun certGetsUpdated() {
|
||||
val repoId = repoDao.insertOrReplace(getRandomRepo())
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(null, repoDao.getRepositories()[0].certificate)
|
||||
|
||||
val cert = getRandomString()
|
||||
repoDao.updateRepository(repoId, cert)
|
||||
|
||||
assertEquals(1, repoDao.getRepositories().size)
|
||||
assertEquals(cert, repoDao.getRepositories()[0].certificate)
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,17 @@ import org.junit.Assert
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
internal object TestUtils {
|
||||
|
||||
fun assertTimestampRecent(timestamp: Long?) {
|
||||
assertNotNull(timestamp)
|
||||
assertTrue(System.currentTimeMillis() - timestamp < 2000)
|
||||
}
|
||||
|
||||
fun assertRepoEquals(repoV2: RepoV2, repo: Repository) {
|
||||
val repoId = repo.repoId
|
||||
// mirrors
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.fdroid.CompatibilityChecker
|
||||
import org.fdroid.database.DbTest
|
||||
import org.fdroid.database.IndexFormatVersion.TWO
|
||||
import org.fdroid.database.Repository
|
||||
import org.fdroid.database.TestUtils.assertTimestampRecent
|
||||
import org.fdroid.download.Downloader
|
||||
import org.fdroid.download.DownloaderFactory
|
||||
import org.fdroid.index.IndexUpdateResult
|
||||
@@ -27,6 +28,7 @@ import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
@@ -65,6 +67,7 @@ internal class IndexV2UpdaterTest : DbTest() {
|
||||
val updatedRepo = repoDao.getRepository(repoId) ?: fail()
|
||||
assertEquals(TWO, updatedRepo.formatVersion)
|
||||
assertEquals(CERTIFICATE, updatedRepo.certificate)
|
||||
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -79,6 +82,7 @@ internal class IndexV2UpdaterTest : DbTest() {
|
||||
val result = indexUpdater.updateNewRepo(repo, FINGERPRINT).noError()
|
||||
assertEquals(IndexUpdateResult.Processed, result)
|
||||
assertDbEquals(repoId, TestDataMidV2.index)
|
||||
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -93,6 +97,7 @@ internal class IndexV2UpdaterTest : DbTest() {
|
||||
val result = indexUpdater.updateNewRepo(repo, FINGERPRINT).noError()
|
||||
assertEquals(IndexUpdateResult.Processed, result)
|
||||
assertDbEquals(repoId, TestDataMaxV2.index)
|
||||
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,6 +112,7 @@ internal class IndexV2UpdaterTest : DbTest() {
|
||||
val result = indexUpdater.update(repo).noError()
|
||||
assertEquals(IndexUpdateResult.Processed, result)
|
||||
assertDbEquals(repoId, TestDataMidV2.index)
|
||||
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,6 +128,7 @@ internal class IndexV2UpdaterTest : DbTest() {
|
||||
val result = indexUpdater.update(repo).noError()
|
||||
assertEquals(IndexUpdateResult.Processed, result)
|
||||
assertDbEquals(repoId, TestDataMinV2.index)
|
||||
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -137,6 +144,7 @@ internal class IndexV2UpdaterTest : DbTest() {
|
||||
val result = indexUpdater.update(repo).noError()
|
||||
assertEquals(IndexUpdateResult.Processed, result)
|
||||
assertDbEquals(repoId, TestDataMaxV2.index)
|
||||
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -152,6 +160,7 @@ internal class IndexV2UpdaterTest : DbTest() {
|
||||
val result = indexUpdater.update(repo).noError()
|
||||
assertEquals(IndexUpdateResult.Unchanged, result)
|
||||
assertDbEquals(repoId, TestDataMinV2.index)
|
||||
assertNull(repoDao.getRepository(repoId)?.lastUpdated)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -96,6 +96,8 @@ public interface AppDao {
|
||||
public fun getInstalledAppListItems(packageManager: PackageManager): LiveData<List<AppListItem>>
|
||||
|
||||
public fun getNumberOfAppsInCategory(category: String): Int
|
||||
|
||||
public fun getNumberOfAppsInRepository(repoId: Long): Int
|
||||
}
|
||||
|
||||
public enum class AppListSortOrder {
|
||||
@@ -452,6 +454,9 @@ internal interface AppDaoInt : AppDao {
|
||||
WHERE pref.enabled = 1 AND categories LIKE '%,' || :category || ',%'""")
|
||||
override fun getNumberOfAppsInCategory(category: String): Int
|
||||
|
||||
@Query("SELECT COUNT(*) FROM AppMetadata WHERE repoId = :repoId")
|
||||
override fun getNumberOfAppsInRepository(repoId: Long): Int
|
||||
|
||||
@Query("DELETE FROM AppMetadata WHERE repoId = :repoId AND packageId = :packageId")
|
||||
fun deleteAppMetadata(repoId: Long, packageId: String)
|
||||
|
||||
|
||||
@@ -121,8 +121,7 @@ public data class Repository(
|
||||
*/
|
||||
@JvmOverloads
|
||||
public fun getAllMirrors(includeUserMirrors: Boolean = true): List<org.fdroid.download.Mirror> {
|
||||
// FIXME decide whether we need to add our own address here
|
||||
return listOf(org.fdroid.download.Mirror(address)) + mirrors.map {
|
||||
return mirrors.map {
|
||||
it.toDownloadMirror()
|
||||
} + if (includeUserMirrors) userMirrors.map {
|
||||
org.fdroid.download.Mirror(it)
|
||||
|
||||
@@ -21,30 +21,76 @@ import org.fdroid.index.v2.RepoV2
|
||||
public interface RepositoryDao {
|
||||
/**
|
||||
* Inserts a new [InitialRepository] from a fixture.
|
||||
*
|
||||
* @return the [Repository.repoId] of the inserted repo.
|
||||
*/
|
||||
public fun insert(initialRepo: InitialRepository)
|
||||
public fun insert(initialRepo: InitialRepository): Long
|
||||
|
||||
/**
|
||||
* Removes all repos and their preferences.
|
||||
* Inserts an empty [Repository] for an initial update.
|
||||
*
|
||||
* @return the [Repository.repoId] of the inserted repo.
|
||||
*/
|
||||
public fun clearAll()
|
||||
|
||||
public fun getRepository(repoId: Long): Repository?
|
||||
public fun insertEmptyRepo(
|
||||
address: String,
|
||||
username: String? = null,
|
||||
password: String? = null,
|
||||
): Long
|
||||
|
||||
public fun deleteRepository(repoId: Long)
|
||||
/**
|
||||
* Returns the repository with the given [repoId] or null, if none was found with that ID.
|
||||
*/
|
||||
public fun getRepository(repoId: Long): Repository?
|
||||
|
||||
/**
|
||||
* Returns a list of all [Repository]s in the database.
|
||||
*/
|
||||
public fun getRepositories(): List<Repository>
|
||||
|
||||
/**
|
||||
* Same as [getRepositories], but does return a [LiveData].
|
||||
*/
|
||||
public fun getLiveRepositories(): LiveData<List<Repository>>
|
||||
public fun countAppsPerRepository(repoId: Long): Int
|
||||
public fun setRepositoryEnabled(repoId: Long, enabled: Boolean)
|
||||
public fun updateUserMirrors(repoId: Long, mirrors: List<String>)
|
||||
public fun updateUsernameAndPassword(repoId: Long, username: String?, password: String?)
|
||||
public fun updateDisabledMirrors(repoId: Long, disabledMirrors: List<String>)
|
||||
|
||||
/**
|
||||
* Returns a live data of all categories declared by all [Repository]s.
|
||||
*/
|
||||
public fun getLiveCategories(): LiveData<List<Category>>
|
||||
|
||||
/**
|
||||
* Enables or disables the repository with the given [repoId].
|
||||
* Data from disabled repositories is ignored in many queries.
|
||||
*/
|
||||
public fun setRepositoryEnabled(repoId: Long, enabled: Boolean)
|
||||
|
||||
/**
|
||||
* Updates the user-defined mirrors of the repository with the given [repoId].
|
||||
* The existing mirrors get overwritten with the given [mirrors].
|
||||
*/
|
||||
public fun updateUserMirrors(repoId: Long, mirrors: List<String>)
|
||||
|
||||
/**
|
||||
* Updates the user name and password (for basic authentication)
|
||||
* of the repository with the given [repoId].
|
||||
* The existing user name and password get overwritten with the given [username] and [password].
|
||||
*/
|
||||
public fun updateUsernameAndPassword(repoId: Long, username: String?, password: String?)
|
||||
|
||||
/**
|
||||
* Updates the disabled mirrors of the repository with the given [repoId].
|
||||
* The existing disabled mirrors get overwritten with the given [disabledMirrors].
|
||||
*/
|
||||
public fun updateDisabledMirrors(repoId: Long, disabledMirrors: List<String>)
|
||||
|
||||
/**
|
||||
* Removes a [Repository] with the given [repoId] with all associated data from the database.
|
||||
*/
|
||||
public fun deleteRepository(repoId: Long)
|
||||
|
||||
/**
|
||||
* Removes all repos and their preferences.
|
||||
*/
|
||||
public fun clearAll()
|
||||
}
|
||||
|
||||
@Dao
|
||||
@@ -72,7 +118,7 @@ internal interface RepositoryDaoInt : RepositoryDao {
|
||||
fun insert(repositoryPreferences: RepositoryPreferences)
|
||||
|
||||
@Transaction
|
||||
override fun insert(initialRepo: InitialRepository) {
|
||||
override fun insert(initialRepo: InitialRepository): Long {
|
||||
val repo = CoreRepository(
|
||||
name = mapOf("en-US" to initialRepo.name),
|
||||
address = initialRepo.address,
|
||||
@@ -92,6 +138,7 @@ internal interface RepositoryDaoInt : RepositoryDao {
|
||||
enabled = initialRepo.enabled,
|
||||
)
|
||||
insert(repositoryPreferences)
|
||||
return repoId
|
||||
}
|
||||
|
||||
@Transaction
|
||||
@@ -125,37 +172,38 @@ internal interface RepositoryDaoInt : RepositoryDao {
|
||||
|
||||
@Transaction
|
||||
@VisibleForTesting
|
||||
fun insertOrReplace(repository: RepoV2): Long {
|
||||
val repoId = insertOrReplace(repository.toCoreRepository(version = 0))
|
||||
insertRepositoryPreferences(repoId)
|
||||
fun insertOrReplace(repository: RepoV2, version: Long = 0): Long {
|
||||
val repoId = insertOrReplace(repository.toCoreRepository(version = version))
|
||||
val currentMaxWeight = getMaxRepositoryWeight()
|
||||
val repositoryPreferences = RepositoryPreferences(repoId, currentMaxWeight + 1)
|
||||
insert(repositoryPreferences)
|
||||
insertRepoTables(repoId, repository)
|
||||
return repoId
|
||||
}
|
||||
|
||||
private fun insertRepositoryPreferences(repoId: Long) {
|
||||
val currentMaxWeight = getMaxRepositoryWeight()
|
||||
val repositoryPreferences = RepositoryPreferences(repoId, currentMaxWeight + 1)
|
||||
insert(repositoryPreferences)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use when replacing an existing repo with a full index.
|
||||
* This removes all existing index data associated with this repo from the database,
|
||||
* but does not touch repository preferences.
|
||||
* @throws IllegalStateException if no repo with the given [repoId] exists.
|
||||
*/
|
||||
@Transaction
|
||||
fun clear(repoId: Long) {
|
||||
val repo = getRepository(repoId) ?: error("repo with id $repoId does not exist")
|
||||
// this clears all foreign key associated data since the repo gets replaced
|
||||
insertOrReplace(repo.repository)
|
||||
}
|
||||
@Query("SELECT MAX(weight) FROM RepositoryPreferences")
|
||||
fun getMaxRepositoryWeight(): Int
|
||||
|
||||
@Transaction
|
||||
override fun clearAll() {
|
||||
deleteAllCoreRepositories()
|
||||
deleteAllRepositoryPreferences()
|
||||
}
|
||||
@Query("SELECT * FROM CoreRepository WHERE repoId = :repoId")
|
||||
override fun getRepository(repoId: Long): Repository?
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM CoreRepository")
|
||||
override fun getRepositories(): List<Repository>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM CoreRepository")
|
||||
override fun getLiveRepositories(): LiveData<List<Repository>>
|
||||
|
||||
@Query("SELECT * FROM RepositoryPreferences WHERE repoId = :repoId")
|
||||
fun getRepositoryPreferences(repoId: Long): RepositoryPreferences?
|
||||
|
||||
@RewriteQueriesToDropUnusedColumns
|
||||
@Query("""SELECT * FROM Category
|
||||
JOIN RepositoryPreferences AS pref USING (repoId)
|
||||
WHERE pref.enabled = 1 GROUP BY id HAVING MAX(pref.weight)""")
|
||||
override fun getLiveCategories(): LiveData<List<Category>>
|
||||
|
||||
/**
|
||||
* Updates an existing repo with new data from a full index update.
|
||||
@@ -180,10 +228,25 @@ internal interface RepositoryDaoInt : RepositoryDao {
|
||||
insertReleaseChannels(repository.releaseChannels.toRepoReleaseChannel(repoId))
|
||||
}
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM CoreRepository WHERE repoId = :repoId")
|
||||
override fun getRepository(repoId: Long): Repository?
|
||||
@Update
|
||||
fun updateRepository(repo: CoreRepository): Int
|
||||
|
||||
/**
|
||||
* Updates the certificate for the [Repository] with the given [repoId].
|
||||
* This should be used for V1 index updating where we only get the full cert
|
||||
* after reading the entire index file.
|
||||
* V2 index should use [update] instead as there the certificate is known
|
||||
* before reading full index.
|
||||
*/
|
||||
@Query("UPDATE CoreRepository SET certificate = :certificate WHERE repoId = :repoId")
|
||||
fun updateRepository(repoId: Long, certificate: String)
|
||||
|
||||
@Update
|
||||
fun updateRepositoryPreferences(preferences: RepositoryPreferences)
|
||||
|
||||
/**
|
||||
* Used to update an existing repository with a given [jsonObject] JSON diff.
|
||||
*/
|
||||
@Transaction
|
||||
fun updateRepository(repoId: Long, version: Long, jsonObject: JsonObject) {
|
||||
// get existing repo
|
||||
@@ -237,15 +300,6 @@ internal interface RepositoryDaoInt : RepositoryDao {
|
||||
)
|
||||
}
|
||||
|
||||
@Update
|
||||
fun updateRepository(repo: CoreRepository): Int
|
||||
|
||||
@Query("UPDATE CoreRepository SET certificate = :certificate WHERE repoId = :repoId")
|
||||
fun updateRepository(repoId: Long, certificate: String)
|
||||
|
||||
@Update
|
||||
fun updateRepositoryPreferences(preferences: RepositoryPreferences)
|
||||
|
||||
@Query("UPDATE RepositoryPreferences SET enabled = :enabled WHERE repoId = :repoId")
|
||||
override fun setRepositoryEnabled(repoId: Long, enabled: Boolean)
|
||||
|
||||
@@ -260,73 +314,6 @@ internal interface RepositoryDaoInt : RepositoryDao {
|
||||
WHERE repoId = :repoId""")
|
||||
override fun updateDisabledMirrors(repoId: Long, disabledMirrors: List<String>)
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM CoreRepository")
|
||||
override fun getRepositories(): List<Repository>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM CoreRepository")
|
||||
override fun getLiveRepositories(): LiveData<List<Repository>>
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT * FROM Mirror")
|
||||
fun getMirrors(): List<Mirror>
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("DELETE FROM Mirror WHERE repoId = :repoId")
|
||||
fun deleteMirrors(repoId: Long)
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT * FROM AntiFeature")
|
||||
fun getAntiFeatures(): List<AntiFeature>
|
||||
|
||||
@Query("SELECT * FROM RepositoryPreferences WHERE repoId = :repoId")
|
||||
fun getRepositoryPreferences(repoId: Long): RepositoryPreferences?
|
||||
|
||||
@Query("SELECT MAX(weight) FROM RepositoryPreferences")
|
||||
fun getMaxRepositoryWeight(): Int
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId")
|
||||
fun deleteAntiFeatures(repoId: Long)
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId AND id = :id")
|
||||
fun deleteAntiFeature(repoId: Long, id: String)
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT * FROM Category")
|
||||
fun getCategories(): List<Category>
|
||||
|
||||
@RewriteQueriesToDropUnusedColumns
|
||||
@Query("""SELECT * FROM Category
|
||||
JOIN RepositoryPreferences AS pref USING (repoId)
|
||||
WHERE pref.enabled = 1 GROUP BY id HAVING MAX(pref.weight)""")
|
||||
override fun getLiveCategories(): LiveData<List<Category>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM AppMetadata WHERE repoId = :repoId")
|
||||
override fun countAppsPerRepository(repoId: Long): Int
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("DELETE FROM Category WHERE repoId = :repoId")
|
||||
fun deleteCategories(repoId: Long)
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("DELETE FROM Category WHERE repoId = :repoId AND id = :id")
|
||||
fun deleteCategory(repoId: Long, id: String)
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT * FROM ReleaseChannel")
|
||||
fun getReleaseChannels(): List<ReleaseChannel>
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId")
|
||||
fun deleteReleaseChannels(repoId: Long)
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId AND id = :id")
|
||||
fun deleteReleaseChannel(repoId: Long, id: String)
|
||||
|
||||
@Transaction
|
||||
override fun deleteRepository(repoId: Long) {
|
||||
deleteCoreRepository(repoId)
|
||||
@@ -338,13 +325,90 @@ internal interface RepositoryDaoInt : RepositoryDao {
|
||||
@Query("DELETE FROM CoreRepository WHERE repoId = :repoId")
|
||||
fun deleteCoreRepository(repoId: Long)
|
||||
|
||||
@Query("DELETE FROM CoreRepository")
|
||||
fun deleteAllCoreRepositories()
|
||||
|
||||
@Query("DELETE FROM RepositoryPreferences WHERE repoId = :repoId")
|
||||
fun deleteRepositoryPreferences(repoId: Long)
|
||||
|
||||
@Query("DELETE FROM CoreRepository")
|
||||
fun deleteAllCoreRepositories()
|
||||
|
||||
@Query("DELETE FROM RepositoryPreferences")
|
||||
fun deleteAllRepositoryPreferences()
|
||||
|
||||
/**
|
||||
* Used for diffing.
|
||||
*/
|
||||
@Query("DELETE FROM Mirror WHERE repoId = :repoId")
|
||||
fun deleteMirrors(repoId: Long)
|
||||
|
||||
/**
|
||||
* Used for diffing.
|
||||
*/
|
||||
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId")
|
||||
fun deleteAntiFeatures(repoId: Long)
|
||||
|
||||
/**
|
||||
* Used for diffing.
|
||||
*/
|
||||
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId AND id = :id")
|
||||
fun deleteAntiFeature(repoId: Long, id: String)
|
||||
|
||||
/**
|
||||
* Used for diffing.
|
||||
*/
|
||||
@Query("DELETE FROM Category WHERE repoId = :repoId")
|
||||
fun deleteCategories(repoId: Long)
|
||||
|
||||
/**
|
||||
* Used for diffing.
|
||||
*/
|
||||
@Query("DELETE FROM Category WHERE repoId = :repoId AND id = :id")
|
||||
fun deleteCategory(repoId: Long, id: String)
|
||||
|
||||
/**
|
||||
* Used for diffing.
|
||||
*/
|
||||
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId")
|
||||
fun deleteReleaseChannels(repoId: Long)
|
||||
|
||||
/**
|
||||
* Used for diffing.
|
||||
*/
|
||||
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId AND id = :id")
|
||||
fun deleteReleaseChannel(repoId: Long, id: String)
|
||||
|
||||
/**
|
||||
* Use when replacing an existing repo with a full index.
|
||||
* This removes all existing index data associated with this repo from the database,
|
||||
* but does not touch repository preferences.
|
||||
* @throws IllegalStateException if no repo with the given [repoId] exists.
|
||||
*/
|
||||
@Transaction
|
||||
fun clear(repoId: Long) {
|
||||
val repo = getRepository(repoId) ?: error("repo with id $repoId does not exist")
|
||||
// this clears all foreign key associated data since the repo gets replaced
|
||||
insertOrReplace(repo.repository)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
override fun clearAll() {
|
||||
deleteAllCoreRepositories()
|
||||
deleteAllRepositoryPreferences()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT COUNT(*) FROM Mirror")
|
||||
fun countMirrors(): Int
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT COUNT(*) FROM AntiFeature")
|
||||
fun countAntiFeatures(): Int
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT COUNT(*) FROM Category")
|
||||
fun countCategories(): Int
|
||||
|
||||
@VisibleForTesting
|
||||
@Query("SELECT COUNT(*) FROM ReleaseChannel")
|
||||
fun countReleaseChannels(): Int
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user