Author: pmouawad
Date: Thu Mar 24 21:14:46 2016
New Revision: 1736508

URL: http://svn.apache.org/viewvc?rev=1736508&view=rev
Log:
Bug 58941 - Create a new Starter that runs thread groups in validation mode (1 
thread only, 1 iteration, no pause all customizable)
Bugzilla Id: 58941

Added:
    jmeter/trunk/src/core/org/apache/jmeter/gui/action/validation/
    
jmeter/trunk/src/core/org/apache/jmeter/gui/action/validation/TreeClonerForValidation.java
   (with props)
Modified:
    jmeter/trunk/bin/jmeter.properties
    jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
    jmeter/trunk/src/core/org/apache/jmeter/gui/action/Start.java
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    
jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java
    jmeter/trunk/xdocs/changes.xml

Modified: jmeter/trunk/bin/jmeter.properties
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/bin/jmeter.properties?rev=1736508&r1=1736507&r2=1736508&view=diff
==============================================================================
--- jmeter/trunk/bin/jmeter.properties (original)
+++ jmeter/trunk/bin/jmeter.properties Thu Mar 24 21:14:46 2016
@@ -1304,3 +1304,24 @@ system.properties=system.properties
 # Comma separated list of files that contain reference to templates and their 
description
 # Path must be relative to jmeter root folder
 #template.files=/bin/templates/templates.xml
