You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by fs...@apache.org on 2019/06/16 17:57:23 UTC

[jmeter] branch master updated: At end of scheduler duration lots of Samplers gets executed at the same time

This is an automated email from the ASF dual-hosted git repository.

fschumacher 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 a72e68c  At end of scheduler duration lots of Samplers gets executed at the same time
a72e68c is described below

commit a72e68ca69e874be020b1bda5ccf3a5756e14f21
Author: Felix Schumacher <fe...@internetallee.de>
AuthorDate: Sun Jun 16 19:55:54 2019 +0200

    At end of scheduler duration lots of Samplers gets executed at the same time
    
    The old behaviour lead to strange long sampling times at the end of scheduled
    test runs.
    
    Bugzilla Id: 63490
---
 .../org/apache/jmeter/threads/JMeterThread.java    |  14 +++
 .../org/apache/jmeter/timers/TimerService.java     |   4 +-
 .../apache/jmeter/threads/TestJMeterThread.java    | 104 ++++++++++++++++++++-
 .../org/apache/jmeter/timers/TimerServiceTest.java |  17 +++-
 xdocs/changes.xml                                  |   1 +
 5 files changed, 135 insertions(+), 5 deletions(-)

diff --git a/src/core/org/apache/jmeter/threads/JMeterThread.java b/src/core/org/apache/jmeter/threads/JMeterThread.java
index 1c6ab44..98c046e 100644
--- a/src/core/org/apache/jmeter/threads/JMeterThread.java
+++ b/src/core/org/apache/jmeter/threads/JMeterThread.java
@@ -935,6 +935,15 @@ public class JMeterThread implements Runnable, Interruptible {
         }
     }
 
