From 47d97f306f07fd41583b797eb85722134524a924 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Wed, 1 Dec 2021 19:36:07 +0100 Subject: [PATCH] Migrate from Spek to Kotest --- build.gradle.kts | 12 +- .../docker/compose/ComposeFileReaderTest.kt | 1310 +++++++++-------- .../compose/interpolation/TemplateTest.kt | 186 ++- 3 files changed, 757 insertions(+), 751 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8e63d68c..ae642ffd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -66,8 +66,7 @@ dependencies { // implementation("com.github.fge:json-schema-validator:2.2.6") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") - testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.17") - testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.17") + testImplementation("io.kotest:kotest-runner-junit5:4.6.4") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } @@ -79,7 +78,8 @@ val dependencyVersions = listOf( ) val dependencyGroupVersions = mapOf( - "org.junit.jupiter" to "5.8.1" + "org.junit.jupiter" to "5.8.1", + "org.junit.platform" to "1.8.1" ) configurations.all { @@ -105,10 +105,8 @@ tasks { kotlinOptions.jvmTarget = "1.8" } - withType(Test::class.java) { - useJUnitPlatform { - includeEngines("spek2") - } + withType { + useJUnitPlatform() } } diff --git a/src/test/kotlin/de/gesellix/docker/compose/ComposeFileReaderTest.kt b/src/test/kotlin/de/gesellix/docker/compose/ComposeFileReaderTest.kt index 6e97b35b..1e56609e 100644 --- a/src/test/kotlin/de/gesellix/docker/compose/ComposeFileReaderTest.kt +++ b/src/test/kotlin/de/gesellix/docker/compose/ComposeFileReaderTest.kt @@ -33,640 +33,648 @@ import de.gesellix.docker.compose.types.StackService import de.gesellix.docker.compose.types.StackVolume import de.gesellix.docker.compose.types.Ulimits import de.gesellix.docker.compose.types.UpdateConfig -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe +import io.kotest.core.spec.style.DescribeSpec import java.nio.file.Paths import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue -class ComposeFileReaderTest : Spek({ - - describe("a sample compose file") { - - context("ComposeFileReader().loadYaml(parse/sample.yaml)") { - - val composeFile = ComposeFileReaderTest::class.java.getResource("parse/sample.yaml") - val json = ComposeFileReaderTest::class.java.getResourceAsStream("parse/sample.json")?.let { inputStream -> - Parser.default().parse(inputStream) - } as JsonObject - val expected = json.map as HashMap - - var result = hashMapOf() - - beforeEachTest { - result = ComposeFileReader().loadYaml(composeFile.openStream()) as HashMap - } - it("should return the same content as the reference json") { - // TODO we should compare the complete objects with each other - //assertEquals(expected, result) - assertEquals(expected.keys, result.keys) - } - } - context("ComposeFileReader().load(sampleConfig)") { - - val composeFile = ComposeFileReaderTest::class.java.getResource("parse/sample.yaml") - var expected = ComposeConfig() - var result = ComposeConfig() - - beforeEachTest { - expected = newSampleConfig() - result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - } - - it("should return the same services as the reference") { - assertEquals(expected.services, result.services) - } - it("should return the same networks as the reference") { - assertEquals(expected.networks, result.networks) - } - it("should return the same volumes as the reference") { - assertEquals(expected.volumes, result.volumes) - } - it("should return the same secrets as the reference") { - assertEquals(expected.secrets, result.secrets) - } - it("should return the same result as the reference") { - assertEquals(expected.version, result.version) - } - } - } - - describe("environment") { +class ComposeFileReaderTest : DescribeSpec({ - context("environment/sample.yaml") { + describe("a sample compose file") { - val composeFile = ComposeFileReaderTest::class.java.getResource("environment/sample.yaml") - var expectedEnv = Environment() - var result = ComposeConfig() + context("ComposeFileReader().loadYaml(parse/sample.yaml)") { - beforeEachTest { - expectedEnv = Environment(hashMapOf( - Pair("FOO", "1"), - Pair("BAR", "2"), - Pair("BAZ", "2.5"), - Pair("QUUX", "") - )) - result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - } + val composeFile = ComposeFileReaderTest::class.java.getResource("parse/sample.yaml") + val json = ComposeFileReaderTest::class.java.getResourceAsStream("parse/sample.json")?.let { inputStream -> + Parser.default().parse(inputStream) + } as JsonObject + val expected = json.map as HashMap - it("should load environments as dict") { - assertEquals(expectedEnv, result.services!!.getValue("dict-env").environment) - } + val result = ComposeFileReader().loadYaml(composeFile.openStream()) as HashMap - it("should load environments as list") { - assertEquals(expectedEnv, result.services!!.getValue("list-env").environment) - } - } + it("should return the same content as the reference json") { + // TODO we should compare the complete objects with each other + //assertEquals(expected, result) + assertEquals(expected.keys, result.keys) + } + } + context("ComposeFileReader().load(sampleConfig)") { + + val composeFile = ComposeFileReaderTest::class.java.getResource("parse/sample.yaml") + val expected = newSampleConfig() + val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! + + it("should return the same services as the reference") { + assertEquals(expected.services, result.services) + } + it("should return the same networks as the reference") { + assertEquals(expected.networks, result.networks) + } + it("should return the same volumes as the reference") { + assertEquals(expected.volumes, result.volumes) + } + it("should return the same secrets as the reference") { + assertEquals(expected.secrets, result.secrets) + } + it("should return the same result as the reference") { + assertEquals(expected.version, result.version) + } } + } - describe("version 3.1") { + describe("environment") { - context("version_3_1/sample.yaml") { + context("environment/sample.yaml") { - val composeFile = ComposeFileReaderTest::class.java.getResource("version_3_1/sample.yaml") - val sampleConfig = newSampleConfigVersion_3_1() - var result = ComposeConfig() + val composeFile = ComposeFileReaderTest::class.java.getResource("environment/sample.yaml") + val expectedEnv = Environment( + hashMapOf( + Pair("FOO", "1"), + Pair("BAR", "2"), + Pair("BAZ", "2.5"), + Pair("QUUX", "") + ) + ) - beforeEachTest { - result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - } + val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - it("should load a config based on a 3.1 schema") { - assertEquals(sampleConfig.services, result.services) - assertEquals(sampleConfig.secrets, result.secrets) - assertEquals(sampleConfig, result) - } - } - } + it("should load environments as dict") { + assertEquals(expectedEnv, result.services!!.getValue("dict-env").environment) + } - describe("attachable") { + it("should load environments as list") { + assertEquals(expectedEnv, result.services!!.getValue("list-env").environment) + } + } + } - context("attachable/sample.yaml") { + describe("version 3.1") { - val composeFile = ComposeFileReaderTest::class.java.getResource("attachable/sample.yaml") - val sampleConfig = hashMapOf().apply { - put("mynet1", StackNetwork(driver = "overlay", attachable = true)) - put("mynet2", StackNetwork(driver = "bridge", attachable = false)) - } - var result = ComposeConfig() + context("version_3_1/sample.yaml") { - beforeEachTest { - result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - } + val composeFile = ComposeFileReaderTest::class.java.getResource("version_3_1/sample.yaml") + val sampleConfig = newSampleConfigVersion_3_1() + val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - it("should load a config with attachable networks") { - assertEquals(sampleConfig["mynet1"], result.networks!!["mynet1"]) - assertEquals(sampleConfig["mynet2"], result.networks!!["mynet2"]) - } - } + it("should load a config based on a 3.1 schema") { + assertEquals(sampleConfig.services, result.services) + assertEquals(sampleConfig.secrets, result.secrets) + assertEquals(sampleConfig, result) + } } + } + + describe("attachable") { - describe("portformats") { + context("attachable/sample.yaml") { - context("portformats/sample.yaml") { - val composeFile = ComposeFileReaderTest::class.java.getResource("portformats/sample.yaml") - val sampleConfig = newSampleConfigPortFormats() - val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! + val composeFile = ComposeFileReaderTest::class.java.getResource("attachable/sample.yaml") + val sampleConfig = hashMapOf().apply { + put("mynet1", StackNetwork(driver = "overlay", attachable = true)) + put("mynet2", StackNetwork(driver = "bridge", attachable = false)) + } + val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - it("should load expanded port formats") { - assertEquals(sampleConfig, result.services!!.getValue("web").ports) - } - } + it("should load a config with attachable networks") { + assertEquals(sampleConfig["mynet1"], result.networks!!["mynet1"]) + assertEquals(sampleConfig["mynet2"], result.networks!!["mynet2"]) + } } + } - describe("interpolation") { - - context("interpolation/sample.yaml") { - - val composeFile = ComposeFileReaderTest::class.java.getResource("interpolation/sample.yaml") - val home = "/home/foo" - val expectedLabels = Labels(hashMapOf().apply { - put("home1", home) - put("home2", home) - put("nonexistent", "") - put("default", "default") - }) - val result = ComposeFileReader().load( - composeFile.openStream(), - Paths.get(composeFile.toURI()).parent.toString(), - hashMapOf( - Pair("HOME", home), - Pair("FOO", "foo")) - )!! - - it("should interpolate environment variables") { - assertEquals(expectedLabels, result.services!!.getValue("test").labels) - assertEquals(home, result.networks!!["test"]!!.driver) - assertEquals(home, result.volumes!!["test"]!!.driver) - } - } + describe("portformats") { + + context("portformats/sample.yaml") { + val composeFile = ComposeFileReaderTest::class.java.getResource("portformats/sample.yaml") + val sampleConfig = newSampleConfigPortFormats() + val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! + + it("should load expanded port formats") { + assertEquals(sampleConfig, result.services!!.getValue("web").ports) + } + } + } + + describe("interpolation") { + + context("interpolation/sample.yaml") { + + val composeFile = ComposeFileReaderTest::class.java.getResource("interpolation/sample.yaml") + val home = "/home/foo" + val expectedLabels = Labels(hashMapOf().apply { + put("home1", home) + put("home2", home) + put("nonexistent", "") + put("default", "default") + }) + val result = ComposeFileReader().load( + composeFile.openStream(), + Paths.get(composeFile.toURI()).parent.toString(), + hashMapOf( + Pair("HOME", home), + Pair("FOO", "foo") + ) + )!! + + it("should interpolate environment variables") { + assertEquals(expectedLabels, result.services!!.getValue("test").labels) + assertEquals(home, result.networks!!["test"]!!.driver) + assertEquals(home, result.volumes!!["test"]!!.driver) + } } + } - describe("full sample") { + describe("full sample") { - context("full/sample.yaml") { + context("full/sample.yaml") { - val composeFile = ComposeFileReaderTest::class.java.getResource("full/sample.yaml") - val sampleConfig = newSampleConfigFull() - val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! + val composeFile = ComposeFileReaderTest::class.java.getResource("full/sample.yaml") + val sampleConfig = newSampleConfigFull() + val result = ComposeFileReader().load(composeFile.openStream(), Paths.get(composeFile.toURI()).parent.toString(), System.getenv())!! - it("should load all top level attributes") { - assertEquals(sampleConfig.version, result.version) - assertEquals(sampleConfig.volumes, result.volumes) - assertEquals(sampleConfig.networks, result.networks) - assertEquals(sampleConfig.services, result.services) - assertEquals(sampleConfig.secrets, result.secrets) + it("should load all top level attributes") { + assertEquals(sampleConfig.version, result.version) + assertEquals(sampleConfig.volumes, result.volumes) + assertEquals(sampleConfig.networks, result.networks) + assertEquals(sampleConfig.services, result.services) + assertEquals(sampleConfig.secrets, result.secrets) // assertEquals(sampleConfig.configs, result.configs) - assertEquals(sampleConfig, result) - } - } + assertEquals(sampleConfig, result) + } } + } - describe("volumes") { + describe("volumes") { - context("volumes/sample.yaml") { + context("volumes/sample.yaml") { - val composeFile = ComposeFileReaderTest::class.java.getResource("volumes/sample.yaml") - val workingDir = Paths.get(composeFile.toURI()).parent.toString() - val result = ComposeFileReader().load(composeFile.openStream(), workingDir, System.getenv())!! + val composeFile = ComposeFileReaderTest::class.java.getResource("volumes/sample.yaml") + val workingDir = Paths.get(composeFile.toURI()).parent.toString() + val result = ComposeFileReader().load(composeFile.openStream(), workingDir, System.getenv())!! - it("should set volume type") { - assertEquals(ServiceVolumeType.TypeBind.typeName, result.services!!.getValue("foo").volumes!!.first().type) - } - } + it("should set volume type") { + assertEquals(ServiceVolumeType.TypeBind.typeName, result.services!!.getValue("foo").volumes!!.first().type) + } } - - describe("configs") { - - context("configs/sample.yaml") { - - val composeFile = ComposeFileReaderTest::class.java.getResource("configs/sample.yaml") - val workingDir = Paths.get(composeFile.toURI()).parent.toString() - val result = ComposeFileReader().load(composeFile.openStream(), workingDir, System.getenv())!! - - val configs = result.services!!.getValue("foo").configs!! - it("should have 3 config") { - assertEquals(3, configs.size) - } - - it("config external") { - assertTrue(configs[0].containsKey("config-external")) - assertNotNull(configs[0]["config-external"]) - val serviceConfig = configs[0]["config-external"]!! - assertEquals("config-external", serviceConfig.source) - assertEquals("/config/external.txt", serviceConfig.target) - assertEquals("1000", serviceConfig.uid) - assertEquals("1000", serviceConfig.gid) - assertEquals("444", serviceConfig.mode.toString(8)) - } - it("config file") { - assertTrue(configs[1].containsKey("config-file")) - assertNotNull(configs[1]["config-file"]) - val serviceConfig = configs[1]["config-file"]!! - assertEquals("config-file", serviceConfig.source) - assertEquals("/config/file.txt", serviceConfig.target) - assertEquals("1000", serviceConfig.uid) - assertEquals("1000", serviceConfig.gid) - assertEquals("644", serviceConfig.mode.toString(8)) - } - it("config short format") { - assertTrue(configs[2].containsKey("config-short")) - assertNull(configs[2]["config-short"]) - } - } + } + + describe("configs") { + + context("configs/sample.yaml") { + + val composeFile = ComposeFileReaderTest::class.java.getResource("configs/sample.yaml") + val workingDir = Paths.get(composeFile.toURI()).parent.toString() + val result = ComposeFileReader().load(composeFile.openStream(), workingDir, System.getenv())!! + + val configs = result.services!!.getValue("foo").configs!! + it("should have 3 config") { + assertEquals(3, configs.size) + } + + it("config external") { + assertTrue(configs[0].containsKey("config-external")) + assertNotNull(configs[0]["config-external"]) + val serviceConfig = configs[0]["config-external"]!! + assertEquals("config-external", serviceConfig.source) + assertEquals("/config/external.txt", serviceConfig.target) + assertEquals("1000", serviceConfig.uid) + assertEquals("1000", serviceConfig.gid) + assertEquals("444", serviceConfig.mode.toString(8)) + } + it("config file") { + assertTrue(configs[1].containsKey("config-file")) + assertNotNull(configs[1]["config-file"]) + val serviceConfig = configs[1]["config-file"]!! + assertEquals("config-file", serviceConfig.source) + assertEquals("/config/file.txt", serviceConfig.target) + assertEquals("1000", serviceConfig.uid) + assertEquals("1000", serviceConfig.gid) + assertEquals("644", serviceConfig.mode.toString(8)) + } + it("config short format") { + assertTrue(configs[2].containsKey("config-short")) + assertNull(configs[2]["config-short"]) + } } + } }) fun newSampleConfigPortFormats(): PortConfigs { - return PortConfigs(listOf( - PortConfig( - "ingress", - 8080, - 80, - "tcp" - ), - PortConfig( - "ingress", - 8081, - 81, - "tcp" - ), - PortConfig( - "ingress", - 8082, - 82, - "tcp" - ), - PortConfig( - "ingress", - 8090, - 90, - "udp" - ), - PortConfig( - "ingress", - 8091, - 91, - "udp" - ), - PortConfig( - "ingress", - 8092, - 92, - "udp" - ), - PortConfig( - "ingress", - 8500, - 85, - "tcp" - ), - PortConfig( - "ingress", - 8600, - 0, - "tcp" - ), - PortConfig( - "", - 53, - 10053, - "udp" - ), - PortConfig( - "host", - 22, - 10022, - "" - ) - )) + return PortConfigs( + listOf( + PortConfig( + "ingress", + 8080, + 80, + "tcp" + ), + PortConfig( + "ingress", + 8081, + 81, + "tcp" + ), + PortConfig( + "ingress", + 8082, + 82, + "tcp" + ), + PortConfig( + "ingress", + 8090, + 90, + "udp" + ), + PortConfig( + "ingress", + 8091, + 91, + "udp" + ), + PortConfig( + "ingress", + 8092, + 92, + "udp" + ), + PortConfig( + "ingress", + 8500, + 85, + "tcp" + ), + PortConfig( + "ingress", + 8600, + 0, + "tcp" + ), + PortConfig( + "", + 53, + 10053, + "udp" + ), + PortConfig( + "host", + 22, + 10022, + "" + ) + ) + ) } fun newSampleConfig(): ComposeConfig { - return ComposeConfig( - "3", - hashMapOf().apply { - put("foo", StackService( - image = "busybox", - environment = Environment(), - networks = hashMapOf(Pair("with_me", null))) - ) - put("bar", StackService( - image = "busybox", - environment = Environment(entries = hashMapOf(Pair("FOO", "1"))), - networks = hashMapOf(Pair("with_ipam", null))) - ) - }, - hashMapOf().apply { - put("default", StackNetwork( - driver = "bridge", - driverOpts = DriverOpts(options = hashMapOf(Pair("beep", "boop")))) - ) - put("with_ipam", StackNetwork( - ipam = Ipam( - driver = "default", - config = listOf(IpamConfig(subnet = "172.28.0.0/16")))) - ) - }, - hashMapOf().apply { - put("hello", StackVolume( - driver = "default", - driverOpts = DriverOpts(options = hashMapOf(Pair("beep", "boop"))) - )) - } - ) + return ComposeConfig( + "3", + hashMapOf().apply { + put( + "foo", StackService( + image = "busybox", + environment = Environment(), + networks = hashMapOf(Pair("with_me", null)) + ) + ) + put( + "bar", StackService( + image = "busybox", + environment = Environment(entries = hashMapOf(Pair("FOO", "1"))), + networks = hashMapOf(Pair("with_ipam", null)) + ) + ) + }, + hashMapOf().apply { + put( + "default", StackNetwork( + driver = "bridge", + driverOpts = DriverOpts(options = hashMapOf(Pair("beep", "boop"))) + ) + ) + put( + "with_ipam", StackNetwork( + ipam = Ipam( + driver = "default", + config = listOf(IpamConfig(subnet = "172.28.0.0/16")) + ) + ) + ) + }, + hashMapOf().apply { + put( + "hello", StackVolume( + driver = "default", + driverOpts = DriverOpts(options = hashMapOf(Pair("beep", "boop"))) + ) + ) + } + ) } fun newSampleConfigVersion_3_1(): ComposeConfig { - return ComposeConfig( - version = "3.1", - services = hashMapOf().apply { - put("foo", StackService( - image = "busybox", - secrets = arrayListOf( - hashMapOf(Pair("super", null)), - // 292 decimal == 0444 octal - hashMapOf(Pair("duper", ServiceSecret(source = "duper", mode = 292)))))) - }, - secrets = hashMapOf().apply { - put("super", StackSecret(external = External(external = true))) - put("duper", StackSecret(external = External(external = true))) - }) + return ComposeConfig( + version = "3.1", + services = hashMapOf().apply { + put( + "foo", StackService( + image = "busybox", + secrets = arrayListOf( + hashMapOf(Pair("super", null)), + // 292 decimal == 0444 octal + hashMapOf(Pair("duper", ServiceSecret(source = "duper", mode = 292))) + ) + ) + ) + }, + secrets = hashMapOf().apply { + put("super", StackSecret(external = External(external = true))) + put("duper", StackSecret(external = External(external = true))) + }) } fun newSampleConfigFull(): ComposeConfig { // workingDir, err := os.Getwd() // homeDir := os.Getenv("HOME") - val fooService = StackService( - capAdd = setOf("ALL"), - capDrop = setOf("NET_ADMIN", "SYS_ADMIN"), - cgroupParent = "m-executor-abcd", - command = Command(parts = arrayListOf("bundle", "exec", "thin", "-p", "3000")), - containerName = "my-web-container", - dependsOn = setOf( - "db", - "redis" - ), - deploy = Deploy( - mode = "replicated", - replicas = 6, - labels = Labels(hashMapOf(Pair("FOO", "BAR"))), - updateConfig = UpdateConfig( - parallelism = 3, - delay = "10s", - failureAction = "continue", - monitor = "60s", - maxFailureRatio = 0.3f, - order = "start-first" - ), - resources = Resources( - limits = Limits( - nanoCpus = "0.001", - memory = "50M" - ), - reservations = Reservations( - nanoCpus = "0.0001", - memory = "20M" - ) - ), - restartPolicy = RestartPolicy( - condition = "on-failure", - delay = "5s", - maxAttempts = 3, - window = "120s" - ), - placement = Placement(constraints = listOf("node=foo")) - ), - devices = setOf("/dev/ttyUSB0:/dev/ttyUSB0"), - dns = listOf( - "8.8.8.8", - "9.9.9.9" - ), - dnsSearch = listOf( - "dc1.example.com", - "dc2.example.com"), - domainname = "foo.com", - entrypoint = Entrypoint(parts = arrayListOf("/code/entrypoint.sh", "-p", "3000")), - envFile = listOf( - "./example1.env", - "./example2.env" - ), - environment = Environment(hashMapOf().apply { - put("RACK_ENV", "development") - put("SHOW", "true") - put("SESSION_SECRET", "") + val fooService = StackService( + capAdd = setOf("ALL"), + capDrop = setOf("NET_ADMIN", "SYS_ADMIN"), + cgroupParent = "m-executor-abcd", + command = Command(parts = arrayListOf("bundle", "exec", "thin", "-p", "3000")), + containerName = "my-web-container", + dependsOn = setOf( + "db", + "redis" + ), + deploy = Deploy( + mode = "replicated", + replicas = 6, + labels = Labels(hashMapOf(Pair("FOO", "BAR"))), + updateConfig = UpdateConfig( + parallelism = 3, + delay = "10s", + failureAction = "continue", + monitor = "60s", + maxFailureRatio = 0.3f, + order = "start-first" + ), + resources = Resources( + limits = Limits( + nanoCpus = "0.001", + memory = "50M" + ), + reservations = Reservations( + nanoCpus = "0.0001", + memory = "20M" + ) + ), + restartPolicy = RestartPolicy( + condition = "on-failure", + delay = "5s", + maxAttempts = 3, + window = "120s" + ), + placement = Placement(constraints = listOf("node=foo")) + ), + devices = setOf("/dev/ttyUSB0:/dev/ttyUSB0"), + dns = listOf( + "8.8.8.8", + "9.9.9.9" + ), + dnsSearch = listOf( + "dc1.example.com", + "dc2.example.com" + ), + domainname = "foo.com", + entrypoint = Entrypoint(parts = arrayListOf("/code/entrypoint.sh", "-p", "3000")), + envFile = listOf( + "./example1.env", + "./example2.env" + ), + environment = Environment(hashMapOf().apply { + put("RACK_ENV", "development") + put("SHOW", "true") + put("SESSION_SECRET", "") // put("FOO", "1") // put("BAR", "2") - put("BAZ", "3") - }), - expose = Exposes(arrayListOf("3000", - "8000")), - externalLinks = setOf( - "redis_1", - "project_db_1:mysql", - "project_db_1:postgresql" - ), - extraHosts = ExtraHosts(hashMapOf().apply { - put("otherhost", "50.31.209.229") - put("somehost", "162.242.195.82") - }), - // HealthCheck: &types.HealthCheckConfig{ + put("BAZ", "3") + }), + expose = Exposes( + arrayListOf( + "3000", + "8000" + ) + ), + externalLinks = setOf( + "redis_1", + "project_db_1:mysql", + "project_db_1:postgresql" + ), + extraHosts = ExtraHosts(hashMapOf().apply { + put("otherhost", "50.31.209.229") + put("somehost", "162.242.195.82") + }), + // HealthCheck: &types.HealthCheckConfig{ // Test: types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}), // }, - healthcheck = Healthcheck( - interval = "10s", - retries = 5f, - test = Command(parts = arrayListOf("echo \"hello world\"")), - timeout = "1s" - ), - hostname = "foo", - image = "redis", - ipc = "host", - labels = Labels(hashMapOf().apply { - put("com.example.description", "Accounting webapp") - put("com.example.number", "42") - put("com.example.empty-label", "") - }), - links = setOf( - "db", - "db:database", - "redis" - ), - logging = Logging( - driver = "syslog", - options = hashMapOf(Pair("syslog-address", "tcp://192.168.0.42:123")) - ), - networks = hashMapOf().apply { - put("some-network", ServiceNetwork( - aliases = listOf("alias1", "alias3") - )) - put("other-network", ServiceNetwork( - ipv4Address = "172.16.238.10", - ipv6Address = "2001:3984:3989::10" - )) - put("other-other-network", null) - }, - macAddress = "02:42:ac:11:65:43", - networkMode = "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b", - pid = "host", - ports = PortConfigs( - listOf( - PortConfig( - "ingress", - 3000, - 0, - "tcp" - ), - PortConfig( - "ingress", - 3000, - 0, - "tcp" - ), - PortConfig( - "ingress", - 3001, - 0, - "tcp" - ), - PortConfig( - "ingress", - 3002, - 0, - "tcp" - ), - PortConfig( - "ingress", - 3003, - 0, - "tcp" - ), - PortConfig( - "ingress", - 3004, - 0, - "tcp" - ), - PortConfig( - "ingress", - 3005, - 0, - "tcp" - ), - PortConfig( - "ingress", - 8000, - 8000, - "tcp" - ), - PortConfig( - "ingress", - 8080, - 9090, - "tcp" - ), - PortConfig( - "ingress", - 8081, - 9091, - "tcp" - ), - PortConfig( - "ingress", - 22, - 49100, - "tcp" - ), - PortConfig( - "ingress", - 8001, - 8001, - "tcp" - ), - PortConfig( - "ingress", - 5000, - 5000, - "tcp" - ), - PortConfig( - "ingress", - 5001, - 5001, - "tcp" - ), - PortConfig( - "ingress", - 5002, - 5002, - "tcp" - ), - PortConfig( - "ingress", - 5003, - 5003, - "tcp" - ), - PortConfig( - "ingress", - 5004, - 5004, - "tcp" - ), - PortConfig( - "ingress", - 5005, - 5005, - "tcp" - ), - PortConfig( - "ingress", - 5006, - 5006, - "tcp" - ), - PortConfig( - "ingress", - 5007, - 5007, - "tcp" - ), - PortConfig( - "ingress", - 5008, - 5008, - "tcp" - ), - PortConfig( - "ingress", - 5009, - 5009, - "tcp" - ), - PortConfig( - "ingress", - 5010, - 5010, - "tcp" - ) - ) - ), - privileged = true, - readOnly = true, - restart = "always", - securityOpt = setOf( - "label=level:s0:c100,c200", - "label=type:svirt_apache_t" - ), - stdinOpen = true, - stopGracePeriod = "20s", - stopSignal = "SIGUSR1", - tmpfs = listOf("/run", "/tmp"), - tty = true, - // Ulimits: map[string]*types.UlimitsConfig{ + healthcheck = Healthcheck( + interval = "10s", + retries = 5f, + test = Command(parts = arrayListOf("echo \"hello world\"")), + timeout = "1s" + ), + hostname = "foo", + image = "redis", + ipc = "host", + labels = Labels(hashMapOf().apply { + put("com.example.description", "Accounting webapp") + put("com.example.number", "42") + put("com.example.empty-label", "") + }), + links = setOf( + "db", + "db:database", + "redis" + ), + logging = Logging( + driver = "syslog", + options = hashMapOf(Pair("syslog-address", "tcp://192.168.0.42:123")) + ), + networks = hashMapOf().apply { + put( + "some-network", ServiceNetwork( + aliases = listOf("alias1", "alias3") + ) + ) + put( + "other-network", ServiceNetwork( + ipv4Address = "172.16.238.10", + ipv6Address = "2001:3984:3989::10" + ) + ) + put("other-other-network", null) + }, + macAddress = "02:42:ac:11:65:43", + networkMode = "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b", + pid = "host", + ports = PortConfigs( + listOf( + PortConfig( + "ingress", + 3000, + 0, + "tcp" + ), + PortConfig( + "ingress", + 3000, + 0, + "tcp" + ), + PortConfig( + "ingress", + 3001, + 0, + "tcp" + ), + PortConfig( + "ingress", + 3002, + 0, + "tcp" + ), + PortConfig( + "ingress", + 3003, + 0, + "tcp" + ), + PortConfig( + "ingress", + 3004, + 0, + "tcp" + ), + PortConfig( + "ingress", + 3005, + 0, + "tcp" + ), + PortConfig( + "ingress", + 8000, + 8000, + "tcp" + ), + PortConfig( + "ingress", + 8080, + 9090, + "tcp" + ), + PortConfig( + "ingress", + 8081, + 9091, + "tcp" + ), + PortConfig( + "ingress", + 22, + 49100, + "tcp" + ), + PortConfig( + "ingress", + 8001, + 8001, + "tcp" + ), + PortConfig( + "ingress", + 5000, + 5000, + "tcp" + ), + PortConfig( + "ingress", + 5001, + 5001, + "tcp" + ), + PortConfig( + "ingress", + 5002, + 5002, + "tcp" + ), + PortConfig( + "ingress", + 5003, + 5003, + "tcp" + ), + PortConfig( + "ingress", + 5004, + 5004, + "tcp" + ), + PortConfig( + "ingress", + 5005, + 5005, + "tcp" + ), + PortConfig( + "ingress", + 5006, + 5006, + "tcp" + ), + PortConfig( + "ingress", + 5007, + 5007, + "tcp" + ), + PortConfig( + "ingress", + 5008, + 5008, + "tcp" + ), + PortConfig( + "ingress", + 5009, + 5009, + "tcp" + ), + PortConfig( + "ingress", + 5010, + 5010, + "tcp" + ) + ) + ), + privileged = true, + readOnly = true, + restart = "always", + securityOpt = setOf( + "label=level:s0:c100,c200", + "label=type:svirt_apache_t" + ), + stdinOpen = true, + stopGracePeriod = "20s", + stopSignal = "SIGUSR1", + tmpfs = listOf("/run", "/tmp"), + tty = true, + // Ulimits: map[string]*types.UlimitsConfig{ // "nproc": { // Single: 65535, // }, @@ -675,9 +683,9 @@ fun newSampleConfigFull(): ComposeConfig { // Hard: 40000, // }, // }, - ulimits = Ulimits(), - user = "someone", - // Volumes: []string{ + ulimits = Ulimits(), + user = "someone", + // Volumes: []string{ // "/var/lib/mysql", // "/opt/data:/var/lib/mysql", // fmt.Sprintf("%s:/code", workingDir), @@ -685,70 +693,92 @@ fun newSampleConfigFull(): ComposeConfig { // fmt.Sprintf("%s/configs:/etc/configs/:ro", homeDir), // "datavolume:/var/lib/mysql", // }, - volumes = arrayListOf( - ServiceVolume(type = ServiceVolumeType.TypeVolume.typeName, target = "/var/lib/mysql"), - ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "/opt/data", target = "/var/lib/mysql"), - ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = ".", target = "/code"), - ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "./static", target = "/var/www/html"), - ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "~/configs", target = "/etc/configs/", readOnly = true), - ServiceVolume(type = ServiceVolumeType.TypeVolume.typeName, source = "datavolume", target = "/var/lib/mysql"), - ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "./opt", target = "/opt", consistency = "cached")), - workingDir = "/code" + volumes = arrayListOf( + ServiceVolume(type = ServiceVolumeType.TypeVolume.typeName, target = "/var/lib/mysql"), + ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "/opt/data", target = "/var/lib/mysql"), + ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = ".", target = "/code"), + ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "./static", target = "/var/www/html"), + ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "~/configs", target = "/etc/configs/", readOnly = true), + ServiceVolume(type = ServiceVolumeType.TypeVolume.typeName, source = "datavolume", target = "/var/lib/mysql"), + ServiceVolume(type = ServiceVolumeType.TypeBind.typeName, source = "./opt", target = "/opt", consistency = "cached") + ), + workingDir = "/code" + ) + + val composeConfig = ComposeConfig() + + composeConfig.version = "3.4" + + composeConfig.services = hashMapOf(Pair("foo", fooService)) + + composeConfig.networks = hashMapOf().apply { + put("some-network", null) + put( + "other-network", StackNetwork( + driver = "overlay", + driverOpts = DriverOpts(hashMapOf().apply { + put("foo", "bar") + put("baz", "1") + }), + ipam = Ipam( + driver = "overlay", + config = listOf( + IpamConfig("172.16.238.0/24"), + IpamConfig("2001:3984:3989::/64") + ) + ) + ) ) + put( + "external-network", StackNetwork( + external = External( + //name = "external-network", + external = true + ) + ) + ) + put( + "other-external-network", StackNetwork( + external = External( + name = "my-cool-network", + external = true + ) + ) + ) + } + + composeConfig.volumes = hashMapOf().apply { + put("some-volume", null) + put( + "other-volume", StackVolume( + driver = "flocker", + driverOpts = DriverOpts( + hashMapOf( + Pair("foo", "bar"), + Pair("baz", "1") + ) + ) + ) + ) + put( + "external-volume", StackVolume( + external = External( + //name = "external-volume", + external = true + ) + ) + ) + put( + "other-external-volume", StackVolume( + external = External( + name = "my-cool-volume", + external = true + ) + ) + ) + } - val composeConfig = ComposeConfig() - - composeConfig.version = "3.4" - - composeConfig.services = hashMapOf(Pair("foo", fooService)) - - composeConfig.networks = hashMapOf().apply { - put("some-network", null) - put("other-network", StackNetwork( - driver = "overlay", - driverOpts = DriverOpts(hashMapOf().apply { - put("foo", "bar") - put("baz", "1") - }), - ipam = Ipam( - driver = "overlay", - config = listOf( - IpamConfig("172.16.238.0/24"), - IpamConfig("2001:3984:3989::/64"))))) - put("external-network", StackNetwork( - external = External( - //name = "external-network", - external = true) - )) - put("other-external-network", StackNetwork( - external = External( - name = "my-cool-network", - external = true) - )) - } - - composeConfig.volumes = hashMapOf().apply { - put("some-volume", null) - put("other-volume", StackVolume( - driver = "flocker", - driverOpts = DriverOpts(hashMapOf( - Pair("foo", "bar"), - Pair("baz", "1") - )) - )) - put("external-volume", StackVolume( - external = External( - //name = "external-volume", - external = true) - )) - put("other-external-volume", StackVolume( - external = External( - name = "my-cool-volume", - external = true) - )) - } - - composeConfig.secrets = null + composeConfig.secrets = null - return composeConfig + return composeConfig } diff --git a/src/test/kotlin/de/gesellix/docker/compose/interpolation/TemplateTest.kt b/src/test/kotlin/de/gesellix/docker/compose/interpolation/TemplateTest.kt index 69d125a2..00bb439d 100644 --- a/src/test/kotlin/de/gesellix/docker/compose/interpolation/TemplateTest.kt +++ b/src/test/kotlin/de/gesellix/docker/compose/interpolation/TemplateTest.kt @@ -1,128 +1,106 @@ package de.gesellix.docker.compose.interpolation -import org.spekframework.spek2.Spek -import org.spekframework.spek2.style.specification.describe +import io.kotest.core.spec.style.DescribeSpec import kotlin.test.assertEquals import kotlin.test.assertFailsWith -class TemplateTest : Spek({ +class TemplateTest : DescribeSpec({ - describe("Template") { - val defaults = hashMapOf().apply { - put("FOO", "first") - put("BAR", "") - } + describe("Template") { + val defaults = hashMapOf().apply { + put("FOO", "first") + put("BAR", "") + } - context("an escaped template") { - val t = "\$\${foo}" - var rendered = "" - beforeEachTest { - rendered = Template().substitute(t, defaults) - } + context("an escaped template") { + val t = "\$\${foo}" + val rendered = Template().substitute(t, defaults) - it("should return the un-escaped input '\${foo}'") { - assertEquals("\${foo}", rendered) - } - } + it("should return the un-escaped input '\${foo}'") { + assertEquals("\${foo}", rendered) + } + } - context("an invalid template") { - listOf( - "\${", - "\$}", - "\${}", - "\${ }", - "\${ foo}", - "\${foo }", - "\${foo!}" - ).forEach { t -> - it("should fail for $t") { - assertFailsWith(Exception::class) { Template().substitute(t, defaults) } - } - } + context("an invalid template") { + listOf( + "\${", + "\$}", + "\${}", + "\${ }", + "\${ foo}", + "\${foo }", + "\${foo!}" + ).forEach { t -> + it("should fail for $t") { + assertFailsWith(Exception::class) { Template().substitute(t, defaults) } } + } + } - context("a template without value and without default") { - listOf( - "This \${missing} var", - "This \${BAR} var" - ).forEach { t -> - var rendered = "" - beforeEachTest { - rendered = Template().substitute(t, defaults) - } - - it("should render $t as 'This var'") { - assertEquals("This var", rendered) - } - } - } + context("a template without value and without default") { + listOf( + "This \${missing} var", + "This \${BAR} var" + ).forEach { t -> + val rendered = Template().substitute(t, defaults) - context("a template with value and without default") { - listOf( - "This \$FOO var", - "This \${FOO} var" - ).forEach { t -> - var rendered = "" - beforeEachTest { - rendered = Template().substitute(t, defaults) - } - - it("should render $t as 'This first var'") { - assertEquals("This first var", rendered) - } - } + it("should render $t as 'This var'") { + assertEquals("This var", rendered) } + } + } + + context("a template with value and without default") { + listOf( + "This \$FOO var", + "This \${FOO} var" + ).forEach { t -> + val rendered = Template().substitute(t, defaults) - context("a template without value but with default") { - listOf( - "ok \${missing:-def}", - "ok \${missing-def}" - ).forEach { t -> - var rendered = "" - beforeEachTest { - rendered = Template().substitute(t, defaults) - } - - it("should render $t as 'ok def'") { - assertEquals("ok def", rendered) - } - } + it("should render $t as 'This first var'") { + assertEquals("This first var", rendered) } + } + } - context("a template with empty value but with soft default") { - val t = "ok \${BAR:-def}" - var rendered = "" - beforeEachTest { - rendered = Template().substitute(t, defaults) - } + context("a template without value but with default") { + listOf( + "ok \${missing:-def}", + "ok \${missing-def}" + ).forEach { t -> + val rendered = Template().substitute(t, defaults) - it("should render $t as 'ok def'") { - assertEquals("ok def", rendered) - } + it("should render $t as 'ok def'") { + assertEquals("ok def", rendered) } + } + } - context("a template with empty value but with hard default") { - val t = "ok \${BAR-def}" - var rendered = "" - beforeEachTest { - rendered = Template().substitute(t, defaults) - } + context("a template with empty value but with soft default") { + val t = "ok \${BAR:-def}" + val rendered = Template().substitute(t, defaults) - it("should render $t as 'ok def'") { - assertEquals("ok ", rendered) - } - } + it("should render $t as 'ok def'") { + assertEquals("ok def", rendered) + } + } - context("a non alphanumeric default") { - val t = "ok \${BAR:-/non:-alphanumeric}" - var rendered = "" - beforeEachTest { - rendered = Template().substitute(t, defaults) - } + context("a template with empty value but with hard default") { + val t = "ok \${BAR-def}" + val rendered = Template().substitute(t, defaults) - it("should render $t as 'ok /non:-alphanumeric'") { - assertEquals("ok /non:-alphanumeric", rendered) - } - } + it("should render $t as 'ok def'") { + assertEquals("ok ", rendered) + } + } + + context("a non alphanumeric default") { + val t = "ok \${BAR:-/non:-alphanumeric}" + val rendered = Template().substitute(t, defaults) + + it("should render $t as 'ok /non:-alphanumeric'") { + assertEquals("ok /non:-alphanumeric", rendered) + } } + } })