Skip to content

Commit

Permalink
feat: updated the XML builder to be able to set an elements text content
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed Aug 5, 2020
1 parent 1198763 commit 517c4cf
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 19 deletions.
3 changes: 2 additions & 1 deletion consumer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ dependencies {
testRuntime "org.junit.vintage:junit-vintage-engine:${project.junit5Version}"
testCompile "org.junit.jupiter:junit-jupiter-params:${project.junit5Version}"
testCompile "org.codehaus.groovy:groovy:${project.groovyVersion}"
testCompile "org.codehaus.groovy:groovy-dateutil:${project.groovyVersion}"
testCompile "org.codehaus.groovy:groovy-json:${project.groovyVersion}"
testCompile "org.codehaus.groovy:groovy-xml:${project.groovyVersion}"
testCompile "org.codehaus.groovy:groovy-dateutil:${project.groovyVersion}"
testCompile 'org.hamcrest:hamcrest:2.1'
testCompile('org.spockframework:spock-core:2.0-M2-groovy-3.0') {
exclude group: 'org.codehaus.groovy'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void provider2Fails() throws IOException {
mockTestProvider2.validateResultWith((result, t) -> {
assertThat(t, is(instanceOf(AssertionError.class)));
assertThat(t.getMessage(), is("The following mismatched requests occurred:\n" +
"BodyMismatch: Expected 'larry' (String) but received 'farry' (String)"));
"BodyMismatch: $.name Expected 'larry' (String) but received 'farry' (String)"));
assertThat(result, is(instanceOf(PactVerificationResult.Mismatches.class)));
PactVerificationResult.Mismatches error = (PactVerificationResult.Mismatches) result;
assertThat(error.getMismatches(), hasSize(1));
Expand Down Expand Up @@ -152,7 +152,7 @@ public void bothprovidersFail() throws IOException {
mockTestProvider2.validateResultWith((result, t) -> {
assertThat(t, is(instanceOf(AssertionError.class)));
assertThat(t.getMessage(), is("The following mismatched requests occurred:\n" +
"BodyMismatch: Expected 'larry' (String) but received 'farry' (String)"));
"BodyMismatch: $.name Expected 'larry' (String) but received 'farry' (String)"));
assertThat(result, is(instanceOf(PactVerificationResult.Mismatches.class)));
PactVerificationResult.Mismatches error = (PactVerificationResult.Mismatches) result;
assertThat(error.getMismatches(), hasSize(1));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package au.com.dius.pact.consumer.junit5.xml

import au.com.dius.pact.consumer.MockServer
import au.com.dius.pact.consumer.dsl.PactDslWithProvider
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt
import au.com.dius.pact.consumer.junit5.PactTestFor
import au.com.dius.pact.consumer.xml.PactXmlBuilder
import au.com.dius.pact.core.model.RequestResponsePact
import au.com.dius.pact.core.model.annotations.Pact
import org.apache.http.HttpResponse
import org.apache.http.client.fluent.Request
import org.apache.http.entity.ContentType
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith

import static au.com.dius.pact.consumer.dsl.Matchers.regexp

@ExtendWith(PactConsumerTestExt)
@PactTestFor(providerName = 'XMLProvider')
class XMLPactTest {
@Pact(consumer = 'XMLConsumer')
RequestResponsePact xmlMessage(PactDslWithProvider builder) {
builder
.uponReceiving('a POST request with an XML message')
.method('POST')
.path('/message')
.body(new PactXmlBuilder('Message').build(message -> {
message.setAttributes([type: 'Request'])
message.appendElement('Head', [:], head -> {
head.appendElement('Client', [name: 'WebCheck'], client -> {
client.appendElement('Version', regexp(/\d+\.\d+\.\d+\.\d+/, "2.2.8.2"))
})
head.appendElement('Server', [:], server -> {
server.appendElement('Name', [:], "SrvCheck")
server.appendElement('Version', [:], "3.0")
})
head.appendElement('Authentication', [:], authentication -> {
authentication.appendElement('User', [:], regexp(/\w+/, "user_name"))
authentication.appendElement('Password', [:], regexp(/\w+/, "password"))
})
head.appendElement('Token', [:], '1234567323211242144')
})
message.appendElement('Body', [:], body -> {
body.appendElement('Call', [method: 'getInfo', service: 'CheckRpcService'], call -> {
call.appendElement('Param', [name: regexp(/exportId|mtpId/, 'exportId')], param -> {
param.appendElement('ExportId', regexp(/\d+/, '1234567890'))
})
})
})
}))
.willRespondWith()
.status(200)
.body(new PactXmlBuilder("Message").build(message -> {
message.appendElement('Head', [:], head -> {
head.appendElement('Server', [:], server -> {
server.appendElement('Name', [:], regexp(/\w+/, 'server_name'))
server.appendElement('Version', [:], regexp(/.+/, 'server_version'))
server.appendElement('Timestamp', [:], regexp(/.+/, 'server_timestamp'))
})
})
message.appendElement('Body', [:], body -> {
body.appendElement('Result', [state: 'SUCCESS'])
})
}))
.toPact()
}

@Test
void testXMLPost(MockServer mockServer) {
HttpResponse httpResponse = Request.Post("${mockServer.url}/message")
.bodyString(
'''<?xml version="1.0" encoding="UTF-8"?>
<Message type="Request">
<Head>
<Client name="WebCheck">
<Version>2.2.8.3</Version>
</Client>
<Server>
<Name>SrvCheck</Name>
<Version>3.0</Version>
</Server>
<Authentication>
<User>peter</User>
<Password>token_placeholder</Password>
</Authentication>
<Token>1234567323211242144</Token>
</Head>
<Body>
<Call method="getInfo" service="CheckRpcService">
<Param name="exportId">
<ExportId>123456789</ExportId>
</Param>
</Call>
</Body>
</Message>
''', ContentType.APPLICATION_XML
)
.execute().returnResponse()
assert httpResponse.statusLine.statusCode == 200
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,34 @@ class XmlNode(private val builder: PactXmlBuilder, private val element: Element,
@JvmOverloads
fun appendElement(name: String, attributes: Map<String, Any?> = emptyMap(), cl: Consumer<XmlNode>? = null) {
val element = builder.doc.createElement(name)
setElementAttributes(attributes, element)

val node = XmlNode(builder, element, this.path + element.tagName)
cl?.accept(node)
this.element.appendChild(element)
}

@JvmOverloads
fun appendElement(name: String, attributes: Map<String, Any?> = emptyMap(), contents: String) {
val element = builder.doc.createElement(name)
setElementAttributes(attributes, element)
element.textContent = contents
this.element.appendChild(element)
}

@JvmOverloads
fun appendElement(name: String, attributes: Map<String, Any?> = emptyMap(), contents: Matcher) {
val element = builder.doc.createElement(name)
setElementAttributes(attributes, element)
element.textContent = contents.value.toString()
builder.matchingRules.addRule(matcherKey(path, name, "#text"), contents.matcher!!)
if (contents.generator != null) {
builder.generators.addGenerator(BODY, matcherKey(path, name, "#text"), contents.generator!!)
}
this.element.appendChild(element)
}

private fun setElementAttributes(attributes: Map<String, Any?>, element: Element) {
attributes.forEach {
if (it.value is Matcher) {
val matcherDef = it.value as Matcher
Expand All @@ -118,9 +146,5 @@ class XmlNode(private val builder: PactXmlBuilder, private val element: Element,
element.setAttribute(it.key, it.value.toString())
}
}

val node = XmlNode(builder, element, this.path + element.tagName)
cl?.accept(node)
this.element.appendChild(element)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ data class BodyMismatch @JvmOverloads constructor(
val path: String = "/",
val diff: String? = null
) : Mismatch() {
override fun description() = "BodyMismatch: $mismatch"
override fun description() = "BodyMismatch: $path $mismatch"
}

object BodyMismatchFactory : MismatchFactory<BodyMismatch> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,9 @@ class XmlBodyMatcherSpec extends Specification {

then:
result.size() == 3
result*.description() == ['BodyMismatch: Unexpected child <dog/>', 'BodyMismatch: Unexpected child <cat/>',
'BodyMismatch: Unexpected child <cat/>']
result*.description() == ['BodyMismatch: $.animals.dog.1 Unexpected child <dog/>',
'BodyMismatch: $.animals.cat.1 Unexpected child <cat/>',
'BodyMismatch: $.animals.cat.2 Unexpected child <cat/>']
}

def 'type matcher when an element has different types of children'() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package au.com.dius.pact.core.model
import org.apache.commons.collections4.iterators.PushbackIterator

const val PATH_SPECIAL_CHARS = "'[].@ \t\n"
const val EXP_ALLOWED_SPECIAL_CHARS = "-_:"
const val EXP_ALLOWED_SPECIAL_CHARS = "-_:#@"

sealed class PathToken {
object Root : PathToken()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import au.com.dius.pact.core.model.messaging.Message
import com.github.michaelbull.result.Ok
import spock.lang.Specification

@SuppressWarnings('LineLength')
class MessageComparisonSpec extends Specification {

def 'compares the message contents as JSON'() {
Expand All @@ -20,7 +21,7 @@ class MessageComparisonSpec extends Specification {
then:
result instanceof Ok
result.value.mismatches.collectEntries { [ it.key, it.value*.description() ] } == [
'$.b': ['BodyMismatch: Expected \'2\' (String) but received \'3\' (String)']
'$.b': ['BodyMismatch: $.b Expected \'2\' (String) but received \'3\' (String)']
]
}

Expand All @@ -37,7 +38,7 @@ class MessageComparisonSpec extends Specification {
result instanceof Ok
result.value.mismatches.collectEntries { [ it.key, it.value*.description() ] } == [
'/': [
'BodyMismatch: Expected body \'{"a":1,"b":"2"}\' to match \'{"a":1,"b":"3"}\' using equality but did not match'
'BodyMismatch: / Expected body \'{"a":1,"b":"2"}\' to match \'{"a":1,"b":"3"}\' using equality but did not match'
]
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import com.github.michaelbull.result.Ok
import spock.lang.Specification
import spock.lang.Unroll

@SuppressWarnings('UnnecessaryGetter')
@SuppressWarnings(['UnnecessaryGetter', 'LineLength'])
class ResponseComparisonSpec extends Specification {

private Closure<Map> subject
Expand Down Expand Up @@ -111,7 +111,7 @@ class ResponseComparisonSpec extends Specification {
expect:
result instanceof Ok
result.value.mismatches.collectEntries { [ it.key, it.value*.description() ] } == [
'$.stuff': ["BodyMismatch: Expected 'is good' (String) but received 'should make the test fail' (String)"]
'$.stuff': ["BodyMismatch: \$.stuff Expected 'is good' (String) but received 'should make the test fail' (String)"]
]
result.value.diff[1] == '- "stuff": "is good"'
result.value.diff[2] == '+ "stuff": "should make the test fail"'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ class JsonReporterSpec extends Specification {
reportJson.execution[0].interactions[0].verification.status == ['expected status of 201 but was 200']
reportJson.execution[0].interactions[0].verification.header == ['HEADER-X': ["Expected a header 'HEADER-X' but was missing"]]
reportJson.execution[0].interactions[0].verification.body.mismatches == [
'$.0': ['BodyMismatch: Expected doesNotExist="Test" but was missing'],
'$.1': ['BodyMismatch: Expected doesNotExist="Test" but was missing']
'$.0': ['BodyMismatch: $.0 Expected doesNotExist="Test" but was missing'],
'$.1': ['BodyMismatch: $.1 Expected doesNotExist="Test" but was missing']
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ class MarkdownReporterSpec extends Specification {
|
|| Path | Failure |
|| ---- | ------- |
||`$.0`|BodyMismatch: Expected doesNotExist="Test" but was missing|
||`$.1`|BodyMismatch: Expected doesNotExist="Test" but was missing|
||`$.0`|BodyMismatch: $.0 Expected doesNotExist="Test" but was missing|
||`$.1`|BodyMismatch: $.1 Expected doesNotExist="Test" but was missing|
|
|
|Diff:
Expand Down

0 comments on commit 517c4cf

Please sign in to comment.