Skip to content
Merged
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 .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ sudo: false
language: java

before_script:
- test "x$RUN_CHECKSTYLE" != 'x' || ant -Djava.awt.headless=true download_jars install
- test "x$RUN_CHECKSTYLE" != 'x' || ant -Djava.awt.headless=true clean download_jars install
- test "x$RUN_CHECKSTYLE" != 'xtrue' || ant -Djava.awt.headless=true download_checkstyle

before_install:
Expand Down
5 changes: 5 additions & 0 deletions src/core/org/apache/jmeter/resources/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ attribute_field=Attribute\:
attrs=Attributes
auth_base_url=Base URL
auth_manager_clear_per_iter=Clear auth on each iteration?
auth_manager_clear_controlled_by_threadgroup=Use Thread Group configuration to control clearing
auth_manager_options=Options
auth_manager_title=HTTP Authorization Manager
auths_stored=Authorizations Stored in the Authorization Manager
Expand Down Expand Up @@ -175,6 +176,7 @@ busy_testing=I'm busy testing, please stop the test before changing settings
cache_manager_size=Max Number of elements in cache
cache_manager_title=HTTP Cache Manager
cache_session_id=Cache Session Id?
cache_clear_controlled_by_threadgroup=Use Thread Group configuration to control cache clearing
cancel=Cancel
cancel_exit_to_save=There are test items that have not been saved. Do you wish to save before exiting?
cancel_new_from_template=There are test items that have not been saved. Do you wish to save before creating a test plan from selected template?
Expand Down Expand Up @@ -229,6 +231,7 @@ cookie_manager_policy=Cookie Policy:
cookie_manager_title=HTTP Cookie Manager
cookie_options=Options
cookies_stored=User-Defined Cookies
cookie_clear_controlled_by_threadgroup=Use Thread Group configuration to control cookie clearing
copy=Copy
counter_config_title=Counter
counter_per_user=Track counter independently for each user
Expand Down Expand Up @@ -1280,6 +1283,8 @@ thread_group_title=Thread Group
thread_group_scheduler_warning=If Loop Count is not -1 or Forever, duration will be min(Duration, Loop Count * iteration duration)
thread_properties=Thread Properties
threadgroup=Thread Group
threadgroup_same_user=Same user on each iteration
threadgroup_different_user=Different User on Each Iteration
throughput_control_bynumber_label=Total Executions
throughput_control_bypercent_label=Percent Executions
throughput_control_perthread_label=Per User
Expand Down
5 changes: 5 additions & 0 deletions src/core/org/apache/jmeter/resources/messages_fr.properties
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ attribute_field=Attribut \:
attrs=Attributs
auth_base_url=URL de base
auth_manager_clear_per_iter=Réauthentifier à chaque itération ?
auth_manager_clear_controlled_by_threadgroup=Utiliser la configuration du groupe de threads pour contrôler la Réauthentification
auth_manager_options=Options
auth_manager_title=Gestionnaire d'autorisation HTTP
auths_stored=Autorisations stockées
Expand Down Expand Up @@ -170,6 +171,7 @@ busy_testing=Je suis occupé à tester, veuillez arrêter le test avant de chang
cache_manager_size=Nombre maximum d'éléments dans le cache
cache_manager_title=Gestionnaire de cache HTTP
cache_session_id=Identifiant de session de cache ?
cache_clear_controlled_by_threadgroup=Utiliser thread group pour contrôler l'effacement de cache
cancel=Annuler
cancel_exit_to_save=Il y a des éléments qui n'ont pas été sauvés. Voulez-vous enregistrer avant de sortir ?
cancel_new_from_template=Il y a des éléments qui n'ont pas été sauvés. Voulez-vous enregistrer avant de charger le modèle ?
Expand Down Expand Up @@ -224,6 +226,7 @@ cookie_manager_policy=Politique des cookies \:
cookie_manager_title=Gestionnaire de cookies HTTP
cookie_options=Options
cookies_stored=Cookies stockés
cookie_clear_controlled_by_threadgroup=Utiliser thread group pour contrôler l'effacement des cookies
copy=Copier
counter_config_title=Compteur
counter_per_user=Suivre le compteur indépendamment pour chaque unité de test
Expand Down Expand Up @@ -1269,6 +1272,8 @@ thread_group_title=Groupe d'unités
thread_group_scheduler_warning=Si le nombre de boucles n'est pas -1 ou Infini, la durée sera min (Durée, Nombre d'itérations * durée de l'itération).
thread_properties=Propriétés du groupe d'unités
threadgroup=Groupe d'unités
threadgroup_same_user=Même utilisateur à chaque itération
threadgroup_different_user=Utilisateur différent à chaque itération
throughput_control_bynumber_label=Exécutions totales
throughput_control_bypercent_label=Pourcentage d'exécution
throughput_control_perthread_label=Par utilisateur
Expand Down
28 changes: 28 additions & 0 deletions src/core/org/apache/jmeter/threads/AbstractThreadGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.testelement.property.IntegerProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.TestElementProperty;
Expand Down Expand Up @@ -72,6 +73,10 @@ public abstract class AbstractThreadGroup extends AbstractTestElement
public static final String NUM_THREADS = "ThreadGroup.num_threads";

