fix and upgrade gradle
This commit is contained in:
+39
-35
@@ -1,7 +1,7 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinJvm)
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.ktor)
|
||||
application
|
||||
}
|
||||
@@ -12,8 +12,11 @@ version = "1.0.0"
|
||||
// Enable Gradle caching and parallel execution for better build performance
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_21) // Set appropriate JVM target
|
||||
freeCompilerArgs.set(listOf("-Xjsr305=strict", "-opt-in=kotlin.RequiresOptIn"))
|
||||
jvmTarget.set(JvmTarget.JVM_21)
|
||||
freeCompilerArgs = listOf(
|
||||
"-Xjsr305=strict",
|
||||
"-opt-in=kotlin.RequiresOptIn"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,65 +25,66 @@ application {
|
||||
mainClass.set("at.mocode.server.ApplicationKt")
|
||||
applicationDefaultJvmArgs = listOf(
|
||||
"-Dio.ktor.development=${extra["io.ktor.development"] ?: "false"}",
|
||||
// "-XX:+UseG1GC", // Use G1 Garbage Collector
|
||||
// "-XX:MaxGCPauseMillis=100", // Target max GC pause time
|
||||
// "-Djava.awt.headless=true" // Headless mode for server
|
||||
"-XX:+UseG1GC", // Use G1 Garbage Collector
|
||||
"-XX:MaxGCPauseMillis=100", // Target max GC pause time
|
||||
"-Djava.awt.headless=true" // Headless mode for server
|
||||
)
|
||||
}
|
||||
|
||||
// Configure tests
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform() // Use JUnit 5 platform
|
||||
testLogging {
|
||||
events("passed", "skipped", "failed")
|
||||
}
|
||||
// Parallel test execution if tests are independent
|
||||
maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Project dependencies
|
||||
// Projekt-Abhängigkeiten
|
||||
implementation(projects.shared)
|
||||
// Kotlin and related libraries
|
||||
|
||||
// Kotlin und verwandte Bibliotheken
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
implementation(libs.uuid)
|
||||
implementation(libs.bignum)
|
||||
|
||||
// Ktor server components
|
||||
// Ktor Server-Komponenten
|
||||
implementation(libs.ktor.server.core)
|
||||
implementation(libs.ktor.server.netty)
|
||||
implementation(libs.ktor.server.config.yaml)
|
||||
implementation(libs.ktor.server.html.builder)
|
||||
|
||||
// Ktor server plugins
|
||||
implementation("io.ktor:ktor-server-content-negotiation:${libs.versions.ktor.get()}")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:${libs.versions.ktor.get()}")
|
||||
implementation("io.ktor:ktor-server-cors:${libs.versions.ktor.get()}")
|
||||
implementation("io.ktor:ktor-server-call-logging:${libs.versions.ktor.get()}")
|
||||
implementation("io.ktor:ktor-server-default-headers:${libs.versions.ktor.get()}")
|
||||
implementation("io.ktor:ktor-server-status-pages:${libs.versions.ktor.get()}")
|
||||
implementation("io.ktor:ktor-server-auth:${libs.versions.ktor.get()}")
|
||||
implementation("io.ktor:ktor-server-auth-jwt:${libs.versions.ktor.get()}")
|
||||
// Ktor Server-Plugins
|
||||
implementation(libs.ktor.server.contentNegotiation)
|
||||
implementation(libs.ktor.server.serializationKotlinxJson)
|
||||
implementation(libs.ktor.server.cors)
|
||||
implementation(libs.ktor.server.callLogging)
|
||||
implementation(libs.ktor.server.defaultHeaders)
|
||||
implementation(libs.ktor.server.statusPages)
|
||||
implementation(libs.ktor.server.auth)
|
||||
implementation(libs.ktor.server.authJwt)
|
||||
|
||||
// Database - Exposed ORM
|
||||
// Datenbank - Exposed ORM
|
||||
implementation(libs.exposed.core)
|
||||
implementation(libs.exposed.dao)
|
||||
implementation(libs.exposed.jdbc)
|
||||
implementation(libs.exposed.kotlin.datetime)
|
||||
implementation(libs.exposed.kotlinDatetime)
|
||||
|
||||
// Connection pooling
|
||||
// Connection Pooling
|
||||
implementation(libs.hikari.cp)
|
||||
|
||||
// Logging
|
||||
implementation(libs.logback)
|
||||
|
||||
// Database drivers
|
||||
runtimeOnly(libs.postgresql.driver) // Production
|
||||
runtimeOnly(libs.h2.driver) // Development and testing
|
||||
// Datenbanktreiber
|
||||
runtimeOnly(libs.postgresql.driver)
|
||||
runtimeOnly(libs.h2.driver)
|
||||
|
||||
// Testing
|
||||
testImplementation(libs.ktor.server.tests)
|
||||
testImplementation(libs.kotlin.test.junit)
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testImplementation(libs.junitJupiter)
|
||||
|
||||
}
|
||||
|
||||
// Configure tests
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events("passed", "skipped", "failed")
|
||||
}
|
||||
maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1
|
||||
}
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
package at.mocode.server.plugins
|
||||
|
||||
import at.mocode.server.tables.ArtikelTable
|
||||
import at.mocode.server.tables.LizenzenTable
|
||||
import at.mocode.server.tables.PersonenTable
|
||||
import at.mocode.server.tables.PferdeTable
|
||||
import at.mocode.server.tables.PlaetzeTable
|
||||
import at.mocode.server.tables.TurniereTable
|
||||
import at.mocode.server.tables.VeranstaltungenTable
|
||||
import at.mocode.server.tables.VereineTable
|
||||
import at.mocode.server.tables.*
|
||||
import com.zaxxer.hikari.HikariConfig
|
||||
import com.zaxxer.hikari.HikariDataSource
|
||||
import io.ktor.server.application.*
|
||||
@@ -15,6 +8,7 @@ import io.ktor.server.config.*
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@@ -69,7 +63,7 @@ fun Application.configureDatabase() {
|
||||
/**
|
||||
* Configures an in-memory H2 database for testing
|
||||
*/
|
||||
private fun configureTestDatabase(log: org.slf4j.Logger): Boolean {
|
||||
private fun configureTestDatabase(log: Logger): Boolean {
|
||||
log.info("Test environment detected, using in-memory H2 database (test)...")
|
||||
return try {
|
||||
Database.connect(
|
||||
@@ -89,7 +83,7 @@ private fun configureTestDatabase(log: org.slf4j.Logger): Boolean {
|
||||
/**
|
||||
* Configures an in-memory H2 database for development
|
||||
*/
|
||||
private fun configureDevelopmentDatabase(log: org.slf4j.Logger): Boolean {
|
||||
private fun configureDevelopmentDatabase(log: Logger): Boolean {
|
||||
log.info("Development environment detected, using in-memory H2 database (dev)...")
|
||||
return try {
|
||||
Database.connect(
|
||||
@@ -109,7 +103,7 @@ private fun configureDevelopmentDatabase(log: org.slf4j.Logger): Boolean {
|
||||
/**
|
||||
* Configures a PostgreSQL database for production
|
||||
*/
|
||||
private fun configureProductionDatabase(log: org.slf4j.Logger, dbConfig: ApplicationConfig?): Boolean {
|
||||
private fun configureProductionDatabase(log: Logger, dbConfig: ApplicationConfig?): Boolean {
|
||||
log.info("Production environment detected, connecting to PostgreSQL...")
|
||||
|
||||
// Get database configuration from application.yaml or environment variables
|
||||
@@ -175,7 +169,7 @@ private fun configureProductionDatabase(log: org.slf4j.Logger, dbConfig: Applica
|
||||
/**
|
||||
* Initializes the database schema
|
||||
*/
|
||||
private fun initializeSchema(log: org.slf4j.Logger, isTestEnvironment: Boolean, isIdeaEnvironment: Boolean) {
|
||||
private fun initializeSchema(log: Logger, isTestEnvironment: Boolean, isIdeaEnvironment: Boolean) {
|
||||
transaction {
|
||||
log.info("Initializing/Verifying database schema...")
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package at.mocode.server.tables
|
||||
|
||||
|
||||
import at.mocode.shared.model.enums.LizenzTyp
|
||||
import at.mocode.shared.model.enums.Sparte
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
|
||||
@@ -41,7 +41,7 @@ security:
|
||||
audience: "meldestelle-clients"
|
||||
realm: "meldestelle"
|
||||
# Secret should be set via 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)
|
||||
validity: 86400000
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package at.mocode.server
|
||||
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Basic tests for the application
|
||||
*/
|
||||
class ApplicationTest {
|
||||
private val logger = LoggerFactory.getLogger(ApplicationTest::class.java)
|
||||
|
||||
@Test
|
||||
fun testEnvironmentSetup() {
|
||||
// Set test environment flag
|
||||
System.setProperty("isTestEnvironment", "true")
|
||||
|
||||
// Verify the flag is set correctly
|
||||
assertTrue(System.getProperty("isTestEnvironment").toBoolean())
|
||||
logger.info("Test environment flag set successfully")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testApplicationFilesExist() {
|
||||
// Verify the Application.kt file exists
|
||||
val applicationFile = File("src/main/kotlin/at/mocode/server/Application.kt")
|
||||
assertTrue(applicationFile.exists() || File("server/" + applicationFile.path).exists(),
|
||||
"Application.kt file should exist")
|
||||
|
||||
// Verify the Database.kt file exists
|
||||
val databaseFile = File("src/main/kotlin/at/mocode/server/plugins/Database.kt")
|
||||
assertTrue(databaseFile.exists() || File("server/" + databaseFile.path).exists(),
|
||||
"Database.kt file should exist")
|
||||
|
||||
logger.info("Application files exist")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConfigurationFileExists() {
|
||||
// Verify the application.yaml file exists
|
||||
val configFile = File("src/main/resources/application.yaml")
|
||||
assertTrue(configFile.exists() || File("server/" + configFile.path).exists(),
|
||||
"application.yaml file should exist")
|
||||
|
||||
logger.info("Configuration file exists")
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
package at.mocode.server.plugins
|
||||
|
||||
import at.mocode.server.tables.*
|
||||
import io.ktor.server.config.*
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Tests for the Database.kt file
|
||||
*/
|
||||
class DatabaseTest {
|
||||
private val logger = LoggerFactory.getLogger(DatabaseTest::class.java)
|
||||
|
||||
// Create a temporary directory for test resources
|
||||
@TempDir
|
||||
lateinit var tempDir: File
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
// Clear any system properties that might affect the tests
|
||||
System.clearProperty("isTestEnvironment")
|
||||
|
||||
// Clear environment variables by setting them to null
|
||||
// Note: This is a workaround since we can't actually clear environment variables in Java
|
||||
System.getProperties().remove("DB_HOST")
|
||||
System.getProperties().remove("DB_NAME")
|
||||
System.getProperties().remove("DB_USER")
|
||||
System.getProperties().remove("DB_PASSWORD")
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
// Clear any system properties set during tests
|
||||
System.clearProperty("isTestEnvironment")
|
||||
System.getProperties().remove("DB_HOST")
|
||||
System.getProperties().remove("DB_NAME")
|
||||
System.getProperties().remove("DB_USER")
|
||||
System.getProperties().remove("DB_PASSWORD")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTestDatabaseConfiguration() {
|
||||
// Set test environment flag
|
||||
System.setProperty("isTestEnvironment", "true")
|
||||
|
||||
// Create a direct database connection for testing
|
||||
val db = Database.connect(
|
||||
url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=PostgreSQL",
|
||||
driver = "org.h2.Driver",
|
||||
user = "sa",
|
||||
password = ""
|
||||
)
|
||||
|
||||
// Verify that we can execute a simple query
|
||||
transaction(db) {
|
||||
// If this doesn't throw an exception, the connection is working
|
||||
exec("SELECT 1") { rs ->
|
||||
assertTrue(rs.next())
|
||||
assertEquals(1, rs.getInt(1))
|
||||
true
|
||||
}
|
||||
logger.info("Test database connection verified")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDevelopmentDatabaseConfiguration() {
|
||||
// Ensure test environment flag is not set
|
||||
System.clearProperty("isTestEnvironment")
|
||||
|
||||
// Create a direct database connection for testing
|
||||
val db = Database.connect(
|
||||
url = "jdbc:h2:mem:dev;DB_CLOSE_DELAY=-1;MODE=PostgreSQL",
|
||||
driver = "org.h2.Driver",
|
||||
user = "sa",
|
||||
password = ""
|
||||
)
|
||||
|
||||
// Verify that we can execute a simple query
|
||||
transaction(db) {
|
||||
// If this doesn't throw an exception, the connection is working
|
||||
exec("SELECT 1") { rs ->
|
||||
assertTrue(rs.next())
|
||||
assertEquals(1, rs.getInt(1))
|
||||
true
|
||||
}
|
||||
logger.info("Development database connection verified")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSchemaInitialization() {
|
||||
// Set test environment flag
|
||||
System.setProperty("isTestEnvironment", "true")
|
||||
|
||||
// Create a direct database connection for testing
|
||||
val db = Database.connect(
|
||||
url = "jdbc:h2:mem:test_schema;DB_CLOSE_DELAY=-1;MODE=PostgreSQL",
|
||||
driver = "org.h2.Driver",
|
||||
user = "sa",
|
||||
password = ""
|
||||
)
|
||||
|
||||
// Initialize schema
|
||||
transaction(db) {
|
||||
SchemaUtils.create(
|
||||
VereineTable,
|
||||
PersonenTable,
|
||||
PferdeTable,
|
||||
VeranstaltungenTable,
|
||||
TurniereTable,
|
||||
ArtikelTable,
|
||||
PlaetzeTable,
|
||||
LizenzenTable
|
||||
)
|
||||
}
|
||||
|
||||
// Verify that tables were created
|
||||
transaction(db) {
|
||||
// Check if tables exist by querying the H2 metadata
|
||||
val tables = listOf(
|
||||
VereineTable,
|
||||
PersonenTable,
|
||||
PferdeTable,
|
||||
VeranstaltungenTable,
|
||||
TurniereTable,
|
||||
ArtikelTable,
|
||||
PlaetzeTable,
|
||||
LizenzenTable
|
||||
)
|
||||
|
||||
for (table in tables) {
|
||||
val tableName = table.tableName.uppercase()
|
||||
val result = exec("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '$tableName'") { rs ->
|
||||
rs.next()
|
||||
rs.getInt(1)
|
||||
}
|
||||
assertEquals(1, result, "Table $tableName should exist")
|
||||
}
|
||||
|
||||
logger.info("Schema initialization verified")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorHandlingInTestEnvironment() {
|
||||
// Set test environment flag
|
||||
System.setProperty("isTestEnvironment", "true")
|
||||
|
||||
// Create a test application with a broken database URL
|
||||
try {
|
||||
// Use reflection to access the private function
|
||||
val method = this::class.java.classLoader
|
||||
.loadClass("at.mocode.server.plugins.DatabaseKt")
|
||||
.getDeclaredMethod("configureTestDatabase", org.slf4j.Logger::class.java)
|
||||
|
||||
method.isAccessible = true
|
||||
|
||||
// Create a mock Database object that throws an exception when connect is called
|
||||
val originalConnect = Database::class.java.getDeclaredMethod("connect",
|
||||
String::class.java, String::class.java, String::class.java, String::class.java)
|
||||
|
||||
// Store the original method
|
||||
val originalAccessible = originalConnect.canAccess(originalConnect)
|
||||
originalConnect.isAccessible = true
|
||||
|
||||
try {
|
||||
// Call the method with an invalid URL to trigger an exception
|
||||
assertThrows(Exception::class.java) {
|
||||
method.invoke(null, logger)
|
||||
}
|
||||
logger.info("Error handling in test environment verified")
|
||||
} finally {
|
||||
// Restore the original method
|
||||
originalConnect.isAccessible = originalAccessible
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// If we can't use reflection, just log a message
|
||||
logger.warn("Could not test error handling using reflection: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProductionDatabaseConfigurationValidation() {
|
||||
// Ensure test environment flag is not set
|
||||
System.clearProperty("isTestEnvironment")
|
||||
|
||||
// Set DB_HOST to trigger production configuration but leave other required variables unset
|
||||
System.setProperty("DB_HOST", "localhost")
|
||||
System.getProperties().remove("DB_NAME")
|
||||
System.getProperties().remove("DB_USER")
|
||||
System.getProperties().remove("DB_PASSWORD")
|
||||
|
||||
// Create a logger to pass to the function
|
||||
val log = LoggerFactory.getLogger("TestLogger")
|
||||
|
||||
// Call the production database configuration function directly
|
||||
val method = this::class.java.classLoader
|
||||
.loadClass("at.mocode.server.plugins.DatabaseKt")
|
||||
.getDeclaredMethod("configureProductionDatabase", org.slf4j.Logger::class.java, ApplicationConfig::class.java)
|
||||
|
||||
method.isAccessible = true
|
||||
|
||||
// This should throw an exception because we don't have all required environment variables
|
||||
try {
|
||||
method.invoke(null, log, null)
|
||||
fail("Expected an exception to be thrown")
|
||||
} catch (e: java.lang.reflect.InvocationTargetException) {
|
||||
// The actual exception is wrapped in an InvocationTargetException
|
||||
val cause = e.cause
|
||||
assertTrue(cause is IllegalStateException, "Expected IllegalStateException but got ${cause?.javaClass?.name}")
|
||||
logger.info("Production database configuration validation verified: ${cause?.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user