outofcoffee / imposter

Scriptable, multipurpose mock server. Run standalone mock servers, or embed mocks within your tests.
https://imposter.sh
Other
349 stars 58 forks source link

Unable to match multiple values in request body using XPath in SOAP plugin #576

Open ismailastighfar opened 1 month ago

ismailastighfar commented 1 month ago

Description: I encountered an issue while trying to match multiple values in the request body using XPath in the SOAP plugin. Here are the details:

Problem: When configuring the Imposter with a SOAP plugin and defining the request body XPath to match multiple values, the matching does not work as expected, i didn't find any examples so if you have any resources or modifications i should do to make this work

my config file :



resources:  
  - operation: RetrievePatientInfoWithVIPIndicatorRequest
    requestBody:
      xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sInstitutionCode"
      value: "SGH"
      xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sUserID"
      value: "GSRVWCMSTG"
      xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sPatNRIC"
      value: "S2192071A"
      xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sCallerSysADID:"
      value: "WCMS"
      xmlNamespaces:
        env: "http://schemas.xmlsoap.org/soap/envelope/"
        urn: "urn:sap-com:document:sap:rfc:functions"
    response:
      staticFile: ./oas/S2192071A.xml
outofcoffee commented 1 month ago

Hi @ismailastighfar, thanks for raising this.

A good fit here is the allOf (or anyOf) block. For example:

resources:  
  - operation: RetrievePatientInfoWithVIPIndicatorRequest
    requestBody:
      allOf:
        - xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sInstitutionCode"
          value: "SGH"
        - xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sUserID"
          value: "GSRVWCMSTG"
        - xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sPatNRIC"
          value: "S2192071A"
        - xPath: "/env:Envelope/env:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sCallerSysADID:"
          value: "WCMS"
      xmlNamespaces:
        env: "http://schemas.xmlsoap.org/soap/envelope/"
        urn: "urn:sap-com:document:sap:rfc:functions"
    response:
      staticFile: ./oas/S2192071A.xml

More info here: https://docs.imposter.sh/request_matching/#using-multiple-request-body-matchers

ismailastighfar commented 1 month ago

Firstly, I would like to thank you for the response to my previous issue. I appreciate the support and guidance provided.

Despite following the suggested configuration, I am still encountering an error when trying to match multiple values in the SOAP request body using XPath. Below are the detailed error log.

08:47:31 DEBUG i.g.i.p.s.SoapResourceMatcher - Matched 0 operations in binding OASWebServiceBinding based on body root element: urn:RetrievePatientInfoWithVIPIndicatorRequest
08:47:31 WARN  i.g.i.p.s.SoapResourceMatcher - No operations found matching body root element: urn:RetrievePatientInfoWithVIPIndicatorRequest
08:47:31 WARN  i.g.i.u.BodyQueryUtil - Error evaluating XPath expression '/env:Envelope/soapenv:Body/urn:RetrievePatientInfoWithVIPIndicatorRequest/sInstitutionCode' against request body for [19ebc49a-42dd-41eb-aceb-2f6dddb9e8cd] POST http://localhost:8082/WCMS_OAS
java.lang.IllegalArgumentException: Namespace with prefix 'env' has not been declared.
        at org.jdom2.xpath.util.AbstractXPathCompiled.getNamespace(AbstractXPathCompiled.java:256) ~[jdom2-2.0.6.1.jar:?]
        at org.jdom2.xpath.jaxen.JaxenCompiled.translateNamespacePrefixToUri(JaxenCompiled.java:171) ~[jdom2-2.0.6.1.jar:?]
        at org.jaxen.ContextSupport.translateNamespacePrefixToUri(ContextSupport.java:188) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.expr.DefaultNameStep.matches(DefaultNameStep.java:351) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.expr.DefaultNameStep.evaluate(DefaultNameStep.java:204) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.expr.DefaultLocationPath.evaluate(DefaultLocationPath.java:140) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.expr.DefaultAbsoluteLocationPath.evaluate(DefaultAbsoluteLocationPath.java:107) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.expr.DefaultXPathExpr.asList(DefaultXPathExpr.java:96) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.BaseXPath.selectNodesForContext(BaseXPath.java:662) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.BaseXPath.selectNodes(BaseXPath.java:215) ~[jaxen-2.0.0.jar:?]
        at org.jaxen.BaseXPath.selectSingleNode(BaseXPath.java:236) ~[jaxen-2.0.0.jar:?]
        at org.jdom2.xpath.jaxen.JaxenCompiled.evaluateRawFirst(JaxenCompiled.java:208) ~[jdom2-2.0.6.1.jar:?]
        at org.jdom2.xpath.util.AbstractXPathCompiled.evaluateFirst(AbstractXPathCompiled.java:364) ~[jdom2-2.0.6.1.jar:?]
        at io.gatehill.imposter.util.BodyQueryUtil.getXPathValue(BodyQueryUtil.kt:164) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.util.BodyQueryUtil.queryRequestBodyXPath(BodyQueryUtil.kt:154) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.http.AbstractResourceMatcher.matchRequestBodyXPath(AbstractResourceMatcher.kt:265) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.http.AbstractResourceMatcher.matchUsingBodyConfig(AbstractResourceMatcher.kt:235) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.http.AbstractResourceMatcher.matchRequestBody(AbstractResourceMatcher.kt:194) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.plugin.soap.SoapResourceMatcher.matchRequest(SoapResourceMatcher.kt:88) ~[imposter-mock-soap-3.40.0.jar:?]
        at io.gatehill.imposter.http.AbstractResourceMatcher.filterResourceConfigs(AbstractResourceMatcher.kt:131) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.http.AbstractResourceMatcher.matchResourceConfig(AbstractResourceMatcher.kt:79) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.service.HandlerServiceImpl.handle(HandlerServiceImpl.kt:280) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.service.HandlerServiceImpl.access$handle(HandlerServiceImpl.kt:83) ~[imposter-engine-3.40.0.jar:?]
        at io.gatehill.imposter.service.HandlerServiceImpl$build$2$1.invoke$lambda$2(HandlerServiceImpl.kt:119) ~[imposter-engine-3.40.0.jar:?]
        at io.vertx.core.impl.ContextBase.lambda$executeBlocking$0(ContextBase.java:167) ~[vertx-core-4.4.5.jar:4.4.5]
        at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:277) ~[vertx-core-4.4.5.jar:4.4.5]
        at io.vertx.core.impl.ContextBase.lambda$internalExecuteBlocking$2(ContextBase.java:199) ~[vertx-core-4.4.5.jar:4.4.5]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[?:?]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.97.Final.jar:4.1.97.Final]
        at java.lang.Thread.run(Unknown Source) ~[?:?]
