| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to you under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jmeter.threads; |
| |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.time.Instant; |
| |
| 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.AbstractTestElement; |
| import org.apache.jmeter.testelement.ThreadListener; |
| import org.apache.jmeter.timers.Timer; |
| import org.apache.jorphan.collections.HashTree; |
| import org.junit.jupiter.api.Test; |
| |
| 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().equals(obj.getClass())) { |
| return false; |
| } |
| DummySampler other = (DummySampler) obj; |
| return called == other.called; |
| } |
| |
| } |
| |
| private static class DummyTimer extends AbstractTestElement implements Timer { |
| private static final long serialVersionUID = 5641410390783919241L; |
| private long delay; |
| |
| void setDelay(long delay) { |
| this.delay = delay; |
| } |
| |
| @Override |
| public long delay() { |
| return delay; |
| } |
| } |
| |
| private static class ThrowingThreadListener implements ThreadListener { |
| private boolean throwError; |
| |
| public ThrowingThreadListener(boolean throwError) { |
| this.throwError = throwError; |
| } |
| |
| @Override |
| public void threadStarted() { |
| if (throwError) { |
| throw new NoClassDefFoundError("Throw for Bug TestJMeterThread"); |
| } else { |
| throw new RuntimeException("Throw for Bug TestJMeterThread"); |
| } |
| } |
| |
| @Override |
| public void threadFinished() { |
| if (throwError) { |
| throw new NoClassDefFoundError("Throw for Bug TestJMeterThread"); |
| } else { |
| throw new RuntimeException("Throw for Bug TestJMeterThread"); |
| } |
| } |
| } |
| |
| @Test |
| void testBug61661OnError() { |
| HashTree hashTree = new HashTree(); |
| hashTree.add("Test", new ThrowingThreadListener(true)); |
| JMeterThread.ThreadListenerTraverser traverser = |
| new JMeterThread.ThreadListenerTraverser(true); |
| assertThrows( |
| NoClassDefFoundError.class, |
| () -> hashTree.traverse(traverser)); |
| } |
| |
| @Test |
| void testBug61661OnException() { |
| HashTree hashTree = new HashTree(); |
| hashTree.add("Test", new ThrowingThreadListener(false)); |
| JMeterThread.ThreadListenerTraverser traverser = |
| new JMeterThread.ThreadListenerTraverser(true); |
| hashTree.traverse(traverser); |
| } |
| |
| @Test |
| 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); |
| Instant startTime = Instant.now(); |
| jMeterThread.run(); |
| long duration = Instant.now().toEpochMilli() - startTime.toEpochMilli(); |
| |
| assertFalse(dummySampler.isCalled(), "Sampler should not be called"); |
| |
| // 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(duration <= maxDuration, "Test plan should not run for longer than duration"); |
| } |
| |
| 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 Timer createConstantTimer(long delay) { |
| DummyTimer timer = new DummyTimer(); |
| timer.setEnabled(true); |
| timer.setDelay(delay); |
| timer.setName("Long delay"); |
| return timer; |
| } |
| } |