Skip to content

Commit

Permalink
Add a test for soap message content, as used in #234. Fix soap
Browse files Browse the repository at this point in the history
implementation.
  • Loading branch information
pdvrieze committed Sep 11, 2024
1 parent 768babf commit b8776d3
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@
package nl.adaptivity.xml.serialization.regressions

import io.github.pdvrieze.xmlutil.testutil.assertXmlEquals
import kotlinx.serialization.decodeFromString
import nl.adaptivity.xml.serialization.regressions.soap.Envelope
import nl.adaptivity.xml.serialization.regressions.soap.Fault
import nl.adaptivity.xmlutil.*
import nl.adaptivity.xmlutil.core.impl.multiplatform.StringWriter
import nl.adaptivity.xmlutil.core.impl.multiplatform.use
import nl.adaptivity.xmlutil.dom2.*
import nl.adaptivity.xmlutil.serialization.XML
import nl.adaptivity.xmlutil.util.CompactFragment
import nl.adaptivity.xmlutil.util.CompactFragmentSerializer
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.*


/**
Expand Down Expand Up @@ -107,46 +108,87 @@ class TestSoapHelper {
assertFalse(parseResult.namespaces.iterator().hasNext(), "Unexpected namespaces: ${parseResult.namespaces.joinToString()} - '${parseResult.contentString}'")
}

@Test
fun testResponse3_234() {
val xml: XML = XML { recommended_0_90_2() }
val soap = xml.decodeFromString<Envelope<Fault>>(SOAP_RESPONSE3)
val fault = soap.body.child
assertNull(fault.role)
assertNull(fault.node)

assertEquals("s:Client", fault.code.textContent)
val ns = fault.code.lookupNamespaceURI("s")
assertEquals(Envelope.NAMESPACE, ns)

val reasonText = assertIs<Element>(fault.reason.childNodes.singleOrNull { ! (it is Text && isXmlWhitespace(it.data))} )
val reason = assertIs<Text>(reasonText.childNodes.singleOrNull())
assertEquals("UPnPError", reason.textContent)

val detail = assertIs<Element>(fault.detail?.childNodes?.singleOrNull { (it !is Text) || !isXmlWhitespace(it.data) })
assertEquals("UPnPError", detail.localName)
assertEquals("urn:schemas-upnp-org:control-1-0", detail.namespaceURI)

val errorChildren = detail.childNodes.filterNot { it is Text && isXmlWhitespace(it.data) }
assertEquals(2, errorChildren.size)
}

companion object {

private val SOAP_RESPONSE1_BODY = """<getProcessNodeInstanceSoapResponse>
<rpc:result xmlns:rpc="http://www.w3.org/2003/05/soap-rpc">result</rpc:result>
<result>
<pe:nodeInstance xmlns:pe="http://adaptivity.nl/ProcessEngine/" handle="18" nodeid="ac2" processinstance="5" state="Acknowledged">
<pe:predecessor>16</pe:predecessor>
<pe:body>
<env:Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:umh="http://adaptivity.nl/userMessageHandler" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<Body>
<umh:postTask xmlns="http://adaptivity.nl/userMessageHandler">
<repliesParam>
<jbi:endpointDescriptor xmlns:jbi="http://adaptivity.nl/jbi" endpointLocation="http://localhost:8080/ProcessEngine" endpointName="soap" serviceLocalName="ProcessEngine" serviceNS="http://adaptivity.nl/ProcessEngine/"/>
</repliesParam>
<taskParam>
<task instancehandle="5" owner="pdvrieze" remotehandle="18" summary="Task Bar">
<item type="label" value="Hi . Welcome!"/>
</task>
</taskParam>
</umh:postTask>
</Body>
</env:Envelope>
</pe:body>
</pe:nodeInstance>
</result>
</getProcessNodeInstanceSoapResponse>
"""
private val SOAP_RESPONSE1_BODY = """|<getProcessNodeInstanceSoapResponse>
| <rpc:result xmlns:rpc="http://www.w3.org/2003/05/soap-rpc">result</rpc:result>
| <result>
| <pe:nodeInstance xmlns:pe="http://adaptivity.nl/ProcessEngine/" handle="18" nodeid="ac2" processinstance="5" state="Acknowledged">
| <pe:predecessor>16</pe:predecessor>
| <pe:body>
| <env:Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:umh="http://adaptivity.nl/userMessageHandler" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" encodingStyle="http://www.w3.org/2003/05/soap-encoding">
| <Body>
| <umh:postTask xmlns="http://adaptivity.nl/userMessageHandler">
| <repliesParam>
| <jbi:endpointDescriptor xmlns:jbi="http://adaptivity.nl/jbi" endpointLocation="http://localhost:8080/ProcessEngine" endpointName="soap" serviceLocalName="ProcessEngine" serviceNS="http://adaptivity.nl/ProcessEngine/"/>
| </repliesParam>
| <taskParam>
| <task instancehandle="5" owner="pdvrieze" remotehandle="18" summary="Task Bar">
| <item type="label" value="Hi . Welcome!"/>
| </task>
| </taskParam>
| </umh:postTask>
| </Body>
| </env:Envelope>
| </pe:body>
| </pe:nodeInstance>
| </result>
|</getProcessNodeInstanceSoapResponse>""".trimMargin()

private val SOAP_RESPONSE1 =
"""<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">$SOAP_RESPONSE1_BODY </soap:Body>
</soap:Envelope>
"""
"""|<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
| <soap:Body soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">$SOAP_RESPONSE1_BODY </soap:Body>
|</soap:Envelope>""".trimMargin()

private val SOAP_RESPONSE2 =
"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\">\n" +
" <soap:Body soap:encodingStyle=\"http://www.w3.org/2003/05/soap-encoding\">" + ("<getProcessNodeInstanceSoapResponse>\n" +
" </getProcessNodeInstanceSoapResponse>\n" +
" ") +
" </soap:Body>\n" +
"</soap:Envelope>\n"
"""|<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
| <soap:Body soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding"><getProcessNodeInstanceSoapResponse>
| </getProcessNodeInstanceSoapResponse>
| </soap:Body>
|</soap:Envelope>
""".trimMargin()

private val SOAP_RESPONSE3 =
"""|<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" s:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
| <s:Body>
| <s:Fault>
| <s:Detail>
| <UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
| <errorCode>401</errorCode>
| <errorDescription>Invalid Action</errorDescription>
| </UPnPError>
| </s:Detail>
| <s:Code>s:Client</s:Code>
| <s:Reason>
| <s:Text xml:lang="en">UPnPError</s:Text>
| </s:Reason>
| </s:Fault>
| </s:Body>
|</s:Envelope>""".trimMargin()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,12 @@ class Body<out T: Any>(
else -> true
}
}.associate { QName(it.namespaceUri, it.localName, it.prefix) to it.value }

child = decodeSerializableElement(descriptor, 2, contentSerializer, null)
if (input.nextTag() != EventType.END_ELEMENT) throw SerializationException("Extra content in body")
if (input.nextTag() != EventType.END_ELEMENT) {
child = decodeSerializableElement(descriptor, 2, contentSerializer, null)
if (input.nextTag() != EventType.END_ELEMENT) throw SerializationException("Extra content in body")
}
}
return Body(child)
return Body(child, encodingStyle, otherAttributes)
}

override fun serialize(encoder: Encoder, value: Body<T>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import kotlinx.serialization.encoding.encodeStructure
import nl.adaptivity.serialutil.decodeElements
import nl.adaptivity.xmlutil.*
import nl.adaptivity.xmlutil.serialization.XML
import nl.adaptivity.xmlutil.serialization.XmlOtherAttributes
import nl.adaptivity.xmlutil.serialization.XmlSerialName
import nl.adaptivity.xmlutil.serialization.XmlValue
import nl.adaptivity.xmlutil.util.CompactFragment
Expand Down Expand Up @@ -77,9 +78,11 @@ import kotlin.jvm.JvmStatic
* setter.
*/
@Serializable(Envelope.Serializer::class)
@XmlSerialName(Envelope.ELEMENTLOCALNAME, Envelope.NAMESPACE, Envelope.PREFIX)
class Envelope<out T : Any>(
val body: Body<T>,
val header: Header = Header(),
@XmlOtherAttributes
val otherAttributes: Map<QName, String> = emptyMap(),
) {

Expand All @@ -95,7 +98,8 @@ class Envelope<out T : Any>(
override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("org.w3c.dom.Envelope", bodyContentSerializer.descriptor) {
annotations = SoapSerialObjects.envelopeAnnotations
element("otherAttributes", SoapSerialObjects.attrsSerializer.descriptor, isOptional = true)
element<String>("encodingStyle", SoapSerialObjects.encodingStyleAnnotations, isOptional = true)
element("otherAttributes", SoapSerialObjects.attrsSerializer.descriptor, listOf(XmlOtherAttributes()), isOptional = true)
element<Header>("header", isOptional = true)
element("body", bodySerializer.descriptor)
}
Expand All @@ -112,8 +116,10 @@ class Envelope<out T : Any>(
0 -> otherAttributes =
decodeSerializableElement(descriptor, idx, SoapSerialObjects.attrsSerializer)

1 -> header = decodeSerializableElement(descriptor, idx, Header.serializer())
2 -> body = decodeSerializableElement(descriptor, idx, bodySerializer)
1 -> encodingStyle = decodeStringElement(descriptor, idx)

2 -> header = decodeSerializableElement(descriptor, idx, Header.serializer())
3 -> body = decodeSerializableElement(descriptor, idx, bodySerializer)
}
}
}
Expand Down Expand Up @@ -187,9 +193,9 @@ class Envelope<out T : Any>(
value.otherAttributes
)
if (value.header.blocks.isNotEmpty() || value.header.otherAttributes.isNotEmpty()) {
encodeSerializableElement(descriptor, 1, Header.serializer(), value.header)
encodeSerializableElement(descriptor, 2, Header.serializer(), value.header)
}
encodeSerializableElement(descriptor, 2, bodySerializer, value.body)
encodeSerializableElement(descriptor, 3, bodySerializer, value.body)
}
}

Expand Down Expand Up @@ -243,6 +249,8 @@ internal object SoapSerialObjects {

val bodyAnnotations = listOf(XmlSerialName(Body.ELEMENTLOCALNAME, Envelope.NAMESPACE, Envelope.PREFIX))

val faultAnnotations = listOf(XmlSerialName("Fault", Envelope.NAMESPACE, Envelope.PREFIX))

val encodingStyleAnnotations = listOf(XmlSerialName("encodingStyle", Envelope.NAMESPACE, Envelope.PREFIX))

val valueAnnotations = listOf(XmlValue(true))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2024.
*
* This file is part of xmlutil.
*
* This file is licenced to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You should have received a copy of the license with the source distribution.
* Alternatively, 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 nl.adaptivity.xml.serialization.regressions.soap

import kotlinx.serialization.Serializable
import nl.adaptivity.xmlutil.dom2.Element
import nl.adaptivity.xmlutil.serialization.XmlSerialName

@Serializable
@XmlSerialName("Fault", Envelope.NAMESPACE, Envelope.PREFIX)
class Fault(
@XmlSerialName("Code", Envelope.NAMESPACE)
val code: Element,
@XmlSerialName("Reason", Envelope.NAMESPACE)
val reason: Element,
@XmlSerialName("Node", Envelope.NAMESPACE)
val node: Element? = null,
@XmlSerialName("Role", Envelope.NAMESPACE)
val role: Element? = null,
@XmlSerialName("Detail", Envelope.NAMESPACE)
val detail: Element? = null,
) {
}

0 comments on commit b8776d3

Please sign in to comment.