Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build-logic/build-parameters/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ buildParameters {
description.set("Collect test coverage")
}
integer("targetJavaVersion") {
defaultValue.set(17)
defaultValue.set(21)
mandatory.set(true)
description.set("Java version for source and target compatibility")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.jmeter.visualizers.backend.influxdb;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -120,7 +121,7 @@ public void setup(String influxdbUrl, String influxDBToken) throws Exception {
.disableCookieManagement()
.disableConnectionState()
.build();
url = new URL(influxdbUrl);
url = URI.create(influxdbUrl).toURL();
token = influxDBToken;
httpRequest = createRequest(url, token);
httpClient.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
Expand Down Expand Up @@ -55,7 +56,7 @@ public void setUp() throws MalformedURLException {
jmctx.setVariables(vars);
jmctx.setPreviousResult(sample);
sample.setResponseData("response Data\nline 2\n\nEOF", null);
sample.setURL(new URL("http://localhost/Sampler/Data/"));
sample.setURL(URI.create("http://localhost/Sampler/Data/").toURL());
sample.setResponseCode("401");
sample.setResponseHeaders("X-Header: abcd");
sample.setRequestHeaders("X-reqHeader: cdef");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.net.URI;
import java.net.URL;

import org.apache.jmeter.samplers.SampleResult;
Expand Down Expand Up @@ -314,7 +315,7 @@ public void testVariableExtraction8() throws Exception {
assertTrue(extractor.useUrl(), "useURL should be true");
extractor.process();
assertNull(vars.get("regVal"));
result.setURL(new URL("http://jakarta.apache.org/index.html?abcd"));
result.setURL(URI.create("http://jakarta.apache.org/index.html?abcd").toURL());
extractor.process();
assertEquals("index", vars.get("regVal"));
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/src/main/java/org/apache/jmeter/JMeter.java
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public void start(String[] args) {

Thread.setDefaultUncaughtExceptionHandler(
(Thread t, Throwable e) -> {
if (!(e instanceof ThreadDeath)) {
if (!(e instanceof VirtualMachineError)) {
log.error("Uncaught exception in thread {}", t, e);
System.err.println("Uncaught Exception " + e + " in thread " + t + ". See log file for details.");//NOSONAR
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.jmeter.JMeter;
import org.apache.jmeter.samplers.SampleEvent;
Expand Down Expand Up @@ -92,19 +92,17 @@ public class StandardJMeterEngine implements JMeterEngine, Runnable {
/** Whether to call System.exit(0) unconditionally at end of non-GUI test */
private static final boolean SYSTEM_EXIT_FORCED = JMeterUtils.getPropDefault("jmeterengine.force.system.exit", false);

private static final AtomicInteger THREAD_COUNTER = new AtomicInteger(0);

/**
* Executor service to execute management tasks like "start test", "stop test".
* The use of {@link ExecutorService} allows propagating the exception from the threads.
* Thread keepalive time is set to 1 second, so threads are released early,
* so the application can shut down faster.
* Uses platform threads to keep the JVM alive while tests run
* (virtual threads are daemon threads and would allow premature JVM exit).
*/
private static final ExecutorService EXECUTOR_SERVICE =
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
1L, TimeUnit.SECONDS,
new java.util.concurrent.SynchronousQueue<>(),
(runnable) -> new Thread(runnable, "StandardJMeterEngine-" + THREAD_COUNTER.incrementAndGet()));
Executors.newThreadPerTaskExecutor(
Thread.ofPlatform().name("StandardJMeterEngine-", 1).factory());

private static final ReentrantLock REGISTER_LOCK = new ReentrantLock();
private final ReentrantLock stopTestLock = new ReentrantLock();

private volatile Future<?> runningTest;

Expand Down Expand Up @@ -156,8 +154,13 @@ public static void stopEngine() {
}
}

public static synchronized void register(TestStateListener tl) {
testList.add(tl);
public static void register(TestStateListener tl) {
REGISTER_LOCK.lock();
try {
testList.add(tl);
} finally {
REGISTER_LOCK.unlock();
}
}

public static boolean stopThread(String threadName) {
Expand Down Expand Up @@ -296,14 +299,19 @@ public void reset() {
* Stop Test Now
*/
@Override
public synchronized void stopTest() {
public void stopTest() {
stopTest(true);
}

@Override
@SuppressWarnings("FutureReturnValueIgnored")
public synchronized void stopTest(boolean now) {
EXECUTOR_SERVICE.submit(new StopTest(now));
public void stopTest(boolean now) {
stopTestLock.lock();
try {
EXECUTOR_SERVICE.submit(new StopTest(now));
} finally {
stopTestLock.unlock();
}
}

private class StopTest implements Runnable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ public String getStaticLabel() {
@Override
public String getDocAnchor() {
// Ensure we use default bundle
String label = JMeterUtils.getResString(getLabelResource(), new Locale("",""));
String label = JMeterUtils.getResString(getLabelResource(), Locale.ROOT);
return label.replace(' ', '_');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ public void doActionAfterCheck(ActionEvent e) {

int sep = locale.indexOf('_');
if (sep > 0) {
loc = new Locale(locale.substring(0, sep), locale.substring(sep + 1));
loc = Locale.of(locale.substring(0, sep), locale.substring(sep + 1));
} else {
loc = new Locale(locale, "");
loc = Locale.of(locale);
}
log.debug("Changing locale to {}", loc);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ public void localeChanged(LocaleChangeEvent event) {
public String getDocAnchor() {
ResourceBundle resourceBundle = ResourceBundle.getBundle(
testBeanClass.getName() + "Resources", // $NON-NLS-1$
new Locale("",""));
Locale.ROOT);

String name = resourceBundle.getString("displayName");
return name.replace(' ', '_');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.time.Duration;
import java.util.IdentityHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.jmeter.control.Controller;
import org.apache.jmeter.control.IteratingController;
Expand Down Expand Up @@ -50,6 +51,7 @@ public abstract class AbstractThreadGroup extends AbstractTestElement

// Only create the map if it is required
private final transient IdentityHashMap<TestElement, Object> children = new IdentityHashMap<>();
private final transient ReentrantLock childrenLock = new ReentrantLock();

private static final Object DUMMY = new Object();

Expand Down Expand Up @@ -166,11 +168,14 @@ public void addTestElement(TestElement child) {
*/
@Override
public final boolean addTestElementOnce(TestElement child){
synchronized (children) {
childrenLock.lock();
try {
if (children.putIfAbsent(child, DUMMY) == null) {
addTestElement(child);
return true;
}
} finally {
childrenLock.unlock();
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.jmeter.util.JMeterUtils;

Expand All @@ -39,6 +40,7 @@ public final class JMeterContextService {

private static final AtomicInteger TOTAL_THREADS = new AtomicInteger();

private static final ReentrantLock TEST_LIFECYCLE_LOCK = new ReentrantLock();
private static UnmodifiableJMeterVariables variables;


Expand Down Expand Up @@ -81,11 +83,16 @@ public static void replaceContext(JMeterContext context) {
* Zeroes numberOfActiveThreads.
* Saves current time in a field and in the JMeter property "TESTSTART.MS"
*/
public static synchronized void startTest() {
if (testStart.get() == 0) {
NUMBER_OF_ACTIVE_THREADS.set(0);
testStart.set(System.currentTimeMillis());
JMeterUtils.setProperty("TESTSTART.MS", Long.toString(testStart.get()));// $NON-NLS-1$
public static void startTest() {
TEST_LIFECYCLE_LOCK.lock();
try {
if (testStart.get() == 0) {
NUMBER_OF_ACTIVE_THREADS.set(0);
testStart.set(System.currentTimeMillis());
JMeterUtils.setProperty("TESTSTART.MS", Long.toString(testStart.get()));// $NON-NLS-1$
}
} finally {
TEST_LIFECYCLE_LOCK.unlock();
}
}

Expand Down Expand Up @@ -122,9 +129,14 @@ public static ThreadCounts getThreadCounts() {
* Called by MainFrame#testEnded().
* Clears start time field.
*/
public static synchronized void endTest() {
testStart.set(0);
resetClientSideVariables();
public static void endTest() {
TEST_LIFECYCLE_LOCK.lock();
try {
testStart.set(0);
resetClientSideVariables();
} finally {
TEST_LIFECYCLE_LOCK.unlock();
}
}

public static long getTestStartTime() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,6 @@ public void run() {
}
} catch (Exception | JMeterError e) {
log.error("Test failed!", e);
} catch (ThreadDeath e) {
throw e; // Must not ignore this one
} finally {
currentSamplerForInterruption = null; // prevent any further interrupts
interruptLock.lock(); // make sure current interrupt is finished, prevent another starting yet
Expand Down
14 changes: 11 additions & 3 deletions src/core/src/main/java/org/apache/jmeter/threads/TestCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.jmeter.assertions.Assertion;
import org.apache.jmeter.config.ConfigTestElement;
Expand Down Expand Up @@ -64,6 +65,7 @@ public class TestCompiler implements HashTreeTraverser {
* Otherwise, the child is added to the parent and the pair is added to the Set.
*/
private static final Set<ObjectPair> PAIRING = new HashSet<>();
private static final ReentrantLock PAIRING_LOCK = new ReentrantLock();

// TODO: replace with ArrayDequeue
private final LinkedList<TestElement> stack = new LinkedList<>();
Expand All @@ -84,9 +86,12 @@ public TestCompiler(HashTree testTree) {
* test run.
*/
public static void initialize() {
// synch is probably not needed as only called before run starts
synchronized (PAIRING) {
// lock is probably not needed as only called before run starts
PAIRING_LOCK.lock();
try {
PAIRING.clear();
} finally {
PAIRING_LOCK.unlock();
}
}

Expand Down Expand Up @@ -152,13 +157,16 @@ else if(child instanceof TransactionController transactionController) {
duplicate = !te.addTestElementOnce(child);
} else { // this is only possible for 3rd party controllers by default
ObjectPair pair = new ObjectPair(child, parent);
synchronized (PAIRING) {// Called from multiple threads
PAIRING_LOCK.lock();
try { // Called from multiple threads
if (!PAIRING.contains(pair)) {
parent.addTestElement(child);
PAIRING.add(pair);
} else {
duplicate = true;
}
} finally {
PAIRING_LOCK.unlock();
}
}
}
Expand Down
Loading