This is an automated email from the ASF dual-hosted git repository.
vladimirsitnikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git
The following commit(s) were added to refs/heads/master by this push:
new 5df1cd0017 chore: use 127.0.0.1 or ::1 for client-server tests
5df1cd0017 is described below
commit 5df1cd0017c80af2580fa93f46205dfc7f586425
Author: Vladimir Sitnikov <[email protected]>
AuthorDate: Sat Oct 25 20:57:10 2025 +0300
chore: use 127.0.0.1 or ::1 for client-server tests
InetAddress.getLocalHost().canonicalHostName might resolve to a public NAT
DNS name, and there will be no way to bind a server port for it.
Here's an example how the bind fails in Apache Jenkins EC2 instance:
[server] Server failed to start: java.rmi.server.ExportException: Listen
failed on port: 0; nested exception is:
[server] java.io.IOException: Could not bind to
bb-worker1-ec2-va.apache.org/3.234.254.195 using port 0
The workaround is to avoid InetAddress.getLocalHost() altogether,
so we use 127.0.0.1 when IPv4 is available or ::1 otherwise.
---
.../jmeter/buildtools/batchtest/BatchTest.kt | 46 ++++++++++++++++++++--
.../jmeter/buildtools/batchtest/BatchTestServer.kt | 28 ++++++-------
2 files changed, 55 insertions(+), 19 deletions(-)
diff --git
a/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTest.kt
b/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTest.kt
index cf19f44612..45291f1eb7 100644
---
a/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTest.kt
+++
b/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTest.kt
@@ -32,9 +32,12 @@ import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.JavaExec
+import org.gradle.api.tasks.PathSensitive
+import org.gradle.api.tasks.PathSensitivity
import org.gradle.kotlin.dsl.property
import java.io.File
import java.net.InetAddress
+import java.net.ServerSocket
import javax.inject.Inject
open class BatchTest @Inject constructor(objects: ObjectFactory) : JavaExec() {
@@ -107,13 +110,23 @@ open class BatchTest @Inject constructor(objects:
ObjectFactory) : JavaExec() {
get() =
project.rootProject.layout.projectDirectory.dir("lib").asFileTree
@get:InputFile
+ @get:PathSensitive(PathSensitivity.NONE)
val jmeterJar
get() =
project.rootProject.layout.projectDirectory.dir("bin").file("ApacheJMeter.jar")
+ @Internal
+ val serverWorkingDir = objects.directoryProperty()
+ .convention(project.rootProject.layout.projectDirectory.dir("bin"))
+
+ @InputFile
+ @PathSensitive(PathSensitivity.NONE)
+ val jmeterProperties = objects.fileProperty()
+ .convention(serverWorkingDir.file("jmeter.properties"))
+
init {
group = BATCH_TESTS_GROUP_NAME
description = "Runs jmx file via process fork and verifies outputs"
- workingDir = File(project.rootDir, "bin")
+ workingDir = serverWorkingDir.get().asFile
mainClass.set("org.apache.jmeter.NewDriver")
classpath(jmeterJar)
@@ -121,10 +134,37 @@ open class BatchTest @Inject constructor(objects:
ObjectFactory) : JavaExec() {
// It enables to override the properties later (e.g. in the build
script)
maxHeapSize = "128m"
jvmArgs("-Xss256k", "-XX:MaxMetaspaceSize=128m")
- systemProperty("java.rmi.server.hostname",
InetAddress.getLocalHost().canonicalHostName)
+ systemProperty("java.rmi.server.hostname", getServerHost())
systemProperty("java.awt.headless", "true")
}
+ @Internal
+ protected fun getServerHost(): String {
+ // If JVM has IPv4 enabled, 127.0.0.1 will work; otherwise fall back
to ::1
+ return try {
+ // Will throw if IPv4 is completely disabled in the JVM/OS
+ InetAddress.getByAddress(byteArrayOf(127, 0, 0, 1))
+ "127.0.0.1"
+ } catch (_: Exception) {
+ "::1"
+ }
+ }
+
+ protected fun getFreePort(retries: Int = 10): Int {
+ repeat(retries - 1) {
+ try {
+ ServerSocket(0).use {
+ return it.localPort
+ }
+ } catch (_: Exception) {
+ Thread.sleep(25)
+ }
+ }
+ ServerSocket(0).use {
+ return it.localPort
+ }
+ }
+
fun jmeterArgument(name: String, value: String) {
args("-J$name=$value")
}
@@ -162,7 +202,7 @@ open class BatchTest @Inject constructor(objects:
ObjectFactory) : JavaExec() {
systemProperty("user.language", userLanguage.get())
systemProperty("user.region", userRegion.get())
systemProperty("user.country", userCountry.get())
- args("-pjmeter.properties")
+ args("-p${jmeterProperties.get().asFile.name}")
args("-q", batchProperties.get())
args("-n")
args("-t", jmx.get())
diff --git
a/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTestServer.kt
b/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTestServer.kt
index b48369d62c..096867d4db 100644
---
a/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTestServer.kt
+++
b/build-logic/batchtest/src/main/kotlin/org/apache/jmeter/buildtools/batchtest/BatchTestServer.kt
@@ -25,11 +25,9 @@ import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.kotlin.dsl.findByType
import org.gradle.kotlin.dsl.property
+import org.gradle.process.ExecOperations
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
-import java.io.File
import java.net.ConnectException
-import java.net.InetAddress
-import java.net.ServerSocket
import java.net.Socket
import java.time.Duration
import java.util.concurrent.Executors
@@ -37,7 +35,7 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import javax.inject.Inject
-open class BatchTestServer @Inject constructor(objects: ObjectFactory) :
BatchTest(objects) {
+abstract class BatchTestServer @Inject constructor(objects: ObjectFactory) :
BatchTest(objects) {
private val executor =
Executors.newFixedThreadPool(project.gradle.startParameter.maxWorkerCount)
@@ -53,22 +51,20 @@ open class BatchTestServer @Inject constructor(objects:
ObjectFactory) : BatchTe
val startupTimeout = objects.property<Duration>()
.convention(Duration.ofSeconds(15))
+ @get:Inject
+ abstract val execOperations: ExecOperations
+
private fun deleteWorkfiles() {
project.delete(serverLogFile)
}
- private fun getFreePort(): Int =
- ServerSocket(0).use {
- return it.localPort
- }
-
private fun waitForPort(host: String, port: Int, timeout: Duration):
Boolean {
- val deadline = System.nanoTime() + timeout.toNanos()
- while (System.nanoTime() < deadline) {
+ val start = System.nanoTime()
+ while (System.nanoTime() - start < timeout.toNanos()) {
try {
Socket(host, port).close()
return true
- } catch (e: ConnectException) {
+ } catch (_: ConnectException) {
/* ignore */
Thread.sleep(50)
}
@@ -86,7 +82,7 @@ open class BatchTestServer @Inject constructor(objects:
ObjectFactory) : BatchTe
val client = this
val serverPort = getFreePort()
- val serverHost = InetAddress.getLocalHost().canonicalHostName
+ val serverHost = getServerHost()
args("-R$serverHost:$serverPort")
val jacoco = extensions.findByType<JacocoTaskExtension>()
// The extension might not exist, so don't fail if so
@@ -106,8 +102,8 @@ open class BatchTestServer @Inject constructor(objects:
ObjectFactory) : BatchTe
jvmarg
}
val server = executor.submit {
- project.javaexec {
- workingDir = File(project.rootDir, "bin")
+ execOperations.javaexec {
+ workingDir = serverWorkingDir.get().asFile
mainClass.set("org.apache.jmeter.NewDriver")
classpath(client.classpath)
standardOutput = System.out.writer().withPrefix("[server] ")
@@ -124,7 +120,7 @@ open class BatchTestServer @Inject constructor(objects:
ObjectFactory) : BatchTe
systemProperty("user.region", userRegion.get())
systemProperty("user.country", userCountry.get())
- args("-pjmeter.properties")
+ args("-p${jmeterProperties.get().asFile.name}")
args("-q", batchProperties.get())
args("-i", log4jXml.get())
args("-j", serverLogFile.get())