From 2a336257dcf3084440fcddcf070e99dc681bf74b Mon Sep 17 00:00:00 2001 From: Mehdi Mollaverdi Date: Tue, 4 Jun 2024 01:36:16 +1000 Subject: [PATCH] Try to close reused sockets in TestDynamoDbService (#185) --- .../testing/internal/TestDynamoDbService.kt | 24 +++++++++++-------- .../tempest/testing/internal/TestUtils.kt | 4 ++++ .../testing/internal/TestDynamoDbService.kt | 24 +++++++++++-------- .../tempest2/testing/internal/TestUtils.kt | 4 ++++ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestDynamoDbService.kt b/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestDynamoDbService.kt index 3f4bd4d9..a5456930 100644 --- a/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestDynamoDbService.kt +++ b/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestDynamoDbService.kt @@ -4,6 +4,7 @@ import app.cash.tempest.testing.TestDynamoDbClient import app.cash.tempest.testing.TestDynamoDbServer import app.cash.tempest.testing.TestTable import com.google.common.util.concurrent.AbstractIdleService +import java.net.ServerSocket import java.util.concurrent.ConcurrentHashMap /** @@ -45,24 +46,27 @@ class TestDynamoDbService private constructor( } companion object { - private val defaultPorts = ConcurrentHashMap() - private fun defaultPort(key: String): PortHolder { - var releasePort: () -> Unit = {} + private val allocatedSockets = ConcurrentHashMap() + private fun defaultPortHolder(key: String): PortHolder { // Only pick random port once to share one test server with multiple tests. - val port = defaultPorts.getOrPut(key) { - val socket = allocateRandomPort() - releasePort = { socket.close() } - socket.localPort + val socket = allocatedSockets.getOrPut(key) { allocateRandomPort() } + return PortHolder(socket.localPort) { + if (!socket.isClosed) { + socket.close() + } } - return PortHolder(port, releasePort) } private val runningServers = ConcurrentHashMap.newKeySet() private val log = getLogger() @JvmStatic - fun create(serverFactory: TestDynamoDbServer.Factory<*>, tables: List, port: Int? = null): TestDynamoDbService { - val portHolder = port?.let { PortHolder(it) } ?: defaultPort(serverFactory.toString()) + fun create( + serverFactory: TestDynamoDbServer.Factory<*>, + tables: List, + port: Int? = null + ): TestDynamoDbService { + val portHolder = port?.let { PortHolder(it) } ?: defaultPortHolder(serverFactory.toString()) return TestDynamoDbService( DefaultTestDynamoDbClient(tables, portHolder.value), serverFactory.create(portHolder.value, portHolder.releasePort) diff --git a/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestUtils.kt b/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestUtils.kt index 4e9042a7..104219c6 100644 --- a/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestUtils.kt +++ b/tempest-testing-internal/src/main/kotlin/app/cash/tempest/testing/internal/TestUtils.kt @@ -32,6 +32,10 @@ import java.net.InetSocketAddress import java.net.ServerSocket import java.net.Socket +fun pickRandomPort(): Int { + ServerSocket(0).use { socket -> return socket.localPort } +} + fun allocateRandomPort(): ServerSocket { val socket = ServerSocket(0) Runtime.getRuntime().addShutdownHook( diff --git a/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestDynamoDbService.kt b/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestDynamoDbService.kt index 7da757a6..06400581 100644 --- a/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestDynamoDbService.kt +++ b/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestDynamoDbService.kt @@ -4,6 +4,7 @@ import app.cash.tempest2.testing.TestDynamoDbClient import app.cash.tempest2.testing.TestDynamoDbServer import app.cash.tempest2.testing.TestTable import com.google.common.util.concurrent.AbstractIdleService +import java.net.ServerSocket import java.util.concurrent.ConcurrentHashMap /** @@ -45,24 +46,27 @@ class TestDynamoDbService( } companion object { - private val defaultPorts = ConcurrentHashMap() - private fun defaultPort(key: String): PortHolder { - var releasePort: () -> Unit = {} + private val allocatedSockets = ConcurrentHashMap() + private fun defaultPortHolder(key: String): PortHolder { // Only pick random port once to share one test server with multiple tests. - val port = defaultPorts.getOrPut(key) { - val socket = allocateRandomPort() - releasePort = { socket.close() } - socket.localPort + val socket = allocatedSockets.getOrPut(key) { allocateRandomPort() } + return PortHolder(socket.localPort) { + if (!socket.isClosed) { + socket.close() + } } - return PortHolder(port, releasePort) } private val runningServers = ConcurrentHashMap.newKeySet() private val log = getLogger() @JvmStatic - fun create(serverFactory: TestDynamoDbServer.Factory<*>, tables: List, port: Int? = null): TestDynamoDbService { - val portHolder = port?.let { PortHolder(it) } ?: defaultPort(serverFactory.toString()) + fun create( + serverFactory: TestDynamoDbServer.Factory<*>, + tables: List, + port: Int? = null + ): TestDynamoDbService { + val portHolder = port?.let { PortHolder(it) } ?: defaultPortHolder(serverFactory.toString()) return TestDynamoDbService( DefaultTestDynamoDbClient(tables, portHolder.value), serverFactory.create(portHolder.value, portHolder.releasePort) diff --git a/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestUtils.kt b/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestUtils.kt index e5e6088c..57c93298 100644 --- a/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestUtils.kt +++ b/tempest2-testing-internal/src/main/kotlin/app/cash/tempest2/testing/internal/TestUtils.kt @@ -33,6 +33,10 @@ import java.net.ServerSocket import java.net.Socket import java.net.URI +fun pickRandomPort(): Int { + ServerSocket(0).use { socket -> return socket.localPort } +} + fun allocateRandomPort(): ServerSocket { val socket = ServerSocket(0) Runtime.getRuntime().addShutdownHook(