Skip to content

Commit

Permalink
fix: Message metadata is parsed as JSON, so need to check for JSON ty…
Browse files Browse the repository at this point in the history
…pes #1749
  • Loading branch information
rholshausen committed Apr 22, 2024
1 parent 8695303 commit 1df2b1f
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 6 deletions.
@@ -0,0 +1,39 @@
package au.com.dius.pact.consumer.junit5;

import au.com.dius.pact.consumer.MessagePactBuilder;
import au.com.dius.pact.consumer.dsl.Matchers;
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
import au.com.dius.pact.core.model.V4Interaction;
import au.com.dius.pact.core.model.V4Pact;
import au.com.dius.pact.core.model.annotations.Pact;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import java.util.List;
import java.util.Map;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.core.Is.is;

@ExtendWith(PactConsumerTestExt.class)
@PactTestFor(providerName = "AmqpProviderWithMetadata", providerType = ProviderType.ASYNCH)
public class AsyncMessageWithMetadataTest {

@Pact(consumer = "test_consumer")
public V4Pact withMetadata(MessagePactBuilder builder) {
return builder
.given("Some State")
.expectsToReceive("A message with metadata")
.withMetadata(Map.of("someKey", Matchers.string("someString")))
.withContent(new PactDslJsonBody().stringType("someField", "someValue"))
.toPact(V4Pact.class);
}

@Test
@PactTestFor
void test(List<V4Interaction.AsynchronousMessage> messages) {
assertThat(new String(messages.get(0).contentsAsBytes()), is("{\"someField\":\"someValue\"}"));
assertThat(messages.get(0).getMetadata(), hasEntry("someKey", "someString"));
}
}
Expand Up @@ -247,7 +247,7 @@ fun <M : Mismatch> matchType(
expected is Attr && actual is Attr && QualifiedName(actual) == QualifiedName(expected)
) {
emptyList()
} else if (expected is String && actual is String ||
} else if (isString(expected) && isString(actual) ||
expected is List<*> && actual is List<*> ||
expected is Array<*> && actual is Array<*> ||
expected is ByteArray && actual is ByteArray ||
Expand All @@ -259,6 +259,7 @@ fun <M : Mismatch> matchType(
} else {
val empty = when (actual) {
is String -> actual.isEmpty()
is JsonValue.StringValue -> actual.toString().isEmpty()
is List<*> -> actual.isEmpty()
is Array<*> -> actual.isEmpty()
is ByteArray -> actual.isEmpty()
Expand Down Expand Up @@ -359,8 +360,7 @@ fun matchDecimal(actual: Any?): Boolean {
bigDecimal == BigDecimal.ZERO || bigDecimal.scale() > 0
}
actual is JsonValue.Integer -> decimalRegex.matches(actual.toString())
actual is String -> decimalRegex.matches(actual)
actual is JsonValue.StringValue -> decimalRegex.matches(actual.toString())
isString(actual) -> decimalRegex.matches(actual.toString())
actual is Attr -> decimalRegex.matches(actual.nodeValue)
else -> false
}
Expand All @@ -376,8 +376,7 @@ fun matchInteger(actual: Any?): Boolean {
actual is JsonValue.Integer -> true
actual is BigDecimal && actual.scale() == 0 -> true
actual is JsonValue.Decimal -> integerRegex.matches(actual.toString())
actual is String -> integerRegex.matches(actual)
actual is JsonValue.StringValue -> integerRegex.matches(actual.toString())
isString(actual) -> integerRegex.matches(actual.toString())
actual is Attr -> integerRegex.matches(actual.nodeValue)
else -> false
}
Expand All @@ -402,14 +401,16 @@ fun <M : Mismatch> matchBoolean(
actual is Boolean -> emptyList()
actual is JsonValue && actual.isBoolean -> emptyList()
actual is Attr && actual.nodeValue.matches(booleanRegex) -> emptyList()
actual is String && actual.matches(booleanRegex) -> emptyList()
isString(actual) && actual.toString().matches(booleanRegex) -> emptyList()
actual is List<*> -> emptyList()
actual is Map<*, *> -> emptyList()
else -> listOf(mismatchFactory.create(expected, actual,
"Expected ${valueOf(actual)} (${typeOf(actual)}) to match a boolean", path))
}
}

private fun isString(value: Any?) = value is String || value is JsonValue.StringValue

fun <M : Mismatch> matchDate(
pattern: String,
path: List<String>,
Expand Down
Expand Up @@ -119,6 +119,8 @@ class MatcherExecutorSpec extends Specification {
xml('<a:e xmlns:a="a"/>') | xml('<b:e xmlns:b="a"/>') || true
xml('<e xmlns="a"/>') | xml('<e xmlns="b"/>') || false
json('"hello"') | json('"hello"') || true
json('"hello"') | 'hello' || true
'hello' | json('"hello"') || true
json('100') | json('200') || true
2.3d | 2.300d || true
2.3g | 2.300g || true
Expand Down Expand Up @@ -395,6 +397,7 @@ class MatcherExecutorSpec extends Specification {
expected | actual || mustBeEmpty
'Harry' | 'Some other string' || true
'Harry' | '' || false
'Harry' | json('""') || false
100 | 200.3 || true
true | false || true
null | null || true
Expand Down
@@ -0,0 +1,34 @@
package au.com.dius.pact.provider.junit5;

import au.com.dius.pact.provider.MessageAndMetadata;
import au.com.dius.pact.provider.PactVerifyProvider;
import au.com.dius.pact.provider.junitsupport.Provider;
import au.com.dius.pact.provider.junitsupport.loader.PactFolder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;

import java.util.Map;

@Provider("AmqpProviderWithMetadata")
@PactFolder("src/test/resources/amqp_pacts")
class MessageWithMetadataTest {
@TestTemplate
@ExtendWith(PactVerificationInvocationContextProvider.class)
void testTemplate(PactVerificationContext context) {
context.verifyInteraction();
}

@BeforeEach
void before(PactVerificationContext context) {
context.setTarget(new MessageTestTarget());
}

@PactVerifyProvider("A message with metadata")
public MessageAndMetadata verifyV4MessageWithMetadataForOrder() {
return new MessageAndMetadata(
"{\"someField\": \"someValue\"}".getBytes(),
Map.of("someKey", "different string pact but same type")
);
}
}
@@ -0,0 +1,56 @@
{
"consumer": {
"name": "test_consumer"
},
"interactions": [
{
"contents": {
"content": {
"someField": "someValue"
},
"contentType": "application/json",
"encoded": false
},
"description": "A message with metadata",
"matchingRules": {
"body": {
"$.someField": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
}
},
"metadata": {
"someKey": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
}
}
},
"metadata": {
"contentType": "application/json",
"someKey": "someString"
},
"pending": false,
"type": "Asynchronous/Messages"
}
],
"metadata": {
"pact-jvm": {
"version": "4.6.5"
},
"pactSpecification": {
"version": "4.0"
}
},
"provider": {
"name": "AmqpProviderWithMetadata"
}
}

0 comments on commit 1df2b1f

Please sign in to comment.