+    /**
+     * Run all configured timers and sleep the total amount of time.
+     * <p>
+     * If the amount of time would amount to an ending after endTime, then
+     * end the current thread by setting {@code running} to {@code false} and
+     * return immediately.
+     *
+     * @param timers to be used for calculating the delay
+     */
     private void delay(List<Timer> timers) {
         long totalDelay = 0;
         for (Timer timer : timers) {
@@ -955,6 +964,11 @@ public class JMeterThread implements Runnable, Interruptible {
                     // We reduce pause to ensure end of test is not delayed by a sleep ending after test scheduled end
                     // See Bug 60049
                     totalDelay = TIMER_SERVICE.adjustDelay(totalDelay, endTime);
+                    if (totalDelay < 0) {
+                        log.debug("The delay would be longer than the scheduled period, so stop thread now.");
+                        running = false;
+                        return;
+                    }
                 }
                 TimeUnit.MILLISECONDS.sleep(totalDelay);
             } catch (InterruptedException e) {
diff --git a/src/core/org/apache/jmeter/timers/TimerService.java b/src/core/org/apache/jmeter/timers/TimerService.java
index 15d7df9..6636bc9 100644
--- a/src/core/org/apache/jmeter/timers/TimerService.java
+++ b/src/core/org/apache/jmeter/timers/TimerService.java
@@ -60,13 +60,13 @@ public class TimerService {
      * Adjust delay so that initialDelay does not exceed end of test
      * @param initialDelay initial delay in millis
      * @param endTime End time of JMeterThread
-     * @return initialDelay or adjusted delay
+     * @return initialDelay or {@code -1} if delay is too long
      */
     public long adjustDelay(final long initialDelay, long endTime) {
         if (endTime > 0) {
             long now = System.currentTimeMillis();
             if (initialDelay > endTime - now) {
-                return endTime - now;
+                return -1;
             }
         }
         return initialDelay;
diff --git a/test/src/org/apache/jmeter/threads/TestJMeterThread.java b/test/src/org/apache/jmeter/threads/TestJMeterThread.java
index 002b78f..042348e 100644
--- a/test/src/org/apache/jmeter/threads/TestJMeterThread.java
+++ b/test/src/org/apache/jmeter/threads/TestJMeterThread.java
@@ -18,7 +18,17 @@
 
 package org.apache.jmeter.threads;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Date;
+
+import org.apache.jmeter.control.LoopController;
+import org.apache.jmeter.samplers.AbstractSampler;
+import org.apache.jmeter.samplers.Entry;
+import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.testelement.ThreadListener;
+import org.apache.jmeter.timers.ConstantTimer;
 import org.apache.jorphan.collections.HashTree;
 import org.junit.Test;
 
@@ -26,6 +36,43 @@ import org.junit.Test;
  * Tests for {@link JMeterThread}
  */
 public class TestJMeterThread {
+
+    private static final class DummySampler extends AbstractSampler {
+        private static final long serialVersionUID = 1L;
+        private boolean called = false;
+
+        public boolean isCalled() {
+            return called;
+        }
+
+        @Override
+        public SampleResult sample(Entry e) {
+            called = true;
+            return null;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + (called ? 1231 : 1237);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (!super.equals(obj))
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            DummySampler other = (DummySampler) obj;
+            return called == other.called;
+        }
+
+    }
+
     private static class ThrowingThreadListener implements ThreadListener {
 
         private boolean throwError;
@@ -71,5 +118,60 @@ public class TestJMeterThread {
                 new JMeterThread.ThreadListenerTraverser(true);
         hashTree.traverse(traverser);
     }
-    
+
+    @Test
+    public void testBug63490EndTestWhenDelayIsTooLongForScheduler() {
+
+        JMeterContextService.getContext().setVariables(new JMeterVariables());
+
+        HashTree testTree = new HashTree();
+        LoopController samplerController = createLoopController();
+        testTree.add(samplerController);
+        testTree.add(samplerController, createConstantTimer("3000"));
+        DummySampler dummySampler = createSampler();
+        testTree.add(samplerController, dummySampler);
+
+        TestCompiler compiler = new TestCompiler(testTree);
+        testTree.traverse(compiler);
+
+        ThreadGroup threadGroup = new ThreadGroup();
+        threadGroup.setNumThreads(1);
+        long maxDuration = 2000l;
+        threadGroup.setDuration(maxDuration);
+
+        JMeterThread jMeterThread = new JMeterThread(testTree, threadGroup, null);
+        jMeterThread.setScheduled(true);
+        jMeterThread.setEndTime(System.currentTimeMillis() + maxDuration);
+        jMeterThread.setThreadGroup(threadGroup);
+        long startTime = new Date().getTime();
+        jMeterThread.run();
+        long duration = new Date().getTime() - startTime;
+
+        assertFalse("Sampler should not be called", dummySampler.isCalled());
+
+        // the duration of this test plan should currently be around zero seconds,
+        // but it is allowed to take up to maxDuration amount of time
+        assertTrue("Test plan should not run for longer than duration", duration <= maxDuration);
+    }
+
+    private LoopController createLoopController() {
+        LoopController result = new LoopController();
+        result.setLoops(LoopController.INFINITE_LOOP_COUNT);
+        result.setEnabled(true);
+        return result;
+    }
+
+    private DummySampler createSampler() {
+        DummySampler result = new DummySampler();
+        result.setName("Call me");
+        return result;
+    }
+
+    private ConstantTimer createConstantTimer(String delay) {
+        ConstantTimer constantTimer = new ConstantTimer();
+        constantTimer.setEnabled(true);
+        constantTimer.setDelay(delay);
+        constantTimer.setName("Long delay");
+        return constantTimer;
+    }
 }
diff --git a/test/src/org/apache/jmeter/timers/TimerServiceTest.java b/test/src/org/apache/jmeter/timers/TimerServiceTest.java
index 652c8d3..428efd2 100644
--- a/test/src/org/apache/jmeter/timers/TimerServiceTest.java
+++ b/test/src/org/apache/jmeter/timers/TimerServiceTest.java
@@ -30,8 +30,21 @@ public class TimerServiceTest {
     public void testBigInitialDelay() {
         long now = System.currentTimeMillis();
         long adjustedDelay = sut.adjustDelay(Long.MAX_VALUE, now + 1000L);
-        // As #adjustDelay uses System#currentTimeMillis we can't be sure, that the value is exact 1000L
-        Assert.assertThat(Math.abs(adjustedDelay - 1000L) < 150L, CoreMatchers.is(true));
+        Assert.assertThat("TimerService should return -1 as delay would lead to a time after end time",
+                Long.valueOf(adjustedDelay), CoreMatchers.is(Long.valueOf(-1)));
+    }
+
+    @Test
+    public void testSmallInitialDelay() {
+        long now = System.currentTimeMillis();
+        Assert.assertThat("TimerService should not change the delay as the end time is far away",
+                Long.valueOf(sut.adjustDelay(1000L, now + 20000L)), CoreMatchers.is(Long.valueOf(1000L)));
+    }
+
+    @Test
+    public void testNegativeEndTime() {
+        Assert.assertThat("TimerService should not change the delay as the indicated end time is far away",
+                Long.valueOf(sut.adjustDelay(1000L, -1)), CoreMatchers.is(Long.valueOf(1000L)));
     }
 
 }
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index 75c60bc..f4b8421 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -188,6 +188,7 @@ to view the last major behaviors with the version 5.1.1.
 <ul>
     <li><bug>63394</bug>JMeter should fail with non-zero when test execution fails (due to missing test plan or other reason). Contributed by Ubik Load Pack (support at ubikloadpack.com)</li>
     <li><bug>63464</bug>image/svg+xml is wrongly considered as binary</li>
+    <li><bug>63490</bug>At end of scheduler duration lots of Samplers gets executed at the same time</li>
 </ul>
 
  <!--  =================== Thanks =================== -->