08:47:31 DEBUG i.g.i.p.s.SoapResourceMatcher - Matched 0 operations in binding OASWebServiceBinding based on body root element: urn:RetrievePatientInfoWithVIPIndicatorRequest
08:47:31 WARN  i.g.i.p.s.SoapResourceMatcher - No operations found matching body root element: urn:RetrievePatientInfoWithVIPIndicatorRequest
08:47:31 WARN  i.g.i.p.s.SoapPluginImpl - Unable to find a matching binding operation using SOAPAction or SOAP request body

WSDL file :

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  targetNamespace="urn:sap-com:document:sap:rfc:functions">

    <wsdl:message name="RetrievePatientInfoWithVIPIndicatorRequest">
        <wsdl:part name="sInstitutionCode" type="xsd:string"/>
        <wsdl:part name="sUserID" type="xsd:string"/>
        <wsdl:part name="sPatNRIC" type="xsd:string"/>
        <wsdl:part name="sCallerSysADID" type="xsd:string"/>
    </wsdl:message>

    <wsdl:message name="RetrievePatientInfoWithVIPIndicatorResponse">
        <wsdl:part name="PatientNRIC" type="xsd:string"/>
        <wsdl:part name="PatientNRICType" type="xsd:string"/>
        <wsdl:part name="PatientName" type="xsd:string"/>
        <wsdl:part name="PatientBirthDate" type="xsd:string"/>
        <wsdl:part name="VIPVVIPIndicator" type="xsd:string"/>
        <wsdl:part name="InstitutionSpecificAddress" type="xsd:string"/>
        <wsdl:part name="StatusCode" type="xsd:string"/>
        <wsdl:part name="StatusDescription" type="xsd:string"/>
    </wsdl:message>

    <wsdl:portType name="OASWebServicePortType">
        <wsdl:operation name="RetrievePatientInfoWithVIPIndicatorRequest">
            <wsdl:input message="tns:RetrievePatientInfoWithVIPIndicatorRequest"/>
            <wsdl:output message="tns:RetrievePatientInfoWithVIPIndicatorResponse"/>
        </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="OASWebServiceBinding" type="tns:OASWebServicePortType">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="RetrievePatientInfoWithVIPIndicatorRequest">
            <soap:operation soapAction=""/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>

    <wsdl:service name="OASWebService">
        <wsdl:port name="OASWebServicePort" binding="tns:OASWebServiceBinding">
            <soap:address location="http://localhost:8082/WCMS_OAS"/>
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>

SOAP Request

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:sap-com:document:sap:rfc:functions">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:RetrievePatientInfoWithVIPIndicatorRequest>
        <urn:sInstitutionCode>SGH</urn:sInstitutionCode>
        <urn:sUserID>GSRVWCMSTG</urn:sUserID>
        <urn:sPatNRIC>S2192071A</urn:sPatNRIC>
        <urn:sCallerSysADID>WCMS</urn:sCallerSysADID>
      </urn:RetrievePatientInfoWithVIPIndicatorRequest>
   </soapenv:Body>
</soapenv:Envelope>

Could you please help me identify what might be going wrong in my configuration or suggest any modifications to resolve this namespace declaration error?

Thank you for your continued support.

outofcoffee commented 2 weeks ago

Hi @ismailastighfar, in the SOAP request, this namespace is declared:

xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"

Could you try updating the namespace prefix from soapenv to env? If this works, it may still be a bug we need to fix, but it would be good to have confirmation.

ismailastighfar commented 2 weeks ago

I attempted to follow your suggestion to update the namespace prefix from soapenv to env in the SOAP request. However, I am still experiencing the same issue.

Response Received Here's the response I received after updating the namespace prefix as suggested this is the default response if nothing is matching , the same as the namespace soapenv :

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
    <env:Header/>
    <env:Body>
        <urn:PatientNRIC xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:PatientNRIC>
        <urn:PatientNRICType xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:PatientNRICType>
        <urn:PatientName xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:PatientName>
        <urn:PatientBirthDate xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:PatientBirthDate>
        <urn:VIPVVIPIndicator xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:VIPVVIPIndicator>
        <urn:InstitutionSpecificAddress xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:InstitutionSpecificAddress>
        <urn:StatusCode xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:StatusCode>
        <urn:StatusDescription xmlns:urn="urn:sap-com:document:sap:rfc:functions">string</urn:StatusDescription>
    </env:Body>
</env:Envelope>
outofcoffee commented 1 week ago

Hi @ismailastighfar, thank you for confirming this.

There was a condition that the WSDL parser didn't handle properly - the document wrapped style. This is used in the WSDL you provided, and was resulting in the matching not working.

This should be fixed in v3.44.0.

Please let us know if this helps.