Compare commits
1 Commits
itsLucario
...
pact-jvm-l
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8216c90168 |
0
.idea/modules/spring-boot-testing.iml
generated
Normal file
0
.idea/modules/spring-boot-testing.iml
generated
Normal file
@@ -1,4 +1,10 @@
|
||||
userservice:
|
||||
ribbon:
|
||||
eureka:
|
||||
enabled: false
|
||||
listOfServers: localhost:8080
|
||||
|
||||
rootservice:
|
||||
ribbon:
|
||||
eureka:
|
||||
enabled: false
|
||||
|
||||
@@ -22,6 +22,6 @@ dependencies {
|
||||
compile("org.springframework.cloud:spring-cloud-starter-feign:1.4.1.RELEASE")
|
||||
compile('com.h2database:h2:1.4.196')
|
||||
testCompile('org.codehaus.groovy:groovy-all:2.4.6')
|
||||
testCompile("au.com.dius:pact-jvm-consumer-junit_2.11:3.5.2")
|
||||
compile("au.com.dius:pact-jvm-consumer-junit_2.11:3.5.16")
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test:${springboot_version}")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package io.reflectoring.dsl;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
|
||||
import au.com.dius.pact.consumer.dsl.PactDslJsonRootValue;
|
||||
|
||||
public class PactDslJsonBodyLikeMapper {
|
||||
|
||||
private static final Set<Class<?>> SIMPLE_TYPES = new HashSet<>(Arrays.asList(
|
||||
Boolean.class,
|
||||
boolean.class,
|
||||
Integer.class,
|
||||
int.class,
|
||||
Double.class,
|
||||
double.class,
|
||||
Float.class,
|
||||
float.class,
|
||||
BigDecimal.class,
|
||||
Number.class,
|
||||
String.class,
|
||||
Long.class,
|
||||
long.class
|
||||
));
|
||||
|
||||
public static PactDslJsonBody like(Object object) {
|
||||
return like(object, new PactDslJsonBody());
|
||||
}
|
||||
|
||||
public static PactDslJsonBody like(Object object, PactDslJsonBody body) {
|
||||
try {
|
||||
return recursiveLike(object, body);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("could not create PactDslJsonBody due to exception!", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static PactDslJsonBody recursiveLike(Object object, PactDslJsonBody body) throws IllegalAccessException {
|
||||
Field[] fields = object.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
|
||||
Object fieldValue = field.get(object);
|
||||
|
||||
if (fieldValue == null) {
|
||||
// fields with null values will not be mapped
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isSimpleType(field.getType())) {
|
||||
mapSimpleFieldWithName(field.getName(), fieldValue, body);
|
||||
} else if (isCollectionType(field.getType())) {
|
||||
mapCollectionField(field.getName(), (Collection) fieldValue, body);
|
||||
} else {
|
||||
mapComplexField(field.getName(), fieldValue, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
private static void mapSimpleFieldWithName(String fieldName, Object fieldValue, PactDslJsonBody body) throws IllegalAccessException {
|
||||
Class<?> type = fieldValue.getClass();
|
||||
if (String.class == type) {
|
||||
body.stringType(fieldName, (String) fieldValue);
|
||||
} else if (Boolean.class == type || boolean.class == type) {
|
||||
body.booleanType(fieldName, (Boolean) fieldValue);
|
||||
} else if (Integer.class == type || int.class == type || Long.class == type || long.class == type) {
|
||||
body.integerType(fieldName, (Integer) fieldValue);
|
||||
} else if (Double.class == type || double.class == type) {
|
||||
body.decimalType(fieldName, (Double) fieldValue);
|
||||
} else if (Float.class == type || float.class == type) {
|
||||
body.decimalType(fieldName, ((Float) fieldValue).doubleValue());
|
||||
} else if (BigDecimal.class == type) {
|
||||
body.decimalType(fieldName, (BigDecimal) fieldValue);
|
||||
} else if (Number.class.isAssignableFrom(type)) {
|
||||
body.numberType(fieldName, (Number) fieldValue);
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("field '%s' of type '%s' is not a simple field", fieldName, type));
|
||||
}
|
||||
}
|
||||
|
||||
private static PactDslJsonRootValue getRootValueForType(Class<?> type) {
|
||||
if (String.class == type) {
|
||||
return PactDslJsonRootValue.stringType();
|
||||
} else if (Boolean.class == type || boolean.class == type) {
|
||||
return PactDslJsonRootValue.booleanType();
|
||||
} else if (Integer.class == type || int.class == type || Long.class == type || long.class == type) {
|
||||
return PactDslJsonRootValue.integerType();
|
||||
} else if (Double.class == type || double.class == type) {
|
||||
return PactDslJsonRootValue.decimalType();
|
||||
} else if (Float.class == type || float.class == type) {
|
||||
return PactDslJsonRootValue.decimalType();
|
||||
} else if (BigDecimal.class == type) {
|
||||
return PactDslJsonRootValue.decimalType();
|
||||
} else if (Number.class.isAssignableFrom(type)) {
|
||||
return PactDslJsonRootValue.numberType();
|
||||
} else {
|
||||
throw new IllegalStateException(String.format("unsupported type '%s'", type));
|
||||
}
|
||||
}
|
||||
|
||||
private static void mapCollectionField(String fieldName, Collection<?> collection, PactDslJsonBody body) throws IllegalAccessException {
|
||||
if (collection.isEmpty()) {
|
||||
throw new IllegalArgumentException("matching empty lists is not supported!");
|
||||
}
|
||||
|
||||
Class<?> listType = collection.iterator().next().getClass();
|
||||
|
||||
if (isSimpleType(listType)) {
|
||||
PactDslJsonRootValue rootValue = getRootValueForType(listType);
|
||||
body.eachLike(fieldName, rootValue);
|
||||
} else if (isCollectionType(listType)) {
|
||||
throw new IllegalArgumentException("collections of collections are not supported");
|
||||
} else {
|
||||
PactDslJsonBody nestedBody = body.eachLike(fieldName);
|
||||
for (Object complexObject : collection) {
|
||||
mapComplexFieldWithoutOpeningObject(complexObject, nestedBody);
|
||||
}
|
||||
nestedBody.closeObject().closeArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void mapComplexField(String fieldName, Object fieldValue, PactDslJsonBody body) throws IllegalAccessException {
|
||||
PactDslJsonBody nestedBody = body.object(fieldName);
|
||||
mapComplexFieldWithoutOpeningObject(fieldValue, nestedBody);
|
||||
}
|
||||
|
||||
private static void mapComplexFieldWithoutOpeningObject(Object fieldValue, PactDslJsonBody nestedBody) throws IllegalAccessException {
|
||||
recursiveLike(fieldValue, nestedBody);
|
||||
nestedBody.closeObject();
|
||||
}
|
||||
|
||||
private static boolean isSimpleType(Class<?> type) {
|
||||
return SIMPLE_TYPES.contains(type);
|
||||
}
|
||||
|
||||
private static boolean isCollectionType(Class<?> type) {
|
||||
return Collection.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.reflectoring.dsl;
|
||||
|
||||
public class Nested {
|
||||
|
||||
private String stringField = "nested string";
|
||||
private Integer integerField = 42;
|
||||
private String nullField = null;
|
||||
|
||||
public String getStringField() {
|
||||
return stringField;
|
||||
}
|
||||
|
||||
public void setStringField(String stringField) {
|
||||
this.stringField = stringField;
|
||||
}
|
||||
|
||||
public Integer getIntegerField() {
|
||||
return integerField;
|
||||
}
|
||||
|
||||
public void setIntegerField(Integer integerField) {
|
||||
this.integerField = integerField;
|
||||
}
|
||||
|
||||
public String getNullField() {
|
||||
return nullField;
|
||||
}
|
||||
|
||||
public void setNullField(String nullField) {
|
||||
this.nullField = nullField;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package io.reflectoring.dsl;
|
||||
|
||||
import au.com.dius.pact.consumer.Pact;
|
||||
import au.com.dius.pact.consumer.PactProviderRuleMk2;
|
||||
import au.com.dius.pact.consumer.PactVerification;
|
||||
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
|
||||
import au.com.dius.pact.consumer.dsl.PactDslJsonRootValue;
|
||||
import au.com.dius.pact.consumer.dsl.PactDslWithProvider;
|
||||
import au.com.dius.pact.model.RequestResponsePact;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties = {
|
||||
// overriding provider address
|
||||
"rootservice.ribbon.listOfServers: localhost:8888"
|
||||
})
|
||||
public class PactDslJsonBodyLikeMapperConsumerTest {
|
||||
|
||||
@Rule
|
||||
public PactProviderRuleMk2 stubProvider = new PactProviderRuleMk2("testprovider", "localhost", 8888, this);
|
||||
|
||||
@Autowired
|
||||
private RootClient rootClient;
|
||||
|
||||
@Pact(state = "teststate", provider = "testprovider", consumer = "testclient")
|
||||
public RequestResponsePact createPact(PactDslWithProvider builder) {
|
||||
return builder
|
||||
.given("teststate")
|
||||
.uponReceiving("a POST request with a Root object")
|
||||
.path("/root")
|
||||
.method("POST")
|
||||
// .body(PactDslJsonBodyLikeMapper.like(new PactDslJsonBodyLikeMapperTest.Root()))
|
||||
.willRespondWith()
|
||||
.status(201)
|
||||
.matchHeader("Content-Type", "application/json")
|
||||
.body(PactDslJsonBodyLikeMapper.like(new Root()))
|
||||
.toPact();
|
||||
}
|
||||
|
||||
@Pact(state = "teststate2", provider = "testprovider", consumer = "testclient")
|
||||
public RequestResponsePact createPact2(PactDslWithProvider builder) {
|
||||
return builder
|
||||
.given("teststate2")
|
||||
.uponReceiving("a POST request with a Root object")
|
||||
.path("/root")
|
||||
.method("POST")
|
||||
.willRespondWith()
|
||||
.status(201)
|
||||
.matchHeader("Content-Type", "application/json")
|
||||
.body(new PactDslJsonBody()
|
||||
.eachLike("arrayField", PactDslJsonRootValue.numberType()))
|
||||
.toPact();
|
||||
}
|
||||
|
||||
@Test
|
||||
@PactVerification(fragment = "createPact")
|
||||
public void verifyPact() {
|
||||
rootClient.createRoot(new Root());
|
||||
}
|
||||
|
||||
@Test
|
||||
@PactVerification(fragment = "createPact2")
|
||||
public void verifyPact2() {
|
||||
rootClient.createRoot(new Root());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package io.reflectoring.dsl;
|
||||
|
||||
|
||||
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class PactDslJsonBodyLikeMapperTest {
|
||||
|
||||
@Test
|
||||
public void createsMatchersForAllFields() {
|
||||
Root object = new Root();
|
||||
PactDslJsonBody jsonBody = PactDslJsonBodyLikeMapper.like(object);
|
||||
assertNoMatcher(jsonBody, ".nullField");
|
||||
assertMatcherType(jsonBody, ".stringField", "type");
|
||||
assertMatcherType(jsonBody, ".booleanField", "type");
|
||||
assertMatcherType(jsonBody, ".primitiveBooleanField", "type");
|
||||
assertMatcherType(jsonBody, ".integerField", "integer");
|
||||
assertMatcherType(jsonBody, ".primitiveIntegerField", "integer");
|
||||
assertMatcherType(jsonBody, ".doubleField", "decimal");
|
||||
assertMatcherType(jsonBody, ".primitiveDoubleField", "decimal");
|
||||
assertMatcherType(jsonBody, ".floatField", "decimal");
|
||||
assertMatcherType(jsonBody, ".primitiveFloatField", "decimal");
|
||||
assertMatcherType(jsonBody, ".bigDecimalField", "decimal");
|
||||
assertMatcherType(jsonBody, ".numberField", "number");
|
||||
assertMatcherType(jsonBody, ".nested.stringField", "type");
|
||||
assertMatcherType(jsonBody, ".nested.integerField", "integer");
|
||||
assertNoMatcher(jsonBody, ".nested.nullField");
|
||||
assertMatcherType(jsonBody, ".complexListField[*].stringField", "type");
|
||||
assertMatcherType(jsonBody, ".complexListField[*].integerField", "integer");
|
||||
assertMatcherType(jsonBody, ".simpleListField[*]", "integer");
|
||||
}
|
||||
|
||||
private void assertMatcherType(PactDslJsonBody jsonBody, String fieldName, String expectedMatcher) {
|
||||
assertMatcher(jsonBody, fieldName);
|
||||
assertEquals(String.format("expected matcher for field '%s' to be of type '%s'", fieldName, expectedMatcher),
|
||||
ImmutableMap.of("match", expectedMatcher),
|
||||
jsonBody.getMatchers().getMatchingRules().get(fieldName).getRules().get(0).toMap());
|
||||
}
|
||||
|
||||
private void assertMatcher(PactDslJsonBody jsonBody, String fieldName) {
|
||||
assertNotNull(String.format("expected a matcher for field '%s'", fieldName),
|
||||
jsonBody.getMatchers().getMatchingRules().get(fieldName));
|
||||
}
|
||||
|
||||
private void assertNoMatcher(PactDslJsonBody jsonBody, String fieldName) {
|
||||
assertNull(jsonBody.getMatchers().getMatchingRules().get(fieldName));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package io.reflectoring.dsl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Root {
|
||||
|
||||
private String nullField = null;
|
||||
private String stringField = "string";
|
||||
private Boolean booleanField = Boolean.TRUE;
|
||||
private Integer integerField = 1;
|
||||
private Double doubleField = 1d;
|
||||
private Float floatField = 1f;
|
||||
private BigDecimal bigDecimalField = BigDecimal.ONE;
|
||||
private boolean primitiveBooleanField = true;
|
||||
private int primitiveIntegerField = 1;
|
||||
private double primitiveDoubleField = 1d;
|
||||
private float primitiveFloatField = 1f;
|
||||
private Number numberField = BigInteger.valueOf(1L);
|
||||
private Nested nested = new Nested();
|
||||
private List<Nested> complexListField = Arrays.asList(new Nested(), new Nested());
|
||||
private List<Integer> simpleListField = Arrays.asList(1,2);
|
||||
|
||||
public String getNullField() {
|
||||
return nullField;
|
||||
}
|
||||
|
||||
public void setNullField(String nullField) {
|
||||
this.nullField = nullField;
|
||||
}
|
||||
|
||||
public String getStringField() {
|
||||
return stringField;
|
||||
}
|
||||
|
||||
public void setStringField(String stringField) {
|
||||
this.stringField = stringField;
|
||||
}
|
||||
|
||||
public Boolean getBooleanField() {
|
||||
return booleanField;
|
||||
}
|
||||
|
||||
public void setBooleanField(Boolean booleanField) {
|
||||
this.booleanField = booleanField;
|
||||
}
|
||||
|
||||
public Integer getIntegerField() {
|
||||
return integerField;
|
||||
}
|
||||
|
||||
public void setIntegerField(Integer integerField) {
|
||||
this.integerField = integerField;
|
||||
}
|
||||
|
||||
public Double getDoubleField() {
|
||||
return doubleField;
|
||||
}
|
||||
|
||||
public void setDoubleField(Double doubleField) {
|
||||
this.doubleField = doubleField;
|
||||
}
|
||||
|
||||
public Float getFloatField() {
|
||||
return floatField;
|
||||
}
|
||||
|
||||
public void setFloatField(Float floatField) {
|
||||
this.floatField = floatField;
|
||||
}
|
||||
|
||||
public BigDecimal getBigDecimalField() {
|
||||
return bigDecimalField;
|
||||
}
|
||||
|
||||
public void setBigDecimalField(BigDecimal bigDecimalField) {
|
||||
this.bigDecimalField = bigDecimalField;
|
||||
}
|
||||
|
||||
public boolean isPrimitiveBooleanField() {
|
||||
return primitiveBooleanField;
|
||||
}
|
||||
|
||||
public void setPrimitiveBooleanField(boolean primitiveBooleanField) {
|
||||
this.primitiveBooleanField = primitiveBooleanField;
|
||||
}
|
||||
|
||||
public int getPrimitiveIntegerField() {
|
||||
return primitiveIntegerField;
|
||||
}
|
||||
|
||||
public void setPrimitiveIntegerField(int primitiveIntegerField) {
|
||||
this.primitiveIntegerField = primitiveIntegerField;
|
||||
}
|
||||
|
||||
public double getPrimitiveDoubleField() {
|
||||
return primitiveDoubleField;
|
||||
}
|
||||
|
||||
public void setPrimitiveDoubleField(double primitiveDoubleField) {
|
||||
this.primitiveDoubleField = primitiveDoubleField;
|
||||
}
|
||||
|
||||
public float getPrimitiveFloatField() {
|
||||
return primitiveFloatField;
|
||||
}
|
||||
|
||||
public void setPrimitiveFloatField(float primitiveFloatField) {
|
||||
this.primitiveFloatField = primitiveFloatField;
|
||||
}
|
||||
|
||||
public Number getNumberField() {
|
||||
return numberField;
|
||||
}
|
||||
|
||||
public void setNumberField(Number numberField) {
|
||||
this.numberField = numberField;
|
||||
}
|
||||
|
||||
public Nested getNested() {
|
||||
return nested;
|
||||
}
|
||||
|
||||
public void setNested(Nested nested) {
|
||||
this.nested = nested;
|
||||
}
|
||||
|
||||
public List<Nested> getComplexListField() {
|
||||
return complexListField;
|
||||
}
|
||||
|
||||
public void setComplexListField(List<Nested> complexListField) {
|
||||
this.complexListField = complexListField;
|
||||
}
|
||||
|
||||
public List<Integer> getSimpleListField() {
|
||||
return simpleListField;
|
||||
}
|
||||
|
||||
public void setSimpleListField(List<Integer> simpleListField) {
|
||||
this.simpleListField = simpleListField;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.reflectoring.dsl;
|
||||
|
||||
import org.springframework.cloud.netflix.feign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@FeignClient(name = "rootservice")
|
||||
public interface RootClient {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, path = "/root")
|
||||
Root createRoot(@RequestBody Root root);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user