public static final String MAIN_CONTROLLER = "ThreadGroup.main_controller";

/** The same user or different users */
public static final String IS_SAME_USER_ON_NEXT_ITERATION = "ThreadGroup.same_user_on_next_iteration";


private final AtomicInteger numberOfThreads = new AtomicInteger(0); // Number of active threads in this group

Expand Down Expand Up @@ -299,4 +304,27 @@ public boolean getOnErrorStopTestNow() {
public void breakThreadLoop() {
((LoopController) getSamplerController()).breakLoop();
}

/**
* Set the kind of user
*
* @param isSameUserOnNextIteration
* true is the same user on next iteration of loop
* false is a different user on next iteration of loop
*/
public void setIsSameUserOnNextIteration(boolean isSameUserOnNextIteration) {
setProperty(new BooleanProperty(IS_SAME_USER_ON_NEXT_ITERATION, isSameUserOnNextIteration));
}

/**
* Get kind of user:
* <ul>
* <li>true means same user running multiple iterations</li>
* <li>false means a different user for each iteration</li>
* </ul>
* @return the kind of user.
*/
public boolean isSameUserOnNextIteration() {
return getPropertyAsBoolean(ThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION);
}
}
12 changes: 9 additions & 3 deletions src/core/org/apache/jmeter/threads/JMeterThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,10 @@ public class JMeterThread implements Runnable, Interruptible {

private long endTime = 0;

private boolean scheduler = false;
private final boolean isSameUserOnNextIteration;

// based on this scheduler is enabled or disabled
private boolean scheduler = false;

// Gives access to parent thread threadGroup
private AbstractThreadGroup threadGroup;
Expand All @@ -149,6 +151,10 @@ public class JMeterThread implements Runnable, Interruptible {
private final ReentrantLock interruptLock = new ReentrantLock(); // ensure that interrupt cannot overlap with shutdown

public JMeterThread(HashTree test, JMeterThreadMonitor monitor, ListenerNotifier note) {
this(test, monitor, note, false);
}

public JMeterThread(HashTree test, JMeterThreadMonitor monitor, ListenerNotifier note,Boolean isSameUserOnNextIteration) {
this.monitor = monitor;
threadVars = new JMeterVariables();
testTree = test;
Expand All @@ -162,6 +168,7 @@ public JMeterThread(HashTree test, JMeterThreadMonitor monitor, ListenerNotifier
sampleMonitors = sampleMonitorSearcher.getSearchResults();
notifier = note;
running = true;
this.isSameUserOnNextIteration = isSameUserOnNextIteration;
}

public void setInitialContext(JMeterContext context) {
Expand Down Expand Up @@ -237,13 +244,11 @@ private void startScheduler() {
public void setThreadName(String threadName) {
this.threadName = threadName;
}

@Override
public void run() {
// threadContext is not thread-safe, so keep within thread
JMeterContext threadContext = JMeterContextService.getContext();
LoopIterationListener iterationListener = null;

try {
iterationListener = initRun(threadContext);
while (running) {
Expand Down Expand Up @@ -687,6 +692,7 @@ private List<SampleListener> getSampleListeners(SamplePackage samplePack, Sample
* @return the iteration listener
*/
private IterationListener initRun(JMeterContext threadContext) {
threadVars.putObject(JMeterVariables.VAR_IS_SAME_USER_KEY, isSameUserOnNextIteration);
threadContext.setVariables(threadVars);
threadContext.setThreadNum(getThreadNum());
threadContext.getVariables().put(LAST_SAMPLE_OK, TRUE);
Expand Down
9 changes: 9 additions & 0 deletions src/core/org/apache/jmeter/threads/JMeterVariables.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class JMeterVariables {
"TESTSTART.MS", // $NON-NLS-1$
};

static final String VAR_IS_SAME_USER_KEY = "__jmv_SAME_USER";

/**
* Constructor, that preloads the variables from the JMeter properties
*/
Expand Down Expand Up @@ -171,4 +173,11 @@ public Iterator<Entry<String, Object>> getIterator(){
public Set<Entry<String, Object>> entrySet(){
return Collections.unmodifiableMap(variables).entrySet();
}

/**
* @return boolean true if user is the same on next iteration of Thread loop, false otherwise
*/
public boolean isSameUserOnNextIteration() {
return Boolean.TRUE.equals(variables.get(VAR_IS_SAME_USER_KEY));
}
}
25 changes: 14 additions & 11 deletions src/core/org/apache/jmeter/threads/ThreadGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public class ThreadGroup extends AbstractThreadGroup {

/** Scheduler start delay, overrides start time */
public static final String DELAY = "ThreadGroup.delay";

//- JMX entries

private transient Thread threadStarter;
Expand Down Expand Up @@ -216,6 +215,7 @@ public void start(int groupNum, ListenerNotifier notifier, ListedHashTree thread
this.threadGroupTree = threadGroupTree;
int numThreads = getNumThreads();
int rampUpPeriodInSeconds = getRampUp();
boolean isSameUserOnNextIteration = isSameUserOnNextIteration();
delayedStartup = isDelayedStartup(); // Fetch once; needs to stay constant
log.info("Starting thread group... number={} threads={} ramp-up={} delayedStart={}", groupNumber,
numThreads, rampUpPeriodInSeconds, delayedStartup);
Expand All @@ -236,11 +236,11 @@ public void start(int groupNum, ListenerNotifier notifier, ListedHashTree thread
delayForNextThreadInMillis += perThreadDelayInMillis - timeElapsedToStartLastThread;
}
if (log.isDebugEnabled()) {
log.debug("Computed delayForNextThreadInMillis:{} for thread:{}", delayForNextThreadInMillis);
log.debug("Computed delayForNextThreadInMillis:{} for thread:{}", delayForNextThreadInMillis, Thread.currentThread().getId());
}
lastThreadStartInMillis = nowInMillis;
startNewThread(notifier, threadGroupTree, engine, threadNum, context, nowInMillis,
Math.max(0, delayForNextThreadInMillis));
startNewThread(notifier, threadGroupTree, engine, threadNum, context,
nowInMillis, Math.max(0, delayForNextThreadInMillis), isSameUserOnNextIteration);
}
}
log.info("Started thread group number {}", groupNumber);
Expand All @@ -255,11 +255,12 @@ public void start(int groupNum, ListenerNotifier notifier, ListedHashTree thread
* @param context {@link JMeterContext}
* @param now Nom in milliseconds
* @param delay int delay in milliseconds
* @param isSameUserOnNextIteration boolean indicating a next iteration will simulate a new or returning user
* @return {@link JMeterThread} newly created
*/
private JMeterThread startNewThread(ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine,
int threadNum, final JMeterContext context, long now, int delay) {
JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, threadNum, context);
int threadNum, final JMeterContext context, long now, int delay, Boolean isSameUserOnNextIteration) {
JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, threadNum, context, isSameUserOnNextIteration);
scheduleThread(jmThread, now); // set start and end time
jmThread.setInitialDelay(delay);
Thread newThread = new Thread(jmThread, jmThread.getThreadName());
Expand Down Expand Up @@ -292,18 +293,19 @@ private void registerStartedThread(JMeterThread jMeterThread, Thread newThread)
* @param engine {@link StandardJMeterEngine}
* @param threadNumber int thread number
* @param context {@link JMeterContext}
* @param isSameUserOnNextIteration Boolean
* @return {@link JMeterThread}
*/
private JMeterThread makeThread(
ListenerNotifier notifier, ListedHashTree threadGroupTree,
StandardJMeterEngine engine, int threadNumber,
JMeterContext context) { // N.B. Context needs to be fetched in the correct thread
StandardJMeterEngine engine, int threadNumber,
JMeterContext context, Boolean isSameUserOnNextIteration) { // N.B. Context needs to be fetched in the correct thread
boolean onErrorStopTest = getOnErrorStopTest();
boolean onErrorStopTestNow = getOnErrorStopTestNow();
boolean onErrorStopThread = getOnErrorStopThread();
boolean onErrorStartNextLoop = getOnErrorStartNextLoop();
String groupName = getName();
final JMeterThread jmeterThread = new JMeterThread(cloneTree(threadGroupTree), this, notifier);
final JMeterThread jmeterThread = new JMeterThread(cloneTree(threadGroupTree), this, notifier, isSameUserOnNextIteration);
jmeterThread.setThreadNum(threadNumber);
jmeterThread.setThreadGroup(this);
jmeterThread.setInitialContext(context);
Expand All @@ -329,7 +331,7 @@ public JMeterThread addNewThread(int delay, StandardJMeterEngine engine) {
numThreads = getNumThreads();
setNumThreads(numThreads + 1);
}
newJmThread = startNewThread(notifier, threadGroupTree, engine, numThreads, context, now, delay);
newJmThread = startNewThread(notifier, threadGroupTree, engine, numThreads, context, now, delay, isSameUserOnNextIteration());
JMeterContextService.addTotalThreads( 1 );
log.info("Started new thread in group {}", groupNumber);
return newJmThread;
Expand Down Expand Up @@ -597,6 +599,7 @@ public void run() {
final int numThreads = getNumThreads();
final float rampUpOriginInMillis = (float) getRampUp() * 1000;
final long startTimeInMillis = System.currentTimeMillis();
final boolean isSameUserOnNextIteration = isSameUserOnNextIteration();
for (int threadNumber = 0; running && threadNumber < numThreads; threadNumber++) {
if (threadNumber > 0) {
long elapsedInMillis = System.currentTimeMillis() - startTimeInMillis;
Expand All @@ -607,7 +610,7 @@ public void run() {
if (usingScheduler && System.currentTimeMillis() > endtime) {
break; // no point continuing beyond the end time
}
JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, threadNumber, context);
JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, threadNumber, context, isSameUserOnNextIteration);
jmThread.setInitialDelay(0); // Already waited
if (usingScheduler) {
jmThread.setScheduled(true);
Expand Down
31 changes: 30 additions & 1 deletion src/core/org/apache/jmeter/threads/gui/ThreadGroupGui.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@
import java.awt.event.ItemListener;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.control.gui.LoopControlPanel;
import org.apache.jmeter.gui.util.HorizontalPanel;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.property.BooleanProperty;
Expand Down Expand Up @@ -62,6 +65,10 @@ public class ThreadGroupGui extends AbstractThreadGroupGui implements ItemListen

private JTextField delay; // Relative start-up time

private JRadioButton sameUserBox;

private JRadioButton differentUserBox;

public ThreadGroupGui() {
this(true);
}
Expand Down Expand Up @@ -100,6 +107,7 @@ public void modifyTestElement(TestElement tg) {
tg.setProperty(new BooleanProperty(ThreadGroup.SCHEDULER, scheduler.isSelected()));
tg.setProperty(ThreadGroup.DURATION, duration.getText());
tg.setProperty(ThreadGroup.DELAY, delay.getText());
tg.setProperty(AbstractThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION,sameUserBox.isSelected());
}

@Override
Expand All @@ -117,6 +125,12 @@ public void configure(TestElement tg) {

duration.setText(tg.getPropertyAsString(ThreadGroup.DURATION));
delay.setText(tg.getPropertyAsString(ThreadGroup.DELAY));
final boolean isSameUser = tg.getPropertyAsBoolean(AbstractThreadGroup.IS_SAME_USER_ON_NEXT_ITERATION, false);
if (isSameUser){
sameUserBox.setSelected(true);
} else {
differentUserBox.setSelected(true);
}
}

@Override
Expand Down Expand Up @@ -193,6 +207,8 @@ private void initGui(){
scheduler.setSelected(false);
delay.setText(""); // $NON-NLS-1$
duration.setText(""); // $NON-NLS-1$
sameUserBox.setSelected(true);
differentUserBox.setSelected(false);
}

private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
Expand Down Expand Up @@ -228,7 +244,7 @@ private void init() { // WARNING: called from ctor so must not be overridden (i.

// LOOP COUNT
threadPropsPanel.add(createControllerPanel());

threadPropsPanel.add(createUserOptionsPanel());
if (showDelayedStart) {
delayedStart = new JCheckBox(JMeterUtils.getResString("delayed_start")); // $NON-NLS-1$
threadPropsPanel.add(delayedStart);
Expand All @@ -252,4 +268,17 @@ private void init() { // WARNING: called from ctor so must not be overridden (i.
intgrationPanel.add(mainPanel);
add(intgrationPanel, BorderLayout.CENTER);
}

private JPanel createUserOptionsPanel(){
ButtonGroup group = new ButtonGroup();
sameUserBox = new JRadioButton(JMeterUtils.getResString("threadgroup_same_user")); //$NON-NLS-1$
group.add(sameUserBox);
sameUserBox.setSelected(true);
differentUserBox = new JRadioButton(JMeterUtils.getResString("threadgroup_different_user")); //$NON-NLS-1$
group.add(differentUserBox);
JPanel optionsPanel = new HorizontalPanel();
optionsPanel.add(sameUserBox);
optionsPanel.add(differentUserBox);
return optionsPanel;
}
}
Loading