You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2017/12/09 14:10:53 UTC

svn commit: r1817611 - in /jmeter/trunk: src/components/org/apache/jmeter/assertions/ src/components/org/apache/jmeter/control/ test/src/org/apache/jmeter/ test/src/org/apache/jmeter/assertions/ test/src/org/apache/jmeter/control/ test/src/org/apache/j...

Author: pmouawad
Date: Sat Dec  9 14:10:53 2017
New Revision: 1817611

URL: http://svn.apache.org/viewvc?rev=1817611&view=rev
Log:
Re-wrote some existing tests in Spock
Contributed by Graham Russell
This closes #353

Added:
    jmeter/trunk/test/src/org/apache/jmeter/assertions/MD5HexAssertionSpec.groovy
    jmeter/trunk/test/src/org/apache/jmeter/control/RandomOrderControllerSpec.groovy
    jmeter/trunk/test/src/org/apache/jmeter/control/ThroughputControllerSpec.groovy
    jmeter/trunk/test/src/org/apache/jmeter/engine/util/PackageSpec.groovy
Removed:
    jmeter/trunk/test/src/org/apache/jmeter/assertions/MD5HexAssertionTest.java
    jmeter/trunk/test/src/org/apache/jmeter/control/TestRandomOrderController.java
    jmeter/trunk/test/src/org/apache/jmeter/control/TestThroughputController.java
    jmeter/trunk/test/src/org/apache/jmeter/engine/util/PackageTest.java
Modified:
    jmeter/trunk/src/components/org/apache/jmeter/assertions/MD5HexAssertion.java
    jmeter/trunk/src/components/org/apache/jmeter/control/RandomOrderController.java
    jmeter/trunk/src/components/org/apache/jmeter/control/ThroughputController.java
    jmeter/trunk/test/src/org/apache/jmeter/JMeterVersionTest.java
    jmeter/trunk/test/src/org/apache/jmeter/engine/DistributedRunnerTest.java
    jmeter/trunk/xdocs/changes.xml

Modified: jmeter/trunk/src/components/org/apache/jmeter/assertions/MD5HexAssertion.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/assertions/MD5HexAssertion.java?rev=1817611&r1=1817610&r2=1817611&view=diff
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/assertions/MD5HexAssertion.java (original)
+++ jmeter/trunk/src/components/org/apache/jmeter/assertions/MD5HexAssertion.java Sat Dec  9 14:10:53 2017
@@ -47,9 +47,6 @@ public class MD5HexAssertion extends Abs
     /** Key for storing assertion-information in the jmx-file. */
     private static final String MD5HEX_KEY = "MD5HexAssertion.size";
 
-    /*
-     * @param response @return
-     */
     @Override
     public AssertionResult getResult(SampleResult response) {
 
@@ -72,15 +69,16 @@ public class MD5HexAssertion extends Abs
             return result;
         }
 
-        String md5Result = baMD5Hex(resultData);
+        String md5Result = md5Hex(resultData);
 
         if (!md5Result.equalsIgnoreCase(getAllowedMD5Hex())) {
             result.setFailure(true);
 
             Object[] arguments = { md5Result, getAllowedMD5Hex() };
-            String message = MessageFormat.format(JMeterUtils.getResString("md5hex_assertion_failure"), arguments); // $NON-NLS-1$
+            String message = MessageFormat.format(
+                    JMeterUtils.getResString("md5hex_assertion_failure"), // $NON-NLS-1$
+                    arguments);
             result.setFailureMessage(message);
-
         }
 
         return result;
@@ -94,13 +92,11 @@ public class MD5HexAssertion extends Abs
         return getPropertyAsString(MD5HexAssertion.MD5HEX_KEY);
     }
 
