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/18 12:51:09 UTC
svn commit: r1818562 - in /jmeter/trunk:
src/components/org/apache/jmeter/extractor/BoundaryExtractor.java
src/components/org/apache/jmeter/visualizers/RenderAsBoundaryExtractor.java
test/src/org/apache/jmeter/extractor/BoundaryExtractorSpec.groovy
Author: pmouawad
Date: Mon Dec 18 12:51:09 2017
New Revision: 1818562
URL: http://svn.apache.org/viewvc?rev=1818562&view=rev
Log:
Bug 61852 - Add a Boundary Extractor Tester in View Results Tree
BoundaryExtractor refactor
Contributed by Graham Russell
This closes #355
Bugzilla Id: 61852
Added:
jmeter/trunk/test/src/org/apache/jmeter/extractor/BoundaryExtractorSpec.groovy
Modified:
jmeter/trunk/src/components/org/apache/jmeter/extractor/BoundaryExtractor.java
jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsBoundaryExtractor.java
Modified: jmeter/trunk/src/components/org/apache/jmeter/extractor/BoundaryExtractor.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/extractor/BoundaryExtractor.java?rev=1818562&r1=1818561&r2=1818562&view=diff
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/extractor/BoundaryExtractor.java (original)
+++ jmeter/trunk/src/components/org/apache/jmeter/extractor/BoundaryExtractor.java Mon Dec 18 12:51:09 2017
@@ -22,6 +22,9 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
@@ -37,30 +40,23 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- *
+ * Extracts Strings from a text response between a start and end boundary.
*/
public class BoundaryExtractor extends AbstractScopedTestElement implements PostProcessor, Serializable {
private static final Logger log = LoggerFactory.getLogger(BoundaryExtractor.class);
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
private static final String REFNAME = "BoundaryExtractor.refname"; // $NON-NLS-1$
-
private static final String MATCH_NUMBER = "BoundaryExtractor.match_number"; // $NON-NLS-1$
-
private static final String L_BOUNDARY = "BoundaryExtractor.lboundary"; // $NON-NLS-1$
-
private static final String R_BOUNDARY = "BoundaryExtractor.rboundary"; // $NON-NLS-1$
-
private static final String DEFAULT_EMPTY_VALUE = "BoundaryExtractor.default_empty_value"; // $NON-NLS-1$
-
private static final String DEFAULT = "BoundaryExtractor.default"; // $NON-NLS-1$
-
private static final String REF_MATCH_NR = "_matchNr"; // $NON-NLS-1$
-
private static final char UNDERSCORE = '_'; // $NON-NLS-1$
-
+
// What to match against. N.B. do not change the string value or test plans will break!
private static final String MATCH_AGAINST = "BoundaryExtractor.useHeaders"; // $NON-NLS-1$
/*
@@ -71,21 +67,21 @@ public class BoundaryExtractor extends A
* These are passed to the setUseField() method
*
* Do not change these values!
- */
- public static final String USE_HDRS = "true"; // $NON-NLS-1$
- public static final String USE_REQUEST_HDRS = "request_headers"; // $NON-NLS-1$
- public static final String USE_BODY = "false"; // $NON-NLS-1$
- public static final String USE_BODY_UNESCAPED = "unescaped"; // $NON-NLS-1$
- public static final String USE_BODY_AS_DOCUMENT = "as_document"; // $NON-NLS-1$
- public static final String USE_URL = "URL"; // $NON-NLS-1$
- public static final String USE_CODE = "code"; // $NON-NLS-1$
- public static final String USE_MESSAGE = "message"; // $NON-NLS-1$
+ */
+ private static final String USE_HDRS = "true"; // $NON-NLS-1$
+ private static final String USE_REQUEST_HDRS = "request_headers"; // $NON-NLS-1$
+ private static final String USE_BODY = "false"; // $NON-NLS-1$
+ private static final String USE_BODY_UNESCAPED = "unescaped"; // $NON-NLS-1$
+ private static final String USE_BODY_AS_DOCUMENT = "as_document"; // $NON-NLS-1$
+ private static final String USE_URL = "URL"; // $NON-NLS-1$
+ private static final String USE_CODE = "code"; // $NON-NLS-1$
+ private static final String USE_MESSAGE = "message"; // $NON-NLS-1$
/**
* Parses the response data using Boundaries and saving the results
* into variables for use later in the test.
*
- * @see org.apache.jmeter.processor.PostProcessor#process()
+ * @see PostProcessor#process()
*/
@Override
public void process() {
@@ -94,66 +90,108 @@ public class BoundaryExtractor extends A
if (previousResult == null) {
return;
}
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("Boundary Extractor {}: processing result", getName());
}
- if(StringUtils.isAnyEmpty(getLeftBoundary(), getRightBoundary(), getRefName())) {
- throw new IllegalArgumentException("One of the mandatory properties is missing in Boundary Extractor:"+
- getName());
+ if (StringUtils.isAnyEmpty(getLeftBoundary(), getRightBoundary(), getRefName())) {
+ throw new IllegalArgumentException(
+ "One of the mandatory properties is missing in Boundary Extractor:" + getName());
}
- // Fetch some variables
+
JMeterVariables vars = context.getVariables();
-
+
String refName = getRefName();
- int matchNumber = getMatchNumber();
final String defaultValue = getDefaultValue();
-
- if (defaultValue.length() > 0 || isEmptyDefaultValue()){// Only replace default if it is provided or empty default value is explicitly requested
+
+ if (StringUtils.isNotBlank(defaultValue) || isEmptyDefaultValue()) {
vars.put(refName, defaultValue);
}
-
- try {
- List<String> matches =
- extractMatchingStrings(vars, getLeftBoundary(), getRightBoundary(), matchNumber, previousResult);
- int prevCount = 0;
- String prevString = vars.get(refName + REF_MATCH_NR);
- if (prevString != null) {
- vars.remove(refName + REF_MATCH_NR);// ensure old value is not left defined
- try {
- prevCount = Integer.parseInt(prevString);
- } catch (NumberFormatException nfe) {
- if (log.isWarnEnabled()) {
- log.warn("{}: Could not parse number: '{}'.", getName(), prevString);
- }
- }
- }
- int matchCount=0;// Number of refName_n variable sets to keep
- String match;
- if (matchNumber >= 0) {// Original match behaviour
- match = getCorrectMatch(matches, matchNumber);
- if (match != null) {
- vars.put(refName, match);
- }
- } else // < 0 means we save all the matches
- {
- matchCount = matches.size();
- vars.put(refName + REF_MATCH_NR, Integer.toString(matchCount));// Save the count
- for (int i = 1; i <= matchCount; i++) {
- match = getCorrectMatch(matches, i);
- if (match != null) {
- final String refNameN = new StringBuilder(refName).append(UNDERSCORE).append(i).toString();
- vars.put(refNameN, match);
- }
- }
+
+ int matchNumber = getMatchNumber();
+ int prevCount = 0;
+ int matchCount = 0;
+ try {
+ prevCount = removePrevCount(vars, refName);
+ List<String> matches = extractMatches(previousResult, vars, matchNumber);
+ matchCount = saveMatches(vars, refName, matchNumber, matchCount, matches);
+ } catch (RuntimeException e) {
+ if (log.isWarnEnabled()) {
+ log.warn("{}: Error while generating result. {}", getName(), e.toString()); // NOSONAR We don't want to be too verbose
}
+ } finally {
// Remove any left-over variables
for (int i = matchCount + 1; i <= prevCount; i++) {
- final String refNameN = new StringBuilder(refName).append(UNDERSCORE).append(i).toString();
- vars.remove(refNameN);
+ vars.remove(refName + UNDERSCORE + i);
}
- } catch (RuntimeException e) {
- if (log.isWarnEnabled()) {
- log.warn("{}: Error while generating result. {}", getName(), e.toString()); // NOSONAR We don't want to be too verbose
+ }
+ }
+
+ private int removePrevCount(JMeterVariables vars, String refName) {
+ int prevCount = 0;
+ String prevString = vars.get(refName + REF_MATCH_NR);
+ if (prevString != null) {
+ // ensure old value is not left defined
+ vars.remove(refName + REF_MATCH_NR);
+ try {
+ prevCount = Integer.parseInt(prevString);
+ } catch (NumberFormatException nfe) {
+ if (log.isWarnEnabled()) {
+ log.warn("{}: Could not parse number: '{}'.", getName(), prevString);
+ }
+ }
+ }
+ return prevCount;
+ }
+
+ private List<String> extractMatches(SampleResult previousResult, JMeterVariables vars, int matchNumber) {
+ if (isScopeVariable()) {
+ String inputString = vars.get(getVariableName());
+ if (inputString == null && log.isWarnEnabled()) {
+ log.warn("No variable '{}' found to process by Boundary Extractor '{}', skipping processing",
+ getVariableName(), getName());
+ }
+ return extract(getLeftBoundary(), getRightBoundary(), matchNumber, inputString);
+ } else {
+ Stream<String> inputs = getSampleList(previousResult).stream().map(this::getInputString);
+ return extract(getLeftBoundary(), getRightBoundary(), matchNumber, inputs);
+ }
+ }
+
+ private int saveMatches(JMeterVariables vars, String refName, int matchNumber, int matchCount, List<String> matches) {
+ if (matchNumber == 0) {
+ saveRandomMatch(vars, refName, matches);
+ } else if (matchNumber > 0) {
+ saveOneMatch(vars, refName, matches);
+ } else {
+ matchCount = matches.size();
+ saveAllMatches(vars, refName, matches);
+ }
+ return matchCount;
+ }
+
+ private void saveRandomMatch(JMeterVariables vars, String refName, List<String> matches) {
+ String match = matches.get(JMeterUtils.getRandomInt(matches.size()));
+ if (match != null) {
+ vars.put(refName, match);
+ }
+ }
+
+ private void saveOneMatch(JMeterVariables vars, String refName, List<String> matches) {
+ if (matches.size() == 1) { // if not then invalid matchNum was likely supplied
+ String match = matches.get(0);
+ if (match != null) {
+ vars.put(refName, match);
+ }
+ }
+ }
+
+ private void saveAllMatches(JMeterVariables vars, String refName, List<String> matches) {
+ vars.put(refName + REF_MATCH_NR, Integer.toString(matches.size()));
+ for (int i = 0; i < matches.size(); i++) {
+ String match = matches.get(i);
+ if (match != null) {
+ int varNum = i + 1;
+ vars.put(refName + UNDERSCORE + varNum, match);
}
}
}
@@ -168,117 +206,65 @@ public class BoundaryExtractor extends A
: useBodyAsDocument() ? Document.getTextFromDocument(result.getResponseData())
: result.getResponseDataAsString() // Bug 36898
;
- log.debug("Input = '{}'", inputString);
- return inputString;
- }
- /**
- * Grab the appropriate result from the list.
- *
- * @param matches
- * list of matches
- * @param entry
- * the entry number in the list
- * @return MatchResult
- */
- private String getCorrectMatch(List<String> matches, int entry) {
- int matchSize = matches.size();
-
- if (matchSize <= 0 || entry > matchSize){
- return null;
- }
-
- if (entry == 0) // Random match
- {
- return matches.get(JMeterUtils.getRandomInt(matchSize));
- }
-
- return matches.get(entry - 1);
+ log.debug("Input = '{}'", inputString);
+ return inputString;
}
- private List<String> extractMatchingStrings(JMeterVariables vars,
- String leftBoundary, String rightBoundary, int matchNumber,
- SampleResult previousResult) {
- int found = 0;
- List<String> result = new ArrayList<>();
- if (isScopeVariable()){
- String inputString=vars.get(getVariableName());
- if(!StringUtils.isEmpty(inputString)) {
- extract(leftBoundary, rightBoundary, matchNumber, inputString, result, found);
- } else {
- if(inputString==null) {
- if (log.isWarnEnabled()) {
- log.warn("No variable '{}' found to process by Boundary Extractor '{}', skipping processing",
- getVariableName(), getName());
- }
- }
- return Collections.emptyList();
- }
- } else {
- List<SampleResult> sampleList = getSampleList(previousResult);
- for (SampleResult sr : sampleList) {
- String inputString = getInputString(sr);
- found = extract(leftBoundary, rightBoundary, matchNumber, inputString, result, found);
- if (matchNumber > 0 && found == matchNumber){// no need to process further
- break;
- }
- }
- }
- return result;
+ private List<String> extract(
+ String leftBoundary, String rightBoundary, int matchNumber, Stream<String> previousResults) {
+ boolean allItems = matchNumber <= 0;
+ return previousResults
+ .flatMap(input -> extractAll(leftBoundary, rightBoundary, input).stream())
+ .skip(allItems ? 0L : matchNumber - 1)
+ .limit(allItems ? Long.MAX_VALUE : 1L)
+ .collect(Collectors.toList());
}
/**
- * Extracts text fragments, that are between the boundaries, into
- * {@code result}.<br>
- * The number of extracted fragments can be controlled by
- * {@code matchNumber}
+ * Extracts text fragments, that are between the boundaries, into {@code result}.
+ * The number of extracted fragments can be controlled by {@code matchNumber}
*
- * @param leftBoundary
- * fragment representing the left boundary of the searched text
- * @param rightBoundary
- * fragment representing the right boundary of the searched text
- * @param matchNumber
- * if < 0, all found matches will be added, else only those
- * matches, where {@code matchNumber} is less then {@code found}
- * plus the number of matches found in this round
- * @param inputString
- * text in which to look for the fragments
- * @param result
- * list where the found text fragments will be placed
- * @param found
- * specifies how many fragments where found before calling us
- * @return updated found (found plus number of fragements added to
- * {@code result})
+ * @param leftBoundary fragment representing the left boundary of the searched text
+ * @param rightBoundary fragment representing the right boundary of the searched text
+ * @param matchNumber if {@code <=0}, all found matches will be returned, else only
+ * up to {@code matchNumber} matches
+ * @param inputString text in which to look for the fragments
+ * @return list where the found text fragments will be placed
*/
- public int extract(String leftBoundary, String rightBoundary, int matchNumber, String inputString,
- List<String> result, int found) {
- int startIndex = -1;
- int endIndex;
- int newFound = found;
- final int leftBoundarylength = leftBoundary.length();
+ private List<String> extract(String leftBoundary, String rightBoundary, int matchNumber, String inputString) {
+ if (StringUtils.isBlank(inputString)) {
+ return Collections.emptyList();
+ }
+ Objects.requireNonNull(leftBoundary);
+ Objects.requireNonNull(rightBoundary);
+
List<String> matches = new ArrayList<>();
- while(true) {
- startIndex = inputString.indexOf(leftBoundary, startIndex+1);
- if(startIndex >= 0) {
- endIndex = inputString.indexOf(rightBoundary, startIndex+leftBoundarylength);
- if(endIndex >= 0) {
- matches.add(inputString.substring(startIndex+leftBoundarylength, endIndex));
- } else {
- break;
+ int leftBoundaryLen = leftBoundary.length();
+ boolean collectAll = matchNumber <= 0;
+ int found = 0;
+
+ for (int startIndex = 0;
+ (startIndex = inputString.indexOf(leftBoundary, startIndex)) != -1;
+ startIndex += leftBoundaryLen) {
+ int endIndex = inputString.indexOf(rightBoundary, startIndex + leftBoundaryLen);
+ if (endIndex >= 0) {
+ found++;
+ if (collectAll) {
+ matches.add(inputString.substring(startIndex + leftBoundaryLen, endIndex));
+ } else if (found == matchNumber) {
+ return Collections.singletonList(inputString.substring(startIndex + leftBoundaryLen, endIndex));
}
} else {
break;
}
}
- for (String element : matches) {
- if (matchNumber <= 0 || newFound != matchNumber) {
- result.add(element);
- newFound++;
- } else {
- break;
- }
- }
- return newFound;
+ return matches;
+ }
+
+ public List<String> extractAll(
+ String leftBoundary, String rightBoundary, String textToParse) {
+ return extract(leftBoundary, rightBoundary, -1, textToParse);
}
public void setRefName(String refName) {
@@ -310,19 +296,19 @@ public class BoundaryExtractor extends A
public String getMatchNumberAsString() {
return getPropertyAsString(MATCH_NUMBER);
}
-
+
public void setLeftBoundary(String leftBoundary) {
setProperty(L_BOUNDARY, leftBoundary);
}
-
+
public String getLeftBoundary() {
return getPropertyAsString(L_BOUNDARY);
}
-
+
public void setRightBoundary(String rightBoundary) {
setProperty(R_BOUNDARY, rightBoundary);
}
-
+
public String getRightBoundary() {
return getPropertyAsString(R_BOUNDARY);
}
@@ -342,15 +328,16 @@ public class BoundaryExtractor extends A
public void setDefaultEmptyValue(boolean defaultEmptyValue) {
setProperty(DEFAULT_EMPTY_VALUE, defaultEmptyValue);
}
-
+
/**
* Get the default value for the variable if no matches are found
+ *
* @return The default value for the variable
*/
public String getDefaultValue() {
return getPropertyAsString(DEFAULT);
}
-
+
/**
* @return boolean set value to "" if not found
*/
@@ -358,29 +345,27 @@ public class BoundaryExtractor extends A
return getPropertyAsBoolean(DEFAULT_EMPTY_VALUE);
}
-
public boolean useHeaders() {
- return USE_HDRS.equalsIgnoreCase( getPropertyAsString(MATCH_AGAINST));
+ return USE_HDRS.equalsIgnoreCase(getPropertyAsString(MATCH_AGAINST));
}
public boolean useRequestHeaders() {
return USE_REQUEST_HDRS.equalsIgnoreCase(getPropertyAsString(MATCH_AGAINST));
}
- // Allow for property not yet being set (probably only applies to Test cases)
public boolean useBody() {
String prop = getPropertyAsString(MATCH_AGAINST);
- return prop.length()==0 || USE_BODY.equalsIgnoreCase(prop);// $NON-NLS-1$
+ return prop.length() == 0 || USE_BODY.equalsIgnoreCase(prop);
}
public boolean useUnescapedBody() {
String prop = getPropertyAsString(MATCH_AGAINST);
- return USE_BODY_UNESCAPED.equalsIgnoreCase(prop);// $NON-NLS-1$
+ return USE_BODY_UNESCAPED.equalsIgnoreCase(prop);
}
public boolean useBodyAsDocument() {
String prop = getPropertyAsString(MATCH_AGAINST);
- return USE_BODY_AS_DOCUMENT.equalsIgnoreCase(prop);// $NON-NLS-1$
+ return USE_BODY_AS_DOCUMENT.equalsIgnoreCase(prop);
}
public boolean useUrl() {
@@ -399,6 +384,6 @@ public class BoundaryExtractor extends A
}
public void setUseField(String actionCommand) {
- setProperty(MATCH_AGAINST,actionCommand);
+ setProperty(MATCH_AGAINST, actionCommand);
}
}
Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsBoundaryExtractor.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsBoundaryExtractor.java?rev=1818562&r1=1818561&r2=1818562&view=diff
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsBoundaryExtractor.java (original)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/RenderAsBoundaryExtractor.java Mon Dec 18 12:51:09 2017
@@ -23,7 +23,6 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
@@ -42,7 +41,6 @@ import org.apache.jmeter.util.JMeterUtil
import org.apache.jorphan.gui.GuiUtils;
import org.apache.jorphan.gui.JLabeledTextField;
-
/**
* Implement ResultsRender for Boundary Extractor tester
*/
@@ -95,17 +93,20 @@ public class RenderAsBoundaryExtractor i
private String process(String textToParse) {
- List<String> result = new ArrayList<>();
BoundaryExtractor extractor = new BoundaryExtractor();
-
- final int nbFound = extractor.extract(boundaryExtractorFieldLeft.getText(),boundaryExtractorFieldRight.getText(), -1, textToParse, result, 0);
+ List<String> matches = extractor.extractAll(
+ boundaryExtractorFieldLeft.getText(),
+ boundaryExtractorFieldRight.getText(),
+ textToParse);
+
+ int nbFound = matches.size();
// Construct a multi-line string with all matches
StringBuilder sb = new StringBuilder();
sb.append("Match count: ").append(nbFound).append("\n");
for (int j = 0; j < nbFound; j++) {
- String mr = result.get(j);
- sb.append("Match[").append(j+1).append("]=").append(mr).append("\n");
+ String match = matches.get(j);
+ sb.append("Match[").append(j+1).append("]=").append(match).append("\n");
}
return sb.toString();
Added: jmeter/trunk/test/src/org/apache/jmeter/extractor/BoundaryExtractorSpec.groovy
URL: http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/extractor/BoundaryExtractorSpec.groovy?rev=1818562&view=auto
==============================================================================
--- jmeter/trunk/test/src/org/apache/jmeter/extractor/BoundaryExtractorSpec.groovy (added)
+++ jmeter/trunk/test/src/org/apache/jmeter/extractor/BoundaryExtractorSpec.groovy Mon Dec 18 12:51:09 2017
@@ -0,0 +1,384 @@
+package org.apache.jmeter.extractor
+
+import org.apache.jmeter.samplers.SampleResult
+import org.apache.jmeter.threads.JMeterContext
+import org.apache.jmeter.threads.JMeterContextService
+import org.apache.jmeter.threads.JMeterVariables
+import spock.lang.Specification
+import spock.lang.Unroll
+
+import java.util.stream.Stream
+
+@Unroll
+class BoundaryExtractorSpec extends Specification {
+
+ static LEFT = "LB"
+ static RIGHT = "RB"
+ static DEFAULT_VAL = "defaultVal"
+ static VAR_NAME = "varName"
+
+ def sut = new BoundaryExtractor()
+
+ SampleResult prevResult
+ JMeterVariables vars
+ JMeterContext context
+
+ def setup() {
+ vars = new JMeterVariables()
+ context = JMeterContextService.getContext()
+ context.setVariables(vars)
+
+ sut.setThreadContext(context)
+ sut.setRefName(VAR_NAME)
+ sut.setLeftBoundary(LEFT)
+ sut.setRightBoundary(RIGHT)
+ sut.setDefaultValue(DEFAULT_VAL)
+ sut.setMatchNumber(1)
+
+ prevResult = new SampleResult()
+ prevResult.sampleStart()
+ prevResult.setResponseData(createInputString(1..2), null)
+ prevResult.sampleEnd()
+ context.setPreviousResult(prevResult)
+ }
+
+ def "Extract, where pattern exists, with matchNumber=#matchNumber from #occurances returns #expected"() {
+ given:
+ def input = createInputString(occurrences)
+ when:
+ def matches = sut.extract(LEFT, RIGHT, matchNumber, input)
+ then:
+ matches == expected
+ where:
+ occurrences | matchNumber || expected
+ 1..1 | -1 || ['1']
+ 1..1 | 0 || ['1']
+ 1..1 | 1 || ['1']
+ 1..1 | 2 || []
+ 1..2 | -1 || ['1', '2']
+ 1..2 | 1 || ['1']
+ 1..2 | 2 || ['2']
+ 1..3 | 3 || ['3']
+ }
+
+ def "Extract, where pattern does not exist, with matchNumber=#matchNumber returns an empty list"() {
+ expect:
+ sut.extract(LEFT, RIGHT, matchNumber, 'start end') == []
+ where:
+ matchNumber << [-1, 0, 1, 2, 100]
+ }
+
+ def "Extract, where pattern exists in the stream, with matchNumber=#matchNumber from #occurances returns #expected"() {
+ given:
+ def input = createInputString(occurrences)
+ Stream<String> stream = ([input, "", null] * 10).stream()
+ when:
+ def matches = sut.extract(LEFT, RIGHT, matchNumber, stream)
+ then:
+ matches == expected
+ where:
+ occurrences | matchNumber || expected
+ 1..1 | -1 || ['1'] * 10
+ 1..1 | 0 || ['1'] * 10
+ 1..1 | 1 || ['1']
+ 1..1 | 10 || ['1']
+ 1..1 | 11 || []
+ 1..2 | -1 || ['1', '2'] * 10
+ 1..2 | 1 || ['1']
+ 1..2 | 2 || ['2']
+ 1..3 | 3 || ['3']
+ }
+
+ def "Extract, where pattern does not exist in the stream, with matchNumber=#matchNumber returns an empty list"() {
+ given:
+ Stream<String> stream = (['start end'] * 10).stream()
+ expect:
+ sut.extract(LEFT, RIGHT, matchNumber, stream) == []
+ where:
+ matchNumber << [-1, 0, 1, 2, 100]
+ }
+
+ def "IllegalArgumentException when one of left (#lb), right (#rb), name (#name) are null"() {
+ given:
+ sut.setLeftBoundary(lb)
+ sut.setRightBoundary(rb)
+ sut.setRefName(name)
+ when:
+ sut.process()
+ then:
+ thrown(IllegalArgumentException)
+ where:
+ lb | rb | name
+ null | "r" | "name"
+ "l" | null | "name"
+ "l" | "r" | null
+ }
+
+ def "matching only on left boundary returns default"() {
+ given:
+ sut.setRightBoundary("does-not-exist")
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == DEFAULT_VAL
+ }
+
+ def "matching only on right boundary returns default"() {
+ given:
+ sut.setLeftBoundary("does-not-exist")
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == DEFAULT_VAL
+ }
+
+ def "variables from a previous extraction are removed"() {
+ given:
+ sut.setMatchNumber(-1)
+ sut.process()
+ assert vars.get("${VAR_NAME}_1") == "1"
+ assert vars.get("${VAR_NAME}_matchNr") == "2"
+ when:
+ // Now rerun with match fail
+ sut.setMatchNumber(10)
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == DEFAULT_VAL
+ vars.get("${VAR_NAME}_1") == null
+ vars.get("${VAR_NAME}_matchNr") == null
+ }
+
+ def "with no sub-samples parent and all scope return data but children scope does not"() {
+ given:
+ sut.setScopeParent()
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == "1"
+
+ and:
+ sut.setScopeAll()
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == "1"
+
+ and:
+ sut.setScopeChildren()
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == DEFAULT_VAL
+ }
+
+ def "with sub-samples parent, all and children scope return expected item"() {
+ given:
+ prevResult.addSubResult(createSampleResult("${LEFT}sub1${RIGHT}"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub2${RIGHT}"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub3${RIGHT}"))
+ sut.setScopeParent()
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == "1"
+
+ and:
+ sut.setScopeAll()
+ sut.setMatchNumber(3) // skip 2 in parent sample
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == "sub1"
+
+ and:
+ sut.setScopeChildren()
+ sut.setMatchNumber(3)
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == "sub3"
+ }
+
+ def "with sub-samples parent, all and children scope return expected data"() {
+ given:
+ prevResult.addSubResult(createSampleResult("${LEFT}sub1${RIGHT}"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub2${RIGHT}"))
+ prevResult.addSubResult(createSampleResult("${LEFT}sub3${RIGHT}"))
+ sut.setMatchNumber(-1)
+
+ sut.setScopeParent()
+ when:
+ sut.process()
+ then:
+ vars.get("${VAR_NAME}_matchNr") == "2"
+ getAllVars() == ["1", "2"]
+
+ and:
+ sut.setScopeAll()
+ when:
+ sut.process()
+ then:
+ vars.get("${VAR_NAME}_matchNr") == "5"
+ getAllVars() == ["1", "2", "sub1", "sub2", "sub3"]
+
+ and:
+ sut.setScopeChildren()
+ when:
+ sut.process()
+ then:
+ vars.get("${VAR_NAME}_matchNr") == "3"
+ getAllVars() == ["sub1", "sub2", "sub3"]
+ }
+
+ def "when 'default empty value' is true the default value is allowed to be empty"() {
+ given:
+ sut.setMatchNumber(10) // no matches
+ sut.setDefaultValue("")
+ sut.setDefaultEmptyValue(true)
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == ""
+ }
+
+ def "when default value is empty but not allowed null is returned"() {
+ given:
+ sut.setMatchNumber(10) // no matches
+ sut.setDefaultValue("")
+ sut.setDefaultEmptyValue(false)
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == null
+ }
+
+ def "with no previous results result is null"() {
+ given:
+ context.setPreviousResult(null)
+ sut.setDefaultEmptyValue(true)
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == null
+ }
+
+ def "with non-existent variable result is null"() {
+ given:
+ sut.setDefaultValue(null)
+ sut.setScopeVariable("empty-var-name")
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == null
+ }
+
+ def "not allowing blank default value returns null upon no matches"() {
+ given:
+ sut.setMatchNumber(10) // no matches
+ sut.setDefaultValue("")
+ sut.setDefaultEmptyValue(false)
+ when:
+ sut.process()
+ then:
+ vars.get(VAR_NAME) == null
+ }
+
+ def "extract all matches from variable input"() {
+ given:
+ sut.setMatchNumber(-1)
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", createInputString(1..2))
+ when:
+ sut.process()
+ then:
+ getAllVars() == ["1", "2"]
+ vars.get("${VAR_NAME}_matchNr") == "2"
+ }
+
+ def "extract random from variable returns one of the matches"() {
+ given:
+ sut.setMatchNumber(0)
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", createInputString(1..42))
+ when:
+ sut.process()
+ then:
+ (1..42).collect({ it.toString() }).contains(vars.get(VAR_NAME))
+ vars.get("${VAR_NAME}_matchNr") == null
+ }
+
+ def "extract all from an empty variable returns no results"() {
+ given:
+ sut.setMatchNumber(-1)
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", "")
+ when:
+ sut.process()
+ then:
+ vars.get("${VAR_NAME}_matchNr") == "0"
+ vars.get("${VAR_NAME}_1") == null
+ }
+
+ def "previous extractions are cleared"() {
+ given:
+ sut.setMatchNumber(-1)
+ sut.setScopeVariable("contentvar")
+ vars.put("contentvar", createInputString(1..10))
+ sut.process()
+ assert getAllVars() == (1..10).collect({ it.toString() })
+ assert vars.get("${VAR_NAME}_matchNr") == "10"
+ vars.put("contentvar", createInputString(11..15))
+ sut.setMatchNumber("-1")
+ def expectedMatches = (11..15).collect({ it.toString() })
+ when:
+ sut.process()
+ then:
+ getAllVars() == expectedMatches
+ vars.get("${VAR_NAME}_matchNr") == "5"
+ (6..10).collect { vars.get("${VAR_NAME}_${it}") } == [null] * 5
+
+ and:
+ sut.setMatchNumber(0)
+ when:
+ sut.process()
+ then:
+ expectedMatches.contains(vars.get(VAR_NAME))
+ }
+
+ /**
+ * Creates a string with a "match" for each number in the list.
+ *
+ * @param occurrences list of numbers to be the "body" of a match
+ * @return a string with a start, end and then a left boundary + number + right boundary
+ * e.g. "... LB1RB LB2RB ..."
+ */
+ static createInputString(List<Integer> occurrences) {
+ def middle = occurrences.collect({ LEFT + it + RIGHT }).join(" ")
+ return 'start \t\r\n' + middle + '\n\t end'
+ }
+
+ static createSampleResult(String responseData) {
+ SampleResult child = new SampleResult()
+ child.sampleStart()
+ child.setResponseData(responseData, "ISO-8859-1")
+ child.sampleEnd()
+ return child
+ }
+
+ /**
+ * @return a list of all the variables in the format ${VAR_NAME}_${i}
+ * starting at i = 1 until null is returned
+ */
+ def getAllVars() {
+ def allVars = []
+ def i = 1
+ def var = vars.get("${VAR_NAME}_${i}")
+ while (var != null) {
+ allVars.add(var)
+ i++
+ var = vars.get("${VAR_NAME}_${i}")
+ }
+ return allVars
+ }
+
+}