(fix) Server-Modul
This commit is contained in:
parent
89b8900fb2
commit
2ad447c978
|
|
@ -22,7 +22,7 @@ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||||
|
|
||||||
// Configure application
|
// Configure application
|
||||||
application {
|
application {
|
||||||
mainClass.set("at.mocode.server.ApplicationKt")
|
mainClass.set("at.mocode.ApplicationKt")
|
||||||
applicationDefaultJvmArgs = listOf(
|
applicationDefaultJvmArgs = listOf(
|
||||||
"-Dio.ktor.development=${extra["io.ktor.development"] ?: "false"}",
|
"-Dio.ktor.development=${extra["io.ktor.development"] ?: "false"}",
|
||||||
"-XX:+UseG1GC", // Use G1 Garbage Collector
|
"-XX:+UseG1GC", // Use G1 Garbage Collector
|
||||||
|
|
@ -75,7 +75,7 @@ dependencies {
|
||||||
|
|
||||||
// Testing
|
// Testing
|
||||||
testImplementation(libs.ktor.server.tests)
|
testImplementation(libs.ktor.server.tests)
|
||||||
testImplementation(libs.kotlin.test.junit)
|
testImplementation(libs.kotlin.test)
|
||||||
testImplementation(libs.junitJupiter)
|
testImplementation(libs.junitJupiter)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package at.mocode.server
|
package at.mocode
|
||||||
|
|
||||||
import at.mocode.server.plugins.configureDatabase
|
import at.mocode.plugins.configureDatabase
|
||||||
|
import at.mocode.plugins.configureRouting
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
import io.ktor.serialization.kotlinx.json.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
|
|
@ -11,7 +12,6 @@ import io.ktor.server.plugins.cors.routing.*
|
||||||
import io.ktor.server.plugins.defaultheaders.*
|
import io.ktor.server.plugins.defaultheaders.*
|
||||||
import io.ktor.server.plugins.statuspages.*
|
import io.ktor.server.plugins.statuspages.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.slf4j.event.Level
|
import org.slf4j.event.Level
|
||||||
|
|
@ -22,18 +22,10 @@ fun main(args: Array<String>) {
|
||||||
|
|
||||||
fun Application.module() {
|
fun Application.module() {
|
||||||
val log = LoggerFactory.getLogger("Application")
|
val log = LoggerFactory.getLogger("Application")
|
||||||
|
|
||||||
log.info("Initializing application...")
|
log.info("Initializing application...")
|
||||||
|
|
||||||
// Configure database
|
|
||||||
configureDatabase()
|
configureDatabase()
|
||||||
|
|
||||||
// Configure plugins
|
|
||||||
configurePlugins()
|
configurePlugins()
|
||||||
|
|
||||||
// Configure routing
|
|
||||||
configureRouting()
|
configureRouting()
|
||||||
|
|
||||||
log.info("Application initialized successfully")
|
log.info("Application initialized successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +85,7 @@ private fun Application.configurePlugins() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// Log the error but continue with default configuration
|
// Log the error but continue with the default configuration
|
||||||
this@configurePlugins.log.warn("Failed to configure CORS from config, using defaults: ${e.message}")
|
this@configurePlugins.log.warn("Failed to configure CORS from config, using defaults: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,28 +107,3 @@ private fun Application.configurePlugins() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures all routes for the application
|
|
||||||
*/
|
|
||||||
private fun Application.configureRouting() {
|
|
||||||
routing {
|
|
||||||
// Health check endpoint
|
|
||||||
get("/health") {
|
|
||||||
call.respondText("OK")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Root endpoint with basic information
|
|
||||||
get("/") {
|
|
||||||
// Read application info from config if available
|
|
||||||
val appName = application.environment.config.propertyOrNull("application.name")?.getString() ?: "Meldestelle API Server"
|
|
||||||
val appVersion = application.environment.config.propertyOrNull("application.version")?.getString() ?: "1.0.0"
|
|
||||||
val appEnv = application.environment.config.propertyOrNull("application.environment")?.getString() ?: "development"
|
|
||||||
|
|
||||||
call.respondText("$appName v$appVersion - Running in $appEnv mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
// API routes can be organized in separate files and included here
|
|
||||||
// Example: registerUserRoutes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
server/src/main/kotlin/at/mocode/db/mapping.kt
Normal file
2
server/src/main/kotlin/at/mocode/db/mapping.kt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
package at.mocode.db
|
||||||
|
|
||||||
2
server/src/main/kotlin/at/mocode/model/Event.kt
Normal file
2
server/src/main/kotlin/at/mocode/model/Event.kt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
package at.mocode.model
|
||||||
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package at.mocode.model
|
||||||
|
|
||||||
|
interface EventRepository {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
package at.mocode.model
|
||||||
|
|
||||||
|
class PostgresEventRepository {
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package at.mocode.server.plugins
|
package at.mocode.plugins
|
||||||
|
|
||||||
import at.mocode.server.tables.*
|
|
||||||
import com.zaxxer.hikari.HikariConfig
|
import com.zaxxer.hikari.HikariConfig
|
||||||
import com.zaxxer.hikari.HikariDataSource
|
import com.zaxxer.hikari.HikariDataSource
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
|
|
@ -175,14 +174,14 @@ private fun initializeSchema(log: Logger, isTestEnvironment: Boolean, isIdeaEnvi
|
||||||
try {
|
try {
|
||||||
// Create all tables if they don't exist
|
// Create all tables if they don't exist
|
||||||
SchemaUtils.create(
|
SchemaUtils.create(
|
||||||
VereineTable,
|
_root_ide_package_.at.mocode.tables.VereineTable,
|
||||||
PersonenTable,
|
_root_ide_package_.at.mocode.tables.PersonenTable,
|
||||||
PferdeTable,
|
_root_ide_package_.at.mocode.tables.PferdeTable,
|
||||||
VeranstaltungenTable,
|
_root_ide_package_.at.mocode.tables.VeranstaltungenTable,
|
||||||
TurniereTable,
|
_root_ide_package_.at.mocode.tables.TurniereTable,
|
||||||
ArtikelTable,
|
_root_ide_package_.at.mocode.tables.ArtikelTable,
|
||||||
PlaetzeTable,
|
_root_ide_package_.at.mocode.tables.PlaetzeTable,
|
||||||
LizenzenTable
|
_root_ide_package_.at.mocode.tables.LizenzenTable
|
||||||
// Add more tables here if needed
|
// Add more tables here if needed
|
||||||
)
|
)
|
||||||
log.info("Database schema initialized successfully.")
|
log.info("Database schema initialized successfully.")
|
||||||
32
server/src/main/kotlin/at/mocode/plugins/Routing.kt
Normal file
32
server/src/main/kotlin/at/mocode/plugins/Routing.kt
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package at.mocode.plugins
|
||||||
|
|
||||||
|
import io.ktor.server.application.Application
|
||||||
|
import io.ktor.server.response.respondText
|
||||||
|
import io.ktor.server.routing.application
|
||||||
|
import io.ktor.server.routing.get
|
||||||
|
import io.ktor.server.routing.routing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures all routes for the application
|
||||||
|
*/
|
||||||
|
fun Application.configureRouting() {
|
||||||
|
routing {
|
||||||
|
// Health check endpoint
|
||||||
|
get("/health") {
|
||||||
|
call.respondText("OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root endpoint with basic information
|
||||||
|
get("/") {
|
||||||
|
// Read application info from config if available
|
||||||
|
val appName = application.environment.config.propertyOrNull("application.name")?.getString() ?: "Meldestelle API Server"
|
||||||
|
val appVersion = application.environment.config.propertyOrNull("application.version")?.getString() ?: "1.0.0"
|
||||||
|
val appEnv = application.environment.config.propertyOrNull("application.environment")?.getString() ?: "development"
|
||||||
|
|
||||||
|
call.respondText("$appName v$appVersion - Running in $appEnv mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
// API routes can be organized in separate files and included here
|
||||||
|
// Example: registerUserRoutes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
package at.mocode.plugins
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import at.mocode.shared.model.enums.LizenzTyp
|
|
||||||
import at.mocode.shared.model.enums.Sparte
|
import at.mocode.shared.enums.LizenzTypE
|
||||||
|
import at.mocode.shared.enums.SparteE
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
||||||
|
|
||||||
object LizenzenTable : Table("lizenzen") {
|
object LizenzenTable : Table("lizenzen") {
|
||||||
val id = uuid("id")
|
val id = uuid("id")
|
||||||
val personId = uuid("person_id").references(PersonenTable.id)
|
val personId = uuid("person_id").references(PersonenTable.id)
|
||||||
val lizenzTyp = enumerationByName("lizenz_typ", 50, LizenzTyp::class)
|
val lizenzTyp = enumerationByName("lizenz_typ", 50, LizenzTypE::class)
|
||||||
val stufe = varchar("stufe", 20).nullable()
|
val stufe = varchar("stufe", 20).nullable()
|
||||||
val sparte = enumerationByName("sparte", 50, Sparte::class).nullable()
|
val sparte = enumerationByName("sparte", 50, SparteE::class).nullable()
|
||||||
val gueltigBisJahr = integer("gueltig_bis_jahr").nullable()
|
val gueltigBisJahr = integer("gueltig_bis_jahr").nullable()
|
||||||
val ausgestelltAm = date("ausgestellt_am").nullable()
|
val ausgestelltAm = date("ausgestellt_am").nullable()
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import at.mocode.shared.model.enums.Geschlecht
|
import at.mocode.shared.enums.GeschlechtE
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||||
|
|
@ -12,7 +12,7 @@ object PersonenTable : Table("personen") {
|
||||||
val vorname = varchar("vorname", 100)
|
val vorname = varchar("vorname", 100)
|
||||||
val titel = varchar("titel", 50).nullable()
|
val titel = varchar("titel", 50).nullable()
|
||||||
val geburtsdatum = date("geburtsdatum").nullable()
|
val geburtsdatum = date("geburtsdatum").nullable()
|
||||||
val geschlecht = enumerationByName("geschlecht", 10, Geschlecht::class).nullable()
|
val geschlecht = enumerationByName("geschlecht", 10, GeschlechtE::class).nullable()
|
||||||
val nationalitaet = varchar("nationalitaet", 3).nullable()
|
val nationalitaet = varchar("nationalitaet", 3).nullable()
|
||||||
val email = varchar("email", 255).nullable()
|
val email = varchar("email", 255).nullable()
|
||||||
val telefon = varchar("telefon", 50).nullable()
|
val telefon = varchar("telefon", 50).nullable()
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import at.mocode.shared.model.enums.GeschlechtPferd
|
import at.mocode.shared.enums.GeschlechtPferdE
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ object PferdeTable : Table("pferde") {
|
||||||
val name = varchar("name", 255)
|
val name = varchar("name", 255)
|
||||||
val lebensnummer = varchar("lebensnummer", 20).nullable()
|
val lebensnummer = varchar("lebensnummer", 20).nullable()
|
||||||
val feiPassNr = varchar("fei_pass_nr", 20).nullable()
|
val feiPassNr = varchar("fei_pass_nr", 20).nullable()
|
||||||
val geschlecht = enumerationByName("geschlecht", 10, GeschlechtPferd::class).nullable()
|
val geschlecht = enumerationByName("geschlecht", 10, GeschlechtPferdE::class).nullable()
|
||||||
val geburtsjahr = integer("geburtsjahr").nullable()
|
val geburtsjahr = integer("geburtsjahr").nullable()
|
||||||
val rasse = varchar("rasse", 100).nullable()
|
val rasse = varchar("rasse", 100).nullable()
|
||||||
val farbe = varchar("farbe", 50).nullable()
|
val farbe = varchar("farbe", 50).nullable()
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import at.mocode.shared.model.enums.PlatzTyp
|
import at.mocode.shared.enums.PlatzTypE
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
object PlaetzeTable : Table("plaetze") {
|
object PlaetzeTable : Table("plaetze") {
|
||||||
|
|
@ -9,7 +9,7 @@ object PlaetzeTable : Table("plaetze") {
|
||||||
val name = varchar("name", 100)
|
val name = varchar("name", 100)
|
||||||
val dimension = varchar("dimension", 50).nullable()
|
val dimension = varchar("dimension", 50).nullable()
|
||||||
val boden = varchar("boden", 100).nullable()
|
val boden = varchar("boden", 100).nullable()
|
||||||
val typ = enumerationByName("typ", 20, PlatzTyp::class)
|
val typ = enumerationByName("typ", 20, PlatzTypE::class)
|
||||||
|
|
||||||
override val primaryKey = PrimaryKey(id)
|
override val primaryKey = PrimaryKey(id)
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.date // Für kotlinx-datetime LocalDate
|
import org.jetbrains.exposed.sql.kotlin.datetime.date // Für kotlinx-datetime LocalDate
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import at.mocode.shared.model.enums.VeranstalterTyp
|
import at.mocode.shared.enums.VeranstalterTypE
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
import org.jetbrains.exposed.sql.kotlin.datetime.date
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||||
|
|
@ -13,8 +13,8 @@ object VeranstaltungenTable : Table("veranstaltungen") {
|
||||||
val veranstalterName = varchar("veranstalter_name", 255)
|
val veranstalterName = varchar("veranstalter_name", 255)
|
||||||
val veranstalterOepsNummer = varchar("veranstalter_oeps_nr", 10).nullable()
|
val veranstalterOepsNummer = varchar("veranstalter_oeps_nr", 10).nullable()
|
||||||
val veranstalterTyp =
|
val veranstalterTyp =
|
||||||
enumerationByName("veranstalter_typ", 20, VeranstalterTyp::class).default(
|
enumerationByName("veranstalter_typ", 20, VeranstalterTypE::class).default(
|
||||||
VeranstalterTyp.UNBEKANNT
|
VeranstalterTypE.UNBEKANNT
|
||||||
)
|
)
|
||||||
val veranstaltungsortName = varchar("veranstaltungsort_name", 255)
|
val veranstaltungsortName = varchar("veranstaltungsort_name", 255)
|
||||||
val veranstaltungsortAdresse = varchar("veranstaltungsort_adresse", 500)
|
val veranstaltungsortAdresse = varchar("veranstaltungsort_adresse", 500)
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package at.mocode.server.tables
|
package at.mocode.tables
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
ktor:
|
ktor:
|
||||||
deployment:
|
deployment:
|
||||||
# Server port configuration
|
# Server port configuration
|
||||||
port: 8081
|
port: 8080
|
||||||
# Connection timeout in seconds
|
# Connection timeout in seconds
|
||||||
connectionTimeout: 30
|
connectionTimeout: 30
|
||||||
# Maximum number of concurrent connections
|
# Maximum number of concurrent connections
|
||||||
|
|
@ -13,7 +13,7 @@ ktor:
|
||||||
- resources
|
- resources
|
||||||
application:
|
application:
|
||||||
modules:
|
modules:
|
||||||
- at.mocode.server.ApplicationKt.module
|
- at.mocode.ApplicationKt.module
|
||||||
|
|
||||||
# Database Configuration
|
# Database Configuration
|
||||||
database:
|
database:
|
||||||
|
|
@ -40,8 +40,8 @@ security:
|
||||||
issuer: "meldestelle-server"
|
issuer: "meldestelle-server"
|
||||||
audience: "meldestelle-clients"
|
audience: "meldestelle-clients"
|
||||||
realm: "meldestelle"
|
realm: "meldestelle"
|
||||||
# Secret should be set via environment variable in production
|
# Secret should be set via an environment variable in production
|
||||||
secret: "${JWT_SECRET:dev-secret-key-change-in-production"
|
secret: "${JWT_SECRET:dev-secret-key-change-in-production}"
|
||||||
# Token validity duration in milliseconds (24 hours)
|
# Token validity duration in milliseconds (24 hours)
|
||||||
validity: 86400000
|
validity: 86400000
|
||||||
|
|
||||||
|
|
@ -52,13 +52,6 @@ cors:
|
||||||
- "localhost:3000"
|
- "localhost:3000"
|
||||||
- "127.0.0.1:3000"
|
- "127.0.0.1:3000"
|
||||||
- "meldestelle.mocode.at"
|
- "meldestelle.mocode.at"
|
||||||
# Allow these HTTP methods
|
|
||||||
allowedMethods:
|
|
||||||
- GET
|
|
||||||
- POST
|
|
||||||
- PUT
|
|
||||||
- DELETE
|
|
||||||
- OPTIONS
|
|
||||||
# Allow credentials (cookies, auth headers)
|
# Allow credentials (cookies, auth headers)
|
||||||
allowCredentials: true
|
allowCredentials: true
|
||||||
|
|
||||||
|
|
|
||||||
10
server/src/main/resources/static/index.html
Normal file
10
server/src/main/resources/static/index.html
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
166
server/src/test/kotlin/at/mocode/ApplicationTest.kt
Normal file
166
server/src/test/kotlin/at/mocode/ApplicationTest.kt
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
package at.mocode
|
||||||
|
|
||||||
|
import at.mocode.plugins.configureRouting
|
||||||
|
import io.ktor.client.request.*
|
||||||
|
import io.ktor.client.statement.*
|
||||||
|
import io.ktor.http.*
|
||||||
|
import io.ktor.serialization.kotlinx.json.*
|
||||||
|
import io.ktor.server.application.*
|
||||||
|
import io.ktor.server.plugins.contentnegotiation.*
|
||||||
|
import io.ktor.server.plugins.cors.routing.*
|
||||||
|
import io.ktor.server.plugins.defaultheaders.*
|
||||||
|
import io.ktor.server.response.*
|
||||||
|
import io.ktor.server.routing.*
|
||||||
|
import io.ktor.server.testing.*
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comprehensive test suite for the Meldestelle Server Application.
|
||||||
|
*
|
||||||
|
* This test class verifies:
|
||||||
|
* - Application startup and initialization
|
||||||
|
* - Core routing functionality (health check, root endpoint)
|
||||||
|
* - Plugin configuration (CORS, content negotiation, default headers)
|
||||||
|
* - Error handling
|
||||||
|
* - Basic HTTP functionality
|
||||||
|
*/
|
||||||
|
class ApplicationTest {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
init {
|
||||||
|
// Set test environment property for database configuration
|
||||||
|
// This ensures the application uses H2 in-memory database for testing
|
||||||
|
System.setProperty("isTestEnvironment", "true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testApplicationStartup() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
// Test that the application starts without errors
|
||||||
|
// This test passes if no exceptions are thrown during module initialization
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testHealthEndpoint() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
client.get("/health").apply {
|
||||||
|
assertEquals(HttpStatusCode.OK, status)
|
||||||
|
assertEquals("OK", bodyAsText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRootEndpoint() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
client.get("/").apply {
|
||||||
|
assertEquals(HttpStatusCode.OK, status)
|
||||||
|
val responseText = bodyAsText()
|
||||||
|
// The response format is: "Meldestelle API Server v1.0.0 - Running in development mode"
|
||||||
|
assertTrue(responseText.contains("Meldestelle API Server"), "Response should contain 'Meldestelle API Server', but was: $responseText")
|
||||||
|
assertTrue(responseText.contains("v1.0.0"), "Response should contain 'v1.0.0', but was: $responseText")
|
||||||
|
assertTrue(responseText.contains("development"), "Response should contain 'development', but was: $responseText")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNotFoundEndpoint() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
client.get("/nonexistent").apply {
|
||||||
|
assertEquals(HttpStatusCode.NotFound, status)
|
||||||
|
val responseText = bodyAsText()
|
||||||
|
assertTrue(responseText.contains("404: Page Not Found"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDefaultHeaders() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
client.get("/health").apply {
|
||||||
|
assertEquals(HttpStatusCode.OK, status)
|
||||||
|
// Check that default headers are set
|
||||||
|
assertEquals("Ktor", headers["X-Engine"])
|
||||||
|
assertEquals("nosniff", headers["X-Content-Type-Options"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCorsConfiguration() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
client.get("/health") {
|
||||||
|
header(HttpHeaders.Origin, "http://localhost:3000")
|
||||||
|
}.apply {
|
||||||
|
assertEquals(HttpStatusCode.OK, status)
|
||||||
|
// Check that CORS headers are present
|
||||||
|
assertNotNull(headers[HttpHeaders.AccessControlAllowOrigin])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testContentNegotiation() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
client.get("/health") {
|
||||||
|
header(HttpHeaders.Accept, "application/json")
|
||||||
|
}.apply {
|
||||||
|
assertEquals(HttpStatusCode.OK, status)
|
||||||
|
// The response should still be text for the health endpoint
|
||||||
|
assertEquals("OK", bodyAsText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOptionsRequest() = testApplication {
|
||||||
|
application {
|
||||||
|
module()
|
||||||
|
}
|
||||||
|
client.options("/health") {
|
||||||
|
header(HttpHeaders.Origin, "http://localhost:3000")
|
||||||
|
header(HttpHeaders.AccessControlRequestMethod, "GET")
|
||||||
|
}.apply {
|
||||||
|
// OPTIONS requests should be handled by CORS
|
||||||
|
assertTrue(status.isSuccess() || status == HttpStatusCode.NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBasicRoutingWithoutDatabase() = testApplication {
|
||||||
|
application {
|
||||||
|
// Test routing functionality without full application module
|
||||||
|
// This isolates routing from database dependencies
|
||||||
|
install(DefaultHeaders) {
|
||||||
|
header("X-Engine", "Ktor")
|
||||||
|
header("X-Content-Type-Options", "nosniff")
|
||||||
|
}
|
||||||
|
|
||||||
|
install(ContentNegotiation) {
|
||||||
|
json(Json {
|
||||||
|
prettyPrint = true
|
||||||
|
isLenient = true
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
configureRouting()
|
||||||
|
}
|
||||||
|
|
||||||
|
client.get("/health").apply {
|
||||||
|
assertEquals(HttpStatusCode.OK, status)
|
||||||
|
assertEquals("OK", bodyAsText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
server/src/test/kotlin/at/mocode/SimpleTest.kt
Normal file
10
server/src/test/kotlin/at/mocode/SimpleTest.kt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
package at.mocode
|
||||||
|
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
class SimpleTest {
|
||||||
|
@Test
|
||||||
|
fun testBasic() {
|
||||||
|
assertEquals(1, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,14 +51,5 @@ kotlin {
|
||||||
implementation(kotlin("test"))
|
implementation(kotlin("test"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// val jvmMain by getting {
|
|
||||||
// dependsOn(commonMain)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// val wasmJsMain by getting {
|
|
||||||
// dependsOn(commonMain)
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
41
shared/src/commonMain/kotlin/at/mocode/model/Turnier.kt
Normal file
41
shared/src/commonMain/kotlin/at/mocode/model/Turnier.kt
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
package at.mocode.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a tournament (Turnier) with its details and associated competitions (Bewerbe).
|
||||||
|
* Each tournament can have one or more competitions.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Turnier(
|
||||||
|
/** The name of the tournament, e.g. "CSN-C NEU CSNP-C NEU NEUMARKT/M., OÖ" */
|
||||||
|
val name: String,
|
||||||
|
|
||||||
|
/** The date of the tournament as a formatted string, e.g. "7.JUNI 2025" */
|
||||||
|
val datum: String,
|
||||||
|
|
||||||
|
/** Unique identifier for the tournament */
|
||||||
|
val number: Int,
|
||||||
|
|
||||||
|
/** List of competitions (Bewerbe) associated with this tournament */
|
||||||
|
var bewerbe: List<Bewerb>
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a competition (Bewerb) within a tournament.
|
||||||
|
* A competition has specific details like number, title, class, and optional task.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class Bewerb(
|
||||||
|
/** Competition number, e.g. 1, 2, etc. */
|
||||||
|
val nummer: Int,
|
||||||
|
|
||||||
|
/** Title of the competition, e.g. "Stilspringprüfung" or "Dressurprüfung" */
|
||||||
|
val titel: String,
|
||||||
|
|
||||||
|
/** Class/level of the competition, e.g. "60 cm" or "Kl. A" */
|
||||||
|
val klasse: String,
|
||||||
|
|
||||||
|
/** Optional task identifier, e.g. "DRA 1" */
|
||||||
|
val task: String?
|
||||||
|
)
|
||||||
|
|
@ -18,7 +18,7 @@ enum class CupSerieTypE { CUP_SERIE }
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class LizenzKategorieE { REITERLIZENZ, FAHRERLIZENZ, STARTKARTE }
|
enum class LizenzKategorieE { REITERLIZENZ, FAHRERLIZENZ, STARTKARTE }
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class LizenzTyp { REITER, FAHRER, VOLTIGIERER, WESTERN, WORKING_EQUITATION, POLO, STARTKARTE_ALLG, STARTKARTE_VOLTIGIEREN, STARTKARTE_WESTERN, STARTKARTE_ISLAND, STARTKARTE_FAHREN_JUGEND, STARTKARTE_HORSEBALL, STARTKARTE_POLO, PARAEQUESTRIAN, SONSTIGE }
|
enum class LizenzTypE { REITER, FAHRER, VOLTIGIERER, WESTERN, WORKING_EQUITATION, POLO, STARTKARTE_ALLG, STARTKARTE_VOLTIGIEREN, STARTKARTE_WESTERN, STARTKARTE_ISLAND, STARTKARTE_FAHREN_JUGEND, STARTKARTE_HORSEBALL, STARTKARTE_POLO, PARAEQUESTRIAN, SONSTIGE }
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|
@ -70,4 +70,4 @@ enum class RichterPositionE { C, E, H, M, B, VORSITZ, SEITENRICHTER, SONSTIGE }
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class GeschlechtE { M, W, D, UNBEKANNT }
|
enum class GeschlechtE { M, W, D, UNBEKANNT }
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class GeschlechtPferd { HENGST, STUTE, WALLACH, UNBEKANNT }
|
enum class GeschlechtPferdE { HENGST, STUTE, WALLACH, UNBEKANNT }
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package at.mocode.shared.model
|
package at.mocode.shared.model
|
||||||
|
|
||||||
import at.mocode.shared.model.Artikel
|
import at.mocode.shared.enums.NennungsArtE
|
||||||
import at.mocode.shared.enums.NennungsArt
|
|
||||||
import at.mocode.shared.serializers.BigDecimalSerializer
|
import at.mocode.shared.serializers.BigDecimalSerializer
|
||||||
import at.mocode.shared.serializers.KotlinInstantSerializer
|
import at.mocode.shared.serializers.KotlinInstantSerializer
|
||||||
import at.mocode.shared.serializers.KotlinLocalDateSerializer
|
import at.mocode.shared.serializers.KotlinLocalDateSerializer
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package at.mocode.shared.stammdaten
|
package at.mocode.shared.stammdaten
|
||||||
|
|
||||||
import at.mocode.shared.enums.LizenzTyp
|
import at.mocode.shared.enums.LizenzTypE
|
||||||
import at.mocode.shared.enums.SparteE
|
import at.mocode.shared.enums.SparteE
|
||||||
import at.mocode.shared.serializers.KotlinLocalDateSerializer
|
import at.mocode.shared.serializers.KotlinLocalDateSerializer
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
|
|
@ -8,7 +8,7 @@ import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class LizenzInfo(
|
data class LizenzInfo(
|
||||||
val lizenzTyp: LizenzTyp,
|
val lizenzTyp: LizenzTypE,
|
||||||
val stufe: String?,
|
val stufe: String?,
|
||||||
val sparteE: SparteE?,
|
val sparteE: SparteE?,
|
||||||
val gueltigBisJahr: Int?, // Jahr als Int
|
val gueltigBisJahr: Int?, // Jahr als Int
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package at.mocode.shared.stammdaten
|
package at.mocode.shared.stammdaten
|
||||||
|
|
||||||
import at.mocode.shared.enums.GeschlechtPferd
|
import at.mocode.shared.enums.GeschlechtPferdE
|
||||||
import at.mocode.shared.serializers.KotlinInstantSerializer
|
import at.mocode.shared.serializers.KotlinInstantSerializer
|
||||||
import at.mocode.shared.serializers.UuidSerializer
|
import at.mocode.shared.serializers.UuidSerializer
|
||||||
import com.benasher44.uuid.Uuid
|
import com.benasher44.uuid.Uuid
|
||||||
|
|
@ -18,7 +18,7 @@ data class Pferd(
|
||||||
var name: String,
|
var name: String,
|
||||||
var lebensnummer: String?,
|
var lebensnummer: String?,
|
||||||
var feiPassNr: String?,
|
var feiPassNr: String?,
|
||||||
var geschlecht: GeschlechtPferd?,
|
var geschlecht: GeschlechtPferdE?,
|
||||||
var geburtsjahr: Int?,
|
var geburtsjahr: Int?,
|
||||||
var rasse: String?,
|
var rasse: String?,
|
||||||
var farbe: String?,
|
var farbe: String?,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user