refactor(infra-monitoring)

refactor(infra-gateway)
This commit is contained in:
stefan
2025-08-11 14:32:01 +02:00
parent d87a5a4a93
commit 582678e226
16 changed files with 282 additions and 115 deletions
+4 -53
View File
@@ -1,56 +1,3 @@
/*plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ktor)
alias(libs.plugins.spring.dependencyManagement)
application
}
application {
mainClass.set("at.mocode.infrastructure.gateway.ApplicationKt")
}
dependencies {
api(platform(libs.spring.boot.dependencies))
implementation(projects.platform.platformDependencies)
implementation(projects.core.coreDomain)
implementation(projects.core.coreUtils)
implementation(projects.infrastructure.auth.authClient)
implementation(projects.infrastructure.monitoring.monitoringClient)
// --- Ktor Server ---
implementation(libs.ktor.server.core)
implementation(libs.ktor.server.netty)
implementation(libs.ktor.server.contentNegotiation)
implementation(libs.ktor.server.serialization.kotlinx.json)
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)
implementation(libs.ktor.server.rateLimit)
implementation(libs.ktor.server.metrics.micrometer)
// --- OpenAPI & Swagger for Ktor ---
implementation(libs.ktor.server.openapi)
implementation(libs.ktor.server.swagger)
// --- Ktor Client (damit der Gateway Anfragen an die Backend-Services weiterleiten kann) ---
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.contentNegotiation)
implementation(libs.ktor.client.serialization.kotlinx.json)
// --- Monitoring ---
implementation(libs.micrometer.prometheus)
// --- Testing ---
testImplementation(projects.platform.platformTesting)
testImplementation(libs.ktor.server.tests)
}*/
// Dieses Modul ist das API-Gateway und der einzige öffentliche Einstiegspunkt
// für alle externen Anfragen an das Meldestelle-System.
plugins {
@@ -75,6 +22,8 @@ dependencies {
// Stellt die Spring Cloud Gateway und Consul Discovery Abhängigkeiten bereit
implementation(libs.bundles.spring.cloud.gateway)
// Sichert den reaktiven Webserver (Netty) explizit ab, um Test-/Kontext-Probleme zu vermeiden
implementation("org.springframework.boot:spring-boot-starter-webflux")
// Bindet die wiederverwendbare Logik zur JWT-Validierung ein.
implementation(projects.infrastructure.auth.authClient)
@@ -85,5 +34,7 @@ dependencies {
// Stellt alle Test-Abhängigkeiten gebündelt bereit.
testImplementation(projects.platform.platformTesting)
testImplementation(libs.bundles.testing.jvm)
// Security im Testkontext, um eine permissive Security-Konfiguration bereitstellen zu können
testImplementation(libs.spring.boot.starter.security)
}
@@ -2,13 +2,10 @@ package at.mocode.infrastructure.gateway
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.cloud.client.discovery.EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
class GatewayApplication
fun main(args: Array<String>) {
runApplication<GatewayApplication>(*args)
}
@@ -8,6 +8,20 @@ spring:
name: api-gateway
cloud:
gateway:
# HTTP Client-Timeouts für stabile Upstream-Verbindungen
httpclient:
connect-timeout: 5000 # in Millisekunden
response-timeout: 30s
# Globales CORS-Setup (kann pro Umgebung überschrieben werden)
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
# Antwort-Header bereinigen (verhindert doppelte CORS-Header)
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
# Aktiviert die automatische Routen-Erstellung basierend auf Consul
discovery:
locator:
@@ -0,0 +1,88 @@
package at.mocode.infrastructure.gateway
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.test.web.reactive.server.WebTestClient
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.cloud.gateway.route.RouteLocator
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
import java.time.Duration
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Assertions.assertNotNull
import org.springframework.boot.test.context.TestConfiguration
@SpringBootTest(
classes = [GatewayApplication::class],
webEnvironment = WebEnvironment.RANDOM_PORT,
properties = [
// Use a random port and disable discovery/consul for the test
"server.port=0",
"spring.cloud.discovery.enabled=false",
"spring.cloud.consul.enabled=false",
"spring.cloud.consul.config.enabled=false",
"spring.cloud.consul.discovery.register=false",
// Disable security autoconfiguration for tests
"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration",
// Force a reactive web application so that Spring Cloud Gateway auto-config activates
"spring.main.web-application-type=reactive",
// Gateway discovery locator off; we use explicit test routes
"spring.cloud.gateway.discovery.locator.enabled=false"
]
)
@AutoConfigureWebTestClient
@Import(GatewayApplicationTests.TestRoutes::class, GatewayApplicationTests.InternalHelloController::class, GatewayApplicationTests.TestSecurityConfig::class)
class GatewayApplicationTests {
@Autowired
lateinit var client: WebTestClient
@Autowired
lateinit var routeLocator: RouteLocator
@Test
fun contextLoads() {
// If the application context fails to load, this test will fail.
}
@Test
fun forwardRouteShouldReturnResponseFromInternalController() {
client.get()
.uri("/hello")
.exchange()
.expectStatus().isOk
.expectBody(String::class.java)
.isEqualTo("OK")
}
@RestController
class InternalHelloController {
@GetMapping("/internal/hello")
fun hello(): String = "OK"
}
@Configuration
class TestRoutes {
@Bean
fun routeLocator(builder: RouteLocatorBuilder): RouteLocator = builder.routes()
.route("test-forward") { r -> r.path("/hello").uri("forward:/internal/hello") }
.build()
}
@TestConfiguration
class TestSecurityConfig {
@Bean
fun springSecurityFilterChain(): org.springframework.security.web.server.SecurityWebFilterChain =
org.springframework.security.config.web.server.ServerHttpSecurity
.http()
.csrf { it.disable() }
.authorizeExchange { exchanges -> exchanges.anyExchange().permitAll() }
.build()
}
}