From 9864fff631905f16759a6e3af46c0dc2d92e64ee Mon Sep 17 00:00:00 2001 From: mykhailo-qdxp Date: Mon, 15 Sep 2025 16:38:09 +0200 Subject: [PATCH 1/3] ISSUE-730 # Add property implementation and tests --- .../parallel/ExecutorServiceRunner.java | 44 +++++++++++++++++-- .../zerocode/parallel/simple/LoadTest.java | 34 ++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java b/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java index 119a8d360..2059fd192 100644 --- a/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java +++ b/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java @@ -8,9 +8,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -18,6 +16,7 @@ import static java.lang.Integer.parseInt; import static java.lang.Thread.sleep; import static java.time.LocalDateTime.now; +import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.concurrent.Executors.newFixedThreadPool; public class ExecutorServiceRunner { @@ -29,6 +28,7 @@ public class ExecutorServiceRunner { private int numberOfThreads; private int rampUpPeriod; private int loopCount; + private int abortAfterTimeLapsedInSeconds; private Double delayBetweenTwoThreadsInMilliSecs; @@ -37,6 +37,7 @@ public ExecutorServiceRunner(String loadPropertiesFile) { numberOfThreads = parseInt(properties.getProperty("number.of.threads")); rampUpPeriod = parseInt(properties.getProperty("ramp.up.period.in.seconds")); loopCount = parseInt(properties.getProperty("loop.count")); + abortAfterTimeLapsedInSeconds = parseInt(properties.getProperty("abort.after.time.lapsed.in.seconds")); calculateAndSetDelayBetweenTwoThreadsInSecs(rampUpPeriod); @@ -47,6 +48,17 @@ public ExecutorServiceRunner(int numberOfThreads, int loopCount, int rampUpPerio this.numberOfThreads = numberOfThreads; this.loopCount = loopCount; this.rampUpPeriod = rampUpPeriod; + this.abortAfterTimeLapsedInSeconds = Integer.MAX_VALUE; + + calculateAndSetDelayBetweenTwoThreadsInSecs(this.rampUpPeriod); + logLoadingProperties(); + } + + public ExecutorServiceRunner(int numberOfThreads, int loopCount, int rampUpPeriod, int abortAfterTimeLapsedInSeconds) { + this.numberOfThreads = numberOfThreads; + this.loopCount = loopCount; + this.rampUpPeriod = rampUpPeriod; + this.abortAfterTimeLapsedInSeconds = abortAfterTimeLapsedInSeconds; calculateAndSetDelayBetweenTwoThreadsInSecs(this.rampUpPeriod); logLoadingProperties(); @@ -64,7 +76,7 @@ public ExecutorServiceRunner addCallable(Callable callable) { public void runRunnables() { - + executeWithAbortTimeout(() -> { if (runnables == null || runnables.size() == 0) { throw new RuntimeException("No runnable(s) was found to run. You can add one or more runnables using 'addRunnable(Runnable runnable)'"); } @@ -103,9 +115,11 @@ public void runRunnables() { } LOGGER.debug("**Finished executing all threads**"); } + }); } public void runRunnablesMulti() { + executeWithAbortTimeout(() -> { if (runnables == null || runnables.size() == 0) { throw new RuntimeException("No runnable(s) was found to run. You can add one or more runnables using 'addRunnable(Runnable runnable)'"); } @@ -149,6 +163,7 @@ public void runRunnablesMulti() { } LOGGER.warn("** Completed executing all virtual-user scenarios! **"); } + }); } public void runCallables() { @@ -156,6 +171,7 @@ public void runCallables() { } public void runCallableFutures() { + executeWithAbortTimeout(() -> { if (callables == null || callables.size() == 0) { throw new RuntimeException("No callable(s) was found to run. You can add one or more callables using 'addCallable(Callable callable)'"); @@ -192,6 +208,7 @@ public void runCallableFutures() { } + }); } public Callable createCallableFuture(T objectToConsumer, Consumer consumer) { @@ -210,6 +227,24 @@ private Object execute(Future future) { } } + private void executeWithAbortTimeout(Runnable runnable) { + ExecutorService executorService = newSingleThreadExecutor(); + Future future = executorService.submit(runnable); + try { + future.get(abortAfterTimeLapsedInSeconds, TimeUnit.SECONDS); + } catch (TimeoutException timeoutEx) { + future.cancel(true); + throw new RuntimeException(timeoutEx); + } catch (InterruptedException interruptEx) { + Thread.currentThread().interrupt(); + future.cancel(true); + throw new RuntimeException(interruptEx); + } catch (ExecutionException executionEx) { + throw new RuntimeException(executionEx); + } finally { + executorService.shutdownNow(); + } + } private void calculateAndSetDelayBetweenTwoThreadsInSecs(int rampUpPeriod) { if (rampUpPeriod == 0) { @@ -242,6 +277,7 @@ private void logLoadingProperties() { "\n ### numberOfThreads : " + numberOfThreads + "\n ### rampUpPeriodInSeconds : " + rampUpPeriod + "\n ### loopCount : " + loopCount + + "\n ### abortAfterTimeLapsedInSeconds : " + abortAfterTimeLapsedInSeconds + "\n-----------------------------------\n"); } diff --git a/core/src/test/java/org/jsmart/zerocode/parallel/simple/LoadTest.java b/core/src/test/java/org/jsmart/zerocode/parallel/simple/LoadTest.java index 0958c24a2..9f36cc6fd 100644 --- a/core/src/test/java/org/jsmart/zerocode/parallel/simple/LoadTest.java +++ b/core/src/test/java/org/jsmart/zerocode/parallel/simple/LoadTest.java @@ -10,7 +10,9 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertThrows; import static org.hamcrest.core.Is.is; +import static org.hamcrest.CoreMatchers.equalTo; public class LoadTest { @@ -76,5 +78,37 @@ public void testLoad_Fail() { assertThat(passedCounter.get(), is(0)); } + @Test + public void testLoad_Timeout() { + ExecutorServiceRunner executorServiceRunner = new ExecutorServiceRunner(3, 3, 6, 3); + + final AtomicInteger passedCounter = new AtomicInteger(); + final AtomicInteger failedCounter = new AtomicInteger(); + + Runnable taskSampleTest = () -> { + System.out.println(Thread.currentThread().getName() + " JunitTestSample test- Start. Time = " + LocalDateTime.now()); + + Result result = (new JUnitCore()).run(Request.method(JunitTestSample.class, "testFirstName")); + + System.out.println(Thread.currentThread().getName() + " JunitTestSample test- *Finished Time, result = " + LocalDateTime.now() + " -" + result.wasSuccessful()); + + if(result.wasSuccessful()){ + passedCounter.incrementAndGet(); + } else { + failedCounter.incrementAndGet(); + } + }; + + executorServiceRunner.addRunnable(taskSampleTest); + + RuntimeException e = assertThrows(RuntimeException.class, executorServiceRunner::runRunnables); + assertThat(e.getMessage(), equalTo("java.util.concurrent.TimeoutException")); + + System.out.println(">>> passed count:" + passedCounter.get()); + System.out.println(">>> failed count:" + failedCounter.get()); + System.out.println(">>> Total test count:" + (failedCounter.get() + passedCounter.get())); + + assertThat(failedCounter.get(), is(0)); + } } From f6ad4ac9ef61420f08cf40ed3bba72d36c67d5f0 Mon Sep 17 00:00:00 2001 From: mykhailo-qdxp Date: Mon, 15 Sep 2025 17:05:44 +0200 Subject: [PATCH 2/3] ISSUE-730 # style: normalize indentation --- .../parallel/ExecutorServiceRunner.java | 186 +++++++++--------- 1 file changed, 92 insertions(+), 94 deletions(-) diff --git a/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java b/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java index 2059fd192..233045732 100644 --- a/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java +++ b/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java @@ -77,92 +77,92 @@ public ExecutorServiceRunner addCallable(Callable callable) { public void runRunnables() { executeWithAbortTimeout(() -> { - if (runnables == null || runnables.size() == 0) { - throw new RuntimeException("No runnable(s) was found to run. You can add one or more runnables using 'addRunnable(Runnable runnable)'"); - } + if (runnables == null || runnables.size() == 0) { + throw new RuntimeException("No runnable(s) was found to run. You can add one or more runnables using 'addRunnable(Runnable runnable)'"); + } - ExecutorService executorService = newFixedThreadPool(numberOfThreads); + ExecutorService executorService = newFixedThreadPool(numberOfThreads); - try { - for (int i = 0; i < loopCount; i++) { - runnables.stream().forEach(thisFunction -> { - for (int j = 0; j < numberOfThreads; j++) { - try { - LOGGER.debug("Waiting for the next test flight to adjust the overall ramp up time, " + - "waiting time in the transit now = " + delayBetweenTwoThreadsInMilliSecs); - sleep(delayBetweenTwoThreadsInMilliSecs.longValue()); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + try { + for (int i = 0; i < loopCount; i++) { + runnables.stream().forEach(thisFunction -> { + for (int j = 0; j < numberOfThreads; j++) { + try { + LOGGER.debug("Waiting for the next test flight to adjust the overall ramp up time, " + + "waiting time in the transit now = " + delayBetweenTwoThreadsInMilliSecs); + sleep(delayBetweenTwoThreadsInMilliSecs.longValue()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } - LOGGER.debug(Thread.currentThread().getName() + " Executor - *Start... Time = " + now()); + LOGGER.debug(Thread.currentThread().getName() + " Executor - *Start... Time = " + now()); - executorService.execute(thisFunction); + executorService.execute(thisFunction); - LOGGER.debug(Thread.currentThread().getName() + " Executor - *Finished Time = " + now()); - } - }); - } - } catch (Exception interruptEx) { - throw new RuntimeException(interruptEx); - } finally { - executorService.shutdown(); - while (!executorService.isTerminated()) { - // -------------------------------------- - // wait for all tasks to finish execution - // -------------------------------------- - //LOGGER.info("Still waiting for all threads to complete execution..."); + LOGGER.debug(Thread.currentThread().getName() + " Executor - *Finished Time = " + now()); + } + }); + } + } catch (Exception interruptEx) { + throw new RuntimeException(interruptEx); + } finally { + executorService.shutdown(); + while (!executorService.isTerminated()) { + // -------------------------------------- + // wait for all tasks to finish execution + // -------------------------------------- + //LOGGER.info("Still waiting for all threads to complete execution..."); + } + LOGGER.debug("**Finished executing all threads**"); } - LOGGER.debug("**Finished executing all threads**"); - } }); } public void runRunnablesMulti() { executeWithAbortTimeout(() -> { - if (runnables == null || runnables.size() == 0) { - throw new RuntimeException("No runnable(s) was found to run. You can add one or more runnables using 'addRunnable(Runnable runnable)'"); - } + if (runnables == null || runnables.size() == 0) { + throw new RuntimeException("No runnable(s) was found to run. You can add one or more runnables using 'addRunnable(Runnable runnable)'"); + } - ExecutorService executorService = newFixedThreadPool(numberOfThreads); + ExecutorService executorService = newFixedThreadPool(numberOfThreads); - try { - final AtomicInteger functionIndex = new AtomicInteger(); - - for (int i = 0; i < loopCount; i++) { - for (int j = 0; j < numberOfThreads; j++) { - try { - LOGGER.debug("Waiting for the next test flight to adjust the overall ramp up time, " + - "waiting time in the transit now = " + delayBetweenTwoThreadsInMilliSecs); - sleep(delayBetweenTwoThreadsInMilliSecs.longValue()); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + try { + final AtomicInteger functionIndex = new AtomicInteger(); - LOGGER.debug(Thread.currentThread().getName() + " Executor - *Start... Time = " + now()); + for (int i = 0; i < loopCount; i++) { + for (int j = 0; j < numberOfThreads; j++) { + try { + LOGGER.debug("Waiting for the next test flight to adjust the overall ramp up time, " + + "waiting time in the transit now = " + delayBetweenTwoThreadsInMilliSecs); + sleep(delayBetweenTwoThreadsInMilliSecs.longValue()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + LOGGER.debug(Thread.currentThread().getName() + " Executor - *Start... Time = " + now()); - executorService.execute(runnables.get(functionIndex.getAndIncrement())); + executorService.execute(runnables.get(functionIndex.getAndIncrement())); - LOGGER.debug(Thread.currentThread().getName() + " Executor - *Finished Time = " + now()); + LOGGER.debug(Thread.currentThread().getName() + " Executor - *Finished Time = " + now()); - if(functionIndex.get() == runnables.size()){ - functionIndex.set(0); + if (functionIndex.get() == runnables.size()) { + functionIndex.set(0); + } } - } + } + } catch (Exception interruptEx) { + throw new RuntimeException(interruptEx); + } finally { + executorService.shutdown(); + while (!executorService.isTerminated()) { + // -------------------------------------- + // wait for all tasks to finish execution + // -------------------------------------- + //LOGGER.info("Still waiting for all threads to complete execution..."); + } + LOGGER.warn("** Completed executing all virtual-user scenarios! **"); } - } catch (Exception interruptEx) { - throw new RuntimeException(interruptEx); - } finally { - executorService.shutdown(); - while (!executorService.isTerminated()) { - // -------------------------------------- - // wait for all tasks to finish execution - // -------------------------------------- - //LOGGER.info("Still waiting for all threads to complete execution..."); - } - LOGGER.warn("** Completed executing all virtual-user scenarios! **"); - } }); } @@ -173,41 +173,39 @@ public void runCallables() { public void runCallableFutures() { executeWithAbortTimeout(() -> { - if (callables == null || callables.size() == 0) { - throw new RuntimeException("No callable(s) was found to run. You can add one or more callables using 'addCallable(Callable callable)'"); - } + if (callables == null || callables.size() == 0) { + throw new RuntimeException("No callable(s) was found to run. You can add one or more callables using 'addCallable(Callable callable)'"); + } - ExecutorService executorService = newFixedThreadPool(numberOfThreads); + ExecutorService executorService = newFixedThreadPool(numberOfThreads); - try { - executorService.invokeAll(callables).stream().forEach(future -> { - for (int j = 0; j < numberOfThreads; j++) { - try { - LOGGER.debug("Waiting in the transit for next test flight to adjust overall ramp up time, wait time now = " + delayBetweenTwoThreadsInMilliSecs); - sleep(delayBetweenTwoThreadsInMilliSecs.longValue()); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + try { + executorService.invokeAll(callables).stream().forEach(future -> { + for (int j = 0; j < numberOfThreads; j++) { + try { + LOGGER.debug("Waiting in the transit for next test flight to adjust overall ramp up time, wait time now = " + delayBetweenTwoThreadsInMilliSecs); + sleep(delayBetweenTwoThreadsInMilliSecs.longValue()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } - LOGGER.debug(Thread.currentThread().getName() + " Future execution- Start.... Time = " + now()); + LOGGER.debug(Thread.currentThread().getName() + " Future execution- Start.... Time = " + now()); - execute(future); + execute(future); - LOGGER.debug(Thread.currentThread().getName() + " Future execution- *Finished Time = " + now()); + LOGGER.debug(Thread.currentThread().getName() + " Future execution- *Finished Time = " + now()); + } + }); + } catch (InterruptedException interruptEx) { + throw new RuntimeException(interruptEx); + } finally { + executorService.shutdown(); + while (!executorService.isTerminated()) { + // wait for all tasks to finish executing + // LOGGER.info("Still waiting for all threads to complete execution..."); } - }); - } catch (InterruptedException interruptEx) { - throw new RuntimeException(interruptEx); - } finally { - executorService.shutdown(); - while (!executorService.isTerminated()) { - // wait for all tasks to finish executing - // LOGGER.info("Still waiting for all threads to complete execution..."); + LOGGER.warn("* Completed executing all virtual-user scenarios! *"); } - LOGGER.warn("* Completed executing all virtual-user scenarios! *"); - } - - }); } From 52fba3bd76eba1a7c529dda83e828ec0e10889ad Mon Sep 17 00:00:00 2001 From: mykhailo-qdxp Date: Tue, 16 Sep 2025 00:26:43 +0200 Subject: [PATCH 3/3] ISSUE-730 # Fix: 'package.*' is in the imports --- .../jsmart/zerocode/parallel/ExecutorServiceRunner.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java b/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java index 233045732..b6c6d5f10 100644 --- a/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java +++ b/core/src/main/java/org/jsmart/zerocode/parallel/ExecutorServiceRunner.java @@ -8,7 +8,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer;