improve tests

This commit is contained in:
Aria Moradi
2021-10-31 17:31:46 +03:30
parent d460d3ccdf
commit 5fe69becf3
9 changed files with 243 additions and 52 deletions

3
.gitignore vendored
View File

@@ -3,6 +3,9 @@
.idea
gradle.properties
# But we need these
!.idea/runConfigurations
# Ignore Gradle build output directory
build

View File

@@ -10,7 +10,7 @@ package suwayomi.tachidesk.manga.impl
import org.jetbrains.exposed.sql.SortOrder
import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.deleteWhere
import org.jetbrains.exposed.sql.insert
import org.jetbrains.exposed.sql.insertAndGetId
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
@@ -27,18 +27,21 @@ object Category {
/**
* The new category will be placed at the end of the list
*/
fun createCategory(name: String) {
fun createCategory(name: String): Int {
// creating a category named Default is illegal
if (name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)) return
if (name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)) return -1
transaction {
return transaction {
if (CategoryTable.select { CategoryTable.name eq name }.firstOrNull() == null) {
CategoryTable.insert {
val newCategoryId = CategoryTable.insertAndGetId {
it[CategoryTable.name] = name
it[CategoryTable.order] = Int.MAX_VALUE
}
}.value
normalizeCategories()
}
newCategoryId
} else -1
}
}

View File

