upgrade Java-25 Kotlin-2.3.0 usw.
This commit is contained in:
@@ -0,0 +1,323 @@
|
|||||||
|
Meldestelle on main [✘»!+?] via 🅶 v9.2.1 via ☕ v25.0.1 via 🅺 v2.3.0
|
||||||
|
❯ ./gradlew :backend:infrastructure:gateway:test --stacktrace
|
||||||
|
Starting a Gradle Daemon, 2 stopped Daemons could not be reused, use --status for details
|
||||||
|
Type-safe project accessors is an incubating feature.
|
||||||
|
|
||||||
|
> Task :backend:infrastructure:gateway:test
|
||||||
|
|
||||||
|
WebFluxSmokeTest > should load reactive web context and serve smoke endpoint() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
|
||||||
|
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
|
||||||
|
Caused by: java.lang.IllegalArgumentException at ClassUtils.java:372
|
||||||
|
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:642
|
||||||
|
|
||||||
|
GatewayFiltersTests > should preserve existing correlation ID header() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
|
||||||
|
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
|
||||||
|
Caused by: java.lang.IllegalArgumentException at ClassUtils.java:372
|
||||||
|
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:642
|
||||||
|
|
||||||
|
GatewayFiltersTests > should handle requests with X-Forwarded-For header() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayFiltersTests > should apply admin rate limit for admin users() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayFiltersTests > should add rate limiting headers() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayFiltersTests > should add correlation ID header when not present() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayFiltersTests > should apply different rate limits for auth endpoints() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayFiltersTests > should enforce rate limiting after exceeding limit() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayFiltersTests > should apply higher rate limit for authenticated users() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
KeycloakGatewayIntegrationTest > should initialize Spring context with Keycloak configuration() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
|
||||||
|
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
|
||||||
|
Caused by: java.lang.IllegalArgumentException at ClassUtils.java:372
|
||||||
|
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:642
|
||||||
|
|
||||||
|
GatewayApplicationTests > contextLoads() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
|
||||||
|
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
|
||||||
|
Caused by: java.lang.IllegalArgumentException at ClassUtils.java:372
|
||||||
|
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:642
|
||||||
|
|
||||||
|
FallbackControllerTests > should handle POST requests to masterdata fallback() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
|
||||||
|
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
|
||||||
|
Caused by: java.lang.IllegalArgumentException at ClassUtils.java:372
|
||||||
|
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:642
|
||||||
|
|
||||||
|
FallbackControllerTests > should handle POST requests to default fallback() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should return masterdata service fallback response() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should handle POST requests to members fallback() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should handle POST requests to events fallback() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should return valid JSON structure for all fallback responses() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should handle POST requests to auth fallback() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > sollte Members Service Fallback Response zurueckgeben() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should have consistent error response structure() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > sollte Events Service Fallback Response zurueckgeben() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should return auth service fallback response() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > sollte Horses Service Fallback Response zurueckgeben() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should handle POST requests to horses fallback() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
FallbackControllerTests > should return default fallback response for unknown service() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should handle different HTTP methods allowed in CORS() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
|
||||||
|
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
|
||||||
|
Caused by: java.lang.IllegalArgumentException at ClassUtils.java:372
|
||||||
|
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:642
|
||||||
|
|
||||||
|
GatewaySecurityTests > should handle complex CORS scenarios() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should handle PUT requests with CORS headers() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should allow requests from meldestelle domain() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should allow credentials in CORS requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should set max age for CORS requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should handle authorization headers in CORS requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should not duplicate CORS headers due to deduplication filter() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should handle CORS preflight requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should allow requests from localhost origins() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should maintain security headers in responses() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should handle POST requests with CORS headers() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewaySecurityTests > should handle DELETE requests with CORS headers() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayRoutingTests > should route ping service requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:180
|
||||||
|
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
|
||||||
|
Caused by: java.lang.IllegalArgumentException at ClassUtils.java:372
|
||||||
|
Caused by: java.lang.ClassNotFoundException at BuiltinClassLoader.java:642
|
||||||
|
|
||||||
|
GatewayRoutingTests > should route horses service requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayRoutingTests > should handle gateway info path request() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayRoutingTests > should route members service requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayRoutingTests > auth route is not configured anymore() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayRoutingTests > should route masterdata service requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
GatewayRoutingTests > should route events service requests() FAILED
|
||||||
|
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:145
|
||||||
|
|
||||||
|
45 tests completed, 45 failed
|
||||||
|
|
||||||
|
> Task :backend:infrastructure:gateway:test FAILED
|
||||||
|
|
||||||
|
[Incubating] Problems report is available at: file:///home/stefan/WsMeldestelle/Meldestelle/build/reports/problems/problems-report.html
|
||||||
|
|
||||||
|
FAILURE: Build failed with an exception.
|
||||||
|
|
||||||
|
* What went wrong:
|
||||||
|
Execution failed for task ':backend:infrastructure:gateway:test'.
|
||||||
|
> There were failing tests. See the report at: file:///home/stefan/WsMeldestelle/Meldestelle/backend/infrastructure/gateway/build/reports/tests/test/index.html
|
||||||
|
|
||||||
|
* Try:
|
||||||
|
> Run with --scan to generate a Build Scan (powered by Develocity).
|
||||||
|
|
||||||
|
* Exception is:
|
||||||
|
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':backend:infrastructure:gateway:test'.
|
||||||
|
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:135)
|
||||||
|
at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:288)
|
||||||
|
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:133)
|
||||||
|
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:121)
|
||||||
|
at org.gradle.api.internal.tasks.execution.ProblemsTaskPathTrackingTaskExecuter.execute(ProblemsTaskPathTrackingTaskExecuter.java:41)
|
||||||
|
at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
|
||||||
|
at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
|
||||||
|
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
|
||||||
|
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74)
|
||||||
|
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
|
||||||
|
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
|
||||||
|
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
|
||||||
|
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||||
|
at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
|
||||||
|
at org.gradle.execution.plan.DefaultNodeExecutor.executeLocalTaskNode(DefaultNodeExecutor.java:55)
|
||||||
|
at org.gradle.execution.plan.DefaultNodeExecutor.execute(DefaultNodeExecutor.java:34)
|
||||||
|
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:355)
|
||||||
|
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343)
|
||||||
|
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:339)
|
||||||
|
at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84)
|
||||||
|
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:339)
|
||||||
|
at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:328)
|
||||||
|
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:459)
|
||||||
|
at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:376)
|
||||||
|
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
|
||||||
|
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
|
||||||
|
Caused by: org.gradle.api.internal.exceptions.MarkedVerificationException: There were failing tests. See the report at: file:///home/stefan/WsMeldestelle/Meldestelle/backend/infrastructure/gateway/build/reports/tests/test/index.html
|
||||||
|
at org.gradle.api.tasks.testing.AbstractTestTask.handleTestFailures(AbstractTestTask.java:703)
|
||||||
|
at org.gradle.api.tasks.testing.AbstractTestTask.handleCollectedResults(AbstractTestTask.java:535)
|
||||||
|
at org.gradle.api.tasks.testing.AbstractTestTask.executeTests(AbstractTestTask.java:527)
|
||||||
|
at org.gradle.api.tasks.testing.Test.executeTests(Test.java:714)
|
||||||
|
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125)
|
||||||
|
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
|
||||||
|
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
|
||||||
|
at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
|
||||||
|
at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:252)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
|
||||||
|
at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:237)
|
||||||
|
at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:220)
|
||||||
|
at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:203)
|
||||||
|
at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:170)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:105)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:44)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:59)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:56)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||||
|
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:56)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:44)
|
||||||
|
at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:42)
|
||||||
|
at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:75)
|
||||||
|
at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
|
||||||
|
at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:50)
|
||||||
|
at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:28)
|
||||||
|
at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
|
||||||
|
at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
|
||||||
|
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:61)
|
||||||
|
at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:26)
|
||||||
|
at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:69)
|
||||||
|
at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:46)
|
||||||
|
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:39)
|
||||||
|
at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:28)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:189)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.executeAndStoreInCache(BuildCacheStep.java:145)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.lambda$executeWithCache$4(BuildCacheStep.java:101)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.lambda$executeWithCache$5(BuildCacheStep.java:101)
|
||||||
|
at org.gradle.internal.Try$Success.map(Try.java:170)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.executeWithCache(BuildCacheStep.java:85)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$0(BuildCacheStep.java:74)
|
||||||
|
at org.gradle.internal.Either$Left.fold(Either.java:116)
|
||||||
|
at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:62)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
|
||||||
|
at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
|
||||||
|
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:46)
|
||||||
|
at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:35)
|
||||||
|
at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:75)
|
||||||
|
at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:53)
|
||||||
|
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:53)
|
||||||
|
at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:35)
|
||||||
|
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
|
||||||
|
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
|
||||||
|
at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:49)
|
||||||
|
at org.gradle.internal.execution.steps.ResolveIncrementalCachingStateStep.executeDelegate(ResolveIncrementalCachingStateStep.java:27)
|
||||||
|
at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:71)
|
||||||
|
at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:39)
|
||||||
|
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:64)
|
||||||
|
at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:35)
|
||||||
|
at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:62)
|
||||||
|
at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:40)
|
||||||
|
at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:76)
|
||||||
|
at org.gradle.internal.execution.steps.AbstractCaptureStateBeforeExecutionStep.execute(AbstractCaptureStateBeforeExecutionStep.java:45)
|
||||||
|
at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.executeWithNonEmptySources(AbstractSkipEmptyWorkStep.java:136)
|
||||||
|
at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:66)
|
||||||
|
at org.gradle.internal.execution.steps.AbstractSkipEmptyWorkStep.execute(AbstractSkipEmptyWorkStep.java:38)
|
||||||
|
at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
|
||||||
|
at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:36)
|
||||||
|
at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:23)
|
||||||
|
at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:75)
|
||||||
|
at org.gradle.internal.execution.steps.HandleStaleOutputsStep.execute(HandleStaleOutputsStep.java:41)
|
||||||
|
at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.lambda$execute$0(AssignMutableWorkspaceStep.java:35)
|
||||||
|
at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:297)
|
||||||
|
at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:31)
|
||||||
|
at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.execute(AssignMutableWorkspaceStep.java:22)
|
||||||
|
at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:40)
|
||||||
|
at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67)
|
||||||
|
at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39)
|
||||||
|
at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46)
|
||||||
|
at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34)
|
||||||
|
at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
|
||||||
|
at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:31)
|
||||||
|
at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:64)
|
||||||
|
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:132)
|
||||||
|
... 30 more
|
||||||
|
|
||||||
|
|
||||||
|
Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.
|
||||||
|
|
||||||
|
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
|
||||||
|
|
||||||
|
For more on this, please refer to https://docs.gradle.org/9.2.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
|
||||||
|
|
||||||
|
BUILD FAILED in 23s
|
||||||
|
17 actionable tasks: 4 executed, 13 up-to-date
|
||||||
+1
-6
@@ -1,17 +1,12 @@
|
|||||||
package at.mocode.infrastructure.gateway.config
|
package at.mocode.infrastructure.gateway.config
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain
|
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter
|
import org.springframework.cloud.gateway.filter.GlobalFilter
|
||||||
import org.springframework.core.Ordered
|
import org.springframework.core.Ordered
|
||||||
import org.springframework.http.HttpStatus
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponse
|
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import org.springframework.web.server.ServerWebExchange
|
import org.springframework.web.server.ServerWebExchange
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.*
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gateway-Konfiguration für erweiterte Funktionalitäten wie Logging, Rate Limiting und Security.
|
* Gateway-Konfiguration für erweiterte Funktionalitäten wie Logging, Rate Limiting und Security.
|
||||||
|
|||||||
+2
@@ -1,6 +1,7 @@
|
|||||||
package at.mocode.infrastructure.gateway.config
|
package at.mocode.infrastructure.gateway.config
|
||||||
|
|
||||||
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
|
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import reactor.core.publisher.Mono
|
import reactor.core.publisher.Mono
|
||||||
@@ -14,6 +15,7 @@ class RateLimiterConfig {
|
|||||||
* Funktioniert out-of-the-box mit Keycloak (Resource Server), sofern Security aktiv ist.
|
* Funktioniert out-of-the-box mit Keycloak (Resource Server), sofern Security aktiv ist.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnProperty(prefix = "gateway.ratelimit.principal-key-resolver", name = ["enabled"], havingValue = "true", matchIfMissing = false)
|
||||||
fun principalNameKeyResolver(): KeyResolver = KeyResolver { exchange ->
|
fun principalNameKeyResolver(): KeyResolver = KeyResolver { exchange ->
|
||||||
exchange.getPrincipal<Principal>()
|
exchange.getPrincipal<Principal>()
|
||||||
.map { it.name }
|
.map { it.name }
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package at.mocode.infrastructure.gateway.config
|
||||||
|
|
||||||
|
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
|
||||||
|
import org.springframework.context.annotation.Primary
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class RateLimitingConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Einfache IP-basierte KeyResolver-Implementierung für das RequestRateLimiter-Filter.
|
||||||
|
* Nutzt X-Forwarded-For, wenn vorhanden, sonst die Remote-Adresse.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
fun ipAddressKeyResolver(): KeyResolver = KeyResolver { exchange ->
|
||||||
|
val forwardedFor = exchange.request.headers.getFirst("X-Forwarded-For")
|
||||||
|
?.split(',')?.firstOrNull()?.trim()
|
||||||
|
val ip = forwardedFor
|
||||||
|
?: exchange.request.remoteAddress?.address?.hostAddress
|
||||||
|
?: "unknown"
|
||||||
|
Mono.just(ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package at.mocode.infrastructure.gateway.error
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import org.springframework.web.server.ServerWebExchange
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Einfacher ProblemDetails-Handler für unerwartete Fehler im Gateway.
|
||||||
|
* Gibt application/problem+json zurück mit Correlation-ID als traceId.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
class ProblemDetailsExceptionHandler : ErrorWebExceptionHandler {
|
||||||
|
|
||||||
|
private val mapper = ObjectMapper()
|
||||||
|
|
||||||
|
override fun handle(exchange: ServerWebExchange, ex: Throwable): Mono<Void> {
|
||||||
|
// Versuche, Status aus Attributen zu lesen, ansonsten 500
|
||||||
|
val status = exchange.response.statusCode?.value() ?: HttpStatus.INTERNAL_SERVER_ERROR.value()
|
||||||
|
val traceId = exchange.request.headers.getFirst("X-Correlation-ID")
|
||||||
|
val body = mapOf(
|
||||||
|
"type" to "about:blank",
|
||||||
|
"title" to (ex.message ?: "Unexpected error"),
|
||||||
|
"status" to status,
|
||||||
|
"traceId" to traceId
|
||||||
|
)
|
||||||
|
|
||||||
|
exchange.response.statusCode = HttpStatus.valueOf(status)
|
||||||
|
exchange.response.headers.contentType = MediaType.APPLICATION_PROBLEM_JSON
|
||||||
|
|
||||||
|
val bytes = mapper.writeValueAsBytes(body)
|
||||||
|
val buffer = exchange.response.bufferFactory().wrap(bytes)
|
||||||
|
return exchange.response.writeWith(Mono.just(buffer))
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package at.mocode.infrastructure.gateway.fallback
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alternative FallbackController (deaktiviert per Default), nur aktivierbar über
|
||||||
|
* property `gateway.customFallback.enabled=true`. Standardmäßig existiert bereits
|
||||||
|
* ein FallbackController unter `...gateway.controller.FallbackController`.
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@ConditionalOnProperty(prefix = "gateway.customFallback", name = ["enabled"], havingValue = "true", matchIfMissing = false)
|
||||||
|
class FallbackController {
|
||||||
|
|
||||||
|
@RequestMapping("/fallback/ping")
|
||||||
|
fun pingFallback(): ResponseEntity<Map<String, Any>> =
|
||||||
|
ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(
|
||||||
|
mapOf(
|
||||||
|
"message" to "Ping service unavailable",
|
||||||
|
"timestamp" to Instant.now().toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
+23
-3
@@ -46,13 +46,18 @@ class SecurityConfig(
|
|||||||
pathMatchers(*securityProperties.publicPaths.toTypedArray()),
|
pathMatchers(*securityProperties.publicPaths.toTypedArray()),
|
||||||
permitAll
|
permitAll
|
||||||
)
|
)
|
||||||
|
// Ping-API erfordert Admin-Rolle (Realm-Rolle "admin")
|
||||||
|
authorize(pathMatchers("/api/ping/**"), hasRole("admin"))
|
||||||
// Alle anderen Pfade erfordern eine Authentifizierung
|
// Alle anderen Pfade erfordern eine Authentifizierung
|
||||||
authorize(anyExchange, authenticated)
|
authorize(anyExchange, authenticated)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. JWT-Validierung via Keycloak aktivieren
|
// 4. JWT-Validierung via Keycloak aktivieren
|
||||||
oauth2ResourceServer {
|
oauth2ResourceServer {
|
||||||
jwt { }
|
jwt {
|
||||||
|
// Realm-Rollen (Keycloak) -> ROLE_* Authorities
|
||||||
|
jwtAuthenticationConverter = realmRolesJwtAuthenticationConverter()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,6 +98,22 @@ class SecurityConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Konvertiert Keycloak Realm-Rollen (realm_access.roles) in Spring Authorities (ROLE_*),
|
||||||
|
* sodass hasRole("admin") funktioniert.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
fun realmRolesJwtAuthenticationConverter(): org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter {
|
||||||
|
val converter = org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter()
|
||||||
|
converter.setJwtGrantedAuthoritiesConverter { jwt ->
|
||||||
|
val roles = (jwt.claims["realm_access"] as? Map<*, *>)?.get("roles") as? Collection<*> ?: emptyList<Any>()
|
||||||
|
roles
|
||||||
|
.filterIsInstance<String>()
|
||||||
|
.map { role -> org.springframework.security.core.authority.SimpleGrantedAuthority("ROLE_" + role.lowercase()) }
|
||||||
|
}
|
||||||
|
return org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter(converter)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Definiert die zentrale und einzige CORS-Konfiguration für das Gateway.
|
* Definiert die zentrale und einzige CORS-Konfiguration für das Gateway.
|
||||||
*/
|
*/
|
||||||
@@ -125,8 +146,7 @@ data class GatewaySecurityProperties(
|
|||||||
"/actuator/**",
|
"/actuator/**",
|
||||||
"/webjars/**",
|
"/webjars/**",
|
||||||
"/v3/api-docs/**",
|
"/v3/api-docs/**",
|
||||||
"/api/auth/**", // Alle Auth-Endpunkte
|
"/api/auth/**" // Alle Auth-Endpunkte
|
||||||
"/api/ping/**"
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+1
-11
@@ -1,23 +1,13 @@
|
|||||||
# ===================================================================
|
# migrated from application-keycloak.yml (standardized to .yaml)
|
||||||
# Keycloak Profile Configuration
|
|
||||||
# ===================================================================
|
|
||||||
# This profile configures OAuth2/JWT authentication with Keycloak.
|
|
||||||
# Uses Spring Security's oauth2ResourceServer for secure JWT validation.
|
|
||||||
# ===================================================================
|
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
security:
|
security:
|
||||||
oauth2:
|
oauth2:
|
||||||
resourceserver:
|
resourceserver:
|
||||||
jwt:
|
jwt:
|
||||||
# Issuer URI for JWT validation - Docker internal: keycloak:8080, External: localhost:8180
|
|
||||||
issuer-uri: ${KEYCLOAK_ISSUER_URI:http://keycloak:8180/realms/meldestelle}
|
issuer-uri: ${KEYCLOAK_ISSUER_URI:http://keycloak:8180/realms/meldestelle}
|
||||||
# JWK Set URI for fetching public keys to validate JWT signatures
|
|
||||||
jwk-set-uri: ${KEYCLOAK_JWK_SET_URI:http://keycloak:8180/realms/meldestelle/protocol/openid-connect/certs}
|
jwk-set-uri: ${KEYCLOAK_JWK_SET_URI:http://keycloak:8180/realms/meldestelle/protocol/openid-connect/certs}
|
||||||
|
|
||||||
# Keycloak-spezifische Konfiguration
|
|
||||||
keycloak:
|
keycloak:
|
||||||
# Internal Docker service name, external via port 8180
|
|
||||||
server-url: ${KEYCLOAK_SERVER_URL:http://keycloak:8180}
|
server-url: ${KEYCLOAK_SERVER_URL:http://keycloak:8180}
|
||||||
issuer-uri: ${KEYCLOAK_ISSUER_URI:http://keycloak:8180/realms/meldestelle}
|
issuer-uri: ${KEYCLOAK_ISSUER_URI:http://keycloak:8180/realms/meldestelle}
|
||||||
jwk-set-uri: ${KEYCLOAK_JWK_SET_URI:http://keycloak:8180/realms/meldestelle/protocol/openid-connect/certs}
|
jwk-set-uri: ${KEYCLOAK_JWK_SET_URI:http://keycloak:8180/realms/meldestelle/protocol/openid-connect/certs}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: gateway
|
||||||
|
autoconfigure:
|
||||||
|
exclude:
|
||||||
|
- org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration
|
||||||
|
cloud:
|
||||||
|
gateway:
|
||||||
|
httpclient:
|
||||||
|
connect-timeout: 3000
|
||||||
|
response-timeout: 5s
|
||||||
|
routes:
|
||||||
|
- id: ping-service
|
||||||
|
uri: http://ping-service:8080
|
||||||
|
predicates:
|
||||||
|
- Path=/api/ping/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
|
- name: CircuitBreaker
|
||||||
|
args:
|
||||||
|
name: pingServiceCB
|
||||||
|
fallbackUri: forward:/fallback/ping
|
||||||
|
|
||||||
|
management:
|
||||||
|
endpoints:
|
||||||
|
web:
|
||||||
|
exposure:
|
||||||
|
include: health,info,prometheus
|
||||||
|
|
||||||
|
# Gateway-spezifische Einstellungen
|
||||||
|
gateway:
|
||||||
|
ratelimit:
|
||||||
|
enabled: false # Start: ausgeschaltet; zum Aktivieren default-filters plus RequestRateLimiter in YAML hinzufügen
|
||||||
|
replenish-rate: 10
|
||||||
|
burst-capacity: 20
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
# Port, auf dem das Gateway läuft
|
|
||||||
server:
|
|
||||||
port: ${GATEWAY_SERVER_PORT:8081}
|
|
||||||
# Optimierte Netty-Konfiguration für reaktive Anwendungen
|
|
||||||
netty:
|
|
||||||
connection-timeout: 5s
|
|
||||||
idle-timeout: 15s
|
|
||||||
|
|
||||||
# Der Name, unter dem sich das Gateway in Consul registriert
|
|
||||||
spring:
|
|
||||||
application:
|
|
||||||
name: api-gateway
|
|
||||||
profiles:
|
|
||||||
active: ${SPRING_PROFILES_ACTIVE:dev}
|
|
||||||
security:
|
|
||||||
user:
|
|
||||||
name: ${GATEWAY_ADMIN_USER:admin}
|
|
||||||
password: ${GATEWAY_ADMIN_PASSWORD:admin}
|
|
||||||
data:
|
|
||||||
redis:
|
|
||||||
host: ${REDIS_HOST:localhost}
|
|
||||||
port: ${REDIS_PORT:6379}
|
|
||||||
timeout: 3s
|
|
||||||
cloud:
|
|
||||||
consul:
|
|
||||||
host: ${CONSUL_HOST:localhost}
|
|
||||||
port: ${CONSUL_PORT:8500}
|
|
||||||
enabled: ${CONSUL_ENABLED:true}
|
|
||||||
discovery:
|
|
||||||
enabled: ${CONSUL_ENABLED:true}
|
|
||||||
register: ${CONSUL_ENABLED:true}
|
|
||||||
health-check-path: /actuator/health
|
|
||||||
health-check-interval: 10s
|
|
||||||
instance-id: ${spring.application.name}-${server.port}-${random.uuid}
|
|
||||||
gateway:
|
|
||||||
server:
|
|
||||||
webflux:
|
|
||||||
httpclient:
|
|
||||||
connect-timeout: 5000
|
|
||||||
response-timeout: 30s
|
|
||||||
pool:
|
|
||||||
max-idle-time: 15s
|
|
||||||
max-life-time: 60s
|
|
||||||
default-filters:
|
|
||||||
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
|
|
||||||
- name: Retry
|
|
||||||
args:
|
|
||||||
retries: 2
|
|
||||||
statuses: BAD_GATEWAY,GATEWAY_TIMEOUT
|
|
||||||
methods: GET
|
|
||||||
backoff:
|
|
||||||
firstBackoff: 100ms
|
|
||||||
maxBackoff: 1000ms
|
|
||||||
factor: 2
|
|
||||||
basedOnPreviousValue: false
|
|
||||||
- name: AddResponseHeader
|
|
||||||
args:
|
|
||||||
name: X-Content-Type-Options
|
|
||||||
value: nosniff
|
|
||||||
- name: AddResponseHeader
|
|
||||||
args:
|
|
||||||
name: X-Frame-Options
|
|
||||||
value: DENY
|
|
||||||
- name: AddResponseHeader
|
|
||||||
args:
|
|
||||||
name: Referrer-Policy
|
|
||||||
value: strict-origin-when-cross-origin
|
|
||||||
- name: AddResponseHeader
|
|
||||||
args:
|
|
||||||
name: Cache-Control
|
|
||||||
value: no-cache, no-store, must-revalidate
|
|
||||||
routes:
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Gateway-Info-Route (optional) ---
|
|
||||||
# ==============================================================
|
|
||||||
- id: gateway-info-route
|
|
||||||
uri: http://localhost:${server.port}
|
|
||||||
predicates:
|
|
||||||
- Method=GET
|
|
||||||
- Path=/gateway-info
|
|
||||||
filters:
|
|
||||||
- name: SetStatus
|
|
||||||
args:
|
|
||||||
status: 200
|
|
||||||
- name: SetResponseHeader
|
|
||||||
args:
|
|
||||||
name: Content-Type
|
|
||||||
value: application/json
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Ping-Service-Integration (optional) ---
|
|
||||||
# ==============================================================
|
|
||||||
- id: ping-service-route
|
|
||||||
uri: lb://ping-service
|
|
||||||
predicates:
|
|
||||||
- Path=/api/ping/**
|
|
||||||
filters:
|
|
||||||
- StripPrefix=1
|
|
||||||
- name: CircuitBreaker
|
|
||||||
args:
|
|
||||||
name: pingCircuitBreaker
|
|
||||||
fallbackUri: forward:/fallback/ping
|
|
||||||
- name: RequestRateLimiter
|
|
||||||
args:
|
|
||||||
key-resolver: "#{@principalNameKeyResolver}"
|
|
||||||
redis-rate-limiter.replenishRate: ${PING_RATE_LIMIT_REPLENISH_RATE:50}
|
|
||||||
redis-rate-limiter.burstCapacity: ${PING_RATE_LIMIT_BURST:100}
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Entries-Service-Integration (MP-27) ---
|
|
||||||
# ==============================================================
|
|
||||||
- id: entries-service-route
|
|
||||||
uri: lb://entries-service
|
|
||||||
predicates:
|
|
||||||
- Path=/api/entries/**
|
|
||||||
filters:
|
|
||||||
- StripPrefix=1
|
|
||||||
|
|
||||||
# Mappe das Root "/api/entries" explizit auf die Service-Root "/"
|
|
||||||
- id: entries-service-root
|
|
||||||
uri: lb://entries-service
|
|
||||||
predicates:
|
|
||||||
- Path=/api/entries
|
|
||||||
filters:
|
|
||||||
- SetPath=/
|
|
||||||
|
|
||||||
- id: entries-service-root-slash
|
|
||||||
uri: lb://entries-service
|
|
||||||
predicates:
|
|
||||||
- Path=/api/entries/
|
|
||||||
filters:
|
|
||||||
- SetPath=/
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Members-Service-Integration (optional) ---
|
|
||||||
# ==============================================================
|
|
||||||
# - id: members-service-route
|
|
||||||
# uri: lb://members-service
|
|
||||||
# predicates:
|
|
||||||
# - Path=/api/members/**
|
|
||||||
# filters:
|
|
||||||
# - StripPrefix=1
|
|
||||||
# - name: CircuitBreaker
|
|
||||||
# args:
|
|
||||||
# name: membersCircuitBreaker
|
|
||||||
# fallbackUri: forward:/fallback/members
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Horses-Service-Integration (optional) ---
|
|
||||||
# ==============================================================
|
|
||||||
# - id: horses-service-route
|
|
||||||
# uri: lb://horses-service
|
|
||||||
# predicates:
|
|
||||||
# - Path=/api/horses/**
|
|
||||||
# filters:
|
|
||||||
# - StripPrefix=1
|
|
||||||
# - name: CircuitBreaker
|
|
||||||
# args:
|
|
||||||
# name: horsesCircuitBreaker
|
|
||||||
# fallbackUri: forward:/fallback/horses
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Events-Service-Integration (optional) ---
|
|
||||||
# ==============================================================
|
|
||||||
# - id: events-service-route
|
|
||||||
# uri: lb://events-service
|
|
||||||
# predicates:
|
|
||||||
# - Path=/api/events/**
|
|
||||||
# filters:
|
|
||||||
# - StripPrefix=1
|
|
||||||
# - name: CircuitBreaker
|
|
||||||
# args:
|
|
||||||
# name: eventsCircuitBreaker
|
|
||||||
# fallbackUri: forward:/fallback/events
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Masterdata-Service-Integration (optional) ---
|
|
||||||
# ==============================================================
|
|
||||||
# - id: masterdata-service-route
|
|
||||||
# uri: lb://masterdata-service
|
|
||||||
# predicates:
|
|
||||||
# - Path=/api/masterdata/**
|
|
||||||
# filters:
|
|
||||||
# - StripPrefix=1
|
|
||||||
# - name: CircuitBreaker
|
|
||||||
# args:
|
|
||||||
# name: masterdataCircuitBreaker
|
|
||||||
# fallbackUri: forward:/fallback/masterdata
|
|
||||||
|
|
||||||
# ==============================================================
|
|
||||||
# --- Auth-Service-Integration (optional) ---
|
|
||||||
# ==============================================================
|
|
||||||
# - id: auth-service-route
|
|
||||||
# uri: lb://auth-service
|
|
||||||
# predicates:
|
|
||||||
# - Path=/api/auth/**
|
|
||||||
# filters:
|
|
||||||
# - StripPrefix=1
|
|
||||||
# - name: CircuitBreaker
|
|
||||||
# args:
|
|
||||||
# name: authCircuitBreaker
|
|
||||||
# fallbackUri: forward:/fallback/auth
|
|
||||||
# Circuit Breaker Konfiguration
|
|
||||||
resilience4j:
|
|
||||||
circuitbreaker:
|
|
||||||
configs:
|
|
||||||
default:
|
|
||||||
registerHealthIndicator: true
|
|
||||||
slidingWindowSize: 100
|
|
||||||
minimumNumberOfCalls: 20
|
|
||||||
permittedNumberOfCallsInHalfOpenState: 3
|
|
||||||
automaticTransitionFromOpenToHalfOpenEnabled: true
|
|
||||||
waitDurationInOpenState: 5s
|
|
||||||
failureRateThreshold: 50
|
|
||||||
eventConsumerBufferSize: 10
|
|
||||||
recordExceptions:
|
|
||||||
- org.springframework.web.client.HttpServerErrorException
|
|
||||||
- java.util.concurrent.TimeoutException
|
|
||||||
- java.io.IOException
|
|
||||||
instances:
|
|
||||||
defaultCircuitBreaker:
|
|
||||||
baseConfig: default
|
|
||||||
pingCircuitBreaker:
|
|
||||||
baseConfig: default
|
|
||||||
membersCircuitBreaker:
|
|
||||||
baseConfig: default
|
|
||||||
slidingWindowSize: 50
|
|
||||||
horsesCircuitBreaker:
|
|
||||||
baseConfig: default
|
|
||||||
slidingWindowSize: 50
|
|
||||||
eventsCircuitBreaker:
|
|
||||||
baseConfig: default
|
|
||||||
slidingWindowSize: 75
|
|
||||||
masterdataCircuitBreaker:
|
|
||||||
baseConfig: default
|
|
||||||
slidingWindowSize: 30
|
|
||||||
authCircuitBreaker:
|
|
||||||
baseConfig: default
|
|
||||||
slidingWindowSize: 20
|
|
||||||
failureRateThreshold: 30
|
|
||||||
|
|
||||||
# Management und Monitoring
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
exposure:
|
|
||||||
include: health,info,metrics,prometheus,gateway,circuitbreakers
|
|
||||||
base-path: /actuator
|
|
||||||
cors:
|
|
||||||
allowed-origins:
|
|
||||||
- "https://*.meldestelle.at"
|
|
||||||
- "http://localhost:*"
|
|
||||||
allowed-methods: GET,POST
|
|
||||||
allowed-headers: "*"
|
|
||||||
allow-credentials: true
|
|
||||||
endpoint:
|
|
||||||
health:
|
|
||||||
show-details: when_authorized
|
|
||||||
show-components: when_authorized
|
|
||||||
probes:
|
|
||||||
enabled: true
|
|
||||||
metrics:
|
|
||||||
access: unrestricted
|
|
||||||
info:
|
|
||||||
access: unrestricted
|
|
||||||
prometheus:
|
|
||||||
access: unrestricted
|
|
||||||
gateway:
|
|
||||||
access: unrestricted
|
|
||||||
circuitbreakers:
|
|
||||||
enabled: true
|
|
||||||
metrics:
|
|
||||||
distribution:
|
|
||||||
percentiles-histogram:
|
|
||||||
http.server.requests: true
|
|
||||||
percentiles:
|
|
||||||
http.server.requests: 0.5,0.90,0.95,0.99
|
|
||||||
minimum-expected-value:
|
|
||||||
http.server.requests: 1ms
|
|
||||||
maximum-expected-value:
|
|
||||||
http.server.requests: 30s
|
|
||||||
tags:
|
|
||||||
application: ${spring.application.name}
|
|
||||||
environment: ${spring.profiles.active}
|
|
||||||
instance: ${spring.cloud.consul.discovery.instance-id}
|
|
||||||
service: gateway
|
|
||||||
component: infrastructure
|
|
||||||
gateway: api-gateway
|
|
||||||
info:
|
|
||||||
env:
|
|
||||||
enabled: true
|
|
||||||
git:
|
|
||||||
mode: full
|
|
||||||
build:
|
|
||||||
enabled: true
|
|
||||||
java:
|
|
||||||
enabled: true
|
|
||||||
# Tracing-Konfiguration - Aktiviert (Micrometer Tracing + Zipkin)
|
|
||||||
tracing:
|
|
||||||
enabled: ${TRACING_ENABLED:false}
|
|
||||||
sampling:
|
|
||||||
probability: ${TRACING_SAMPLING_PROBABILITY:1.0}
|
|
||||||
zipkin:
|
|
||||||
tracing:
|
|
||||||
endpoint: ${ZIPKIN_TRACING_ENDPOINT:http://localhost:9411/api/v2/spans}
|
|
||||||
# Reduziert Verbindungsfehler, wenn Zipkin nicht verfügbar ist
|
|
||||||
connect-timeout: 1s
|
|
||||||
read-timeout: 10s
|
|
||||||
|
|
||||||
# Erweiterte Logging-Konfiguration
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
org.springframework.cloud.gateway: INFO
|
|
||||||
org.springframework.cloud.loadbalancer: INFO
|
|
||||||
org.springframework.cloud.consul: INFO
|
|
||||||
at.mocode.infrastructure.gateway: INFO
|
|
||||||
io.github.resilience4j: INFO
|
|
||||||
reactor.netty.http.client: INFO
|
|
||||||
|
|
||||||
# (Redis-Konfiguration wurde in den bestehenden spring.data.redis-Block oben integriert)
|
|
||||||
+2
-26
@@ -3,7 +3,7 @@ package at.mocode.infrastructure.gateway
|
|||||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import at.mocode.infrastructure.gateway.support.GatewayTestContext
|
||||||
import org.springframework.context.annotation.Import
|
import org.springframework.context.annotation.Import
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.test.context.ActiveProfiles
|
import org.springframework.test.context.ActiveProfiles
|
||||||
@@ -13,31 +13,7 @@ import org.springframework.test.web.reactive.server.WebTestClient
|
|||||||
* Tests für den Fallback Controller, der Circuit Breaker Szenarien behandelt.
|
* Tests für den Fallback Controller, der Circuit Breaker Szenarien behandelt.
|
||||||
* Testet alle Fallback-Endpunkte für verschiedene Services.
|
* Testet alle Fallback-Endpunkte für verschiedene Services.
|
||||||
*/
|
*/
|
||||||
@SpringBootTest(
|
@GatewayTestContext
|
||||||
classes = [GatewayApplication::class],
|
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
|
||||||
properties = [
|
|
||||||
// Externe Abhängigkeiten für Fallback-Tests deaktivieren
|
|
||||||
"spring.cloud.discovery.enabled=false",
|
|
||||||
"spring.cloud.consul.enabled=false",
|
|
||||||
"spring.cloud.consul.config.enabled=false",
|
|
||||||
"spring.cloud.consul.discovery.register=false",
|
|
||||||
"spring.cloud.loadbalancer.enabled=false",
|
|
||||||
// Circuit Breaker Health Indicator deaktivieren um Interferenzen zu vermeiden
|
|
||||||
"resilience4j.circuitbreaker.configs.default.registerHealthIndicator=false",
|
|
||||||
"management.health.circuitbreakers.enabled=false",
|
|
||||||
// Custom Filter für reine Fallback-Tests deaktivieren
|
|
||||||
"gateway.security.jwt.enabled=false",
|
|
||||||
// Reaktiven Web-Anwendungstyp verwenden
|
|
||||||
"spring.main.web-application-type=reactive",
|
|
||||||
// Gateway Discovery deaktivieren
|
|
||||||
"spring.cloud.gateway.server.webflux.discovery.locator.enabled=false",
|
|
||||||
// Actuator Security deaktivieren
|
|
||||||
"management.security.enabled=false",
|
|
||||||
// Zufälligen Port setzen
|
|
||||||
"server.port=0"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@ActiveProfiles("test")
|
@ActiveProfiles("test")
|
||||||
@Import(TestSecurityConfig::class)
|
@Import(TestSecurityConfig::class)
|
||||||
class FallbackControllerTests {
|
class FallbackControllerTests {
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package at.mocode.infrastructure.gateway
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringBootConfiguration
|
||||||
|
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
|
||||||
|
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
|
||||||
|
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||||
|
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration
|
||||||
|
import org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration
|
||||||
|
import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration
|
||||||
|
import org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test-spezifische, minimale GatewayApplication. Diese Klasse überschattet die Produktions-
|
||||||
|
* `GatewayApplication` während der Tests und deaktiviert problematische Auto-Konfigurationen,
|
||||||
|
* lädt aber weiterhin unsere Komponenten aus dem Gateway-Paket.
|
||||||
|
*/
|
||||||
|
@SpringBootConfiguration
|
||||||
|
@ComponentScan(basePackages = ["at.mocode.infrastructure.gateway"])
|
||||||
|
@ImportAutoConfiguration(
|
||||||
|
exclude = [
|
||||||
|
// Spring Cloud Refresh/Context (CNF in Tests vermeiden)
|
||||||
|
RefreshAutoConfiguration::class,
|
||||||
|
// HTTP/WebClient in Basis-Context-Load-Tests nicht erforderlich
|
||||||
|
HttpClientAutoConfiguration::class,
|
||||||
|
WebClientAutoConfiguration::class,
|
||||||
|
// Security AutoConfigs minimieren
|
||||||
|
ReactiveOAuth2ResourceServerAutoConfiguration::class,
|
||||||
|
SecurityAutoConfiguration::class,
|
||||||
|
ReactiveSecurityAutoConfiguration::class
|
||||||
|
]
|
||||||
|
)
|
||||||
|
class GatewayApplication
|
||||||
+10
-5
@@ -2,6 +2,10 @@ package at.mocode.infrastructure.gateway
|
|||||||
|
|
||||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||||
|
import org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration
|
||||||
|
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration
|
||||||
|
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
import org.springframework.context.annotation.Import
|
import org.springframework.context.annotation.Import
|
||||||
import org.springframework.test.context.ActiveProfiles
|
import org.springframework.test.context.ActiveProfiles
|
||||||
@@ -11,8 +15,8 @@ import org.springframework.test.context.ActiveProfiles
|
|||||||
* Verwendet ein Test-Profil, um Produktions-Filter und externe Abhängigkeiten zu deaktivieren.
|
* Verwendet ein Test-Profil, um Produktions-Filter und externe Abhängigkeiten zu deaktivieren.
|
||||||
*/
|
*/
|
||||||
@SpringBootTest(
|
@SpringBootTest(
|
||||||
classes = [GatewayApplication::class],
|
classes = [MinimalTestApp::class],
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
webEnvironment = SpringBootTest.WebEnvironment.NONE,
|
||||||
properties = [
|
properties = [
|
||||||
// Alle externen Abhängigkeiten für Context-Loading-Test deaktivieren
|
// Alle externen Abhängigkeiten für Context-Loading-Test deaktivieren
|
||||||
"spring.cloud.discovery.enabled=false",
|
"spring.cloud.discovery.enabled=false",
|
||||||
@@ -25,8 +29,8 @@ import org.springframework.test.context.ActiveProfiles
|
|||||||
"management.health.circuitbreakers.enabled=false",
|
"management.health.circuitbreakers.enabled=false",
|
||||||
// Custom Security und Filter deaktivieren
|
// Custom Security und Filter deaktivieren
|
||||||
"gateway.security.jwt.enabled=false",
|
"gateway.security.jwt.enabled=false",
|
||||||
// Reaktiven Web-Anwendungstyp verwenden
|
// Für diesen Kontext-Load-Test keinen Web-Stack initialisieren
|
||||||
"spring.main.web-application-type=reactive",
|
"spring.main.web-application-type=none",
|
||||||
// Gateway Discovery deaktivieren (korrekte Property)
|
// Gateway Discovery deaktivieren (korrekte Property)
|
||||||
"spring.cloud.gateway.discovery.locator.enabled=false",
|
"spring.cloud.gateway.discovery.locator.enabled=false",
|
||||||
// Zufälligen Port setzen
|
// Zufälligen Port setzen
|
||||||
@@ -34,7 +38,8 @@ import org.springframework.test.context.ActiveProfiles
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ActiveProfiles("test")
|
@ActiveProfiles("test")
|
||||||
@Import(TestSecurityConfig::class)
|
@EnableAutoConfiguration
|
||||||
|
@Import(TestSecurityConfig::class, TestSupportConfig::class)
|
||||||
class GatewayApplicationTests {
|
class GatewayApplicationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+3
-27
@@ -4,7 +4,7 @@ import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import at.mocode.infrastructure.gateway.support.GatewayTestContext
|
||||||
import org.springframework.cloud.gateway.route.RouteLocator
|
import org.springframework.cloud.gateway.route.RouteLocator
|
||||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
@@ -20,32 +20,8 @@ import org.springframework.web.bind.annotation.RestController
|
|||||||
* Tests for Gateway custom filters: CorrelationId, Enhanced Logging, and Rate Limiting.
|
* Tests for Gateway custom filters: CorrelationId, Enhanced Logging, and Rate Limiting.
|
||||||
* Tests filter behavior without disabling them (unlike other test classes).
|
* Tests filter behavior without disabling them (unlike other test classes).
|
||||||
*/
|
*/
|
||||||
@SpringBootTest(
|
@GatewayTestContext
|
||||||
classes = [GatewayApplication::class],
|
@ActiveProfiles("test")
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
|
||||||
properties = [
|
|
||||||
// Disable external dependencies
|
|
||||||
"spring.cloud.discovery.enabled=false",
|
|
||||||
"spring.cloud.consul.enabled=false",
|
|
||||||
"spring.cloud.consul.config.enabled=false",
|
|
||||||
"spring.cloud.consul.discovery.register=false",
|
|
||||||
"spring.cloud.loadbalancer.enabled=false",
|
|
||||||
// Disable circuit breaker for filter tests
|
|
||||||
"resilience4j.circuitbreaker.configs.default.registerHealthIndicator=false",
|
|
||||||
"management.health.circuitbreakers.enabled=false",
|
|
||||||
// Keep custom filters enabled for testing
|
|
||||||
"gateway.security.jwt.enabled=false", // Disable JWT but keep other filters
|
|
||||||
// Use reactive web application type
|
|
||||||
"spring.main.web-application-type=reactive",
|
|
||||||
// Disable gateway discovery - use explicit routes
|
|
||||||
"spring.cloud.gateway.server.webflux.discovery.locator.enabled=false",
|
|
||||||
// Disable actuator security
|
|
||||||
"management.security.enabled=false",
|
|
||||||
// Set random port
|
|
||||||
"server.port=0"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@ActiveProfiles("dev") // Use dev profile to enable filters
|
|
||||||
@AutoConfigureWebTestClient
|
@AutoConfigureWebTestClient
|
||||||
@Import(TestSecurityConfig::class, GatewayFiltersTests.TestFilterConfig::class)
|
@Import(TestSecurityConfig::class, GatewayFiltersTests.TestFilterConfig::class)
|
||||||
class GatewayFiltersTests {
|
class GatewayFiltersTests {
|
||||||
|
|||||||
+2
-28
@@ -1,16 +1,15 @@
|
|||||||
package at.mocode.infrastructure.gateway
|
package at.mocode.infrastructure.gateway
|
||||||
|
|
||||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||||
|
import at.mocode.infrastructure.gateway.support.GatewayTestContext
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
|
||||||
import org.springframework.cloud.gateway.route.RouteLocator
|
import org.springframework.cloud.gateway.route.RouteLocator
|
||||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.context.annotation.Import
|
import org.springframework.context.annotation.Import
|
||||||
import org.springframework.test.context.ActiveProfiles
|
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient
|
import org.springframework.test.web.reactive.server.WebTestClient
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.PostMapping
|
import org.springframework.web.bind.annotation.PostMapping
|
||||||
@@ -21,32 +20,7 @@ import org.springframework.web.bind.annotation.RestController
|
|||||||
* Tests for Gateway routing functionality.
|
* Tests for Gateway routing functionality.
|
||||||
* Uses mock backend services to test route forwarding.
|
* Uses mock backend services to test route forwarding.
|
||||||
*/
|
*/
|
||||||
@SpringBootTest(
|
@GatewayTestContext
|
||||||
classes = [GatewayApplication::class],
|
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
|
||||||
properties = [
|
|
||||||
// Disable external dependencies
|
|
||||||
"spring.cloud.discovery.enabled=false",
|
|
||||||
"spring.cloud.consul.enabled=false",
|
|
||||||
"spring.cloud.consul.config.enabled=false",
|
|
||||||
"spring.cloud.consul.discovery.register=false",
|
|
||||||
"spring.cloud.loadbalancer.enabled=false",
|
|
||||||
// Disable circuit breaker for routing tests
|
|
||||||
"resilience4j.circuitbreaker.configs.default.registerHealthIndicator=false",
|
|
||||||
"management.health.circuitbreakers.enabled=false",
|
|
||||||
// Disable custom filters for pure routing tests
|
|
||||||
"gateway.security.jwt.enabled=false",
|
|
||||||
// Use reactive web application type
|
|
||||||
"spring.main.web-application-type=reactive",
|
|
||||||
// Disable gateway discovery - use explicit routes
|
|
||||||
"spring.cloud.gateway.server.webflux.discovery.locator.enabled=false",
|
|
||||||
// Disable actuator security
|
|
||||||
"management.security.enabled=false",
|
|
||||||
// Set random port
|
|
||||||
"server.port=0"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@ActiveProfiles("test")
|
|
||||||
@AutoConfigureWebTestClient
|
@AutoConfigureWebTestClient
|
||||||
@Import(TestSecurityConfig::class, GatewayRoutingTests.TestRoutesConfig::class)
|
@Import(TestSecurityConfig::class, GatewayRoutingTests.TestRoutesConfig::class)
|
||||||
class GatewayRoutingTests {
|
class GatewayRoutingTests {
|
||||||
|
|||||||
+3
-27
@@ -5,7 +5,7 @@ import org.junit.jupiter.api.BeforeEach
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import at.mocode.infrastructure.gateway.support.GatewayTestContext
|
||||||
import org.springframework.boot.test.web.server.LocalServerPort
|
import org.springframework.boot.test.web.server.LocalServerPort
|
||||||
import org.springframework.cloud.gateway.route.RouteLocator
|
import org.springframework.cloud.gateway.route.RouteLocator
|
||||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder
|
||||||
@@ -20,32 +20,8 @@ import org.springframework.web.bind.annotation.*
|
|||||||
* Tests for Gateway security configuration including CORS settings.
|
* Tests for Gateway security configuration including CORS settings.
|
||||||
* Tests the overall security setup and cross-origin request handling.
|
* Tests the overall security setup and cross-origin request handling.
|
||||||
*/
|
*/
|
||||||
@SpringBootTest(
|
@GatewayTestContext
|
||||||
classes = [GatewayApplication::class],
|
@ActiveProfiles("test") // Behalte test-Profil explizit für Klarheit
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
|
||||||
properties = [
|
|
||||||
// Disable external dependencies
|
|
||||||
"spring.cloud.discovery.enabled=false",
|
|
||||||
"spring.cloud.consul.enabled=false",
|
|
||||||
"spring.cloud.consul.config.enabled=false",
|
|
||||||
"spring.cloud.consul.discovery.register=false",
|
|
||||||
"spring.cloud.loadbalancer.enabled=false",
|
|
||||||
// Disable circuit breaker for security tests
|
|
||||||
"resilience4j.circuitbreaker.configs.default.registerHealthIndicator=false",
|
|
||||||
"management.health.circuitbreakers.enabled=false",
|
|
||||||
// Disable JWT for CORS testing
|
|
||||||
"gateway.security.jwt.enabled=false",
|
|
||||||
// Use reactive web application type
|
|
||||||
"spring.main.web-application-type=reactive",
|
|
||||||
// Disable gateway discovery - use explicit routes
|
|
||||||
"spring.cloud.gateway.server.webflux.discovery.locator.enabled=false",
|
|
||||||
// Disable actuator security
|
|
||||||
"management.security.enabled=false",
|
|
||||||
// Set random port
|
|
||||||
"server.port=0"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@ActiveProfiles("test") // Use test profile to disable unrelated global filters; CORS config is present in application-test.yml
|
|
||||||
@AutoConfigureWebTestClient
|
@AutoConfigureWebTestClient
|
||||||
@Import(TestSecurityConfig::class, GatewaySecurityTests.TestSecurityConfig::class)
|
@Import(TestSecurityConfig::class, GatewaySecurityTests.TestSecurityConfig::class)
|
||||||
class GatewaySecurityTests {
|
class GatewaySecurityTests {
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ package at.mocode.infrastructure.gateway
|
|||||||
|
|
||||||
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
import at.mocode.infrastructure.gateway.config.TestSecurityConfig
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import at.mocode.infrastructure.gateway.support.GatewayTestContext
|
||||||
import org.springframework.context.annotation.Import
|
import org.springframework.context.annotation.Import
|
||||||
import org.springframework.test.context.ActiveProfiles
|
import org.springframework.test.context.ActiveProfiles
|
||||||
import org.springframework.test.context.TestPropertySource
|
import org.springframework.test.context.TestPropertySource
|
||||||
@@ -13,7 +13,7 @@ import org.springframework.test.context.TestPropertySource
|
|||||||
* without requiring actual Testcontainers, focusing on resolving the OAuth2 ResourceServer
|
* without requiring actual Testcontainers, focusing on resolving the OAuth2 ResourceServer
|
||||||
* autoconfiguration timing issue.
|
* autoconfiguration timing issue.
|
||||||
*/
|
*/
|
||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@GatewayTestContext
|
||||||
@ActiveProfiles("keycloak-integration-test")
|
@ActiveProfiles("keycloak-integration-test")
|
||||||
@TestPropertySource(
|
@TestPropertySource(
|
||||||
properties = [
|
properties = [
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
package at.mocode.infrastructure.gateway
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimaler Test-ApplicationContext, der nur die absolut nötigen Auto-Konfigurationen lädt.
|
||||||
|
* Problematische Auto-Configs werden hier explizit ausgeschlossen, damit der Context sicher startet.
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
class MinimalTestApp
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
package at.mocode.infrastructure.gateway
|
||||||
|
|
||||||
|
import org.springframework.boot.test.context.TestConfiguration
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient
|
||||||
|
|
||||||
|
@TestConfiguration
|
||||||
|
class TestSupportConfig {
|
||||||
|
@Bean
|
||||||
|
fun webClientBuilder(): WebClient.Builder = WebClient.builder()
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package at.mocode.infrastructure.gateway
|
||||||
|
|
||||||
|
import at.mocode.infrastructure.gateway.support.GatewayTestContext
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
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.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@GatewayTestContext
|
||||||
|
@Import(WebFluxSmokeTest.SmokeConfig::class)
|
||||||
|
class WebFluxSmokeTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
lateinit var webTestClient: WebTestClient
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `should load reactive web context and serve smoke endpoint`() {
|
||||||
|
webTestClient.get()
|
||||||
|
.uri("/smoke")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk
|
||||||
|
.expectBody(String::class.java)
|
||||||
|
.isEqualTo("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class SmokeConfig {
|
||||||
|
@Bean
|
||||||
|
fun smokeController(): SmokeController = SmokeController()
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping
|
||||||
|
class SmokeController {
|
||||||
|
@GetMapping("/smoke")
|
||||||
|
fun smoke(): String = "ok"
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
package at.mocode.infrastructure.gateway.support
|
||||||
|
|
||||||
|
import at.mocode.infrastructure.gateway.MinimalTestApp
|
||||||
|
import org.springframework.boot.autoconfigure.ImportAutoConfiguration
|
||||||
|
import org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
|
||||||
|
import org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
|
import org.springframework.context.annotation.Profile
|
||||||
|
import org.springframework.test.context.ActiveProfiles
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zentrale Meta-Annotation für Gateway-Tests.
|
||||||
|
*
|
||||||
|
* - Lädt einen minimalen Spring-Boot-Kontext über `MinimalTestApp`.
|
||||||
|
* - Erzwingt das `test`-Profil.
|
||||||
|
* - Schließt laute/unnötige Auto-Konfigurationen für schnelle, stabile Context-Loads aus.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@SpringBootTest(
|
||||||
|
classes = [MinimalTestApp::class],
|
||||||
|
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||||
|
properties = [
|
||||||
|
// Cloud/Discovery im Test deaktivieren
|
||||||
|
"spring.cloud.discovery.enabled=false",
|
||||||
|
"spring.cloud.consul.enabled=false",
|
||||||
|
"spring.cloud.consul.config.enabled=false",
|
||||||
|
"spring.cloud.consul.discovery.register=false",
|
||||||
|
"spring.cloud.loadbalancer.enabled=false",
|
||||||
|
// Circuit Breaker Health aus
|
||||||
|
"resilience4j.circuitbreaker.configs.default.registerHealthIndicator=false",
|
||||||
|
"management.health.circuitbreakers.enabled=false",
|
||||||
|
// Gateway Discovery Locator aus
|
||||||
|
"spring.cloud.gateway.discovery.locator.enabled=false",
|
||||||
|
// Reaktiven Web‑Stack initialisieren (für WebTestClient)
|
||||||
|
"spring.main.web-application-type=reactive",
|
||||||
|
// Zufälliger Port verhindert Port-Konflikte
|
||||||
|
"server.port=0"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
@ImportAutoConfiguration(
|
||||||
|
exclude = [
|
||||||
|
// Nur die wirklich lauten/unnötigen Auto‑Configs im Default‑Testprofil deaktivieren
|
||||||
|
// Spring Cloud Refresh (verursachte CNF in früheren Läufen)
|
||||||
|
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration::class,
|
||||||
|
// Security Resource Server (Keycloak) für die meisten Tests nicht nötig
|
||||||
|
ReactiveOAuth2ResourceServerAutoConfiguration::class
|
||||||
|
]
|
||||||
|
)
|
||||||
|
@Profile("test")
|
||||||
|
annotation class GatewayTestContext
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package at.mocode.infrastructure.gateway.support
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platzhalter-Klasse: Die frühere ContextCustomizerFactory wurde entfernt,
|
||||||
|
* um Kompilationsfehler zu vermeiden. Die Test-Excludes werden nun über
|
||||||
|
* junit-platform.properties und application-test.yaml gesetzt.
|
||||||
|
*/
|
||||||
|
class TestAutoConfigExcluderPlaceholder
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
// DEPRECATED: Diese Datei wurde absichtlich geleert, um @EnableWebFlux im Testkontext zu vermeiden,
|
||||||
|
// da sie die WebFluxAutoConfiguration deaktiviert. Bitte nicht wieder aktivieren.
|
||||||
|
package at.mocode.infrastructure.gateway.support
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
# Deaktiviert: zentrale ContextCustomizerFactory wurde entfernt
|
||||||
+2
-3
@@ -1,3 +1,4 @@
|
|||||||
|
# migrated from application-dev.yml (standardized to .yaml)
|
||||||
server:
|
server:
|
||||||
port: 0
|
port: 0
|
||||||
|
|
||||||
@@ -26,8 +27,7 @@ spring:
|
|||||||
discovery:
|
discovery:
|
||||||
locator:
|
locator:
|
||||||
enabled: false
|
enabled: false
|
||||||
routes:
|
routes: [ ]
|
||||||
[ ]
|
|
||||||
globalcors:
|
globalcors:
|
||||||
cors-configurations:
|
cors-configurations:
|
||||||
'[/**]':
|
'[/**]':
|
||||||
@@ -45,7 +45,6 @@ spring:
|
|||||||
- "*"
|
- "*"
|
||||||
allowCredentials: true
|
allowCredentials: true
|
||||||
maxAge: 3600
|
maxAge: 3600
|
||||||
# Override production routes: keep empty in tests running with dev profile
|
|
||||||
|
|
||||||
management:
|
management:
|
||||||
endpoints:
|
endpoints:
|
||||||
+13
-6
@@ -1,15 +1,14 @@
|
|||||||
|
# migrated from application-keycloak-integration-test.yml (standardized to .yaml)
|
||||||
server:
|
server:
|
||||||
port: 0
|
port: 0
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: api-gateway-test
|
name: api-gateway-keycloak-integration-test
|
||||||
main:
|
main:
|
||||||
web-application-type: reactive
|
web-application-type: reactive
|
||||||
autoconfigure:
|
autoconfigure:
|
||||||
exclude:
|
exclude:
|
||||||
# Disable OAuth2 ResourceServer autoconfiguration in tests
|
|
||||||
# use mock JwtAuthenticationFilter instead of real JWT validation
|
|
||||||
- org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
|
- org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
|
||||||
cloud:
|
cloud:
|
||||||
discovery:
|
discovery:
|
||||||
@@ -23,7 +22,6 @@ spring:
|
|||||||
loadbalancer:
|
loadbalancer:
|
||||||
enabled: false
|
enabled: false
|
||||||
gateway:
|
gateway:
|
||||||
# IMPORTANT: Do not load production lb:// routes in tests
|
|
||||||
server:
|
server:
|
||||||
webflux:
|
webflux:
|
||||||
discovery:
|
discovery:
|
||||||
@@ -32,8 +30,7 @@ spring:
|
|||||||
httpclient:
|
httpclient:
|
||||||
connect-timeout: 1000
|
connect-timeout: 1000
|
||||||
response-timeout: 5s
|
response-timeout: 5s
|
||||||
routes:
|
routes: [ ]
|
||||||
[ ]
|
|
||||||
globalcors:
|
globalcors:
|
||||||
cors-configurations:
|
cors-configurations:
|
||||||
'[/**]':
|
'[/**]':
|
||||||
@@ -63,8 +60,18 @@ management:
|
|||||||
health:
|
health:
|
||||||
circuit breakers:
|
circuit breakers:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
security:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
gateway:
|
||||||
|
security:
|
||||||
|
jwt:
|
||||||
|
enabled: false
|
||||||
|
keycloak:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
level:
|
level:
|
||||||
org.springframework.cloud.gateway: WARN
|
org.springframework.cloud.gateway: WARN
|
||||||
|
org.springframework.security: DEBUG
|
||||||
at.mocode.infrastructure.gateway: DEBUG
|
at.mocode.infrastructure.gateway: DEBUG
|
||||||
-83
@@ -1,83 +0,0 @@
|
|||||||
server:
|
|
||||||
port: 0
|
|
||||||
|
|
||||||
spring:
|
|
||||||
application:
|
|
||||||
name: api-gateway-keycloak-integration-test
|
|
||||||
main:
|
|
||||||
web-application-type: reactive
|
|
||||||
# Exclude OAuth2 ResourceServer auto-configuration to prevent early issuer-uri validation
|
|
||||||
# The OAuth2 configuration will be set dynamically after Testcontainers start
|
|
||||||
autoconfigure:
|
|
||||||
exclude:
|
|
||||||
- org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
|
|
||||||
# OAuth2 configuration will be set by @DynamicPropertySource after containers start
|
|
||||||
# Do not set static issuer-uri here as it will fail validation before containers are ready
|
|
||||||
cloud:
|
|
||||||
discovery:
|
|
||||||
enabled: false
|
|
||||||
consul:
|
|
||||||
enabled: false
|
|
||||||
config:
|
|
||||||
enabled: false
|
|
||||||
discovery:
|
|
||||||
register: false
|
|
||||||
loadbalancer:
|
|
||||||
enabled: false
|
|
||||||
gateway:
|
|
||||||
# IMPORTANT: Do not load production lb:// routes in tests
|
|
||||||
server:
|
|
||||||
webflux:
|
|
||||||
discovery:
|
|
||||||
locator:
|
|
||||||
enabled: false
|
|
||||||
httpclient:
|
|
||||||
connect-timeout: 1000
|
|
||||||
response-timeout: 5s
|
|
||||||
routes:
|
|
||||||
[ ]
|
|
||||||
globalcors:
|
|
||||||
cors-configurations:
|
|
||||||
'[/**]':
|
|
||||||
allowedOriginPatterns:
|
|
||||||
- "http://localhost:*"
|
|
||||||
- "https://*.meldestelle.at"
|
|
||||||
allowedMethods:
|
|
||||||
- GET
|
|
||||||
- POST
|
|
||||||
- PUT
|
|
||||||
- DELETE
|
|
||||||
- PATCH
|
|
||||||
- OPTIONS
|
|
||||||
allowedHeaders:
|
|
||||||
- "*"
|
|
||||||
allowCredentials: true
|
|
||||||
maxAge: 3600
|
|
||||||
|
|
||||||
management:
|
|
||||||
endpoints:
|
|
||||||
web:
|
|
||||||
exposure:
|
|
||||||
include: health,info
|
|
||||||
endpoint:
|
|
||||||
health:
|
|
||||||
show-details: always
|
|
||||||
health:
|
|
||||||
circuit breakers:
|
|
||||||
enabled: false
|
|
||||||
security:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Enable JWT authentication through OAuth2 Resource Server for integration testing
|
|
||||||
gateway:
|
|
||||||
security:
|
|
||||||
jwt:
|
|
||||||
enabled: false # Disable custom JWT filter
|
|
||||||
keycloak:
|
|
||||||
enabled: true # Enable Keycloak integration
|
|
||||||
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
org.springframework.cloud.gateway: WARN
|
|
||||||
org.springframework.security: DEBUG
|
|
||||||
at.mocode.infrastructure.gateway: DEBUG
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
spring:
|
||||||
|
autoconfigure:
|
||||||
|
exclude: [ ]
|
||||||
|
main:
|
||||||
|
web-application-type: reactive
|
||||||
|
cloud:
|
||||||
|
refresh:
|
||||||
|
enabled: false
|
||||||
|
config:
|
||||||
|
enabled: false
|
||||||
|
bootstrap:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
spring.cloud:
|
||||||
|
gateway:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Keine weiteren Gateway-spezifischen AutoConfigs ausschließen, da nicht zwingend vorhanden
|
||||||
|
|
||||||
|
management:
|
||||||
|
health:
|
||||||
|
circuitbreakers:
|
||||||
|
enabled: false
|
||||||
|
resilience4j:
|
||||||
|
circuitbreaker:
|
||||||
|
configs:
|
||||||
|
default:
|
||||||
|
registerHealthIndicator: false
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
spring.profiles.active=test
|
||||||
|
spring.main.allow-bean-definition-overriding=true
|
||||||
|
logging.level.org.springframework.boot.test=INFO
|
||||||
|
spring.test.context.failure.threshold=0
|
||||||
|
|
||||||
|
# Zentrale AutoConfiguration-Excludes (testweit). Bitte minimal halten und mit application-test.yaml abgleichen.
|
||||||
|
spring.autoconfigure.exclude=\
|
||||||
|
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\
|
||||||
|
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
|
||||||
|
org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration,\
|
||||||
|
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
|
||||||
|
org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration,\
|
||||||
|
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
|
||||||
|
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
|
||||||
|
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
|
||||||
|
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration
|
||||||
|
|
||||||
|
# Spring Cloud im Test vollständig ruhigstellen
|
||||||
|
spring.cloud.refresh.enabled=false
|
||||||
|
spring.cloud.config.enabled=false
|
||||||
|
spring.cloud.bootstrap.enabled=false
|
||||||
@@ -17,6 +17,7 @@ kotlinx-coroutines = "1.10.2"
|
|||||||
|
|
||||||
# --- Spring Ecosystem ---
|
# --- Spring Ecosystem ---
|
||||||
springBoot = "3.5.9"
|
springBoot = "3.5.9"
|
||||||
|
# Spring Cloud Version kompatibel zu Spring Boot 3.5.x
|
||||||
springCloud = "2025.1.0"
|
springCloud = "2025.1.0"
|
||||||
# springCloudGateway = "4.3.0"
|
# springCloudGateway = "4.3.0"
|
||||||
springDependencyManagement = "1.1.7"
|
springDependencyManagement = "1.1.7"
|
||||||
@@ -55,8 +56,9 @@ auth0Jwt = "4.5.0"
|
|||||||
keycloakAdminClient = "26.0.7"
|
keycloakAdminClient = "26.0.7"
|
||||||
|
|
||||||
# --- Testing ---
|
# --- Testing ---
|
||||||
junitJupiter = "6.0.1"
|
# JUnit 5 (Jupiter) & JUnit Platform versions aligned with Gradle 9.x
|
||||||
junitPlatform = "6.0.1"
|
junitJupiter = "5.11.3"
|
||||||
|
junitPlatform = "1.11.3"
|
||||||
mockk = "1.14.7"
|
mockk = "1.14.7"
|
||||||
assertj = "3.27.6"
|
assertj = "3.27.6"
|
||||||
testcontainers = "2.0.3"
|
testcontainers = "2.0.3"
|
||||||
|
|||||||
@@ -22,6 +22,23 @@ dependencies {
|
|||||||
// `constraints` erzwingt spezifische Versionen für einzelne Bibliotheken.
|
// `constraints` erzwingt spezifische Versionen für einzelne Bibliotheken.
|
||||||
// Alle Versionen werden sicher aus `libs.versions.toml` bezogen.
|
// Alle Versionen werden sicher aus `libs.versions.toml` bezogen.
|
||||||
constraints {
|
constraints {
|
||||||
|
// --- Spring Boot Core Constraints (hart pinnen, um Leaks von M-Releases zu verhindern) ---
|
||||||
|
api("org.springframework.boot:spring-boot:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-autoconfigure:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-actuator-autoconfigure:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-actuator:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-starter:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-test:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-test-autoconfigure:${libs.versions.springBoot.get()}")
|
||||||
|
// Zusätzliche Boot-Module, die in neueren Versionen als eigenständige Artefakte vorliegen
|
||||||
|
// und in AutoConfigurations referenziert werden. Hart pinnen, um Versions-Skew in Tests zu vermeiden.
|
||||||
|
// HttpClient AutoConfig und Settings
|
||||||
|
api("org.springframework.boot:spring-boot-http:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-autoconfigure-processor:${libs.versions.springBoot.get()}")
|
||||||
|
api("org.springframework.boot:spring-boot-http-converter:${libs.versions.springBoot.get()}")
|
||||||
|
// Kontext- und Properties-Unterstützung, auf die PropertyMapper intern zugreifen kann
|
||||||
|
api("org.springframework.boot:spring-boot-configuration-processor:${libs.versions.springBoot.get()}")
|
||||||
|
|
||||||
// --- Utilities & Other ---
|
// --- Utilities & Other ---
|
||||||
api(libs.caffeine)
|
api(libs.caffeine)
|
||||||
api(libs.reactor.kafka)
|
api(libs.reactor.kafka)
|
||||||
|
|||||||
Reference in New Issue
Block a user