Skip to content

Commit bdfd0d8

Browse files
committed
KTOR-8517 File configuration loading test API short-hand
1 parent 996ef2c commit bdfd0d8

File tree

9 files changed

+112
-30
lines changed

9 files changed

+112
-30
lines changed

ktor-server/ktor-server-core/api/ktor-server-core.api

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ public abstract interface class io/ktor/server/config/ConfigLoader {
325325
public final class io/ktor/server/config/ConfigLoader$Companion {
326326
public final fun load (Ljava/lang/String;)Lio/ktor/server/config/ApplicationConfig;
327327
public static synthetic fun load$default (Lio/ktor/server/config/ConfigLoader$Companion;Ljava/lang/String;ILjava/lang/Object;)Lio/ktor/server/config/ApplicationConfig;
328+
public final fun loadAll ([Ljava/lang/String;)Lio/ktor/server/config/ApplicationConfig;
328329
}
329330

330331
public final class io/ktor/server/config/ConfigLoadersJvmKt {
@@ -354,7 +355,7 @@ public final class io/ktor/server/config/HoconConfigLoader : io/ktor/server/conf
354355

355356
public class io/ktor/server/config/MapApplicationConfig : io/ktor/server/config/ApplicationConfig {
356357
public fun <init> ()V
357-
public fun <init> (Ljava/util/List;)V
358+
public fun <init> (Ljava/util/Collection;)V
358359
public fun <init> ([Lkotlin/Pair;)V
359360
public fun config (Ljava/lang/String;)Lio/ktor/server/config/ApplicationConfig;
360361
public fun configList (Ljava/lang/String;)Ljava/util/List;
@@ -433,6 +434,8 @@ public final class io/ktor/server/engine/ApplicationEnvironmentBuilder {
433434
public final class io/ktor/server/engine/ApplicationEnvironmentBuilderKt {
434435
public static final fun applicationEnvironment (Lkotlin/jvm/functions/Function1;)Lio/ktor/server/application/ApplicationEnvironment;
435436
public static synthetic fun applicationEnvironment$default (Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lio/ktor/server/application/ApplicationEnvironment;
437+
public static final fun configure (Lio/ktor/server/engine/ApplicationEnvironmentBuilder;[Lio/ktor/server/config/ApplicationConfig;)V
438+
public static final fun configure (Lio/ktor/server/engine/ApplicationEnvironmentBuilder;[Ljava/lang/String;)V
436439
}
437440

438441
public abstract class io/ktor/server/engine/BaseApplicationCall : io/ktor/server/application/PipelineCall {

ktor-server/ktor-server-core/api/ktor-server-core.klib.api

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ abstract interface io.ktor.server.config/ConfigLoader { // io.ktor.server.config
117117

118118
final object Companion { // io.ktor.server.config/ConfigLoader.Companion|null[0]
119119
final fun load(kotlin/String? = ...): io.ktor.server.config/ApplicationConfig // io.ktor.server.config/ConfigLoader.Companion.load|load(kotlin.String?){}[0]
120+
final fun loadAll(kotlin/Array<out kotlin/String>...): io.ktor.server.config/ApplicationConfig // io.ktor.server.config/ConfigLoader.Companion.loadAll|loadAll(kotlin.Array<out|kotlin.String>...){}[0]
120121
}
121122
}
122123

@@ -1295,7 +1296,7 @@ open class io.ktor.server.application/DuplicateApplicationPluginException : kotl
12951296

12961297
open class io.ktor.server.config/MapApplicationConfig : io.ktor.server.config/ApplicationConfig { // io.ktor.server.config/MapApplicationConfig|null[0]
12971298
constructor <init>() // io.ktor.server.config/MapApplicationConfig.<init>|<init>(){}[0]
1298-
constructor <init>(kotlin.collections/List<kotlin/Pair<kotlin/String, kotlin/String>>) // io.ktor.server.config/MapApplicationConfig.<init>|<init>(kotlin.collections.List<kotlin.Pair<kotlin.String,kotlin.String>>){}[0]
1299+
constructor <init>(kotlin.collections/Collection<kotlin/Pair<kotlin/String, kotlin/String>>) // io.ktor.server.config/MapApplicationConfig.<init>|<init>(kotlin.collections.Collection<kotlin.Pair<kotlin.String,kotlin.String>>){}[0]
12991300
constructor <init>(kotlin/Array<out kotlin/Pair<kotlin/String, kotlin/String>>...) // io.ktor.server.config/MapApplicationConfig.<init>|<init>(kotlin.Array<out|kotlin.Pair<kotlin.String,kotlin.String>>...){}[0]
13001301

13011302
final val map // io.ktor.server.config/MapApplicationConfig.map|{}map[0]
@@ -1703,6 +1704,8 @@ final fun (io.ktor.server.config/ApplicationConfig).io.ktor.server.config/tryGet
17031704
final fun (io.ktor.server.config/ApplicationConfig).io.ktor.server.config/withFallback(io.ktor.server.config/ApplicationConfig): io.ktor.server.config/ApplicationConfig // io.ktor.server.config/withFallback|[email protected](io.ktor.server.config.ApplicationConfig){}[0]
17041705
final fun (io.ktor.server.engine/ApplicationEngine).io.ktor.server.engine/stopServerOnCancellation(io.ktor.server.application/Application, kotlin/Long = ..., kotlin/Long = ...): kotlinx.coroutines/CompletableJob // io.ktor.server.engine/stopServerOnCancellation|[email protected](io.ktor.server.application.Application;kotlin.Long;kotlin.Long){}[0]
17051706
final fun (io.ktor.server.engine/ApplicationEngine.Configuration).io.ktor.server.engine/loadCommonConfiguration(io.ktor.server.config/ApplicationConfig) // io.ktor.server.engine/loadCommonConfiguration|loadCommonConfiguration@io.ktor.server.engine.ApplicationEngine.Configuration(io.ktor.server.config.ApplicationConfig){}[0]
1707+
final fun (io.ktor.server.engine/ApplicationEnvironmentBuilder).io.ktor.server.engine/configure(kotlin/Array<out io.ktor.server.config/ApplicationConfig>...) // io.ktor.server.engine/configure|[email protected](kotlin.Array<out|io.ktor.server.config.ApplicationConfig>...){}[0]
1708+
final fun (io.ktor.server.engine/ApplicationEnvironmentBuilder).io.ktor.server.engine/configure(kotlin/Array<out kotlin/String>...) // io.ktor.server.engine/configure|[email protected](kotlin.Array<out|kotlin.String>...){}[0]
17061709
final fun (io.ktor.server.engine/EmbeddedServer<*, *>).io.ktor.server.engine/addShutdownHook(kotlin/Function0<kotlin/Unit>) // io.ktor.server.engine/addShutdownHook|[email protected]<*,*>(kotlin.Function0<kotlin.Unit>){}[0]
17071710
final fun (io.ktor.server.engine/EngineConnectorConfig).io.ktor.server.engine/withPort(kotlin/Int): io.ktor.server.engine/EngineConnectorConfig // io.ktor.server.engine/withPort|[email protected](kotlin.Int){}[0]
17081711
final fun (io.ktor.server.request/ApplicationReceivePipeline).io.ktor.server.engine/installDefaultTransformations() // io.ktor.server.engine/installDefaultTransformations|installDefaultTransformations@io.ktor.server.request.ApplicationReceivePipeline(){}[0]

ktor-server/ktor-server-core/common/src/io/ktor/server/config/ApplicationConfig.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public interface ApplicationConfigValue {
106106
public fun getList(): List<String>
107107

108108
/**
109-
* Ge property as a map
109+
* Get property as a map
110110
*
111111
* [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.config.ApplicationConfigValue.getMap)
112112
*/
@@ -124,11 +124,12 @@ public interface ApplicationConfigValue {
124124
/**
125125
* Represents the type of application configuration value.
126126
*
127-
* `Kind` enum outlines the structure or behavior of the config value, aiding in its resolution or manipulation.
127+
* `Type` enum outlines the structure or behavior of the config value, aiding in its resolution or manipulation.
128128
*
129-
* - `Single`: Indicates a single value.
130-
* - `List`: Represents multiple values in list form.
131-
* - `Object`: Represents a structured or nested configuration object.
129+
* - `NULL`: Indicates an absence of value.
130+
* - `SINGLE`: Indicates a single value.
131+
* - `LIST`: Represents multiple values in list form.
132+
* - `OBJECT`: Represents a structured or nested configuration object.
132133
*
133134
* [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.config.ApplicationConfig.Kind)
134135
*/

ktor-server/ktor-server-core/common/src/io/ktor/server/config/ConfigLoaders.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,25 @@ public interface ConfigLoader {
2525
public fun load(path: String?): ApplicationConfig?
2626

2727
public companion object {
28+
/**
29+
* Loads application configurations from the specified configuration paths.
30+
*
31+
* If no paths are provided, a default configuration is loaded.
32+
* If a single path is provided, the configuration from the given path is loaded.
33+
* If multiple paths are provided, the configurations are merged in sequence.
34+
*
35+
* @param configPaths A variable number of configuration file paths to load.
36+
* @return An [ApplicationConfig] instance representing the loaded configuration(s).
37+
*
38+
* [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.config.ConfigLoader.Companion.loadAll)
39+
*/
40+
public fun loadAll(vararg configPaths: String): ApplicationConfig =
41+
when (configPaths.size) {
42+
0 -> load()
43+
1 -> load(configPaths.single())
44+
else -> configPaths.map(::load).reduce(ApplicationConfig::mergeWith)
45+
}
46+
2847
/**
2948
* Find and load a configuration file to [ApplicationConfig].
3049
*

ktor-server/ktor-server-core/common/src/io/ktor/server/engine/ApplicationEnvironmentBuilder.kt

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,8 @@ package io.ktor.server.engine
66

77
import io.ktor.server.application.*
88
import io.ktor.server.config.*
9-
import io.ktor.util.*
109
import io.ktor.util.logging.*
11-
import io.ktor.util.network.*
1210
import io.ktor.utils.io.*
13-
import kotlinx.coroutines.*
14-
import kotlin.coroutines.*
1511

1612
/**
1713
* Engine environment configuration builder
@@ -48,3 +44,25 @@ public fun applicationEnvironment(
4844
): ApplicationEnvironment {
4945
return ApplicationEnvironmentBuilder().apply(block).build()
5046
}
47+
48+
/**
49+
* Configures the application environment using the provided configuration file paths.
50+
*
51+
* If no paths are provided, the default configuration is loaded.
52+
* If one path is provided, the corresponding configuration file is loaded.
53+
* If multiple paths are provided, the configurations are merged in the given order.
54+
*
55+
* @param configPaths Optional paths to configuration files.
56+
*/
57+
public fun ApplicationEnvironmentBuilder.configure(vararg configPaths: String) {
58+
config = ConfigLoader.loadAll(*configPaths)
59+
}
60+
61+
/**
62+
* Configures the application environment builder by merging the provided configurations.
63+
*
64+
* @param configs A variable number of [ApplicationConfig] instances to be merged and set as the builder's configuration.
65+
*/
66+
public fun ApplicationEnvironmentBuilder.configure(vararg configs: ApplicationConfig) {
67+
config = configs.reduce(ApplicationConfig::mergeWith)
68+
}

ktor-server/ktor-server-test-host/api/ktor-server-test-host.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public final class io/ktor/server/testing/TestApplication : io/ktor/server/testi
3636
public class io/ktor/server/testing/TestApplicationBuilder {
3737
public fun <init> ()V
3838
public final fun application (Lkotlin/jvm/functions/Function1;)V
39+
public final fun configure ([Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
40+
public static synthetic fun configure$default (Lio/ktor/server/testing/TestApplicationBuilder;[Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
3941
public final fun engine (Lkotlin/jvm/functions/Function1;)V
4042
public final fun environment (Lkotlin/jvm/functions/Function1;)V
4143
public final fun externalServices (Lkotlin/jvm/functions/Function1;)V

ktor-server/ktor-server-test-host/api/ktor-server-test-host.klib.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ open class io.ktor.server.testing/TestApplicationBuilder { // io.ktor.server.tes
169169

170170
final fun <#A1: io.ktor.util.pipeline/Pipeline<*, io.ktor.server.application/PipelineCall>, #B1: kotlin/Any, #C1: kotlin/Any> install(io.ktor.server.application/Plugin<#A1, #B1, #C1>, kotlin/Function1<#B1, kotlin/Unit> = ...) // io.ktor.server.testing/TestApplicationBuilder.install|install(io.ktor.server.application.Plugin<0:0,0:1,0:2>;kotlin.Function1<0:1,kotlin.Unit>){0§<io.ktor.util.pipeline.Pipeline<*,io.ktor.server.application.PipelineCall>>;1§<kotlin.Any>;2§<kotlin.Any>}[0]
171171
final fun application(kotlin/Function1<io.ktor.server.application/Application, kotlin/Unit>) // io.ktor.server.testing/TestApplicationBuilder.application|application(kotlin.Function1<io.ktor.server.application.Application,kotlin.Unit>){}[0]
172+
final fun configure(kotlin/Array<out kotlin/String>..., kotlin/Function1<kotlin.collections/MutableMap<kotlin/String, kotlin/String>, kotlin/Unit>? = ...) // io.ktor.server.testing/TestApplicationBuilder.configure|configure(kotlin.Array<out|kotlin.String>...;kotlin.Function1<kotlin.collections.MutableMap<kotlin.String,kotlin.String>,kotlin.Unit>?){}[0]
172173
final fun engine(kotlin/Function1<io.ktor.server.testing/TestApplicationEngine.Configuration, kotlin/Unit>) // io.ktor.server.testing/TestApplicationBuilder.engine|engine(kotlin.Function1<io.ktor.server.testing.TestApplicationEngine.Configuration,kotlin.Unit>){}[0]
173174
final fun environment(kotlin/Function1<io.ktor.server.engine/ApplicationEnvironmentBuilder, kotlin/Unit>) // io.ktor.server.testing/TestApplicationBuilder.environment|environment(kotlin.Function1<io.ktor.server.engine.ApplicationEnvironmentBuilder,kotlin.Unit>){}[0]
174175
final fun externalServices(kotlin/Function1<io.ktor.server.testing/ExternalServicesBuilder, kotlin/Unit>) // io.ktor.server.testing/TestApplicationBuilder.externalServices|externalServices(kotlin.Function1<io.ktor.server.testing.ExternalServicesBuilder,kotlin.Unit>){}[0]

ktor-server/ktor-server-test-host/common/src/io/ktor/server/testing/TestApplication.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,35 @@ public open class TestApplicationBuilder {
315315
applicationModules.add { routing(configuration) }
316316
}
317317

318+
/**
319+
* Configures the application environment using the provided configuration file paths.
320+
*
321+
* If no paths are provided, the default configuration is loaded.
322+
* If one path is provided, the corresponding configuration file is loaded.
323+
* If multiple paths are provided, the configurations are merged in the given order.
324+
*
325+
* @param configPaths Optional paths to configuration files.
326+
*/
327+
@KtorDsl
328+
public fun configure(
329+
vararg configPaths: String,
330+
overrides: (MutableMap<String, String>.() -> Unit)? = null
331+
) {
332+
checkNotBuilt()
333+
environment {
334+
if (overrides == null) {
335+
configure(*configPaths)
336+
} else {
337+
val fileConfigs = ConfigLoader.loadAll(*configPaths)
338+
val overrideEntries = mutableMapOf<String, String>()
339+
.apply(overrides)
340+
.entries.map { it.toPair() }
341+
val mapConfig = MapApplicationConfig(overrideEntries)
342+
config = fileConfigs.mergeWith(mapConfig)
343+
}
344+
}
345+
}
346+
318347
private fun checkNotBuilt() {
319348
check(!built) {
320349
"The test application has already been built. Make sure you configure the application " +

ktor-server/ktor-server-test-host/jvm/test/TestApplicationTestJvm.kt

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import io.ktor.client.statement.*
1212
import io.ktor.http.*
1313
import io.ktor.http.content.*
1414
import io.ktor.server.application.*
15-
import io.ktor.server.config.*
1615
import io.ktor.server.response.*
1716
import io.ktor.server.routing.*
1817
import io.ktor.server.testing.*
@@ -95,9 +94,7 @@ class TestApplicationTestJvm {
9594

9695
@Test
9796
fun testCustomEnvironmentKeepsDefaultProperties() = testApplication {
98-
environment {
99-
config = ApplicationConfig("application-custom.conf")
100-
}
97+
configure("application-custom.conf")
10198
routing {
10299
val config = environment.config
103100
get("a") {
@@ -111,9 +108,7 @@ class TestApplicationTestJvm {
111108

112109
@Test
113110
fun testExplicitDefaultConfig() = testApplication {
114-
environment {
115-
config = ConfigLoader.load()
116-
}
111+
configure()
117112
routing {
118113
val config = environment.config
119114
get {
@@ -127,9 +122,7 @@ class TestApplicationTestJvm {
127122

128123
@Test
129124
fun testCustomConfig() = testApplication {
130-
environment {
131-
config = ApplicationConfig("application-custom.conf")
132-
}
125+
configure("application-custom.conf")
133126
routing {
134127
val config = environment.config
135128
get {
@@ -143,9 +136,7 @@ class TestApplicationTestJvm {
143136

144137
@Test
145138
fun testCustomYamlConfig() = testApplication {
146-
environment {
147-
config = ApplicationConfig("application-custom.yaml")
148-
}
139+
configure("application-custom.yaml")
149140
routing {
150141
val config = environment.config
151142
get {
@@ -159,18 +150,33 @@ class TestApplicationTestJvm {
159150

160151
@Test
161152
fun testConfigLoadsModules() = testApplication {
162-
environment {
163-
config = ApplicationConfig("application-with-modules.conf")
164-
}
165-
153+
configure("application-with-modules.conf")
166154
val response = client.get("/")
167155
assertEquals("OK FROM MODULE", response.bodyAsText())
168156
}
169157

158+
@Test
159+
fun configureMultipleFiles() = testApplication {
160+
configure(
161+
"application.conf",
162+
"application-custom.yaml",
163+
"application-with-modules.conf",
164+
)
165+
routing {
166+
val config = environment.config
167+
get("/test") {
168+
call.respond(config.property("ktor.test").getString())
169+
}
170+
}
171+
172+
assertEquals("OK FROM MODULE", client.get("/").bodyAsText())
173+
assertEquals("another_test_value", client.get("/test").bodyAsText())
174+
}
175+
170176
@Test
171177
fun testExternalServicesCustomConfig() = testApplication {
172-
environment {
173-
config = ApplicationConfig("application-custom.conf")
178+
configure("application-custom.conf") {
179+
put("config.test", "other")
174180
}
175181
externalServices {
176182
hosts("http://www.google.com") {

0 commit comments

Comments
 (0)