-    // package protected so can be accessed by test class
-    static String baMD5Hex(byte[] ba) {
+    private static String md5Hex(byte[] bytes) {
         byte[] md5Result = {};
 
         try {
-            MessageDigest md = MessageDigest.getInstance("MD5");
-            md5Result = md.digest(ba);
+            md5Result = MessageDigest.getInstance("MD5").digest(bytes);
         } catch (NoSuchAlgorithmException e) {
             log.error("Message digestion failed.", e);
         }

Modified: jmeter/trunk/src/components/org/apache/jmeter/control/RandomOrderController.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/control/RandomOrderController.java?rev=1817611&r1=1817610&r2=1817611&view=diff
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/control/RandomOrderController.java (original)
+++ jmeter/trunk/src/components/org/apache/jmeter/control/RandomOrderController.java Sat Dec  9 14:10:53 2017
@@ -21,15 +21,11 @@ import java.util.Collections;
 
 /**
  * A controller that runs its children each at most once, but in a random order.
- *
  */
 public class RandomOrderController extends GenericController implements Serializable {
 
     private static final long serialVersionUID = 240L;
 
-    /**
-     * Create a new RandomOrderController.
-     */
     public RandomOrderController() {
     }
 

Modified: jmeter/trunk/src/components/org/apache/jmeter/control/ThroughputController.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/control/ThroughputController.java?rev=1817611&r1=1817610&r2=1817611&view=diff
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/control/ThroughputController.java (original)
+++ jmeter/trunk/src/components/org/apache/jmeter/control/ThroughputController.java Sat Dec  9 14:10:53 2017
@@ -48,27 +48,24 @@ public class ThroughputController
     private static final long serialVersionUID = 234L;
 
     private static final Logger log = LoggerFactory.getLogger(ThroughputController.class);
-    public static final int BYNUMBER = 0;
 
+    public static final int BYNUMBER = 0;
     public static final int BYPERCENT = 1;
 
     private static final String STYLE = "ThroughputController.style";// $NON-NLS-1$
-
     private static final String PERTHREAD = "ThroughputController.perThread";// $NON-NLS-1$
-
     private static final String MAXTHROUGHPUT = "ThroughputController.maxThroughput";// $NON-NLS-1$
-
     private static final String PERCENTTHROUGHPUT = "ThroughputController.percentThroughput";// $NON-NLS-1$
 
     private static class MutableInteger{
         private int integer;
         MutableInteger(int value){
-            integer=value;
+            integer = value;
         }
         int incr(){
             return ++integer;
         }
-        public int intValue() {
+        int intValue() {
             return integer;
         }
     }
@@ -76,9 +73,7 @@ public class ThroughputController
     // These items are shared between threads in a group by the clone() method
     // They are initialised by testStarted() so don't need to be serialised
     private transient MutableInteger globalNumExecutions;
-
     private transient MutableInteger globalIteration;
-
     private transient Object counterLock = new Object(); // ensure counts are updated correctly
 
     /** Number of iterations on which we've chosen to deliver samplers. */
@@ -180,9 +175,6 @@ public class ThroughputController
         return numExecutions;
     }
 
-    /**
-     * @see org.apache.jmeter.control.Controller#next()
-     */
     @Override
     public Sampler next() {
         if (runThisTime) {
@@ -201,18 +193,12 @@ public class ThroughputController
         return (100.0 * executions + 50.0) / (iterations + 1) < getPercentThroughputAsFloat();
     }
 
-    /**
-     * @see org.apache.jmeter.control.Controller#isDone()
-     */
     @Override
     public boolean isDone() {
-        if (subControllersAndSamplers.isEmpty()) {
-            return true;
-        } else {
-            return getStyle() == BYNUMBER
-                    && getExecutions() >= getMaxThroughputAsInt()
-                    && current >= getSubControllers().size();
-        }
+        return subControllersAndSamplers.isEmpty()
+                || (getStyle() == BYNUMBER
+                && getExecutions() >= getMaxThroughputAsInt()
+                && current >= getSubControllers().size());
     }
 
     @Override

Modified: jmeter/trunk/test/src/org/apache/jmeter/JMeterVersionTest.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/JMeterVersionTest.java?rev=1817611&r1=1817610&r2=1817611&view=diff
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/JMeterVersionTest.java (original)
+++ jmeter/trunk/test/src/org/apache/jmeter/JMeterVersionTest.java Sat Dec  9 14:10:53 2017
@@ -168,9 +168,12 @@ public class JMeterVersionTest extends J
                     }
                 }
                 String expected = versions.get(jar);
-                if(expected == null) {
-                    System.err.println("Didn't find version for jar name extracted by regexp, jar name extracted:"+jar+", version extracted:"+version+", current line:"+line);
-                    fail("Didn't find version for jar name extracted by regexp, jar name extracted:"+jar+", version extracted:"+version+", current line:"+line);
+                if (expected == null) {
+                    final String message =
+                            "Didn't find version for jar name extracted by regexp, jar name extracted:"
+                                    + jar + ", version extracted:" + version + ", current line:" + line;
+                    System.err.println(message);
+                    fail(message);
                 }
                 // Process ${xxx.version} references
                 final Matcher mp = versionPat.matcher(expected);

Added: jmeter/trunk/test/src/org/apache/jmeter/assertions/MD5HexAssertionSpec.groovy
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/assertions/MD5HexAssertionSpec.groovy?rev=1817611&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/assertions/MD5HexAssertionSpec.groovy (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/assertions/MD5HexAssertionSpec.groovy Sat Dec  9 14:10:53 2017
@@ -0,0 +1,80 @@
+/*
+ * 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.assertions
+
+import org.apache.commons.lang3.StringUtils
+import org.apache.jmeter.junit.spock.JMeterSpec
+import org.apache.jmeter.samplers.SampleResult
+import spock.lang.Unroll
+
+import java.nio.charset.StandardCharsets
+
+@Unroll
+class MD5HexAssertionSpec extends JMeterSpec {
+
+    def sut = new MD5HexAssertion()
+
+    def "unset allowable hash with empty response fails"() {
+        when:
+            def result = sut.getResult(sampleResult(""))
+        then:
+            result.isFailure()
+            StringUtils.isNotBlank(result.getFailureMessage())
+    }
+
+    def "incorrect hash #allowedHex causes result failure"() {
+        given:
+            sut.setAllowedMD5Hex(allowedHex)
+        when:
+            def result = sut.getResult(sampleResult("anything"))
+        then:
+            result.isFailure()
+            StringUtils.isNotBlank(result.getFailureMessage())
+        where:
+            allowedHex << ["", "anything", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
+    }
+
+    def "example MD5s - '#sampleData' == '#hash'"() {
+        given:
+            sut.setAllowedMD5Hex(hash)
+        when:
+            def result = sut.getResult(sampleResult(sampleData))
+        then:
+            !result.isFailure()
+            !result.isError()
+            result.getFailureMessage() == null
+        where:
+            sampleData | hash
+            "anything" | "f0e166dc34d14d6c228ffac576c9a43c"
+            "anything" | "F0e166Dc34D14d6c228ffac576c9a43c"
+    }
+
+    def "empty array has MD5 hash of D41D8CD98F00B204E9800998ECF8427E"() {
+        given:
+            def emptyByteArray = [] as byte[]
+        expect:
+            MD5HexAssertion.md5Hex(emptyByteArray)
+                    .toUpperCase(Locale.ENGLISH) == "D41D8CD98F00B204E9800998ECF8427E"
+    }
+
+    def sampleResult(String data) {
+        SampleResult response = new SampleResult()
+        response.setResponseData(data.getBytes(StandardCharsets.UTF_8))
+        return response
+    }
+}

Added: jmeter/trunk/test/src/org/apache/jmeter/control/RandomOrderControllerSpec.groovy
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/control/RandomOrderControllerSpec.groovy?rev=1817611&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/control/RandomOrderControllerSpec.groovy (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/control/RandomOrderControllerSpec.groovy Sat Dec  9 14:10:53 2017
@@ -0,0 +1,95 @@
+/*
+ * 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.control
+
+import org.apache.jmeter.junit.stubs.TestSampler
+import org.apache.jmeter.testelement.TestElement
+import spock.lang.Specification
+
+class RandomOrderControllerSpec extends Specification {
+
+    def sut = new RandomOrderController()
+
+    def "next() on an empty controller returns null"() {
+        given:
+            sut.initialize()
+        when:
+            def nextSampler = sut.next()
+        then:
+            nextSampler == null
+    }
+
+    def "next() returns only provided sampler"() {
+        given:
+            def sampler = new TestSampler("the one and only")
+            sut.addTestElement(sampler)
+            sut.initialize()
+        when:
+            def nextSampler = sut.next()
+            def nextSamplerAfterEnd = sut.next()
+        then:
+            nextSampler == sampler
+            nextSamplerAfterEnd == null
+    }
+
+    def "next() returns exactly all added elements in random order"() {
+        given:
+            def samplerNames = (1..50).collect { it.toString() }
+            samplerNames.each {
+                sut.addTestElement(new TestSampler(it))
+            }
+            sut.initialize()
+        when:
+            def elements = getAllTestElements(sut)
+        then: "the same elements are returned but in a different order"
+            def elementNames = elements.collect { it.getName() }
+            elementNames.toSet() == samplerNames.toSet() // same elements
+            elementNames != samplerNames                 // not the same order
+
+    }
+
+    def "next() is null if isDone() is true"() {
+        given:
+            sut.addTestElement(Mock(TestElement))
+            sut.initialize()
+            sut.setDone(true)
+        when:
+            def nextSampler = sut.next()
+        then:
+            sut.isDone()
+            nextSampler == null
+    }
+
+    /**
+     * Builds and returns a list by 'iterating' through the
+     * {@link GenericController}, using {@link GenericController#next()},
+     * placing each item in a list until <code>null</code> is encountered.
+     *
+     * @param controller the {@link GenericController} to 'iterate' though
+     * @return a list of all items (in order) returned from next()
+     * method, excluding null
+     */
+    def getAllTestElements(GenericController controller) {
+        def sample
+        def samplers = []
+        while ((sample = controller.next()) != null) {
+            samplers.add(sample)
+        }
+        return samplers
+    }
+}

Added: jmeter/trunk/test/src/org/apache/jmeter/control/ThroughputControllerSpec.groovy
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/control/ThroughputControllerSpec.groovy?rev=1817611&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/control/ThroughputControllerSpec.groovy (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/control/ThroughputControllerSpec.groovy Sat Dec  9 14:10:53 2017
@@ -0,0 +1,187 @@
+/*
+ * 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.control
+
+import org.apache.jmeter.junit.stubs.TestSampler
+import spock.lang.Specification
+
+class ThroughputControllerSpec extends Specification {
+
+    def sut = new ThroughputController()
+
+    def setup() {
+        sut.addTestElement(new TestSampler("one"))
+        sut.addTestElement(new TestSampler("two"))
+    }
+
+    def "new TC isDone is true"() {
+        given:
+            def newTC = new ThroughputController()
+        expect:
+            newTC.isDone()
+    }
+
+    def "2 maxThroughput runs samplers inside the TC only twice"() {
+        given:
+            sut.setStyle(ThroughputController.BYNUMBER)
+            sut.setMaxThroughput(2)
+
+            def expectedNames =
+                    ["zero", "one", "two", "three",
+                     "zero", "one", "two", "three",
+                     "zero", "three",
+                     "zero", "three",
+                     "zero", "three",]
+
+            def loop = createLoopController(5)
+        when:
+            def actualNames = expectedNames.collect({
+                loop.next().getName()
+            })
+        then:
+            loop.next() == null
+            actualNames == expectedNames
+            sut.isDone()
+            sut.testEnded()
+    }
+
+    def "0 maxThroughput does not run any samplers inside the TC"() {
+        given:
+            sut.setStyle(ThroughputController.BYNUMBER)
+            sut.setMaxThroughput(0)
+
+            def loops = 3
+            def loop = createLoopController(loops)
+
+            def expectedNames = ["zero", "three"] * loops
+        when:
+            def actualNames = expectedNames.collect({
+                loop.next().getName()
+            })
+        then:
+            loop.next() == null
+            actualNames == expectedNames
+            sut.testEnded()
+    }
+
+    def "33.33% will run all the samplers inside the TC every 3 iterations"() {
+        given:
+            sut.setStyle(ThroughputController.BYPERCENT)
+            sut.setPercentThroughput(33.33f)
+
+            def loop = createLoopController(9)
+            // Expected results established using the DDA algorithm - see:
+            // http://www.siggraph.org/education/materials/HyperGraph/scanline/outprims/drawline.htm
+            def expectedNames =
+                    ["zero", "three", // 0/1 vs. 1/1 -> 0 is closer to 33.33
+                     "zero", "one", "two", "three", // 0/2 vs. 1/2 -> 50.0 is closer to 33.33
+                     "zero", "three", // 1/3 vs. 2/3 -> 33.33 is closer to 33.33
+                     "zero", "three", // 1/4 vs. 2/4 -> 25.0 is closer to 33.33
+                     "zero", "one", "two", "three", // 1/5 vs. 2/5 -> 40.0 is closer to 33.33
+                     "zero", "three", // 2/6 vs. 3/6 -> 33.33 is closer to 33.33
+                     "zero", "three", // 2/7 vs. 3/7 -> 0.2857 is closer to 33.33
+                     "zero", "one", "two", "three", // 2/8 vs. 3/8 -> 0.375 is closer to 33.33
+                     "zero", "three", // ...
+                    ]
+        when:
+            def actualNames = expectedNames.collect({
+                loop.next().getName()
+            })
+        then:
+            loop.next() == null
+            actualNames == expectedNames
+            sut.testEnded()
+    }
+
+    def "0% does not run any samplers inside the TC"() {
+        given:
+            sut.setStyle(ThroughputController.BYPERCENT)
+            sut.setPercentThroughput(0.0f)
+
+            def loops = 3
+            def loop = createLoopController(loops)
+
+            def expectedNames = ["zero", "three",] * loops
+        when:
+            def actualNames = expectedNames.collect({
+                loop.next().getName()
+            })
+        then:
+            loop.next() == null
+            actualNames == expectedNames
+            sut.testEnded()
+    }
+
+    def "100% always runs all samplers inside the TC"() {
+        given:
+            sut.setStyle(ThroughputController.BYPERCENT)
+            sut.setPercentThroughput(100.0f)
+
+            def loops = 3
+            def loop = createLoopController(loops)
+
+            def expectedNames = ["zero", "one", "two", "three",] * loops
+        when:
+            def actualNames = expectedNames.collect({
+                loop.next().getName()
+            })
+        then:
+            loop.next() == null
+            actualNames == expectedNames
+            sut.testEnded()
+    }
+
+    /**
+     * Create a LoopController, executed once, which contains an inner loop that
+     * runs {@code innerLoops} times, this inner loop contains a TestSampler ("zero")
+     * the {@link ThroughputController} which contains two test samplers
+     * ("one" and "two") followed by a final TestSampler ("three"):
+     *
+     * <pre>
+     * - outerLoop
+     *   - innerLoop
+     *     - sampler zero
+     *     - ThroughputController (sut)
+     *        - sampler one
+     *        - sampler two
+     *     - sampler three
+     * </pre>
+     *
+     * @param innerLoops number of times to loop the {@link ThroughputController}
+     * @return the {@link LoopController}
+     */
+    def createLoopController(int innerLoops) {
+        LoopController innerLoop = new LoopController()
+        innerLoop.setLoops(innerLoops)
+        innerLoop.addTestElement(new TestSampler("zero"))
+        innerLoop.addTestElement(sut)
+        innerLoop.addIterationListener(sut)
+        innerLoop.addTestElement(new TestSampler("three"))
+
+        def outerLoop = new LoopController()
+        outerLoop.setLoops(1)
+        outerLoop.addTestElement(innerLoop)
+        sut.testStarted()
+        outerLoop.setRunningVersion(true)
+        sut.setRunningVersion(true)
+        innerLoop.setRunningVersion(true)
+        outerLoop.initialize()
+        outerLoop
+    }
+}

Modified: jmeter/trunk/test/src/org/apache/jmeter/engine/DistributedRunnerTest.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/engine/DistributedRunnerTest.java?rev=1817611&r1=1817610&r2=1817611&view=diff
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/engine/DistributedRunnerTest.java (original)
+++ jmeter/trunk/test/src/org/apache/jmeter/engine/DistributedRunnerTest.java Sat Dec  9 14:10:53 2017
@@ -24,9 +24,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
-import java.net.MalformedURLException;
-import java.rmi.NotBoundException;
-import java.rmi.RemoteException;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
@@ -41,7 +38,7 @@ import org.slf4j.LoggerFactory;
 
 public class DistributedRunnerTest {
 
-    public static void createJmeterEnv() throws IOException {
+    public static void createJmeterEnv() {
         File propsFile;
         try {
             propsFile = File.createTempFile("jmeter", ".properties");
@@ -126,8 +123,8 @@ public class DistributedRunnerTest {
         public List<EmulatorEngine> engines = new LinkedList<>();
 
         @Override
-        protected JMeterEngine createEngine(String address) throws RemoteException, NotBoundException, MalformedURLException {
-            if(engines.size()==0) {
+        protected JMeterEngine createEngine(String address) {
+            if (engines.isEmpty()) {
                 throw new IllegalArgumentException("Throwing on Engine creation to simulate failure");
             }
             EmulatorEngine engine = engines.remove(0);

Added: jmeter/trunk/test/src/org/apache/jmeter/engine/util/PackageSpec.groovy
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/engine/util/PackageSpec.groovy?rev=1817611&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/engine/util/PackageSpec.groovy (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/engine/util/PackageSpec.groovy Sat Dec  9 14:10:53 2017
@@ -0,0 +1,137 @@
+/*
+ * 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.engine.util
+
+import org.apache.jmeter.junit.spock.JMeterSpec
+import org.apache.jmeter.samplers.SampleResult
+import org.apache.jmeter.testelement.property.JMeterProperty
+import org.apache.jmeter.testelement.property.StringProperty
+import org.apache.jmeter.threads.JMeterContextService
+import org.apache.jmeter.threads.JMeterVariables
+import spock.lang.Unroll
+
+/**
+ * To run this test stand-alone, ensure that ApacheJMeter_functions.jar is on the classpath,
+ * as it is needed to resolve the functions.
+ */
+class PackageSpec extends JMeterSpec {
+
+    def transformer
+    def jmctx
+
+    def setup() {
+        def variables = ["my_regex": ".*",
+                         "server"  : "jakarta.apache.org"]
+        transformer = new ReplaceStringWithFunctions(new CompoundVariable(), variables)
+        jmctx = JMeterContextService.getContext()
+        jmctx.setVariables(new JMeterVariables())
+        jmctx.setSamplingStarted(true)
+        def result = new SampleResult()
+        result.setResponseData('<a>hello world</a> costs: $3.47,$5.67', null)
+        jmctx.setPreviousResult(result)
+        jmctx.getVariables().put("server", "jakarta.apache.org")
+        jmctx.getVariables().put("my_regex", ".*")
+    }
+
+    def testFunctionParse1() {
+        given:
+            StringProperty prop = new StringProperty("date",
+                    '${__javaScript((new Date().getDate() / 100).toString()' +
+                            '.substr(${__javaScript(1+1,d\\,ay)}\\,2),heute)}')
+        when:
+            JMeterProperty newProp = transformer.transformValue(prop)
+            newProp.setRunningVersion(true)
+        then:
+            newProp.getClass().getName() == "org.apache.jmeter.testelement.property.FunctionProperty"
+            newProp.recoverRunningVersion(null)
+            Integer.parseInt(newProp.getStringValue()) >= 0
+            jmctx.getVariables().getObject("d,ay") == "2"
+    }
+
+    @Unroll
+    def "test parsing StringProperty '#propertyValue' == '#stringValue'"() {
+        given:
+            StringProperty prop = new StringProperty("a", propertyValue)
+        when:
+            JMeterProperty newProp = transformer.transformValue(prop)
+            newProp.setRunningVersion(true)
+        then:
+            newProp.getClass().getName() == 'org.apache.jmeter.testelement.property.StringProperty'
+            newProp.getStringValue() == stringValue
+        where:
+            propertyValue    | stringValue
+            ""               | ""
+            "just some text" | "just some text"
+    }
+
+    @Unroll
+    def "test parsing FunctionProperty '#propertyValue' == '#stringValue'"() {
+        given:
+            StringProperty prop = new StringProperty("a", propertyValue)
+        when:
+            JMeterProperty newProp = transformer.transformValue(prop)
+            newProp.setRunningVersion(true)
+        then:
+            newProp.getClass().getName() == 'org.apache.jmeter.testelement.property.FunctionProperty'
+            newProp.getStringValue() == stringValue
+        where:
+            propertyValue                                                                | stringValue
+            '${__regexFunction(<a>(.*)</a>,$1$)}'                                        | "hello world"
+            'It should say:\\${${__regexFunction(<a>(.+o)(.*)</a>,$1$$2$)}}'             | 'It should say:${hello world}'
+            '${non - existing; function}'                                                | '${non - existing; function}'
+            '${server}'                                                                  | "jakarta.apache.org"
+            '${__regexFunction(<([a-z]*)>,$1$)}'                                         | "a"
+            '${__regexFunction((\\\\$\\d+\\.\\d+),$1$)}'                                 | '$3.47'
+            '${__regexFunction(([$]\\d+\\.\\d+),$1$)}'                                   | '$3.47'
+            '${__regexFunction((\\\\\\$\\d+\\.\\d+\\,\\\\$\\d+\\.\\d+),$1$)}'            | '$3.47,$5.67'
+
+            // Nested examples
+            '${__regexFunction(<a>(${my_regex})</a>,$1$)}'                               | "hello world"
+            '${__regexFunction(<a>(${my_regex})</a>,$1$)}${__regexFunction(<a>(.),$1$)}' | "hello worldh"
+    }
+
+    @Unroll
+    def "Backslashes are removed before escaped dollar, comma and backslash with FunctionProperty"() {
+        // N.B. See Bug 46831 which wanted to changed the behaviour of \$
+        // It's too late now, as this would invalidate some existing test plans,
+        // so document the current behaviour with some more tests.
+        given:
+            StringProperty prop = new StringProperty("a", propertyValue)
+        when:
+            JMeterProperty newProp = transformer.transformValue(prop)
+            newProp.setRunningVersion(true)
+        then:
+            newProp.getClass().getName() == 'org.apache.jmeter.testelement.property.' + className
+            newProp.getStringValue() == stringValue
+
+        where:
+            propertyValue | className        | stringValue
+            // With no variable reference
+            '\\$a'        | "StringProperty" | '\\$a'
+            '\\,'         | "StringProperty" | '\\,'
+            '\\\\'        | "StringProperty" | '\\\\'
+            '\\'          | "StringProperty" | '\\'
+            '\\x'         | "StringProperty" | '\\x'
+        and: // With variable reference
+            '\\$a \\, \\\\ \\ \\x ${server} \\$b\\,z'       | "FunctionProperty" | '$a , \\ \\ \\x jakarta.apache.org $b,z'
+            '\\$a \\, \\\\ \\ \\x ${__missing(a)} \\$b\\,z' | "FunctionProperty" | '$a , \\ \\ \\x ${__missing(a)} $b,z'
+            '\\$a \\, \\\\ \\ \\x ${missing}      \\$b\\,z' | "FunctionProperty" | '$a , \\ \\ \\x ${missing}      $b,z'
+            '\\$a \\, \\\\ ${ z'                            | "FunctionProperty" | '$a , \\  z'
+    }
+
+}

Modified: jmeter/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jmeter/trunk/xdocs/changes.xml?rev=1817611&r1=1817610&r2=1817611&view=diff
==============================================================================
--- jmeter/trunk/xdocs/changes.xml [utf-8] (original)
+++ jmeter/trunk/xdocs/changes.xml [utf-8] Sat Dec  9 14:10:53 2017
@@ -185,6 +185,7 @@ Summary
     <li><pr>349</pr> Add i18n resouces(zh_CN). Contributed by Helly Guo (https://github.com/hellyguo)</li>
     <li><pr>351</pr> Fixed about dialog position on first view. Contributed by Graham Russell (graham at ham1.co.uk)</li>
     <li><pr>352</pr> Menu bar - added mnemonics to more menu items. Contributed by Graham Russell (graham at ham1.co.uk)</li>
+    <li><pr>353</pr> Re-wrote some existing tests in Spock. Contributed by Graham Russell (graham at ham1.co.uk)</li>
 </ul>
 
 <ch_section>Non-functional changes</ch_section>