+
+
+#---------------------------------------------------------------------------
+# Thread Group Validation feature
+#---------------------------------------------------------------------------
+
+# Validation is the name of the feature used to rapidly validate a Thread 
Group runs fine
+# Default implementation is 
org.apache.jmeter.gui.action.validation.TreeClonerForValidation
+# It runs validation without timers, with 1 thread and 1 iteration
+# You can implement your own policy that must extend 
org.apache.jmeter.engine.TreeCloner
+# JMeter will instanciate it and use it to create the Tree used to run 
validation on Thread Group
+#testplan_validation.tree_cloner_class=org.apache.jmeter.gui.action.validation.TreeClonerForValidation
+
+# Number of threads to use to validate a Thread Group
+#testplan_validation.nb_threads_per_thread_group=1
+
+# Ignore timers when validating the thread group of plan
+#testplan_validation.ignore_timers=true
+
+# Number of iterations to use to validate a Thread Group
+#testplan_validation.number_iterations=1
\ No newline at end of file

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java?rev=1736508&r1=1736507&r2=1736508&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java 
(original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/ActionNames.java Thu Mar 
24 21:14:46 2016
@@ -101,6 +101,7 @@ public final class ActionNames {
     public static final String EXPAND           = "expand"; // $NON-NLS-1$
     public static final String RUN_TG           = "run_tg"; // $NON-NLS-1$
     public static final String RUN_TG_NO_TIMERS = "run_tg_no_timers"; // 
$NON-NLS-1$
+    public static final String VALIDATE_TG      = "validate_tg"; //$NON-NLS-1$
 
     // Prevent instantiation
     private ActionNames() {}

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/Start.java
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/Start.java?rev=1736508&r1=1736507&r2=1736508&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/Start.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/Start.java Thu Mar 24 
21:14:46 2016
@@ -33,6 +33,7 @@ import org.apache.jmeter.engine.Standard
 import org.apache.jmeter.engine.TreeCloner;
 import org.apache.jmeter.engine.TreeClonerNoTimer;
 import org.apache.jmeter.gui.GuiPackage;
+import org.apache.jmeter.gui.action.validation.TreeClonerForValidation;
 import org.apache.jmeter.gui.tree.JMeterTreeListener;
 import org.apache.jmeter.gui.tree.JMeterTreeNode;
 import org.apache.jmeter.testelement.TestElement;
@@ -45,12 +46,33 @@ import org.apache.jorphan.collections.Li
 import org.apache.jorphan.logging.LoggingManager;
 import org.apache.log.Logger;
 
+/**
+ * Set of Actions to:
+ * <ul>
+ *      <li>Start a Test Plan</li>
+ *      <li>Start a Test Plan without sleeping on the timers</li>
+ *      <li>Stop a Test Plan</li>
+ *      <li>Shutdown a Test plan</li>
+ *      <li>Run a set of Thread Groups</li>
+ *      <li>Run a set of Thread Groups without sleeping on the timers</li>
+ *      <li>Validate a set of Thread Groups with/without sleeping on the 
timers depending on jmeter properties</li>
+ * </ul>
+ */
 public class Start extends AbstractAction {
     
     private static final Logger LOG = LoggingManager.getLoggerForClass();
 
     private static final Set<String> commands = new HashSet<>();
 
+    private static final String VALIDATION_CLONER_CLASS_PROPERTY_NAME = 
+            "testplan_validation.tree_cloner_class"; //$NON-NLS-1$
+    /**
+     * Implementation of {@link TreeCloner} used to clone the tree before 
running validation
+     */
+    private static final String CLONER_FOR_VALIDATION_CLASS_NAME = 
+            JMeterUtils.getPropDefault(VALIDATION_CLONER_CLASS_PROPERTY_NAME, 
//$NON-NLS-1$ 
+                    TreeClonerForValidation.class.getName());
+
     static {
         commands.add(ActionNames.ACTION_START);
         commands.add(ActionNames.ACTION_START_NO_TIMERS);
@@ -58,6 +80,7 @@ public class Start extends AbstractActio
         commands.add(ActionNames.ACTION_SHUTDOWN);
         commands.add(ActionNames.RUN_TG);
         commands.add(ActionNames.RUN_TG_NO_TIMERS);
+        commands.add(ActionNames.VALIDATE_TG);
     }
 
     private StandardJMeterEngine engine;
@@ -99,15 +122,18 @@ public class Start extends AbstractActio
                 engine.askThreadsToStop();
             }
         } else if (e.getActionCommand().equals(ActionNames.RUN_TG) 
-                || e.getActionCommand().equals(ActionNames.RUN_TG_NO_TIMERS)) {
+                || e.getActionCommand().equals(ActionNames.RUN_TG_NO_TIMERS)
+                || e.getActionCommand().equals(ActionNames.VALIDATE_TG)) {
             popupShouldSave(e);
             boolean noTimers = 
e.getActionCommand().equals(ActionNames.RUN_TG_NO_TIMERS);
+            boolean isValidation = 
e.getActionCommand().equals(ActionNames.VALIDATE_TG);
+            
             JMeterTreeListener treeListener = 
GuiPackage.getInstance().getTreeListener();
             JMeterTreeNode[] nodes = treeListener.getSelectedNodes();
             nodes = Copy.keepOnlyAncestors(nodes);
             AbstractThreadGroup[] tg = keepOnlyThreadGroups(nodes);
             if(nodes.length > 0) {
-                startEngine(noTimers, tg);
+                startEngine(noTimers, isValidation, tg);
             }
             else {
                 LOG.warn("No thread group selected the test will not be 
started");
@@ -143,7 +169,20 @@ public class Start extends AbstractActio
      * @param ignoreTimer flag to ignore timers
      * @param threadGroupsToRun Array of AbstractThreadGroup to run
      */
-    private void startEngine(boolean ignoreTimer, AbstractThreadGroup[] 
threadGroupsToRun) {
+    private void startEngine(boolean ignoreTimer, 
+            AbstractThreadGroup[] threadGroupsToRun) {
+        startEngine(ignoreTimer, false, threadGroupsToRun);
+    }
+    
+    /**
+     * Start JMeter engine
+     * @param ignoreTimer flag to ignore timers
+     * @param isValidationShot 
+     * @param threadGroupsToRun Array of AbstractThreadGroup to run
+     */
+    private void startEngine(boolean ignoreTimer, 
+            boolean isValidationShot,
+            AbstractThreadGroup[] threadGroupsToRun) {
         GuiPackage gui = GuiPackage.getInstance();
         HashTree testTree = gui.getTreeModel().getTestPlan();
         
@@ -151,14 +190,19 @@ public class Start extends AbstractActio
         if(threadGroupsToRun != null && threadGroupsToRun.length>0) {
             removeThreadGroupsFromHashTree(testTree, threadGroupsToRun);
         }
-        
         testTree.add(testTree.getArray()[0], gui.getMainFrame());
         LOG.debug("test plan before cloning is running version: "
                 + ((TestPlan) testTree.getArray()[0]).isRunningVersion());
-        
-        TreeCloner cloner = cloneTree(testTree, ignoreTimer);
-        
-        ListedHashTree clonedTree = cloner.getClonedTree();
+
+        ListedHashTree clonedTree = null;
+        if(isValidationShot) {
+            TreeCloner cloner = createTreeClonerForValidation();
+            testTree.traverse(cloner);
+            clonedTree = cloner.getClonedTree();
+        } else {
+            TreeCloner cloner = cloneTree(testTree, ignoreTimer);      
+            clonedTree = cloner.getClonedTree();
+        }
         engine = new StandardJMeterEngine();
         engine.configure(clonedTree);
         try {
@@ -172,6 +216,23 @@ public class Start extends AbstractActio
     }
 
     /**
+     * 
+     * @return {@link TreeCloner}
+     */
+    private static TreeCloner createTreeClonerForValidation() {
+        Class<?> clazz;
+        try {
+            clazz = Class.forName(CLONER_FOR_VALIDATION_CLASS_NAME, true, 
Thread.currentThread().getContextClassLoader());
+            return (TreeCloner) clazz.newInstance();
+        } catch (InstantiationException | IllegalAccessException | 
ClassNotFoundException ex) {
+            LOG.error("Error instanciating class:'"
+                    +CLONER_FOR_VALIDATION_CLASS_NAME+"' defined in property 
:'"
+                    +VALIDATION_CLONER_CLASS_PROPERTY_NAME+"'", ex);
+            return new TreeClonerForValidation();
+        }
+    }
+
+    /**
      * Remove thread groups from testTree that are not in threadGroupsToKeep
      * @param testTree {@link HashTree}
      * @param threadGroupsToKeep Array of {@link AbstractThreadGroup} to keep

Added: 
jmeter/trunk/src/core/org/apache/jmeter/gui/action/validation/TreeClonerForValidation.java
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/validation/TreeClonerForValidation.java?rev=1736508&view=auto
==============================================================================
--- 
jmeter/trunk/src/core/org/apache/jmeter/gui/action/validation/TreeClonerForValidation.java
 (added)
+++ 
jmeter/trunk/src/core/org/apache/jmeter/gui/action/validation/TreeClonerForValidation.java
 Thu Mar 24 21:14:46 2016
@@ -0,0 +1,86 @@
+/*
+ * 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.gui.action.validation;
+
+import org.apache.jmeter.control.LoopController;
+import org.apache.jmeter.engine.TreeCloner;
+import org.apache.jmeter.threads.AbstractThreadGroup;
+import org.apache.jmeter.threads.ThreadGroup;
+import org.apache.jmeter.timers.Timer;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.logging.LoggingManager;
+import org.apache.log.Logger;
+
+/**
+ * Clones the test tree,  skipping test elements that implement {@link Timer} 
by default.
+ * @since 3.0
+ */
+public class TreeClonerForValidation extends TreeCloner {
+    
+    private static final Logger LOG = LoggingManager.getLoggerForClass();
+
+    /**
+     * Number of Threads to configure when running a Thread Group during a 
validation
+     */
+    protected static final int VALIDATION_NUMBER_OF_THREADS = 
JMeterUtils.getPropDefault("testplan_validation.nb_threads_per_thread_group", 
1); //$NON-NLS-1$
+    /**
+     * Ignore or not timers during a Thread Group validation
+     */
+    protected static final boolean VALIDATION_IGNORE_TIMERS = 
JMeterUtils.getPropDefault("testplan_validation.ignore_timers", true); 
//$NON-NLS-1$
+
+    /**
+     * Number of iterations to run during a Thread Group validation
+     */
+    protected static final int VALIDATION_ITERATIONS = 
JMeterUtils.getPropDefault("testplan_validation.number_iterations", 1); 
//$NON-NLS-1$
+    
+    static {
+        if(LOG.isInfoEnabled()) {
+            LOG.info("Running validation with number of 
threads:"+VALIDATION_NUMBER_OF_THREADS
+                    + ", ignoreTimers:"+VALIDATION_IGNORE_TIMERS
+                    + ", number of iterations:"+VALIDATION_ITERATIONS);
+        }
+    }
+
+    public TreeClonerForValidation() {
+        this(false);
+    }
+
+    public TreeClonerForValidation(boolean honourNoThreadClone) {
+        super(honourNoThreadClone);
+    }
+
+    /**
+     * @see org.apache.jmeter.engine.TreeCloner#addNodeToTree(java.lang.Object)
+     */
+    @Override
+    protected Object addNodeToTree(Object node) {
+        if(VALIDATION_IGNORE_TIMERS && node instanceof Timer) {
+            return node; // don't add the timer
+        } else {
+            Object clonedNode = super.addNodeToTree(node);
+            if(clonedNode instanceof org.apache.jmeter.threads.ThreadGroup) {
+                
((ThreadGroup)clonedNode).setNumThreads(VALIDATION_NUMBER_OF_THREADS);
+                if(((AbstractThreadGroup)clonedNode).getSamplerController() 
instanceof LoopController) {
+                    
((LoopController)((AbstractThreadGroup)clonedNode).getSamplerController()).setLoops(VALIDATION_ITERATIONS);
+                }
+            }
+            return clonedNode;
+        }
+    }
+}

Propchange: 
jmeter/trunk/src/core/org/apache/jmeter/gui/action/validation/TreeClonerForValidation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1736508&r1=1736507&r2=1736508&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties 
(original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Thu 
Mar 24 21:14:46 2016
@@ -1216,6 +1216,7 @@ user_parameters_title=User Parameters
 userdn=Username
 username=Username
 userpw=Password
+validate_threadgroup=Validate
 value=Value
 value_to_quote_meta=Value to escape from ORO Regexp meta chars
 var_name=Reference Name

Modified: 
jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1736508&r1=1736507&r2=1736508&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties 
(original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties 
Thu Mar 24 21:14:46 2016
@@ -1201,6 +1201,7 @@ user_parameters_title=Param\u00E8tres Ut
 userdn=Identifiant
 username=Nom d'utilisateur \:
 userpw=Mot de passe
+validate_threadgroup=Valider
 value=Valeur \:
 value_to_quote_meta=Valeur \u00E0 \u00E9chapper des caract\u00E8res 
sp\u00E9ciaux utilis\u00E8s par ORO Regexp
 var_name=Nom de r\u00E9f\u00E9rence \:

Modified: 
jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java?rev=1736508&r1=1736507&r2=1736508&view=diff
==============================================================================
--- 
jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java 
(original)
+++ 
jmeter/trunk/src/core/org/apache/jmeter/threads/gui/AbstractThreadGroupGui.java 
Thu Mar 24 21:14:46 2016
@@ -94,6 +94,12 @@ public abstract class AbstractThreadGrou
             runTgNotimers.addActionListener(ActionRouter.getInstance());
             runTgNotimers.setActionCommand(ActionNames.RUN_TG_NO_TIMERS);
             pop.add(runTgNotimers);
+
+            JMenuItem validateTg = new 
JMenuItem(JMeterUtils.getResString("validate_threadgroup"));
+            validateTg.setName("validate_threadgroup");
+            validateTg.addActionListener(ActionRouter.getInstance());
+            validateTg.setActionCommand(ActionNames.VALIDATE_TG);
+            pop.add(validateTg);
         }
         
         MenuFactory.addEditMenu(pop, true);

Modified: jmeter/trunk/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1736508&r1=1736507&r2=1736508&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml (original)
+++ jmeter/trunk/xdocs/changes.xml Thu Mar 24 21:14:46 2016
@@ -279,6 +279,7 @@ Summary
 <li><bug>59152</bug>Thread Group: Change "Action to be taken after a Sample 
Error" value from "Continue" to "Start Next thread loop". Contributed by 
Antonio Gomes Rodrigues (ra0077 at gmail.com)</li>
 <li><bug>59197</bug>Thread Group : it should be possible to only run a single 
threadgroup or a selection of threadgroups with a popup menu. Contributed by 
Benoit Wiart (benoit dot wiart at gmail.com)</li>
 <li><bug>59207</bug>Change the font color of errorsOrFatalsLabel to red when 
an error occurs. Contributed by Antonio Gomes Rodrigues (ra0077 at 
gmail.com)</li>
+<li><bug>58941</bug>Create a new Starter that runs thread groups in validation 
mode (1 thread only, 1 iteration, no pause all customizable)</li>
 </ul>
 <ch_section>Non-functional changes</ch_section>
 <ul>


Reply via email to