blob: fcd3a5f6d26558d84f66cb83b1744300c061c0b7 [file] [log] [blame]
/*
* 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;
}
}