diff --git a/api/docker-kotlin.api b/api/docker-kotlin.api index f988c7e2..94afce3e 100644 --- a/api/docker-kotlin.api +++ b/api/docker-kotlin.api @@ -2546,19 +2546,18 @@ public final class me/devnatan/dockerkt/models/image/ImageRootFs$Companion { public final class me/devnatan/dockerkt/models/image/ImageSummary { public static final field Companion Lme/devnatan/dockerkt/models/image/ImageSummary$Companion; - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;IJIJLjava/util/Map;I)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;IJILjava/util/Map;I)V public final fun component1 ()Ljava/lang/String; - public final fun component10 ()I public final fun component2 ()Ljava/lang/String; public final fun component3 ()Ljava/util/List; public final fun component4 ()Ljava/util/List; public final fun component5 ()I public final fun component6 ()J public final fun component7 ()I - public final fun component8 ()J - public final fun component9 ()Ljava/util/Map; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;IJIJLjava/util/Map;I)Lme/devnatan/dockerkt/models/image/ImageSummary; - public static synthetic fun copy$default (Lme/devnatan/dockerkt/models/image/ImageSummary;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;IJIJLjava/util/Map;IILjava/lang/Object;)Lme/devnatan/dockerkt/models/image/ImageSummary; + public final fun component8 ()Ljava/util/Map; + public final fun component9 ()I + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;IJILjava/util/Map;I)Lme/devnatan/dockerkt/models/image/ImageSummary; + public static synthetic fun copy$default (Lme/devnatan/dockerkt/models/image/ImageSummary;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;IJILjava/util/Map;IILjava/lang/Object;)Lme/devnatan/dockerkt/models/image/ImageSummary; public fun equals (Ljava/lang/Object;)Z public final fun getContainers ()I public final fun getCreated ()I @@ -2569,7 +2568,6 @@ public final class me/devnatan/dockerkt/models/image/ImageSummary { public final fun getRepositoryTags ()Ljava/util/List; public final fun getSharedSize ()I public final fun getSize ()J - public final fun getVirtualSize ()J public fun hashCode ()I public fun toString ()Ljava/lang/String; } diff --git a/api/docker-kotlin.klib.api b/api/docker-kotlin.klib.api index 0d48e7be..60fd9dcd 100644 --- a/api/docker-kotlin.klib.api +++ b/api/docker-kotlin.klib.api @@ -1571,7 +1571,7 @@ final class me.devnatan.dockerkt.models.image/ImageRootFs { // me.devnatan.docke } final class me.devnatan.dockerkt.models.image/ImageSummary { // me.devnatan.dockerkt.models.image/ImageSummary|null[0] - constructor (kotlin/String, kotlin/String, kotlin.collections/List, kotlin.collections/List, kotlin/Int, kotlin/Long, kotlin/Int, kotlin/Long, kotlin.collections/Map?, kotlin/Int) // me.devnatan.dockerkt.models.image/ImageSummary.|(kotlin.String;kotlin.String;kotlin.collections.List;kotlin.collections.List;kotlin.Int;kotlin.Long;kotlin.Int;kotlin.Long;kotlin.collections.Map?;kotlin.Int){}[0] + constructor (kotlin/String, kotlin/String, kotlin.collections/List, kotlin.collections/List, kotlin/Int, kotlin/Long, kotlin/Int, kotlin.collections/Map?, kotlin/Int) // me.devnatan.dockerkt.models.image/ImageSummary.|(kotlin.String;kotlin.String;kotlin.collections.List;kotlin.collections.List;kotlin.Int;kotlin.Long;kotlin.Int;kotlin.collections.Map?;kotlin.Int){}[0] final val containers // me.devnatan.dockerkt.models.image/ImageSummary.containers|{}containers[0] final fun (): kotlin/Int // me.devnatan.dockerkt.models.image/ImageSummary.containers.|(){}[0] @@ -1591,20 +1591,17 @@ final class me.devnatan.dockerkt.models.image/ImageSummary { // me.devnatan.dock final fun (): kotlin/Int // me.devnatan.dockerkt.models.image/ImageSummary.sharedSize.|(){}[0] final val size // me.devnatan.dockerkt.models.image/ImageSummary.size|{}size[0] final fun (): kotlin/Long // me.devnatan.dockerkt.models.image/ImageSummary.size.|(){}[0] - final val virtualSize // me.devnatan.dockerkt.models.image/ImageSummary.virtualSize|{}virtualSize[0] - final fun (): kotlin/Long // me.devnatan.dockerkt.models.image/ImageSummary.virtualSize.|(){}[0] final fun component1(): kotlin/String // me.devnatan.dockerkt.models.image/ImageSummary.component1|component1(){}[0] - final fun component10(): kotlin/Int // me.devnatan.dockerkt.models.image/ImageSummary.component10|component10(){}[0] final fun component2(): kotlin/String // me.devnatan.dockerkt.models.image/ImageSummary.component2|component2(){}[0] final fun component3(): kotlin.collections/List // me.devnatan.dockerkt.models.image/ImageSummary.component3|component3(){}[0] final fun component4(): kotlin.collections/List // me.devnatan.dockerkt.models.image/ImageSummary.component4|component4(){}[0] final fun component5(): kotlin/Int // me.devnatan.dockerkt.models.image/ImageSummary.component5|component5(){}[0] final fun component6(): kotlin/Long // me.devnatan.dockerkt.models.image/ImageSummary.component6|component6(){}[0] final fun component7(): kotlin/Int // me.devnatan.dockerkt.models.image/ImageSummary.component7|component7(){}[0] - final fun component8(): kotlin/Long // me.devnatan.dockerkt.models.image/ImageSummary.component8|component8(){}[0] - final fun component9(): kotlin.collections/Map? // me.devnatan.dockerkt.models.image/ImageSummary.component9|component9(){}[0] - final fun copy(kotlin/String = ..., kotlin/String = ..., kotlin.collections/List = ..., kotlin.collections/List = ..., kotlin/Int = ..., kotlin/Long = ..., kotlin/Int = ..., kotlin/Long = ..., kotlin.collections/Map? = ..., kotlin/Int = ...): me.devnatan.dockerkt.models.image/ImageSummary // me.devnatan.dockerkt.models.image/ImageSummary.copy|copy(kotlin.String;kotlin.String;kotlin.collections.List;kotlin.collections.List;kotlin.Int;kotlin.Long;kotlin.Int;kotlin.Long;kotlin.collections.Map?;kotlin.Int){}[0] + final fun component8(): kotlin.collections/Map? // me.devnatan.dockerkt.models.image/ImageSummary.component8|component8(){}[0] + final fun component9(): kotlin/Int // me.devnatan.dockerkt.models.image/ImageSummary.component9|component9(){}[0] + final fun copy(kotlin/String = ..., kotlin/String = ..., kotlin.collections/List = ..., kotlin.collections/List = ..., kotlin/Int = ..., kotlin/Long = ..., kotlin/Int = ..., kotlin.collections/Map? = ..., kotlin/Int = ...): me.devnatan.dockerkt.models.image/ImageSummary // me.devnatan.dockerkt.models.image/ImageSummary.copy|copy(kotlin.String;kotlin.String;kotlin.collections.List;kotlin.collections.List;kotlin.Int;kotlin.Long;kotlin.Int;kotlin.collections.Map?;kotlin.Int){}[0] final fun equals(kotlin/Any?): kotlin/Boolean // me.devnatan.dockerkt.models.image/ImageSummary.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // me.devnatan.dockerkt.models.image/ImageSummary.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // me.devnatan.dockerkt.models.image/ImageSummary.toString|toString(){}[0] diff --git a/src/commonMain/kotlin/me/devnatan/dockerkt/models/image/ImageSummary.kt b/src/commonMain/kotlin/me/devnatan/dockerkt/models/image/ImageSummary.kt index 7a62ed66..1aad02ec 100644 --- a/src/commonMain/kotlin/me/devnatan/dockerkt/models/image/ImageSummary.kt +++ b/src/commonMain/kotlin/me/devnatan/dockerkt/models/image/ImageSummary.kt @@ -17,7 +17,6 @@ public data class ImageSummary( @SerialName("Created") @Required public val created: Int, @SerialName("Size") @Required public val size: Long, @SerialName("SharedSize") @Required public val sharedSize: Int, - @SerialName("VirtualSize") @Required public val virtualSize: Long, @SerialName("Labels") @Required public val labels: Map?, @SerialName("Containers") @Required public val containers: Int, ) diff --git a/src/commonMain/kotlin/me/devnatan/dockerkt/resource/image/ImageResource.kt b/src/commonMain/kotlin/me/devnatan/dockerkt/resource/image/ImageResource.kt index 994ca943..3352ae31 100644 --- a/src/commonMain/kotlin/me/devnatan/dockerkt/resource/image/ImageResource.kt +++ b/src/commonMain/kotlin/me/devnatan/dockerkt/resource/image/ImageResource.kt @@ -41,7 +41,8 @@ public class ImageResource internal constructor( }.execute { response -> val channel = response.body() while (true) { - emit(json.decodeFromString(channel.readUTF8Line() ?: break)) + val line = channel.readUTF8Line() ?: break + emit(json.decodeFromString(line)) } } } diff --git a/src/commonTest/kotlin/me/devnatan/dockerkt/Yoki.kt b/src/commonTest/kotlin/me/devnatan/dockerkt/Client.kt similarity index 81% rename from src/commonTest/kotlin/me/devnatan/dockerkt/Yoki.kt rename to src/commonTest/kotlin/me/devnatan/dockerkt/Client.kt index f7a7eeab..2134eed5 100644 --- a/src/commonTest/kotlin/me/devnatan/dockerkt/Yoki.kt +++ b/src/commonTest/kotlin/me/devnatan/dockerkt/Client.kt @@ -6,7 +6,10 @@ package me.devnatan.dockerkt */ fun createTestDockerClient(block: DockerClientConfigBuilder.() -> Unit = {}): DockerClient = runCatching { - DockerClient { apply(block) } + DockerClient { + debugHttpCalls(true) + apply(block) + } }.onFailure { @Suppress("TooGenericExceptionThrown") throw RuntimeException("Failed to initialize Docker test client", it) diff --git a/src/commonTest/kotlin/me/devnatan/dockerkt/TestUtils.kt b/src/commonTest/kotlin/me/devnatan/dockerkt/TestUtils.kt index fb2db687..9ad860da 100644 --- a/src/commonTest/kotlin/me/devnatan/dockerkt/TestUtils.kt +++ b/src/commonTest/kotlin/me/devnatan/dockerkt/TestUtils.kt @@ -31,35 +31,46 @@ suspend fun DockerClient.withContainer( image: String, options: ContainerCreateOptions.() -> Unit = {}, block: suspend (String) -> R, -) = withImage(image) { imageTag -> - try { - val id = - containers.create { - this.image = imageTag - apply(options) +): Unit = + withImage(image) { imageTag -> + val containerId: String + try { + containerId = + containers.create { + this.image = imageTag + apply(options) + } + } catch (e: Throwable) { + fail("Failed to create container", e) + } + + try { + block(containerId) + } finally { + containers.remove(containerId) { + force = true + removeAnonymousVolumes = true } - block(id) - containers.remove(id) { - force = true - removeAnonymousVolumes = true } - } catch (e: Throwable) { - fail("Failed to create container", e) } -} suspend fun DockerClient.withVolume( config: VolumeCreateOptions.() -> Unit = {}, block: suspend (Volume) -> R, ) { + val volume: Volume = + try { + volumes.create(config) + } catch (e: Throwable) { + fail("Failed to create volume", e) + } + try { - val volume = volumes.create(config) block(volume) + } finally { volumes.remove(volume.name) { force = true } - } catch (e: Throwable) { - fail("Failed to create volume", e) } } diff --git a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/container/StartContainerIT.kt b/src/commonTest/kotlin/me/devnatan/dockerkt/resource/container/StartContainerIT.kt index 88caf093..98bfae20 100644 --- a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/container/StartContainerIT.kt +++ b/src/commonTest/kotlin/me/devnatan/dockerkt/resource/container/StartContainerIT.kt @@ -32,7 +32,7 @@ class StartContainerIT : ResourceIT() { fun `start a container with auto-assigned port bindings`() = runTest { testClient.withContainer( - "busybox:latest", + "nginx:latest", { exposedPort(80u) hostConfig { @@ -41,27 +41,29 @@ class StartContainerIT : ResourceIT() { }, ) { id -> testClient.containers.start(id) - val container = testClient.containers.inspect(id) + val container = testClient.containers.inspect(id) val ports = container.networkSettings.ports - assertTrue { ports.isNotEmpty() } + val exposedPort = ExposedPort(80u, ExposedPortProtocol.TCP) - assertContains(ports, exposedPort) + assertContains(map = ports, key = exposedPort) val port80Bindings = container.networkSettings.ports[exposedPort] assertNotNull(port80Bindings) - assertTrue { port80Bindings.size == 2 } + assertTrue { port80Bindings.isNotEmpty() } val ipv4Binding = port80Bindings[0] assertEquals(ipv4Binding.ip, "0.0.0.0") assertNotNull(ipv4Binding.port) assertTrue { ipv4Binding.port!!.toInt() > 0 } - val ipv6Binding = port80Bindings[1] - assertEquals(ipv6Binding.ip, "::") - assertNotNull(ipv6Binding.port) - assertTrue { ipv6Binding.port!!.toInt() > 0 } + if (port80Bindings.size > 1) { + val ipv6Binding = port80Bindings[1] + assertEquals(ipv6Binding.ip, "::") + assertNotNull(ipv6Binding.port) + assertTrue { ipv6Binding.port!!.toInt() > 0 } + } } } diff --git a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/PullImageIT.kt b/src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/ImageIT.kt similarity index 53% rename from src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/PullImageIT.kt rename to src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/ImageIT.kt index cf4f946f..49d2fb35 100644 --- a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/PullImageIT.kt +++ b/src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/ImageIT.kt @@ -1,15 +1,20 @@ -@file:OptIn(ExperimentalCoroutinesApi::class) - package me.devnatan.dockerkt.resource.image -import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.test.runTest import me.devnatan.dockerkt.resource.ResourceIT import me.devnatan.dockerkt.withImage import kotlin.test.Test import kotlin.test.assertTrue +import kotlin.test.fail + +class ImageIT : ResourceIT() { + @Test + fun `list images`() = + runTest { + testClient.images.list() + } -class PullImageIT : ResourceIT() { @Test fun `image pull`() = runTest { @@ -20,4 +25,18 @@ class PullImageIT : ResourceIT() { ) } } + + @Test + fun `image remove`() = + runTest { + val image = "busybox:latest" + + try { + testClient.images.pull(image).collect() + } catch (e: Throwable) { + fail("Failed to pull image", e) + } + + testClient.images.remove(image) + } } diff --git a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/RemoveImageIT.kt b/src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/RemoveImageIT.kt deleted file mode 100644 index 25284754..00000000 --- a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/image/RemoveImageIT.kt +++ /dev/null @@ -1,26 +0,0 @@ -@file:OptIn(ExperimentalCoroutinesApi::class) - -package me.devnatan.dockerkt.resource.image - -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.test.runTest -import me.devnatan.dockerkt.resource.ResourceIT -import kotlin.test.Test -import kotlin.test.fail - -class RemoveImageIT : ResourceIT() { - @Test - fun `image remove`() = - runTest { - val image = "busybox:latest" - - try { - testClient.images.pull(image).collect() - } catch (e: Throwable) { - fail("Failed to pull image", e) - } - - testClient.images.remove(image) - } -} diff --git a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/volume/VolumeResourceIT.kt b/src/commonTest/kotlin/me/devnatan/dockerkt/resource/volume/VolumeResourceIT.kt index 4ebbd74a..b24ad03f 100644 --- a/src/commonTest/kotlin/me/devnatan/dockerkt/resource/volume/VolumeResourceIT.kt +++ b/src/commonTest/kotlin/me/devnatan/dockerkt/resource/volume/VolumeResourceIT.kt @@ -47,8 +47,8 @@ class VolumeResourceIT : ResourceIT() { @Test fun `list volumes`() = runTest { - val volumes = testClient.volumes.list().volumes - assertTrue("Volumes must be empty, given: $volumes") { volumes.isEmpty() } + testClient.volumes.list().volumes + // Just expect no exception is thrown } @Test @@ -58,6 +58,7 @@ class VolumeResourceIT : ResourceIT() { testClient.volumes .list() .volumes.size + val newCount = 5 repeat(newCount) { testClient.volumes.create() diff --git a/src/jvmMain/kotlin/me/devnatan/dockerkt/resource/container/ContainerResource.jvm.kt b/src/jvmMain/kotlin/me/devnatan/dockerkt/resource/container/ContainerResource.jvm.kt index 472e4ac4..ba8afafc 100644 --- a/src/jvmMain/kotlin/me/devnatan/dockerkt/resource/container/ContainerResource.jvm.kt +++ b/src/jvmMain/kotlin/me/devnatan/dockerkt/resource/container/ContainerResource.jvm.kt @@ -111,8 +111,7 @@ public actual class ContainerResource( } }.body() - // TODO log warns - // result.warnings.forEach(logger::warn) + result.warnings.forEach { warn -> println("Warning from Docker API: $warn") } return result.id }