@@ -23,9 +23,7 @@ object DBManager {
}
}
fun databaseUp() {
// must mention db object so the lazy block executes
val db = DBManager.db
fun databaseUp(db: Database = DBManager.db) {
db.useNestedTransactions = true
val migrations = loadMigrationsFrom("suwayomi.tachidesk.server.database.migration", ServerConfig::class.java)

View File

@@ -1,4 +1,4 @@
package suwayomi
package masstest
/*
* Copyright (C) Contributors to the Suwayomi project

View File

@@ -1,4 +1,4 @@
package suwayomi
package masstest
/*
* Copyright (C) Contributors to the Suwayomi project

View File

@@ -0,0 +1,157 @@
package suwayomi.tachidesk
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import eu.kanade.tachiyomi.App
import eu.kanade.tachiyomi.source.local.LocalSource
import mu.KotlinLogging
import org.jetbrains.exposed.sql.Database
import org.junit.jupiter.api.BeforeAll
import org.kodein.di.DI
import org.kodein.di.bind
import org.kodein.di.conf.global
import org.kodein.di.singleton
import masstest.BASE_PATH
import suwayomi.tachidesk.server.ApplicationDirs
import suwayomi.tachidesk.server.JavalinSetup
import suwayomi.tachidesk.server.ServerConfig
import suwayomi.tachidesk.server.androidCompat
import suwayomi.tachidesk.server.database.databaseUp
import suwayomi.tachidesk.server.serverConfig
import suwayomi.tachidesk.server.systemTrayInstance
import suwayomi.tachidesk.server.util.AppMutex
import xyz.nulldev.androidcompat.AndroidCompatInitializer
import xyz.nulldev.ts.config.CONFIG_PREFIX
import xyz.nulldev.ts.config.ConfigKodeinModule
import xyz.nulldev.ts.config.GlobalConfigManager
import java.io.File
import java.util.Locale
open class ApplicationTest {
companion object {
@BeforeAll
@JvmStatic
fun beforeAll() {
if (!initializedTheApp) {
val dataRoot = File(BASE_PATH).absolutePath
System.setProperty("$CONFIG_PREFIX.server.rootDir", dataRoot)
testingSetup()
databaseSetup()
initializedTheApp = true
}
}
private val logger = KotlinLogging.logger {}
private var initializedTheApp = false
fun testingSetup() {
// Application dirs
val applicationDirs = ApplicationDirs()
DI.global.addImport(
DI.Module("Server") {
bind<ApplicationDirs>() with singleton { applicationDirs }
}
)
logger.debug("Data Root directory is set to: ${applicationDirs.dataRoot}")
// make dirs we need
listOf(
applicationDirs.dataRoot,
applicationDirs.extensionsRoot,
applicationDirs.extensionsRoot + "/icon",
applicationDirs.mangaThumbnailsRoot,
applicationDirs.animeThumbnailsRoot,
applicationDirs.mangaRoot,
applicationDirs.localMangaRoot,
).forEach {
File(it).mkdirs()
}
// register Tachidesk's config which is dubbed "ServerConfig"
GlobalConfigManager.registerModule(
ServerConfig.register(GlobalConfigManager.config)
)
// Make sure only one instance of the app is running
AppMutex.handleAppMutex()
// Load config API
DI.global.addImport(ConfigKodeinModule().create())
// Load Android compatibility dependencies
AndroidCompatInitializer().init()
// start app
androidCompat.startApp(App())
// create conf file if doesn't exist
try {
val dataConfFile = File("${applicationDirs.dataRoot}/server.conf")
if (!dataConfFile.exists()) {
JavalinSetup::class.java.getResourceAsStream("/server-reference.conf").use { input ->
dataConfFile.outputStream().use { output ->
input.copyTo(output)
}
}
}
} catch (e: Exception) {
logger.error("Exception while creating initial server.conf", e)
}
// copy local source icon
try {
val localSourceIconFile = File("${applicationDirs.extensionsRoot}/icon/localSource.png")
if (!localSourceIconFile.exists()) {
JavalinSetup::class.java.getResourceAsStream("/icon/localSource.png").use { input ->
localSourceIconFile.outputStream().use { output ->
input.copyTo(output)
}
}
}
} catch (e: Exception) {
logger.error("Exception while copying Local source's icon", e)
}
// create system tray
if (serverConfig.systemTrayEnabled) {
try {
systemTrayInstance
} catch (e: Throwable) { // cover both java.lang.Exception and java.lang.Error
e.printStackTrace()
}
}
// Disable jetty's logging
System.setProperty("org.eclipse.jetty.util.log.announce", "false")
System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog")
System.setProperty("org.eclipse.jetty.LEVEL", "OFF")
// socks proxy settings
if (serverConfig.socksProxyEnabled) {
System.getProperties()["socksProxyHost"] = serverConfig.socksProxyHost
System.getProperties()["socksProxyPort"] = serverConfig.socksProxyPort
logger.info("Socks Proxy is enabled to ${serverConfig.socksProxyHost}:${serverConfig.socksProxyPort}")
}
}
fun databaseSetup() {
// fixes #119 , ref: https://github.com/Suwayomi/Tachidesk-Server/issues/119#issuecomment-894681292 , source Id calculation depends on String.lowercase()
Locale.setDefault(Locale.ENGLISH)
// in-memory database, don't discard database between connections/transactions
val db = Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;", "org.h2.Driver")
databaseUp(db)
LocalSource.addDbRecords()
}
}
}

View File

@@ -1,27 +1,22 @@
package suwayomi.tachidesk.manga.controller
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import org.jetbrains.exposed.sql.deleteAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import suwayomi.BASE_PATH
import suwayomi.tachidesk.manga.impl.Category
import suwayomi.tachidesk.manga.model.table.CategoryTable
import suwayomi.tachidesk.server.applicationSetup
import xyz.nulldev.ts.config.CONFIG_PREFIX
import java.io.File
internal class CategoryControllerTest {
@BeforeEach
internal fun setUp() {
val dataRoot = File(BASE_PATH).absolutePath
System.setProperty("$CONFIG_PREFIX.server.rootDir", dataRoot)
applicationSetup()
}
import suwayomi.tachidesk.ApplicationTest
internal class CategoryControllerTest : ApplicationTest() {
@Test
fun categoryReorder() {
Category.createCategory("foo")

View File

@@ -0,0 +1,46 @@
package suwayomi.tachidesk.manga.controller
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import org.jetbrains.exposed.sql.deleteAll
import org.jetbrains.exposed.sql.transactions.transaction
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import suwayomi.tachidesk.manga.impl.Category
import suwayomi.tachidesk.manga.model.table.CategoryTable
import suwayomi.tachidesk.ApplicationTest
@TestInstance(PER_CLASS)
internal class SourceControllerTest : ApplicationTest() {
@Test
fun categoryReorder() {
Category.createCategory("foo")
Category.createCategory("bar")
val cats = Category.getCategoryList()
val foo = cats.asSequence().filter { it.name == "foo" }.first()
val bar = cats.asSequence().filter { it.name == "bar" }.first()
assertEquals(1, foo.order)
assertEquals(2, bar.order)
Category.reorderCategory(1, 2)
val catsReordered = Category.getCategoryList()
val fooReordered = catsReordered.asSequence().filter { it.name == "foo" }.first()
val barReordered = catsReordered.asSequence().filter { it.name == "bar" }.first()
assertEquals(2, fooReordered.order)
assertEquals(1, barReordered.order)
}
@AfterEach
internal fun tearDown() {
transaction {
CategoryTable.deleteAll()
}
}
}

View File

@@ -13,10 +13,9 @@ import org.jetbrains.exposed.sql.insertAndGetId
import org.jetbrains.exposed.sql.transactions.transaction
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import suwayomi.BASE_PATH
import suwayomi.tachidesk.manga.impl.Category.DEFAULT_CATEGORY_ID
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.CategoryTable
import suwayomi.tachidesk.manga.model.table.ChapterTable
@@ -26,59 +25,49 @@ import suwayomi.tachidesk.manga.model.table.ChapterTable.name
import suwayomi.tachidesk.manga.model.table.ChapterTable.sourceOrder
import suwayomi.tachidesk.manga.model.table.ChapterTable.url
import suwayomi.tachidesk.manga.model.table.MangaTable
import suwayomi.tachidesk.server.applicationSetup
import xyz.nulldev.ts.config.CONFIG_PREFIX
import java.io.File
import suwayomi.tachidesk.ApplicationTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CategoryMangaTest {
@BeforeEach
fun setUp() {
val dataRoot = File(BASE_PATH).absolutePath
System.setProperty("$CONFIG_PREFIX.server.rootDir", dataRoot)
applicationSetup()
}
class CategoryMangaTest : ApplicationTest() {
@Test
fun getCategoryMangaList() {
val emptyCats = CategoryManga.getCategoryMangaList(0).size
val emptyCats = CategoryManga.getCategoryMangaList(DEFAULT_CATEGORY_ID).size
assertEquals(0, emptyCats, "Default category should be empty at start")
val mangaId = createManga("Psyren")
val mangaId = createLibraryManga("Psyren")
createChapters(mangaId, 10, true)
assertEquals(1, CategoryManga.getCategoryMangaList(0).size, "Default category should have one member")
assertEquals(1, CategoryManga.getCategoryMangaList(DEFAULT_CATEGORY_ID).size, "Default category should have one member")
assertEquals(
0, CategoryManga.getCategoryMangaList(0)[0].unreadCount,
0, CategoryManga.getCategoryMangaList(DEFAULT_CATEGORY_ID)[0].unreadCount,
"Manga should not have any unread chapters"
)
createChapters(mangaId, 10, false)
assertEquals(
10, CategoryManga.getCategoryMangaList(0)[0].unreadCount,
10, CategoryManga.getCategoryMangaList(DEFAULT_CATEGORY_ID)[0].unreadCount,
"Manga should have unread chapters"
)
Category.createCategory("Old") // category id 1
val categoryId = Category.createCategory("Old")
assertEquals(
0,
CategoryManga.getCategoryMangaList(1).size,
CategoryManga.getCategoryMangaList(categoryId).size,
"Newly created category shouldn't have any Mangas"
)
CategoryManga.addMangaToCategory(mangaId, 1)
CategoryManga.addMangaToCategory(mangaId, categoryId)
assertEquals(
1, CategoryManga.getCategoryMangaList(1).size,
1, CategoryManga.getCategoryMangaList(categoryId).size,
"Manga should been moved"
)
assertEquals(
10, CategoryManga.getCategoryMangaList(1)[0].unreadCount,
10, CategoryManga.getCategoryMangaList(categoryId)[0].unreadCount,
"Manga should keep it's unread count in moved category"
)
assertEquals(
0, CategoryManga.getCategoryMangaList(0).size,
0, CategoryManga.getCategoryMangaList(DEFAULT_CATEGORY_ID).size,
"Manga shouldn't be member of default category after moving"
)
}
private fun createManga(
private fun createLibraryManga(
_title: String
): Int {
return transaction {