diff --git a/src/components/org/apache/jmeter/visualizers/NfrListnerGui.java b/src/components/org/apache/jmeter/visualizers/NfrListnerGui.java new file mode 100644 index 00000000000..91520e5cc74 --- /dev/null +++ b/src/components/org/apache/jmeter/visualizers/NfrListnerGui.java @@ -0,0 +1,376 @@ +/* + + * 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.visualizers; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedDeque; + +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.DefaultCellEditor; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.apache.jmeter.config.NfrArgument; +import org.apache.jmeter.gui.GuiPackage; +import org.apache.jmeter.gui.tree.JMeterTreeNode; +import org.apache.jmeter.gui.util.HeaderAsPropertyRenderer; +import org.apache.jmeter.gui.util.TextAreaCellRenderer; +import org.apache.jmeter.gui.util.TextAreaTableCellEditor; +import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy; +import org.apache.jmeter.reporters.AbstractListenerElement; +import org.apache.jmeter.reporters.NfrArguments; +import org.apache.jmeter.samplers.Clearable; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.testelement.TestElement; +import org.apache.jmeter.testelement.TestPlan; +import org.apache.jmeter.testelement.property.JMeterProperty; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.jmeter.visualizers.gui.AbstractListenerGui; +import org.apache.jorphan.gui.GuiUtils; +import org.apache.jorphan.gui.ObjectTableModel; +import org.apache.jorphan.reflect.Functor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Interface for Non-function-requirement Test. + */ +/** + * @author sqq94 + * + */ +public class NfrListnerGui extends AbstractListenerGui + implements Clearable, ActionListener, Visualizer, ChangeListener { + private static final long serialVersionUID = 242L; + private final JCheckBox useGroupName = new JCheckBox(JMeterUtils.getResString("aggregate_graph_use_group_name")); //$NON-NLS-1$ + /** Lock used to protect tableRows update + model update */ + private final transient Object lock = new Object(); + private Deque newRows = new ConcurrentLinkedDeque<>(); + private final JButton add = new JButton("add"); //$NON-NLS-1$ + private final JButton delete = new JButton("delete"); //$NON-NLS-1$ + private final JButton update = new JButton("update"); //$NON-NLS-1$ + private JTable stringTable; + /** Table model for the pattern table. */ + private ObjectTableModel tableModel; + protected NfrArguments collector = new NfrArguments(); + /** Logging. */ + private static final Logger log = LoggerFactory.getLogger(NfrListnerGui.class); + List NodesOfTypeHTTPSamplerProxy = new ArrayList<>(); + JComboBox nameComboBox = new JComboBox<>(); + + @Override + public boolean isStats() { + return false; + } + + protected NfrArguments getModel() { + return collector; + } + + /** + * Invoked when the target of the listener has changed its state. This + * implementation assumes that the target is the FilePanel, and will update the + * result collector for the new filename. + * + * @param e the event that has occurred + */ + @Override + public void stateChanged(ChangeEvent e) { + log.debug("getting new collector"); + collector = (NfrArguments) createTestElement(); + } + + /* Implements JMeterGUIComponent.createTestElement() */ + @Override + public TestElement createTestElement() { + if (collector == null) { + collector = new NfrArguments(); + } + modifyTestElement(collector); + return (TestElement) collector.clone(); + } + + public NfrListnerGui() { + super(); + this.setLayout(new BorderLayout()); + // MAIN PANEL + JPanel mainPanel = new JPanel(); + Border margin = new EmptyBorder(10, 10, 5, 10); + mainPanel.setBorder(margin); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.add(makeTitlePanel()); + this.add(mainPanel, BorderLayout.NORTH); + this.add(createStringPanel(), BorderLayout.CENTER); + JPanel buttonPanel = new JPanel(); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10)); + add.setActionCommand("ADD"); + add.addActionListener(this); + delete.setActionCommand("DELETE"); + delete.addActionListener(this); + update.setActionCommand("UPDATE"); + update.addActionListener(this); + buttonPanel.add(add); + buttonPanel.add(delete); + buttonPanel.add(update); + add.setEnabled(true); + this.add(buttonPanel, BorderLayout.SOUTH); + } + + @Override + public String getLabelResource() { + return "non_function_test"; //$NON-NLS-1$ + } + + @Override + public void add(final SampleResult res) { + SamplingStatCalculator row = collector.getNfrResult() + .computeIfAbsent(res.getSampleLabel(useGroupName.isSelected()), label -> { + SamplingStatCalculator newRow = new SamplingStatCalculator(label); + newRows.add(newRow); + return newRow; + }); + synchronized (row) { + /* + * Synch is needed because multiple threads can update the counts. + */ + row.addSample(res); + } + } + + /** + * Clears this visualizer and its model, and forces a repaint of the table. + */ + @Override + public void clearData() { + synchronized (lock) { + tableModel.clearData(); + collector.clearNfrResult(); + newRows.clear(); + } + } + + /** + * Initialization of table + * + * @return a new panel with the table + */ + /** A table of patterns to test against. */ + private JScrollPane createStringPanel() { + tableModel = new ObjectTableModel(new String[] { "Name", "Criteria", "Symbol", "Value", "Message" }, + NfrArgument.class, new Functor[] { new Functor("getName"), // $NON-NLS-1$ + new Functor("getCriteria"), new Functor("getSymbol"), new Functor("getValue"), + new Functor("getMessage") }, // $NON-NLS-1$ + new Functor[] { new Functor("setName"), // $NON-NLS-1$ + new Functor("setCriteria"), new Functor("setSymbol"), new Functor("setValue"), + new Functor("setMessage") }, // $NON-NLS-1$ + new Class[] { String.class, String.class, String.class, String.class, String.class }); + stringTable = new JTable(tableModel); + stringTable.getTableHeader().setDefaultRenderer(new HeaderAsPropertyRenderer()); + stringTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + JMeterUtils.applyHiDPI(stringTable); + TextAreaCellRenderer renderer = new TextAreaCellRenderer(); + stringTable.setRowHeight(renderer.getPreferredHeight()); + stringTable.setDefaultRenderer(String.class, renderer); + stringTable.setDefaultEditor(String.class, new TextAreaTableCellEditor()); + stringTable.setPreferredScrollableViewportSize(new Dimension(100, 70)); + JComboBox criteriaComboBox = new JComboBox<>(); + criteriaComboBox.addItem("Avg"); + criteriaComboBox.addItem("Min"); + criteriaComboBox.addItem("Max"); + criteriaComboBox.addItem("Error Rate"); + criteriaComboBox.addItem("Sample Rate"); + stringTable.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(criteriaComboBox)); + JComboBox symbolComboBox = new JComboBox<>(); + symbolComboBox.addItem(">"); + symbolComboBox.addItem(">="); + symbolComboBox.addItem("<"); + symbolComboBox.addItem("<="); + symbolComboBox.addItem("="); + stringTable.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(symbolComboBox)); + return new JScrollPane(stringTable); + } + + private List findNodesOfTypeHTTPSamplerProxy() { + JMeterTreeNode parent = (JMeterTreeNode) GuiPackage.getInstance().getCurrentNode().getParent(); + List listHTTPSamplerProxy = new ArrayList<>(); + if (parent.getTestElement().getClass().equals(HTTPSamplerProxy.class)) { + listHTTPSamplerProxy.add((HTTPSamplerProxy) parent.getTestElement()); + } else { + if (parent.getTestElement().getClass().equals(TestPlan.class)) { + List res = GuiPackage.getInstance().getTreeModel() + .getNodesOfType(HTTPSamplerProxy.class); + for (JMeterTreeNode jm : res) { + listHTTPSamplerProxy.add((HTTPSamplerProxy) jm.getTestElement()); + } + } else { + for (int i = 0; i < parent.getChildCount(); i++) { + JMeterTreeNode child = (JMeterTreeNode) parent.getChildAt(i); + if (child.getTestElement().getClass().equals(HTTPSamplerProxy.class)) { + listHTTPSamplerProxy.add((HTTPSamplerProxy) child.getTestElement()); + } + } + } + } + return listHTTPSamplerProxy; + } + + /** + * An ActionListener for deleting a row of table + */ + protected void checkButtonsStatus() { + // Disable DELETE if there are no rows in the table to delete. + if (tableModel.getRowCount() == 0) { + delete.setEnabled(false); + } else { + delete.setEnabled(true); + } + } + + @Override + public void modifyTestElement(TestElement args) { + configureTestElement((AbstractListenerElement) args); + if (args instanceof NfrArguments) { + NfrArguments rc = (NfrArguments) args; + collector = rc; + @SuppressWarnings("unchecked") + Iterator modelData = (Iterator) tableModel.iterator(); + rc.removeAllNfrArguments(); + while (modelData.hasNext()) { + NfrArgument arg = modelData.next(); + rc.addNfrArgument(arg); + } + } + super.configureTestElement(args); + } + + @Override + public void configure(TestElement el) { + super.configure(el); + if (el instanceof NfrArguments) { + NfrArguments rc = (NfrArguments) el; + if (collector == null) { + collector = new NfrArguments(); + } + tableModel.clearData(); + for (JMeterProperty jMeterProperty : rc.getNfrArguments()) { + NfrArgument arg = (NfrArgument) jMeterProperty.getObjectValue(); + tableModel.addRow(arg); + } + } + checkButtonsStatus(); + } + + protected void configureTestElement(AbstractListenerElement mc) { + super.configureTestElement(mc); + mc.setListener(this); + } + + @Override + protected Container makeTitlePanel() { + Container panel = super.makeTitlePanel(); + // Note: the file panel already includes the error logging checkbox, + // so we don't have to add it explicitly. + return panel; + } + + protected void setModel(NfrArguments collector) { + this.collector = collector; + } + + /** + * Clear all rows from the table. + */ + public void clear() { + GuiUtils.stopTableEditing(stringTable); + if (tableModel != null) { + tableModel.clearData(); + } + } + + @Override + public void clearGui() { + GuiUtils.stopTableEditing(stringTable); + if (tableModel != null) { + tableModel.clearData(); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("UPDATE")) { + NodesOfTypeHTTPSamplerProxy = findNodesOfTypeHTTPSamplerProxy(); + nameComboBox.removeAllItems(); + if(findNodesOfTypeHTTPSamplerProxy().isEmpty()){ + stringTable.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(new JTextField())); + } + else { + for (HTTPSamplerProxy httpSamplerProxy : NodesOfTypeHTTPSamplerProxy) { + nameComboBox.addItem(httpSamplerProxy.getName()); + } + stringTable.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(nameComboBox));} + } + if (e.getActionCommand().equals("ADD")) { + GuiUtils.stopTableEditing(stringTable); + tableModel.addRow(new NfrArgument("", "", "", "", "")); + checkButtonsStatus(); + // Highlight (select) and scroll to the appropriate row. + int rowToSelect = tableModel.getRowCount() - 1; + stringTable.setRowSelectionInterval(rowToSelect, rowToSelect); + stringTable.scrollRectToVisible(stringTable.getCellRect(rowToSelect, 0, true)); + } + if (e.getActionCommand().equals("DELETE")) { + GuiUtils.cancelEditing(stringTable); + int[] rowsSelected = stringTable.getSelectedRows(); + stringTable.clearSelection(); + if (rowsSelected.length > 0) { + for (int i = rowsSelected.length - 1; i >= 0; i--) { + tableModel.removeRow(rowsSelected[i]); + } + tableModel.fireTableDataChanged(); + } else { + if (tableModel.getRowCount() > 0) { + tableModel.removeRow(0); + tableModel.fireTableDataChanged(); + } + } + if (stringTable.getModel().getRowCount() == 0) { + delete.setEnabled(false); + } + } + } +} diff --git a/src/core/org/apache/jmeter/config/NfrArgument.java b/src/core/org/apache/jmeter/config/NfrArgument.java new file mode 100644 index 00000000000..e53990dd960 --- /dev/null +++ b/src/core/org/apache/jmeter/config/NfrArgument.java @@ -0,0 +1,168 @@ +/* + * 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.config; + +import java.io.Serializable; + +import org.apache.jmeter.testelement.AbstractTestElement; +import org.apache.jmeter.testelement.property.StringProperty; + +public class NfrArgument extends AbstractTestElement implements Serializable { + @Override + public String toString() { + return "NfrArgument [getName()=" + getName() + ", getValue()=" + getValue() + ", getCriteria()=" + getCriteria() + + ", getSymbol()=" + getSymbol() + ", getMessage()=" + getMessage() + "]"; + } + + private static final long serialVersionUID = 240L; + /** Name used to store the argument's name. */ + public static final String NAME = "NfrArgument.name"; // $NON-NLS-1$ + /** Name used to store the argument's value. */ + public static final String VALUE = "NfrArgument.value"; // $NON-NLS-1$ + /** Name used to store the argument's criteria. */ + public static final String CRITERIA = "NfrArgument.criteria"; // $NON-NLS-1$ + /** Name used to store the argument's symbol. */ + public static final String SYMBOL = "NfrArgument.symbol"; // $NON-NLS-1$ + /** Name used to store the argument's message. */ + public static final String MESSAGE = "NfrArgument.message"; // $NON-NLS-1$ + + /** + * Set the name of the Argument. + * + * @param newName the new name + */ + @Override + public void setName(String newName) { + setProperty(new StringProperty(NAME, newName)); + } + + /** + * Get the name of the Argument. + * + * @return the attribute's name + */ + @Override + public String getName() { + return getPropertyAsString(NAME); + } + + /** + * Sets the value of the Argument. + * + * @param newValue the new value + */ + public void setValue(String newValue) { + setProperty(new StringProperty(VALUE, newValue)); + } + + /** + * Gets the value of the Argument object. + * + * @return the attribute's value + */ + public String getValue() { + return getPropertyAsString(VALUE); + } + + /** + * Sets the criteria of the Argument. + * + * @param newCriteria + */ + public void setCriteria(String newCriteria) { + setProperty(new StringProperty(CRITERIA, newCriteria)); + } + + /** + * Gets the criteria attribute of the Argument. + * + * @return the criteria value + */ + public String getCriteria() { + return getPropertyAsString(CRITERIA); + } + + /** + * Sets the Symbol attribute of the Argument. + * + * @param newSymbol the new symbol + */ + public void setSymbol(String symbol) { + setProperty(new StringProperty(SYMBOL, symbol)); + } + + /** + * Gets the symbol of NFR test + * + * @return the attribute's symbol + */ + public String getSymbol() { + return getPropertyAsString(SYMBOL); + } + + /** + * Gets the message of NFR test + * + * @return the attribute's symbol + */ + public String getMessage() { + return getPropertyAsString(MESSAGE); + } + + /** + * Sets the Message attribute of the Argument. + * + * @param newMessage the new message + */ + public void setMessage(String message) { + setProperty(new StringProperty(MESSAGE, message)); + } + + /** + * Create a new NfrArgument without a name, value, symbol, criteria. + */ + public NfrArgument() { + this(null, null, null, null, null); + } + + /** + * Create a new Argument with the specified name, value, symbol, criteria. + * + * @param name the argument name + * @param value the argument value + * @param symbol the argument symbol + * @param criteria the argument criteria + */ + public NfrArgument(String name, String criteria, String symbol, String value, String message) { + if (name != null) { + setProperty(new StringProperty(NAME, name)); + } + if (value != null) { + setProperty(new StringProperty(VALUE, value)); + } + if (symbol != null) { + setProperty(new StringProperty(SYMBOL, symbol)); + } + if (criteria != null) { + setProperty(new StringProperty(CRITERIA, criteria)); + } + if (message != null) { + setProperty(new StringProperty(MESSAGE, message)); + } + } +} \ No newline at end of file diff --git a/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java b/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java index 5b77d2b6587..de0abff8457 100644 --- a/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java +++ b/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java @@ -28,6 +28,9 @@ import java.util.concurrent.TimeUnit; import org.apache.jmeter.JMeter; +import org.apache.jmeter.gui.GuiPackage; +import org.apache.jmeter.gui.tree.JMeterTreeNode; +import org.apache.jmeter.reporters.NfrArguments; import org.apache.jmeter.samplers.SampleEvent; import org.apache.jmeter.testbeans.TestBean; import org.apache.jmeter.testbeans.TestBeanHelper; @@ -488,7 +491,7 @@ public void run() { } waitThreadsStopped(); // wait for Post threads to stop } - + NFRTest(); notifyTestListenersOfEnd(testListeners); JMeterContextService.endTest(); if (JMeter.isNonGUI() && SYSTEM_EXIT_FORCED) { @@ -497,6 +500,15 @@ public void run() { } } + private void NFRTest() { + List treeNodes = GuiPackage.getInstance().getTreeModel().getNodesOfType(NfrArguments.class); + for(JMeterTreeNode treeNode:treeNodes) { + if (treeNode != null) { + NfrArguments nfrResultCollector = (NfrArguments) treeNode.getTestElement(); + nfrResultCollector.runNFRTest(); + }} + } + private void startThreadGroup(AbstractThreadGroup group, int groupCount, SearchByClass searcher, List testLevelElements, ListenerNotifier notifier) { try { diff --git a/src/core/org/apache/jmeter/reporters/NfrArguments.java b/src/core/org/apache/jmeter/reporters/NfrArguments.java new file mode 100644 index 00000000000..2db4128b37e --- /dev/null +++ b/src/core/org/apache/jmeter/reporters/NfrArguments.java @@ -0,0 +1,455 @@ +/* + * 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.reporters; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.jmeter.config.NfrArgument; +import org.apache.jmeter.engine.util.NoThreadClone; +import org.apache.jmeter.samplers.Clearable; +import org.apache.jmeter.samplers.Remoteable; +import org.apache.jmeter.samplers.SampleEvent; +import org.apache.jmeter.samplers.SampleListener; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.testelement.TestStateListener; +import org.apache.jmeter.testelement.property.CollectionProperty; +import org.apache.jmeter.testelement.property.JMeterProperty; +import org.apache.jmeter.testelement.property.PropertyIterator; +import org.apache.jmeter.testelement.property.TestElementProperty; +import org.apache.jmeter.visualizers.SamplingStatCalculator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class handles all saving of samples. The class must be thread-safe + * because it is shared between threads (NoThreadClone). + */ +public class NfrArguments extends AbstractListenerElement + implements SampleListener, Clearable, Serializable, TestStateListener, Remoteable, NoThreadClone { + private static Map tableRows = new ConcurrentHashMap<>(); + private static final Logger log = LoggerFactory.getLogger(NfrArguments.class); + private static final long serialVersionUID = 234L; + // This string is used to identify local test runs, so must not be a valid host + // name + private static final String TEST_IS_LOCAL = "*local*"; // $NON-NLS-1$ + // Static variables + // Lock used to guard static mutable variables + private static final Object LOCK = new Object(); + /** + * Shutdown Hook that ensures PrintWriter is flushed is CTRL+C or kill is called + * during a test + */ + private static Thread shutdownHook; + /** + * The instance count is used to keep track of whether any tests are currently + * running. It's not possible to use the constructor or threadStarted etc as + * tests may overlap e.g. a remote test may be started, and then a local test + * started whilst the remote test is still running. + */ + private static int instanceCount; // Keep track of how many instances are active + /** + * Is a test running ? + */ + private volatile boolean inTest = false; + private volatile boolean isStats = false; + /** the summarizer to which this result collector will forward the samples */ + private volatile Summariser summariser; + public static final String NFRARGUMENTS = "NfrArguments.nfrarguments"; //$NON-NLS-1$ + + /** + * @return the tableRows + */ + public Map getNfrResult() { + return tableRows; + } + + /** + * @return the tableRows + */ + public SamplingStatCalculator getNfrResultBySamplerName(String name) { + return tableRows.get(name); + } + + /** + * @return the tableRows + */ + public void clearNfrResult() { + tableRows.clear(); + } + + private static final class ShutdownHook implements Runnable { + @Override + public void run() { + log.info("Shutdown hook started"); + log.info("Shutdown hook ended"); + } + } + + /** + * No-arg constructor. + */ + public NfrArguments() { + this(null); + } + + /** + * Constructor which sets the used {@link Summariser} + * + * @param summer The {@link Summariser} to use + */ + public NfrArguments(Summariser summer) { + setProperty(new CollectionProperty(NFRARGUMENTS, new ArrayList())); + summariser = summer; + } + + // Ensure that the sample save config is not shared between copied nodes + // N.B. clone only seems to be used for client-server tests + @Override + public Object clone() { + NfrArguments clone = (NfrArguments) super.clone(); + clone.summariser = this.summariser; + return clone; + } + + /** + * Get the nfrarguments. + * + * @return the nfrarguments + */ + public CollectionProperty getNfrArguments() { + return (CollectionProperty) getProperty(NFRARGUMENTS); + } + + /** + * Set the list of nfrarguments. Any existing arguments will be lost. + * + * @param arguments the new arguments + */ + public void setNfrArguments(List arguments) { + setProperty(new CollectionProperty(NFRARGUMENTS, arguments)); + } + + /** + * Get the arguments as a Map. Each argument name is used as the key, and its + * value as the value. + * + * @return a new Map with String keys and values containing the arguments + */ + public Map getNfrArgumentsAsMap() { + PropertyIterator iter = getNfrArguments().iterator(); + Map argMap = new LinkedHashMap<>(); + while (iter.hasNext()) { + NfrArgument arg = (NfrArgument) iter.next().getObjectValue(); + if (!argMap.containsKey(arg.getName())) { + argMap.put(arg.getName(), arg.getValue()); + } + } + return argMap; + } + + /** + * Add a new argument. + * + * @param arg the new argument + */ + public void addNfrArgument(NfrArgument arg) { + TestElementProperty newArg = new TestElementProperty(arg.getName(), arg); + if (isRunningVersion()) { + this.setTemporary(newArg); + } + getNfrArguments().addItem(newArg); + } + + /** + * Add a new argument with the given name, value, criteria and symbol + * + * @param name + * @param criteria + * @param symbol + * @param value + */ + public void addNfrArgument(String name, String criteria, String symbol, String value, String message) { + addNfrArgument(new NfrArgument(name, criteria, symbol, value, message)); + } + + /** + * Get a PropertyIterator of the nfrarguments. + * + * @return an iteration of the nfrarguments + */ + public PropertyIterator iterator() { + return getNfrArguments().iterator(); + } + + /** + * Create a string representation of the nfrarguments. + * + * @return the string representation of the nfrarguments + */ + /** + * Remove the specified argument from the list. + * + * @param row the index of the argument to remove + */ + public void removeNfrArgument(int row) { + if (row < getNfrArguments().size()) { + getNfrArguments().remove(row); + } + } + + /** + * Remove the specified argument from the list. + * + * @param arg the argument to remove + */ + public void removeNfrArgument(NfrArgument arg) { + PropertyIterator iter = getNfrArguments().iterator(); + while (iter.hasNext()) { + NfrArgument item = (NfrArgument) iter.next().getObjectValue(); + if (arg.equals(item)) { + iter.remove(); + } + } + } + + /** + * Remove the argument with the specified name. + * + * @param argName the name of the argument to remove + */ + public void removeNfrArgument(String argName) { + PropertyIterator iter = getNfrArguments().iterator(); + while (iter.hasNext()) { + NfrArgument arg = (NfrArgument) iter.next().getObjectValue(); + if (arg.getName().equals(argName)) { + iter.remove(); + } + } + } + + /** + * Remove the argument with the specified name and value. + * + * @param argName the name of the argument to remove + * @param argValue the value to compare - must not be null + */ + public void removeNfrArgument(String argName, String argValue) { + PropertyIterator iter = getNfrArguments().iterator(); + while (iter.hasNext()) { + NfrArgument arg = (NfrArgument) iter.next().getObjectValue(); + if (arg.getName().equals(argName) && argValue.equals(arg.getValue())) { + iter.remove(); + } + } + } + + /** + * Remove all arguments from the list. + */ + public void removeAllNfrArguments() { + setProperty(new CollectionProperty(NFRARGUMENTS, new ArrayList())); + } + + /** + * Add a new empty argument to the list. The new argument will have the empty + * string as its name and value, and null metadata. + */ + public void addEmptyNfrArgument() { + addNfrArgument(new NfrArgument("", "", "", "", "")); + } + + /** + * Get the number of arguments in the list. + * + * @return the number of arguments + */ + public int getNfrArgumentCount() { + return getNfrArguments().size(); + } + + /** + * Get a single argument. + * + * @param row the index of the argument to return. + * @return the argument at the specified index, or null if no argument exists at + * that index. + */ + public NfrArgument getNfrArgument(int row) { + NfrArgument argument = null; + if (row < getNfrArguments().size()) { + argument = (NfrArgument) getNfrArguments().get(row).getObjectValue(); + } + return argument; + } + + @Override + public void testEnded(String host) { + synchronized (LOCK) { + instanceCount--; + if (instanceCount <= 0) { + // No need for the hook now + // Bug 57088 - prevent (im?)possible NPE + if (shutdownHook != null) { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } else { + log.warn("Should not happen: shutdownHook==null, instanceCount={}", instanceCount); + } + inTest = false; + } + } + if (summariser != null) { + summariser.testEnded(host); + } + } + + @Override + public void testStarted(String host) { + synchronized (LOCK) { + if (instanceCount == 0) { // Only add the hook once + shutdownHook = new Thread(new ShutdownHook()); + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + instanceCount++; + try { + if (getVisualizer() != null) { + this.isStats = getVisualizer().isStats(); + } + } catch (Exception e) { + log.error("Exception occurred while initializing file output.", e); + } + } + inTest = true; + if (summariser != null) { + summariser.testStarted(host); + } + } + + @Override + public void testEnded() { + testEnded(TEST_IS_LOCAL); + } + + @Override + public void testStarted() { + testStarted(TEST_IS_LOCAL); + } + + @Override + public void sampleStarted(SampleEvent e) { + // NOOP + } + + @Override + public void sampleStopped(SampleEvent e) { + // NOOP + } + + /** + * When a test result is received, display it and save it. + * + * @param event the sample event that was received + */ + @Override + public void sampleOccurred(SampleEvent event) { + SampleResult result = event.getResult(); + sendToVisualizer(result); + if (summariser != null) { + summariser.sampleOccurred(event); + } + } + + protected final void sendToVisualizer(SampleResult r) { + if (getVisualizer() != null) { + getVisualizer().add(r); + } + } + + // This is required so that + // @see org.apache.jmeter.gui.tree.JMeterTreeModel.getNodesOfType() + // can find the Clearable nodes - the userObject has to implement the interface. + @Override + public void clearData() { + super.clear(); + } + + private boolean getResultNfrTest(NfrArgument nfrArgument, SamplingStatCalculator samplingStatCalculator) { + double valueOfsampler = getCriteria(nfrArgument, samplingStatCalculator); + double valueOfUser = Double.parseDouble(nfrArgument.getValue()); + switch (nfrArgument.getSymbol()) { + case "=": + return valueOfsampler == valueOfUser; + case "<": + return valueOfsampler < valueOfUser; + case "<=": + return valueOfsampler <= valueOfUser; + case ">=": + return valueOfsampler >= valueOfUser; + case ">": + return valueOfsampler > valueOfUser; + default: + break; + } + return false; + } + + private double getCriteria(NfrArgument nfrArgument, SamplingStatCalculator samplingStatCalculator) { + double value = 0; + switch (nfrArgument.getCriteria()) { + case "Avg": + value = samplingStatCalculator.getMedian().doubleValue(); + break; + case "Min": + value = samplingStatCalculator.getMin().doubleValue(); + break; + case "Max": + value = samplingStatCalculator.getMax().doubleValue(); + break; + case "Error Rate": + value = samplingStatCalculator.getErrorPercentage(); + break; + case "Sample Rate": + value = samplingStatCalculator.getRate(); + break; + default: + break; + } + return value; + } + + public void runNFRTest() { + for (JMeterProperty jMeterProperty : getNfrArguments()) { + NfrArgument nfrArgument = (NfrArgument) jMeterProperty.getObjectValue(); + SamplingStatCalculator samplingStatCalculator = getNfrResultBySamplerName(nfrArgument.getName()); + if (samplingStatCalculator != null && !nfrArgument.getName().isEmpty() + && !nfrArgument.getCriteria().isEmpty() && !nfrArgument.getSymbol().isEmpty() + && !nfrArgument.getValue().isEmpty()) { + System.out.println("Key = " + nfrArgument.getName() + ", Value = " + samplingStatCalculator); + boolean result = getResultNfrTest(nfrArgument, samplingStatCalculator); + if (!result) { + System.out.println(nfrArgument.getMessage()); + } + System.out.println(result); + } + } + } +} diff --git a/src/core/org/apache/jmeter/resources/messages.properties b/src/core/org/apache/jmeter/resources/messages.properties index 65aa2b44bd7..d4153a0724d 100644 --- a/src/core/org/apache/jmeter/resources/messages.properties +++ b/src/core/org/apache/jmeter/resources/messages.properties @@ -774,6 +774,7 @@ next=Next no=Norwegian notify_child_listeners_fr=Notify Child Listeners of filtered samplers number_of_threads=Number of Threads (users)\: +non_function_test=Non Function Test obsolete_test_element=This test element is obsolete once_only_controller_title=Once Only Controller opcode=opCode diff --git a/src/core/org/apache/jmeter/resources/messages_fr.properties b/src/core/org/apache/jmeter/resources/messages_fr.properties index f4e6d654092..012ce1c2b81 100644 --- a/src/core/org/apache/jmeter/resources/messages_fr.properties +++ b/src/core/org/apache/jmeter/resources/messages_fr.properties @@ -762,6 +762,7 @@ newdn=Nouveau DN next=Suivant no=Norvégien notify_child_listeners_fr=Notifier les récepteurs fils des échantillons filtrés +non_function_test=Non Function Test number_of_threads=Nombre d'unités (utilisateurs) \: obsolete_test_element=Cet élément de test est obsolète once_only_controller_title=Contrôleur Exécution unique