| /* |
| * 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 static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.io.BufferedInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| |
| import org.apache.jmeter.junit.JMeterTestCase; |
| 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 org.junit.jupiter.api.BeforeEach; |
| import org.junit.jupiter.api.Test; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| public class XPathAssertionTest extends JMeterTestCase { |
| private static final Logger log = LoggerFactory.getLogger(XPathAssertionTest.class); |
| |
| private XPathAssertion assertion; |
| private SampleResult result; |
| private JMeterVariables vars; |
| private JMeterContext jmctx; |
| |
| @BeforeEach |
| public void setUp() throws Exception { |
| jmctx = JMeterContextService.getContext(); |
| assertion = new XPathAssertion(); |
| assertion.setThreadContext(jmctx);// This would be done by the run command |
| result = new SampleResult(); |
| result.setResponseData(readFile("testfiles/XPathAssertionTest.xml")); |
| vars = new JMeterVariables(); |
| jmctx.setVariables(vars); |
| jmctx.setPreviousResult(result); |
| } |
| |
| private void setAlternateResponseData(){ |
| String data = "<company-xmlext-query-ret>" + "<row>" + "<value field=\"RetCode\">LIS_OK</value>" |
| + "<value field=\"RetCodeExtension\"></value>" + "<value field=\"alias\"></value>" |
| + "<value field=\"positioncount\"></value>" + "<value field=\"invalidpincount\">0</value>" |
| + "<value field=\"pinposition1\">1</value>" + "<value field=\"pinpositionvalue1\"></value>" |
| + "<value field=\"pinposition2\">5</value>" + "<value field=\"pinpositionvalue2\"></value>" |
| + "<value field=\"pinposition3\">6</value>" + "<value field=\"pinpositionvalue3\"></value>" |
| + "</row>" + "</company-xmlext-query-ret>"; |
| result.setResponseData(data, null); |
| } |
| |
| private ByteArrayOutputStream readBA(String name) throws IOException { |
| BufferedInputStream bis = new BufferedInputStream(new FileInputStream(findTestFile(name))); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(1000); |
| int len = 0; |
| byte[] data = new byte[512]; |
| while ((len = bis.read(data)) >= 0) { |
| baos.write(data, 0, len); |
| } |
| bis.close(); |
| return baos; |
| } |
| |
| private byte[] readFile(String name) throws IOException { |
| return readBA(name).toByteArray(); |
| } |
| |
| @Test |
| public void testAssertionOK() throws Exception { |
| assertion.setXPathString("/"); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertFalse(res.isFailure(), "Should not be a failure"); |
| } |
| |
| @Test |
| public void testAssertionFail() throws Exception { |
| assertion.setXPathString("//x"); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| } |
| |
| @Test |
| public void testAssertionPath1() throws Exception { |
| assertion.setXPathString("//*[code=1]"); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertFalse(res.isFailure(), "Should not be a failure"); |
| } |
| @Test |
| public void testAssertionPath1Negated() { |
| assertion.setXPathString("//*[code=1]"); |
| assertion.setNegated(true); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| } |
| |
| @Test |
| public void testAssertionPath2() throws Exception { |
| assertion.setXPathString("//*[code=2]"); // Not present |
| assertion.setNegated(true); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertFalse(res.isFailure(), "Should not be a failure"); |
| } |
| |
| @Test |
| public void testAssertionPath2Negated() { |
| assertion.setXPathString("//*[code=1]"); |
| assertion.setNegated(true); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should not be a failure"); |
| } |
| |
| @Test |
| public void testAssertionBool1() throws Exception { |
| assertion.setXPathString("count(//error)=2"); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertFalse(res.isFailure(), "Should not be a failure"); |
| } |
| |
| @Test |
| public void testAssertionBool1Negated() { |
| assertion.setXPathString("count(//error)=2"); |
| assertion.setNegated(true); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should not be a failure"); |
| assertEquals("Nodes Matched for count(//error)=2", res.getFailureMessage(), "when isNegated is true, when xpath matches, result should fail"); |
| } |
| |
| @Test |
| public void testAssertionBool2() throws Exception { |
| assertion.setXPathString("count(//*[code=1])=1"); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertFalse(res.isFailure(), "Should not be a failure"); |
| } |
| |
| @Test |
| public void testAssertionBool2Negated() { |
| assertion.setXPathString("count(//*[code=1])=1"); |
| assertion.setNegated(true); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| assertEquals("Nodes Matched for count(//*[code=1])=1", res.getFailureMessage()); |
| |
| } |
| |
| @Test |
| public void testAssertionBool3() throws Exception { |
| assertion.setXPathString("count(//error)=1"); // wrong |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| assertEquals("No Nodes Matched for count(//error)=1", res.getFailureMessage()); |
| } |
| @Test |
| public void testAssertionBool3Negated() { |
| assertion.setXPathString("count(//error)=1"); // wrong |
| assertion.setNegated(true); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertFalse(res.isFailure(), "Should not be a failure"); |
| } |
| |
| @Test |
| public void testAssertionBool4() throws Exception { |
| assertion.setXPathString("count(//*[code=2])=1"); //Wrong |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| } |
| |
| @Test |
| public void testAssertionBool4Negated() throws Exception { |
| assertion.setXPathString("count(//*[code=2])=1"); //Wrong |
| AssertionResult res = assertion.getResult(result); |
| assertion.setNegated(true); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| assertEquals("No Nodes Matched for count(//*[code=2])=1", res.getFailureMessage()); |
| } |
| @Test |
| public void testAssertionNumber() throws Exception { |
| assertion.setXPathString("count(//error)");// not yet handled |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| } |
| |
| @Test |
| public void testAssertionNoResult() throws Exception { |
| // result.setResponseData - not set |
| result = new SampleResult(); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertEquals(AssertionResult.RESPONSE_WAS_NULL, res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| } |
| |
| @Test |
| public void testAssertionEmptyResult() throws Exception { |
| result.setResponseData("", null); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertEquals(AssertionResult.RESPONSE_WAS_NULL, res.getFailureMessage()); |
| assertFalse(res.isError(), "Should not be an error"); |
| assertTrue(res.isFailure(), "Should be a failure"); |
| } |
| |
| @Test |
| public void testAssertionBlankResult() throws Exception { |
| result.setResponseData(" ", null); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertTrue(res.getFailureMessage().indexOf("Premature end of file") > 0); |
| assertTrue(res.isError(), "Should be an error"); |
| assertFalse(res.isFailure(), "Should not be a failure"); |
| } |
| |
| @Test |
| public void testNoTolerance() throws Exception { |
| String data = "<html><head><title>testtitle</title></head>" + "<body>" |
| + "<p><i><b>invalid tag nesting</i></b><hr>" + "</body></html>"; |
| |
| result.setResponseData(data, null); |
| vars = new JMeterVariables(); |
| jmctx.setVariables(vars); |
| jmctx.setPreviousResult(result); |
| assertion.setXPathString("/html/head/title"); |
| assertion.setValidating(false); |
| assertion.setTolerant(false); |
| AssertionResult res = assertion.getResult(result); |
| log.debug("failureMessage: {}", res.getFailureMessage()); |
| assertTrue(res.isError()); |
| assertFalse(res.isFailure()); |
| } |
| |
| @Test |
| public void testAssertion() throws Exception { |
| setAlternateResponseData(); |
| assertion.setXPathString("//row/value[@field = 'alias']"); |
| AssertionResult res = assertion.getResult(jmctx.getPreviousResult()); |
| log.debug(" res {}", res.isError()); |
| log.debug(" failure {}", res.getFailureMessage()); |
| assertFalse(res.isError()); |
| assertFalse(res.isFailure()); |
| } |
| |
| @Test |
| public void testNegateAssertion() throws Exception { |
| setAlternateResponseData(); |
| assertion.setXPathString("//row/value[@field = 'noalias']"); |
| assertion.setNegated(true); |
| |
| AssertionResult res = assertion.getResult(jmctx.getPreviousResult()); |
| log.debug(" res {}", res.isError()); |
| log.debug(" failure {}", res.getFailureMessage()); |
| assertFalse(res.isError()); |
| assertFalse(res.isFailure()); |
| } |
| |
| @Test |
| public void testValidationFailure() throws Exception { |
| setAlternateResponseData(); |
| assertion.setXPathString("//row/value[@field = 'alias']"); |
| assertion.setNegated(false); |
| assertion.setValidating(true); |
| AssertionResult res = assertion.getResult(jmctx.getPreviousResult()); |
| log.debug("{} error: {} failure: {}", res.getFailureMessage(), res.isError(), res.isFailure()); |
| assertTrue(res.isError()); |
| assertFalse(res.isFailure()); |
| } |
| |
| @Test |
| public void testValidationSuccess() throws Exception { |
| String data = "<?xml version=\"1.0\"?>" + "<!DOCTYPE BOOK [" + "<!ELEMENT p (#PCDATA)>" |
| + "<!ELEMENT BOOK (OPENER,SUBTITLE?,INTRODUCTION?,(SECTION | PART)+)>" |
| + "<!ELEMENT OPENER (TITLE_TEXT)*>" + "<!ELEMENT TITLE_TEXT (#PCDATA)>" |
| + "<!ELEMENT SUBTITLE (#PCDATA)>" + "<!ELEMENT INTRODUCTION (HEADER, p+)+>" |
| + "<!ELEMENT PART (HEADER, CHAPTER+)>" + "<!ELEMENT SECTION (HEADER, p+)>" |
| + "<!ELEMENT HEADER (#PCDATA)>" + "<!ELEMENT CHAPTER (CHAPTER_NUMBER, CHAPTER_TEXT)>" |
| + "<!ELEMENT CHAPTER_NUMBER (#PCDATA)>" + "<!ELEMENT CHAPTER_TEXT (p)+>" + "]>" + "<BOOK>" |
| + "<OPENER>" + "<TITLE_TEXT>All About Me</TITLE_TEXT>" + "</OPENER>" + "<PART>" |
| + "<HEADER>Welcome To My Book</HEADER>" + "<CHAPTER>" |
| + "<CHAPTER_NUMBER>CHAPTER 1</CHAPTER_NUMBER>" + "<CHAPTER_TEXT>" |
| + "<p>Glad you want to hear about me.</p>" + "<p>There's so much to say!</p>" |
| + "<p>Where should we start?</p>" + "<p>How about more about me?</p>" + "</CHAPTER_TEXT>" |
| + "</CHAPTER>" + "</PART>" + "</BOOK>"; |
| |
| result.setResponseData(data, null); |
| vars = new JMeterVariables(); |
| jmctx.setVariables(vars); |
| jmctx.setPreviousResult(result); |
| assertion.setXPathString("/"); |
| assertion.setValidating(true); |
| AssertionResult res = assertion.getResult(result); |
| assertFalse(res.isError()); |
| assertFalse(res.isFailure()); |
| } |
| |
| @Test |
| public void testValidationFailureWithDTD() throws Exception { |
| String data = "<?xml version=\"1.0\"?>" + "<!DOCTYPE BOOK [" + "<!ELEMENT p (#PCDATA)>" |
| + "<!ELEMENT BOOK (OPENER,SUBTITLE?,INTRODUCTION?,(SECTION | PART)+)>" |
| + "<!ELEMENT OPENER (TITLE_TEXT)*>" + "<!ELEMENT TITLE_TEXT (#PCDATA)>" |
| + "<!ELEMENT SUBTITLE (#PCDATA)>" + "<!ELEMENT INTRODUCTION (HEADER, p+)+>" |
| + "<!ELEMENT PART (HEADER, CHAPTER+)>" + "<!ELEMENT SECTION (HEADER, p+)>" |
| + "<!ELEMENT HEADER (#PCDATA)>" + "<!ELEMENT CHAPTER (CHAPTER_NUMBER, CHAPTER_TEXT)>" |
| + "<!ELEMENT CHAPTER_NUMBER (#PCDATA)>" + "<!ELEMENT CHAPTER_TEXT (p)+>" + "]>" + "<BOOK>" |
| + "<OPENER>" + "<TITLE_TEXT>All About Me</TITLE_TEXT>" + "</OPENER>" + "<PART>" |
| + "<HEADER>Welcome To My Book</HEADER>" + "<CHAPTER>" |
| + "<CHAPTER_NUMBER>CHAPTER 1</CHAPTER_NUMBER>" + "<CHAPTER_TEXT>" |
| + "<p>Glad you want to hear about me.</p>" + "<p>There's so much to say!</p>" |
| + "<p>Where should we start?</p>" + "<p>How about more about me?</p>" + "</CHAPTER_TEXT>" |
| + "</CHAPTER>" + "<illegal>not defined in dtd</illegal>" + "</PART>" + "</BOOK>"; |
| |
| result.setResponseData(data, null); |
| vars = new JMeterVariables(); |
| jmctx.setVariables(vars); |
| jmctx.setPreviousResult(result); |
| assertion.setXPathString("/"); |
| assertion.setValidating(true); |
| AssertionResult res = assertion.getResult(result); |
| log.debug("failureMessage: {}", res.getFailureMessage()); |
| assertTrue(res.isError()); |
| assertFalse(res.isFailure()); |
| } |
| |
| @Test |
| public void testTolerance() throws Exception { |
| String data = "<html><head><title>testtitle</title></head>" + "<body>" |
| + "<p><i><b>invalid tag nesting</i></b><hr>" + "</body></html>"; |
| |
| result.setResponseData(data, null); |
| vars = new JMeterVariables(); |
| jmctx.setVariables(vars); |
| jmctx.setPreviousResult(result); |
| assertion.setXPathString("/html/head/title"); |
| assertion.setValidating(true); |
| assertion.setTolerant(true); |
| AssertionResult res = assertion.getResult(result); |
| log.debug("failureMessage: {}", res.getFailureMessage()); |
| assertFalse(res.isFailure()); |
| assertFalse(res.isError()); |
| } |
| |
| @Test |
| public void testScope(){ |
| String data = "<html><head><title>testtitle</title></head><body>" |
| + "<p><i><b>invalid tag nesting</i></b><hr></body></html>"; |
| assertion.setScopeVariable("testScope"); |
| vars = new JMeterVariables(); |
| vars.put("testScope", data); |
| jmctx.setVariables(vars); |
| jmctx.setPreviousResult(result); |
| assertion.setXPathString("/html/head/title"); |
| assertion.setValidating(true); |
| assertion.setTolerant(true); |
| AssertionResult res = assertion.getResult(result); |
| log.debug("failureMessage: {}", res.getFailureMessage()); |
| assertFalse(res.isFailure(), "When xpath conforms to xml, the result of assertion " |
| + "should be true "); |
| assertFalse(res.isError()); |
| } |
| @Test |
| public void testScopeFailure(){ |
| String data = "<html><head><title>testtitle</title></head><body>" |
| + "<p><i><b>invalid tag nesting</i></b><hr></body></html>"; |
| assertion.setScopeVariable("testScope"); |
| vars = new JMeterVariables(); |
| vars.put("testScope", data); |
| jmctx.setVariables(vars); |
| jmctx.setPreviousResult(result); |
| assertion.setXPathString("/html/head/tit"); |
| assertion.setValidating(true); |
| assertion.setTolerant(true); |
| AssertionResult res = assertion.getResult(result); |
| log.debug("failureMessage: {}", res.getFailureMessage()); |
| assertTrue(res.isFailure(), "When xpath doesn't conforms to xml, the result " |
| + "of assertion should be false "); |
| assertFalse(res.isError()); |
| } |
| |
| @Test |
| public void testWrongXpathMethod() { |
| assertion.setXPathString("cou(//error)=1"); // wrong |
| assertion.setNegated(true); |
| AssertionResult res = assertion.getResult(result); |
| testLog.debug("isError() {} isFailure() {}", res.isError(), res.isFailure()); |
| testLog.debug("failure message: {}", res.getFailureMessage()); |
| assertTrue(res.isError(), "Should not be an error"); |
| assertTrue(res.getFailureMessage().contains("TransformerException"), "A TransformerException should be thrown"); |
| } |
| @Test |
| public void testWithoutSuitableNamespaces() { |
| setAlternateResponseData(); |
| assertion.setNamespace(true); |
| assertion.setXPathString("//b:row/value[@field = 'alias']"); |
| AssertionResult res = assertion.getResult(jmctx.getPreviousResult()); |
| log.debug(" res {}", res.isError()); |
| log.debug(" failure {}", res.getFailureMessage()); |
| assertTrue(res.getFailureMessage().contains("TransformerException"), "When the user activates namespaces, a TransformerException should be thrown"); |
| } |
| } |