From bd399fdcd38d012607e5d778449c919dad518e1c Mon Sep 17 00:00:00 2001 From: stefan Date: Thu, 8 May 2025 16:21:43 +0200 Subject: [PATCH] fix and upgrade gradle --- build.gradle.kts | 13 +- composeApp/build.gradle.kts | 55 +++-- .../commonMain/kotlin/at/mocode/server/App.kt | 16 +- gradle.properties | 15 ++ gradle/libs.versions.toml | 62 ++--- gradle/wrapper/gradle-wrapper.properties | 2 +- server/build.gradle.kts | 74 +++--- .../at/mocode/server/plugins/Database.kt | 18 +- .../at/mocode/server/tables/LizenzenTable.kt | 1 - server/src/main/resources/application.yaml | 2 +- .../at/mocode/server/ApplicationTest.kt | 48 ---- .../at/mocode/server/plugins/DatabaseTest.kt | 223 ------------------ settings.gradle.kts | 11 +- shared/build.gradle.kts | 20 +- .../shared/model/entitaeten/ArtikelTest.kt | 3 +- .../entitaeten/MeisterschaftReferenzTest.kt | 5 - .../shared/model/entitaeten/PlatzTest.kt | 5 - .../at/mocode/shared/model/enums/EnumsTest.kt | 2 - .../model/serializers/SerializationTest.kt | 2 - .../shared/model/stammdaten/LizenzInfoTest.kt | 4 - 20 files changed, 161 insertions(+), 420 deletions(-) delete mode 100644 server/src/test/kotlin/at/mocode/server/ApplicationTest.kt delete mode 100644 server/src/test/kotlin/at/mocode/server/plugins/DatabaseTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 4ab6f0cf..42437b3f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,9 @@ +// root/build.gradle.kts plugins { - // this is necessary to avoid the plugins to be loaded multiple times - // in each subproject's classloader - alias(libs.plugins.kotlinMultiplatform) apply false - alias(libs.plugins.composeMultiplatform) apply false - alias(libs.plugins.kotlinJvm) apply false - alias(libs.plugins.composeCompiler) apply false + // Dies ist notwendig, um zu verhindern, dass die Plugins mehrfach geladen werden + // im Classloader jedes Subprojekts + alias(libs.plugins.kotlin.multiplatform) apply false + alias(libs.plugins.compose.multiplatform) apply false + alias(libs.plugins.kotlin.jvm) apply false + alias(libs.plugins.compose.compiler) apply false } diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 669a798f..9d389f07 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -1,19 +1,28 @@ @file:OptIn(ExperimentalWasmDsl::class) -import org.jetbrains.compose.desktop.application.dsl.TargetFormat +import org.jetbrains.compose.desktop.application.dsl.TargetFormat // HIER FEHLTE DER IMPORT import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.composeMultiplatform) - alias(libs.plugins.composeCompiler) + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.compose.multiplatform) + alias(libs.plugins.compose.compiler) } kotlin { jvm("desktop") wasmJs { + + var isMpp: Boolean = false // Beispiel: Deine aktuelle Zuweisung + + @Deprecated("Use getMpp() instead", ReplaceWith("getMpp()")) + fun isMpp(): Boolean = isMpp + + fun getMpp(): Boolean = isMpp + + outputModuleName = "composeApp" browser { val rootDirPath = project.rootDir.path @@ -33,27 +42,33 @@ kotlin { } sourceSets { - val desktopMain by getting - - commonMain.dependencies { - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.material) - implementation(compose.ui) - implementation(compose.components.resources) - implementation(compose.components.uiToolingPreview) - implementation(libs.androidx.lifecycle.viewmodel) - implementation(libs.androidx.lifecycle.runtime.compose) - implementation(projects.shared) + val desktopMain by getting { + dependencies { + implementation(compose.desktop.currentOs) + implementation(libs.kotlinx.coroutines.swing) + } } - desktopMain.dependencies { - implementation(compose.desktop.currentOs) - implementation(libs.kotlinx.coroutines.swing) + + val commonMain by getting { + dependencies { + commonMain.dependencies { + implementation(projects.shared) + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + implementation(compose.ui) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + } + desktopMain.dependencies { + implementation(compose.desktop.currentOs) + implementation(libs.kotlinx.coroutines.swing) + } + } } } } - compose.desktop { application { mainClass = "at.mocode.MainKt" diff --git a/composeApp/src/commonMain/kotlin/at/mocode/server/App.kt b/composeApp/src/commonMain/kotlin/at/mocode/server/App.kt index e19f4564..a5ca905d 100644 --- a/composeApp/src/commonMain/kotlin/at/mocode/server/App.kt +++ b/composeApp/src/commonMain/kotlin/at/mocode/server/App.kt @@ -1,20 +1,14 @@ package at.mocode.server import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.Button import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.ui.tooling.preview.Preview -import meldestelle.composeapp.generated.resources.Res -import meldestelle.composeapp.generated.resources.compose_multiplatform @Composable @Preview @@ -22,15 +16,9 @@ fun App() { MaterialTheme { var showContent by remember { mutableStateOf(false) } Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - Button(onClick = { showContent = !showContent }) { - Text("Click me!") - } + AnimatedVisibility(showContent) { - val greeting = remember { Greeting().greet() } - Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { - Image(painterResource(Res.drawable.compose_multiplatform), null) - Text("Compose: $greeting") - } + } } } diff --git a/gradle.properties b/gradle.properties index 79ed7444..50f1aec2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,6 +7,7 @@ org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -XX:+UseParallelGC org.gradle.parallel=true org.gradle.caching=true org.gradle.configureondemand=true +#org.gradle.dependency.verification=strict # Aktiviere Dependency Verification bei Bedarf #Ktor io.ktor.development=true @@ -19,3 +20,17 @@ kotlin.native.ignoreDisabledTargets=true #IntelliJ IDEA idea.project.settings.delegate.build.run.actions.to.gradle=true + +# Optimierungen für Dependency Resolution (können bei Konflikten helfen) +# Abhängigkeits-Locking aktivieren (empfohlen für reproduzierbare Builds und zur Vermeidung unerwarteter transitive Abhängigkeitsänderungen) +# org.gradle.dependency.locking.enabled=true + +# Strikte Abhängigkeitsauflösung erzwingen (kann helfen, subtile Konflikte aufzudecken, aber erfordert sorgfältige Konfiguration) +# configurations.all*.resolutionStrategy.failOnVersionConflict() +# configurations.all*.resolutionStrategy.preferProjectModules() # Bevorzuge Subprojekte gegenüber externen Abhängigkeiten gleicher Identität + +# Optimierung für große Multi-Modul-Projekte +# Aktiviert die Konfiguration von Projekten parallel, aber verzögert die eigentliche Ausführung von Tasks so lange wie möglich +# org.gradle.configureondemand=true # Bereits aktiviert +org.gradle.vfs.watch=true # Nutze das File System Watching für schnellere inkrementelle Builds (Gradle 6.5+) +org.gradle.unsafe.configuration-cache=true # Experimentelles Feature für schnelleren Build-Start (mit Vorsicht verwenden und testen) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9d2bc896..9d5cd9a1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,14 +1,12 @@ [versions] # Kotlin and related libraries kotlin = "2.1.20" -kotlinx-coroutines = "1.10.1" -kotlinx-serialization = "1.8.1" -kotlinx-datetime = "0.6.1" -compose-plugin = "2.1.20" +kotlinxCoroutines = "1.10.1" +kotlinxSerialization = "1.8.1" +kotlinxDatetime = "0.6.1" -# UI frameworks -compose-multiplatform = "1.7.3" -androidx-lifecycle = "2.8.4" +# Compose +composeMultiplatform = "1.8.0" #"1.7.3" # Ktor ktor = "3.1.2" @@ -24,37 +22,49 @@ logback = "1.5.18" # Testing junit = "4.13.2" -junit-jupiter = "5.12.0" +junitJupiter = "5.12.0" # Utilities uuid = "0.8.4" bignum = "0.3.10" -#junit-jupiter-version = "5.8.1" [libraries] # Kotlin and related libraries kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } -kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } -kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" } -kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinx-datetime" } +kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinxCoroutines" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } +kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } -# UI frameworks -androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" } -androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } +# Compose +compose-runtime = { group = "org.jetbrains.compose.runtime", name = "runtime", version.ref = "composeMultiplatform" } +compose-foundation = { group = "org.jetbrains.compose.foundation", name = "foundation", version.ref = "composeMultiplatform" } +compose-material = { group = "org.jetbrains.compose.material", name = "material", version.ref = "composeMultiplatform" } +compose-ui = { group = "org.jetbrains.compose.ui", name = "ui", version.ref = "composeMultiplatform" } +compose-components-resources = { group = "org.jetbrains.compose.components", name = "resources", version.ref = "composeMultiplatform" } +compose-components-uiToolingPreview = { group = "org.jetbrains.compose.components", name = "ui-tooling-preview", version.ref = "composeMultiplatform" } +compose-desktop-currentOs = { group = "org.jetbrains.compose.desktop", name = "compose-desktop", version.ref = "composeMultiplatform" } # Ktor ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor" } ktor-server-netty = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "ktor" } ktor-server-html-builder = { module = "io.ktor:ktor-server-html-builder", version.ref = "ktor" } ktor-server-config-yaml = { module = "io.ktor:ktor-server-config-yaml", version.ref = "ktor" } -ktor-server-tests = { module = "io.ktor:ktor-server-tests-jvm", version.ref = "ktor" } +ktor-server-tests = { module = "io.ktor:ktor-server-test-host-jvm", version.ref = "ktor" } +ktor-server-contentNegotiation = { module = "io.ktor:ktor-server-content-negotiation", version.ref = "ktor" } +ktor-server-serializationKotlinxJson = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } +ktor-server-cors = { module = "io.ktor:ktor-server-cors", version.ref = "ktor" } +ktor-server-callLogging = { module = "io.ktor:ktor-server-call-logging", version.ref = "ktor" } +ktor-server-defaultHeaders = { module = "io.ktor:ktor-server-default-headers", version.ref = "ktor" } +ktor-server-statusPages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" } +ktor-server-auth = { module = "io.ktor:ktor-server-auth", version.ref = "ktor" } +ktor-server-authJwt = { module = "io.ktor:ktor-server-auth-jwt", version.ref = "ktor" } # Database exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" } exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" } exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } -exposed-kotlin-datetime = { module = "org.jetbrains.exposed:exposed-kotlin-datetime", version.ref = "exposed" } +exposed-kotlinDatetime = { module = "org.jetbrains.exposed:exposed-kotlin-datetime", version.ref = "exposed" } postgresql-driver = { module = "org.postgresql:postgresql", version.ref = "postgresql" } hikari-cp = { module = "com.zaxxer:HikariCP", version.ref = "hikari" } h2-driver = { module = "com.h2database:h2", version.ref = "h2" } @@ -64,21 +74,17 @@ logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } # Testing junit = { group = "junit", name = "junit", version.ref = "junit" } -junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit-jupiter" } +junitJupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junitJupiter" } # Utilities uuid = { group = "com.benasher44", name = "uuid", version.ref = "uuid" } bignum = { group = "com.ionspin.kotlin", name = "bignum", version.ref = "bignum" } -#jupiter-junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit-jupiter-version" } [plugins] -kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } - -kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" } - +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" } ktor = { id = "io.ktor.plugin", version.ref = "ktor" } - -jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" } -kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } -composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +#jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "composePlugin" } +kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b1..ca025c83 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/server/build.gradle.kts b/server/build.gradle.kts index fab15b53..f4e53e52 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -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 { 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 { - 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 { + useJUnitPlatform() + testLogging { + events("passed", "skipped", "failed") + } + maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 } diff --git a/server/src/main/kotlin/at/mocode/server/plugins/Database.kt b/server/src/main/kotlin/at/mocode/server/plugins/Database.kt index f18951fe..5524765f 100644 --- a/server/src/main/kotlin/at/mocode/server/plugins/Database.kt +++ b/server/src/main/kotlin/at/mocode/server/plugins/Database.kt @@ -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 { diff --git a/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt b/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt index 547b3a03..154634be 100644 --- a/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt +++ b/server/src/main/kotlin/at/mocode/server/tables/LizenzenTable.kt @@ -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 diff --git a/server/src/main/resources/application.yaml b/server/src/main/resources/application.yaml index 29fec112..2b913604 100644 --- a/server/src/main/resources/application.yaml +++ b/server/src/main/resources/application.yaml @@ -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 diff --git a/server/src/test/kotlin/at/mocode/server/ApplicationTest.kt b/server/src/test/kotlin/at/mocode/server/ApplicationTest.kt deleted file mode 100644 index 833b9a28..00000000 --- a/server/src/test/kotlin/at/mocode/server/ApplicationTest.kt +++ /dev/null @@ -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") - } -} diff --git a/server/src/test/kotlin/at/mocode/server/plugins/DatabaseTest.kt b/server/src/test/kotlin/at/mocode/server/plugins/DatabaseTest.kt deleted file mode 100644 index d6e9f36e..00000000 --- a/server/src/test/kotlin/at/mocode/server/plugins/DatabaseTest.kt +++ /dev/null @@ -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}") - } - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 02d73651..64862ca2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,8 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") pluginManagement { repositories { + gradlePluginPortal() + mavenCentral() google { mavenContent { includeGroupAndSubgroups("androidx") @@ -10,16 +12,12 @@ pluginManagement { includeGroupAndSubgroups("com.google") } } - mavenCentral() - gradlePluginPortal() } } -plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" -} dependencyResolutionManagement { repositories { + mavenCentral() google { mavenContent { includeGroupAndSubgroups("androidx") @@ -27,10 +25,9 @@ dependencyResolutionManagement { includeGroupAndSubgroups("com.google") } } - mavenCentral() } } include(":composeApp") include(":server") -include(":shared") \ No newline at end of file +include(":shared") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index e1c39414..0368520b 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -1,16 +1,25 @@ -import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl +// shared/build.gradle.kts +@file:OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class) + import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.kotlinSerialization) + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.kotlin.serialization) } kotlin { jvm() - @OptIn(ExperimentalWasmDsl::class) wasmJs { + + var isMpp: Boolean = false // Beispiel: Deine aktuelle Zuweisung + + @Deprecated("Use getMpp() instead", ReplaceWith("getMpp()")) + fun isMpp(): Boolean = isMpp + + fun getMpp(): Boolean = isMpp + browser { val rootDirPath = project.rootDir.path val projectDirPath = project.projectDir.path @@ -29,7 +38,7 @@ kotlin { sourceSets { val commonMain by getting { dependencies { - // Multiplatform dependencies + // Multiplatform-Abhängigkeiten implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.datetime) implementation(libs.uuid) @@ -50,5 +59,6 @@ kotlin { // val wasmJsMain by getting { // dependsOn(commonMain) // } + } } diff --git a/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/ArtikelTest.kt b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/ArtikelTest.kt index 6cbdfcde..8ae78732 100644 --- a/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/ArtikelTest.kt +++ b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/ArtikelTest.kt @@ -5,6 +5,7 @@ import com.ionspin.kotlin.bignum.decimal.BigDecimal import kotlinx.datetime.Clock import kotlinx.serialization.json.Json import kotlin.test.* +import kotlin.time.Duration.Companion.milliseconds class ArtikelTest { @@ -71,7 +72,7 @@ class ArtikelTest { artikel.preis = BigDecimal.parseString("15.00") artikel.einheit = "Box" artikel.istVerbandsabgabe = true - artikel.updatedAt = Clock.System.now() + artikel.updatedAt = Clock.System.now().plus(1.milliseconds) // Verify modifications assertEquals("Geänderter Artikel", artikel.bezeichnung) diff --git a/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenzTest.kt b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenzTest.kt index be1a010f..fa04458c 100644 --- a/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenzTest.kt +++ b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/MeisterschaftReferenzTest.kt @@ -1,14 +1,9 @@ package at.mocode.shared.model.entitaeten -import at.mocode.shared.model.serializers.UuidSerializer -import com.benasher44.uuid.Uuid import com.benasher44.uuid.uuid4 -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertNotEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue diff --git a/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/PlatzTest.kt b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/PlatzTest.kt index 959c77c0..26c59e22 100644 --- a/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/PlatzTest.kt +++ b/shared/src/commonTest/kotlin/at/mocode/shared/model/entitaeten/PlatzTest.kt @@ -1,15 +1,10 @@ package at.mocode.shared.model.entitaeten import at.mocode.shared.model.enums.PlatzTyp -import at.mocode.shared.model.serializers.UuidSerializer -import com.benasher44.uuid.Uuid import com.benasher44.uuid.uuid4 -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertNotEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue diff --git a/shared/src/commonTest/kotlin/at/mocode/shared/model/enums/EnumsTest.kt b/shared/src/commonTest/kotlin/at/mocode/shared/model/enums/EnumsTest.kt index fc6bf9ce..bd8f242a 100644 --- a/shared/src/commonTest/kotlin/at/mocode/shared/model/enums/EnumsTest.kt +++ b/shared/src/commonTest/kotlin/at/mocode/shared/model/enums/EnumsTest.kt @@ -1,8 +1,6 @@ package at.mocode.shared.model.enums import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlin.test.Test import kotlin.test.assertEquals diff --git a/shared/src/commonTest/kotlin/at/mocode/shared/model/serializers/SerializationTest.kt b/shared/src/commonTest/kotlin/at/mocode/shared/model/serializers/SerializationTest.kt index a0fd01df..8ccce864 100644 --- a/shared/src/commonTest/kotlin/at/mocode/shared/model/serializers/SerializationTest.kt +++ b/shared/src/commonTest/kotlin/at/mocode/shared/model/serializers/SerializationTest.kt @@ -9,8 +9,6 @@ import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate import kotlinx.datetime.LocalDateTime import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlin.test.Test import kotlin.test.assertEquals diff --git a/shared/src/commonTest/kotlin/at/mocode/shared/model/stammdaten/LizenzInfoTest.kt b/shared/src/commonTest/kotlin/at/mocode/shared/model/stammdaten/LizenzInfoTest.kt index e145c078..f62dd50c 100644 --- a/shared/src/commonTest/kotlin/at/mocode/shared/model/stammdaten/LizenzInfoTest.kt +++ b/shared/src/commonTest/kotlin/at/mocode/shared/model/stammdaten/LizenzInfoTest.kt @@ -2,14 +2,10 @@ package at.mocode.shared.model.stammdaten import at.mocode.shared.model.enums.LizenzTyp import at.mocode.shared.model.enums.Sparte -import at.mocode.shared.model.serializers.KotlinLocalDateSerializer import kotlinx.datetime.LocalDate -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertNotNull import kotlin.test.assertTrue class LizenzInfoTest {