Author: sebb Date: Mon Feb 1 00:17:15 2010 New Revision: 905149 URL: http://svn.apache.org/viewvc?rev=905149&view=rev Log: Add Sampler scope selection to XPathExtractor
Modified: jakarta/jmeter/trunk/docs/images/screenshots/xpath_extractor.png jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/RegexExtractor.java jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/XPathExtractor.java jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/RegexExtractorGui.java jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/XPathExtractorGui.java jakarta/jmeter/trunk/src/core/org/apache/jmeter/testelement/AbstractScopedTestElement.java jakarta/jmeter/trunk/test/src/org/apache/jmeter/extractor/TestXPathExtractor.java jakarta/jmeter/trunk/xdocs/changes.xml jakarta/jmeter/trunk/xdocs/images/screenshots/xpath_extractor.png jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml Modified: jakarta/jmeter/trunk/docs/images/screenshots/xpath_extractor.png URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/docs/images/screenshots/xpath_extractor.png?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== Binary files - no diff available. Modified: jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/RegexExtractor.java URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/RegexExtractor.java?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/RegexExtractor.java (original) +++ jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/RegexExtractor.java Mon Feb 1 00:17:15 2010 @@ -177,17 +177,7 @@ } private List<MatchResult> processMatches(String regex, SampleResult result, int matchNumber) { - List<SampleResult> sampleList = new ArrayList<SampleResult>(); - - String scope = fetchScope(); - if (isScopeParent(scope) || isScopeAll(scope)) { - sampleList.add(result); - } - if (isScopeChildren(scope) || isScopeAll(scope)) { - for (SampleResult subResult : result.getSubResults()) { - sampleList.add(subResult); - } - } + List<SampleResult> sampleList = getSampleList(result); if (log.isDebugEnabled()) { log.debug("Regex = " + regex); Modified: jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/XPathExtractor.java URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/XPathExtractor.java?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/XPathExtractor.java (original) +++ jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/XPathExtractor.java Mon Feb 1 00:17:15 2010 @@ -22,6 +22,8 @@ import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; @@ -29,7 +31,7 @@ import org.apache.jmeter.assertions.AssertionResult; import org.apache.jmeter.processor.PostProcessor; import org.apache.jmeter.samplers.SampleResult; -import org.apache.jmeter.testelement.AbstractTestElement; +import org.apache.jmeter.testelement.AbstractScopedTestElement; import org.apache.jmeter.testelement.property.BooleanProperty; import org.apache.jmeter.threads.JMeterContext; import org.apache.jmeter.threads.JMeterVariables; @@ -77,7 +79,7 @@ * * See Bugzilla: 37183 */ -public class XPathExtractor extends AbstractTestElement implements +public class XPathExtractor extends AbstractScopedTestElement implements PostProcessor, Serializable { private static final Logger log = LoggingManager.getLoggerForClass(); @@ -105,6 +107,10 @@ return new StringBuilder(s1).append("_").append(s2).toString(); // $NON-NLS-1$ } + private String concat(String s1, int i){ + return new StringBuilder(s1).append("_").append(i).toString(); // $NON-NLS-1$ + } + /** * Do the job - extract value from (X)HTML response using XPath Query. * Return value as variable defined by REFNAME. Returns DEFAULT value @@ -119,12 +125,42 @@ JMeterVariables vars = context.getVariables(); String refName = getRefName(); vars.put(refName, getDefaultValue()); - vars.put(concat(refName,MATCH_NR), "0"); // In case parse fails // $NON-NLS-1$ + final String matchNR = concat(refName,MATCH_NR); + int prevCount=0; // number of previous matches + try { + prevCount=Integer.parseInt(vars.get(matchNR)); + } catch (NumberFormatException e) { + // ignored + } + vars.put(matchNR, "0"); // In case parse fails // $NON-NLS-1$ vars.remove(concat(refName,"1")); // In case parse fails // $NON-NLS-1$ + List<SampleResult> samples = getSampleList(previousResult); try{ - Document d = parseResponse(previousResult); - getValuesForXPath(d,getXPathQuery(),vars, refName); + List<String> matches = new ArrayList<String>(); + for (SampleResult res : samples) { + Document d = parseResponse(res); + getValuesForXPath(d,getXPathQuery(),matches); + } + final int matchCount = matches.size(); + vars.put(matchNR, String.valueOf(matchCount)); + if (matchCount > 0){ + String value = matches.get(0); + if (value != null) { + vars.put(refName, value); + } + for(int i=0; i < matchCount; i++){ + value = matches.get(i); + if (value != null) { + vars.put(concat(refName,i+1),matches.get(i)); + } + } + } + vars.remove(concat(refName,matchCount+1)); // Just in case + // Clear any other remaining variables + for(int i=matchCount+2; i <= prevCount; i++) { + vars.remove(concat(refName,i)); + } }catch(IOException e){// e.g. DTD not reachable final String errorMessage = "IOException on ("+getXPathQuery()+")"; log.error(errorMessage,e); @@ -253,7 +289,6 @@ { //TODO: validate contentType for reasonable types? - //TODO: is it really necessary to recode the data? // NOTE: responseData encoding is server specific // Therefore we do byte -> unicode -> byte conversion // to ensure UTF-8 encoding as required by XPathUtil @@ -269,20 +304,20 @@ /** * Extract value from Document d by XPath query. - * @param d - * @param query + * @param d the document + * @param query the query to execute + * @param matchStrings list of matched strings (may include nulls) + * * @throws TransformerException */ - private void getValuesForXPath(Document d,String query, JMeterVariables vars, String refName) - throws TransformerException - { + private void getValuesForXPath(Document d,String query, List<String> matchStrings) + throws TransformerException { String val = null; - XObject xObject = XPathAPI.eval(d, query); + XObject xObject = XPathAPI.eval(d, query); final int objectType = xObject.getType(); if (objectType == XObject.CLASS_NODESET) { NodeList matches = xObject.nodelist(); int length = matches.getLength(); - vars.put(concat(refName,MATCH_NR), String.valueOf(length)); for (int i = 0 ; i < length; i++) { Node match = matches.item(i); if ( match instanceof Element){ @@ -300,25 +335,16 @@ } else { val = match.getNodeValue(); } - if ( val!=null){ - if (i==0) {// Treat 1st match specially - vars.put(refName,val); - } - vars.put(concat(refName,String.valueOf(i+1)),val); - } + matchStrings.add(val); } - vars.remove(concat(refName,String.valueOf(length+1))); } else if (objectType == XObject.CLASS_NULL || objectType == XObject.CLASS_UNKNOWN || objectType == XObject.CLASS_UNRESOLVEDVARIABLE) { log.warn("Unexpected object type: "+xObject.getTypeString()+" returned for: "+getXPathQuery()); - } else { + } else { val = xObject.toString(); - vars.put(concat(refName, MATCH_NR), "1"); - vars.put(refName, val); - vars.put(concat(refName, "1"), val); - vars.remove(concat(refName, "2")); - } + matchStrings.add(val); + } } public void setWhitespace(boolean selected) { Modified: jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/RegexExtractorGui.java URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/RegexExtractorGui.java?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/RegexExtractorGui.java (original) +++ jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/RegexExtractorGui.java Mon Feb 1 00:17:15 2010 @@ -32,6 +32,7 @@ import org.apache.jmeter.extractor.RegexExtractor; import org.apache.jmeter.processor.gui.AbstractPostProcessorGui; +import org.apache.jmeter.testelement.AbstractScopedTestElement; import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.util.JMeterUtils; import org.apache.jorphan.gui.JLabeledTextField; @@ -99,7 +100,7 @@ * @see org.apache.jmeter.gui.JMeterGUIComponent#createTestElement() */ public TestElement createTestElement() { - RegexExtractor extractor = new RegexExtractor(); + AbstractScopedTestElement extractor = new RegexExtractor(); modifyTestElement(extractor); return extractor; } Modified: jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/XPathExtractorGui.java URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/XPathExtractorGui.java?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/XPathExtractorGui.java (original) +++ jakarta/jmeter/trunk/src/components/org/apache/jmeter/extractor/gui/XPathExtractorGui.java Mon Feb 1 00:17:15 2010 @@ -44,16 +44,21 @@ private static final long serialVersionUID = 240L; - private JLabeledTextField defaultField; + private final JLabeledTextField defaultField = + new JLabeledTextField(JMeterUtils.getResString("default_value_field"));//$NON-NLS-1$ - private JLabeledTextField xpathQueryField; + private final JLabeledTextField xpathQueryField = + new JLabeledTextField(JMeterUtils.getResString("xpath_extractor_query"));//$NON-NLS-1$ - private JLabeledTextField refNameField; + private final JLabeledTextField refNameField = + new JLabeledTextField(JMeterUtils.getResString("ref_name_field"));//$NON-NLS-1$ - private JCheckBox getFragment; // Should we return fragment as text, rather than text of fragment? - - private XMLConfPanel xml; + // Should we return fragment as text, rather than text of fragment? + private final JCheckBox getFragment = + new JCheckBox(JMeterUtils.getResString("xpath_extractor_fragment"));//$NON-NLS-1$ + private final XMLConfPanel xml = new XMLConfPanel(); + public String getLabelResource() { return "xpath_extractor_title"; //$NON-NLS-1$ } @@ -67,6 +72,7 @@ public void configure(TestElement el) { super.configure(el); XPathExtractor xpe = (XPathExtractor) el; + showScopeSettings(xpe); xpathQueryField.setText(xpe.getXPathQuery()); defaultField.setText(xpe.getDefaultValue()); refNameField.setText(xpe.getRefName()); @@ -85,6 +91,7 @@ super.configureTestElement(extractor); if ( extractor instanceof XPathExtractor){ XPathExtractor xpath = (XPathExtractor)extractor; + saveScopeSettings(xpath); xpath.setDefaultValue(defaultField.getText()); xpath.setRefName(refNameField.getText()); xpath.setXPathQuery(xpathQueryField.getText()); @@ -112,11 +119,10 @@ Box box = Box.createVerticalBox(); box.add(makeTitlePanel()); - xml = new XMLConfPanel(); + box.add(createScopePanel()); xml.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), JMeterUtils .getResString("xpath_assertion_option"))); //$NON-NLS-1$ box.add(xml); - getFragment = new JCheckBox(JMeterUtils.getResString("xpath_extractor_fragment"));//$NON-NLS-1$ box.add(getFragment); box.add(makeParameterPanel()); add(box, BorderLayout.NORTH); @@ -124,10 +130,6 @@ private JPanel makeParameterPanel() { - xpathQueryField = new JLabeledTextField(JMeterUtils.getResString("xpath_extractor_query"));//$NON-NLS-1$ - defaultField = new JLabeledTextField(JMeterUtils.getResString("default_value_field"));//$NON-NLS-1$ - refNameField = new JLabeledTextField(JMeterUtils.getResString("ref_name_field"));//$NON-NLS-1$ - JPanel panel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); initConstraints(gbc); Modified: jakarta/jmeter/trunk/src/core/org/apache/jmeter/testelement/AbstractScopedTestElement.java URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/src/core/org/apache/jmeter/testelement/AbstractScopedTestElement.java?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/src/core/org/apache/jmeter/testelement/AbstractScopedTestElement.java (original) +++ jakarta/jmeter/trunk/src/core/org/apache/jmeter/testelement/AbstractScopedTestElement.java Mon Feb 1 00:17:15 2010 @@ -18,6 +18,11 @@ package org.apache.jmeter.testelement; +import java.util.ArrayList; +import java.util.List; + +import org.apache.jmeter.samplers.SampleResult; + /** * <p> * Super-class for TestElements that can be applied to main sample, sub-samples or both. @@ -94,4 +99,26 @@ public void setScopeAll() { setProperty(SCOPE, SCOPE_ALL); } + + /** + * Generate a list of qualifying sample results, + * depending on the scope. + * + * @param result current sample + * @return list containing the current sample and/or its child samples + */ + protected List<SampleResult> getSampleList(SampleResult result) { + List<SampleResult> sampleList = new ArrayList<SampleResult>(); + + String scope = fetchScope(); + if (isScopeParent(scope) || isScopeAll(scope)) { + sampleList.add(result); + } + if (isScopeChildren(scope) || isScopeAll(scope)) { + for (SampleResult subResult : result.getSubResults()) { + sampleList.add(subResult); + } + } + return sampleList; + } } Modified: jakarta/jmeter/trunk/test/src/org/apache/jmeter/extractor/TestXPathExtractor.java URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/test/src/org/apache/jmeter/extractor/TestXPathExtractor.java?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/test/src/org/apache/jmeter/extractor/TestXPathExtractor.java (original) +++ jakarta/jmeter/trunk/test/src/org/apache/jmeter/extractor/TestXPathExtractor.java Mon Feb 1 00:17:15 2010 @@ -19,6 +19,8 @@ package org.apache.jmeter.extractor; +import java.io.UnsupportedEncodingException; + import junit.framework.TestCase; import org.apache.jmeter.samplers.SampleResult; @@ -31,6 +33,8 @@ private SampleResult result; + private String data; + private JMeterVariables vars; public TestXPathExtractor(String name) { @@ -42,15 +46,15 @@ private final static String VAL_NAME = "value"; private final static String VAL_NAME_NR = "value_matchNr"; @Override - public void setUp() { + public void setUp() throws UnsupportedEncodingException { jmctx = JMeterContextService.getContext(); extractor = new XPathExtractor(); extractor.setThreadContext(jmctx);// This would be done by the run command extractor.setRefName(VAL_NAME); extractor.setDefaultValue("Default"); result = new SampleResult(); - String data = "<book><preface title='Intro'>zero</preface><page>one</page><page>two</page><empty></empty><a><b></b></a></book>"; - result.setResponseData(data.getBytes()); + data = "<book><preface title='Intro'>zero</preface><page>one</page><page>two</page><empty></empty><a><b></b></a></book>"; + result.setResponseData(data.getBytes("UTF-8")); vars = new JMeterVariables(); jmctx.setVariables(vars); jmctx.setPreviousResult(result); @@ -150,6 +154,56 @@ assertEquals("<a><b/></a>", vars.get(VAL_NAME)); } + public void testScope(){ + extractor.setXPathQuery("/book/preface"); + extractor.process(); + assertEquals("zero", vars.get(VAL_NAME)); + assertEquals("1", vars.get(VAL_NAME_NR)); + assertEquals("zero", vars.get(VAL_NAME+"_1")); + assertNull(vars.get(VAL_NAME+"_2")); + + extractor.setScopeChildren(); // There aren't any + extractor.process(); + assertEquals("Default", vars.get(VAL_NAME)); + assertEquals("0", vars.get(VAL_NAME_NR)); + assertNull(vars.get(VAL_NAME+"_1")); + + extractor.setScopeAll(); // same as Parent + extractor.process(); + assertEquals("zero", vars.get(VAL_NAME)); + assertEquals("1", vars.get(VAL_NAME_NR)); + assertEquals("zero", vars.get(VAL_NAME+"_1")); + assertNull(vars.get(VAL_NAME+"_2")); + + // Try to get data from subresult + result.sampleStart(); // Needed for addSubResult() + result.sampleEnd(); + SampleResult subResult = new SampleResult(); + subResult.sampleStart(); + subResult.setResponseData(result.getResponseData()); + subResult.sampleEnd(); + result.addSubResult(subResult); + + + // Get data from both + extractor.setScopeAll(); + extractor.process(); + assertEquals("zero", vars.get(VAL_NAME)); + assertEquals("2", vars.get(VAL_NAME_NR)); + assertEquals("zero", vars.get(VAL_NAME+"_1")); + assertEquals("zero", vars.get(VAL_NAME+"_2")); + assertNull(vars.get(VAL_NAME+"_3")); + + // get data from child + extractor.setScopeChildren(); + extractor.process(); + assertEquals("zero", vars.get(VAL_NAME)); + assertEquals("1", vars.get(VAL_NAME_NR)); + assertEquals("zero", vars.get(VAL_NAME+"_1")); + assertNull(vars.get(VAL_NAME+"_2")); + + } + public void testInvalidXpath() throws Exception { extractor.setXPathQuery("<"); extractor.process(); Modified: jakarta/jmeter/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/changes.xml?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/xdocs/changes.xml (original) +++ jakarta/jmeter/trunk/xdocs/changes.xml Mon Feb 1 00:17:15 2010 @@ -178,7 +178,8 @@ <li>Added JSR223 Assertion</li> <li>Added BSF Timer and JSR223 Timer</li> <li>Bug 48331 - XpathExtractor does not return XML string representations for a Nodeset</li> -<li>Bug 48511 - add parent,child,all selection to regex extractor panel</li> +<li>Bug 48511 - add parent,child,all selection to regex extractor</li> +<li>Add Sampler scope selection to XPathExtractor</li> </ul> <h3>Functions</h3> Modified: jakarta/jmeter/trunk/xdocs/images/screenshots/xpath_extractor.png URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/images/screenshots/xpath_extractor.png?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== Binary files - no diff available. Modified: jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml URL: http://svn.apache.org/viewvc/jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml?rev=905149&r1=905148&r2=905149&view=diff ============================================================================== --- jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml (original) +++ jakarta/jmeter/trunk/xdocs/usermanual/component_reference.xml Mon Feb 1 00:17:15 2010 @@ -4108,13 +4108,23 @@ </p> </component> -<component name="XPath Extractor" index="§-num;.8.2" width="613" height="269" screenshot="xpath_extractor.png"> - <description>This test element allows the user to extract value from +<component name="XPath Extractor" index="§-num;.8.2" width="612" height="318" screenshot="xpath_extractor.png"> + <description>This test element allows the user to extract value(s) from structured response - XML or (X)HTML - using XPath query language. </description> <properties> - <property name="Name" required="No">Descriptive name for this element that is shown in the tree.</property> + <property name="Name" required="No">Descriptive name for this element that is shown in the tree.</property> + <property name="Which samples to process" required="Yes"> + This is for use with samplers that can generate sub-samples, + e.g. HTTP Sampler with embedded resources, Mail Reader or samples generated by the Transaction Controller. + <ul> + <li>Main sample only - only applies to the main sample</li> + <li>Sub-samples only - only applies to the sub-samples</li> + <li>Main sample and sub-samples - applies to both.</li> + </ul> + XPath matching is applied to all qualifying samples in turn, and all the matching results will be returned. + </property> <property name="Use Tidy (tolerant parser)" required="Yes">If checked use Tidy to parse HTML response into XHTML. <ul> <li>"Use Tidy" should be checked on for HTML response. Such response is converted to valid XHTML (XML compatible HTML) using Tidy</li> --------------------------------------------------------------------- To unsubscribe, e-mail: jmeter-dev-unsubscr...@jakarta.apache.org For additional commands, e-mail: jmeter-dev-h...@jakarta.apache.org