Spring Cloud Contract does not work with Surefire 2.20 - spring-cloud

I am trying Spring Cloud Contact: I have an endpoint "/greeting" in my spring-boot application, and it returns "Hello World!".
The contract is like below:
request {
method 'GET'
url '/greeting'
headers {
contentType('application/json')
}
}
response {
status 200
body([
"content": "Hello, World!"
])
}
My test class:
public class ExampleJavaConsumerPactTestIT {
#Before
public void setup() {
RestAssuredMockMvc.standaloneSetup(new GreetingController());
}
#Test
public void aQuickTest(){
}
}
Everything works fine: if I change the above contract to "content": "Hello!", then the test fails.
However, when I add in my dependency to user Surefire plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
</plugin>
Then I run the test again with the wrong contract(content": "Hello!"), the test should fail but it does not.
Is there anything wrong?

Your setup is wrong. The generated test is called ContractVerifierTest so it's not picked by either of your profiles. Just add the <include>**/*ContractVerifierTest.java</include> line to your surefire configuration.

Related

Can I suppress the default Optional<NativeWebRequest> getRequest() that OpenAPI generates into interfaces?

I have an OpenAPI 3.0 file that specifies two REST resources with operations, let's say:
openapi: 3.0.0
[...]
paths:
/a:
post:
[...]
/b
post:
[...]
Then I use the openapi-generator-maven-plugin like:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>4.1.2</version>
<configuration>
[...]
<configOptions>
<interfaceOnly>true</interfaceOnly>
[...]
</configOptions>
</configuration>
</plugin>
To generate Java interfaces, giving me:
public interface AApi {
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
default ResponseEntity<String> postA([...]) { [...] }
}
public interface BApi {
default Optional<NativeWebRequest> getRequest() {
return Optional.empty();
}
default ResponseEntity<String> postB([...]) { [...] }
}
In the end, I would like to write a single class that implements both interfaces:
class TheController implements AApi, BApi { [...] }
However, the getRequest() method gets in the way, because Java is unable to inherit two default implementations with identical names.
Is there a way to suppress generating this method? (Or some other means to enable implementing both interfaces, that I haven't thought of?)
I know this question is already answered, but I also had this issue and found a different solution. You can also add this in the configOptions section:
<configOptions>
<skipDefaultInterface>true</skipDefaultInterface>
</configOptions>
It does have the 'side effect' that you no longer have default implementations.
See also documentation
You can override the getRequest() method in your implementing controller class.
For further reading, refer to https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.8.4

How I should configure a POJO class to enable it to be used as a resource in JAX-RS rest service? (Liferay 7.1)

I can use String object in JAX-RS rest service but not able to use POJO object. How I should configure a POJO class to enable it to be used as a resource in JAX-RS rest service?
DTO class
public class RestServiceDTO {
private String groupId;
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId)
this.groupId = groupId;
}
#Override
public String toString() {
return "RestServiceDTO [groupId=" + groupId + "]";
}
}
Rest service:
#Component(
immediate = true,
property = {
JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
},
service = Application.class
)
public class RestServiceApplication extends Application {
public Set<Object> getSingletons() {
return Collections.<Object>singleton(this);
}
#POST
#Path("/post")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String test(RestServiceDTO dto) {
String groupid = dto.getGroupId();
return "{'groupid':'" + groupid + "'}";
}
}
Error:
2019-02-12 13:33:58.021 ERROR [http-nio-8080-exec-1][JAXRSUtils:83] No
message body reader has been found for class com.dto.RestServiceDTO,
ContentType: application/json
Since version 7.1 Liferay supports the OSGi JAX-RS Whiteboard specification, which means support for JAX-RS 2.1 using CXF, which also mean that there is support for JAXB annotated POJOs.
If you need to return a simple POJO you would normally be OK just by annotating your POJO class with #XmlRootElement.
Make sure you get JAXB runtime support attached to your application by requiring it on your application component configuration putting the property osgi.jaxrs.extension.select=(osgi.jaxrs.name=jaxb-json) on your application component.
This property will instruct the JAX-RS whiteboard to not start your application until the extension is present and ready for your application.
Since Liferay 7.2 the JAXB default implementation has been changed to Jackson. There is no configuration change needed, but now every POJO can be serialized to JSON even if the POJO is not annotated. Just make sure the jaxb runtime support is attached to your application the same as above.
In both 7.1 and 7.2 you can check the status of your JAX-RS applications, and attached extensions, using the gogo shell command jaxrs:check
Liferay uses the Apache CXF implementation of JAX-RS. As #dkb mentioned in the comments you need to provide the annotation that you have in the sample code.
You need to add the dependencies. See the list below and note that some are provided by the platform but some needs to be included in your jar and don't forget the transitive dependencies.
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.7.9</version>
</dependency>
The last thing is. You need to register your Jackson provider within the JAX-RS app. It is done in teh applicaiton class for example like this (there are more ways how to do it).
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(getJacksonProvider());
return Collections.unmodifiableSet(singletons);
}
Add dependency
for MAVEN:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.10</version>
</dependency>
for GRADLE:
compileOnly group: 'com.fasterxml.jackson.jaxrs', name: 'jackson-jaxrs-json-provider', version: '2.9.10'
now add this method in your Apllication class
private JacksonJsonProvider getJacksonJsonProvider() {
JacksonJsonProvider jacksonJsonProvider = new JacksonJsonProvider();
ObjectMapper objectMapper = new ObjectMapper();
// Prevent serialization of null and empty string values
objectMapper.setSerializationInclusion(Include.NON_EMPTY);
jacksonJsonProvider.setMapper(objectMapper);
jacksonJsonProvider.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return jacksonJsonProvider;
}
now change the code of getSingletons() method of your Application class to
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(this);
singletons.add(getJacksonJsonProvider());
return Collections.unmodifiableSet(singletons);
}
now I think you have to change your return statement to
return Response.ok(JSONFactoryUtil.looseSerializeDeep("{'groupid':'" + groupid + "'}"), MediaType.APPLICATION_JSON).build();
but I am not sure that you have to change your return statement or yours one will run ok

spring mongo query testing

I would like to set up a test (unit or integration test) for a mongo query.
I would like to test the following function:
public ArrayList<Document> search(){
Document textSearch = new Document("$text",new
Document("$search",text));
return randomCollection.find(textSearch).into(new ArrayList<Document>());
}
Im using MongoTemplate to get the mongo collection randomCollection
#SpringBootTest can be used to bootstrap all your Spring configurations. If you will write a test (which you should always do, your test will look something like this):
#RunWith(SpringRunner.class)
#SpringBootTest
public class SomeArbitraryTests {
#Autowired
private ArbitraryResource someResource;
#Test
public void someTest() {
someResource.search(...);
// assertions
}
}
If you would want to add an Embedded Mongodb for your testing purposes, then you might want to add some additional dependencies to your project:
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
Hope this helps!

Aspectj: intercept method from external jar

I am using a X.jar and adding to my AspectJ project(in eclipse). I have written pointcut and advice for a method myMethod() inside X.jar.
But aspectj is not intercepting this method call.
How can I tell aspectj to intercept method calls on external jars.Or is it not possible?
Thanks
There are two options:
a) compile the aspects into the JAR
b) use load time weaving (I'd go with that one)
Both of these are advanced topics, I'd suggest you read AspectJ in Action (2nd Ed) by Ramnivas Laddad to learn more.
To clarify: there are different types of pointcuts. If your code calls the library's methods, you can of course intercept these calls, as they happen in your code. So call() pointcuts will work, but execute() (and many other) pointcuts won't because they change the executing method, which is not in your code base. So you have to either change the byte code of the library (option a) or change how it is loaded into your application (option b).
Here is a simple example with AspectJ Load-Time Weaving on GitHub https://github.com/medvedev1088/aspectj-ltw-example
It uses Joda Time library to demonstrate how to intercept the DateTime#toString() method invocations.
The aspect:
#Aspect
public class DateTimeToStringAspect {
public static final String TO_STRING_RESULT = "test";
#Pointcut("execution(* org.joda.time.base.AbstractDateTime.toString())")
public void dateTimeToString() {
}
#Around("dateTimeToString()")
public Object toLowerCase(ProceedingJoinPoint joinPoint) throws Throwable {
Object ignoredToStringResult = joinPoint.proceed();
System.out.println("DateTime#toString() has been invoked: " + ignoredToStringResult);
return TO_STRING_RESULT;
}
}
aop.xml
<aspectj>
<aspects>
<!-- Aspects -->
<aspect name="com.example.aspectj.DateTimeToStringAspect"/>
</aspects>
<weaver options="-verbose -showWeaveInfo">
<include within="org.joda.time.base.AbstractDateTime"/>
</weaver>
</aspectj>
test:
public class DateTimeToStringAspectTest {
#Test
public void testDateTimeToString() throws Exception {
assertThat(new DateTime().toString(), is(DateTimeToStringAspect.TO_STRING_RESULT));
}
}
Surefire plugin configuration from pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<argLine>-XX:-UseSplitVerifier</argLine>
<argLine>-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/${aspectjweaver.version}/aspectjweaver-${aspectjweaver.version}.jar</argLine>
</configuration>
</plugin>

How can I use a JUnit RunListener in Eclipse?

I wrote a simple RunListener for JUnit which works quite well with Maven. I could register it for the maven-failsafe-plugin via
<properties>
<property>
<name>listener</name>
<value>com.asml.lcp.middleware.common.jboss.test.tps.TestDocumentationListener</value>
</property>
</properties>
and see the correct output from the listener.
Now I want to register the same RunListener in Eclipse to see the same output there, when I run the tests.
Is this possible? For testing purposes and to be consistent it would be nice to have the same output.
I have a set of tests that need a database to be executed. I want to create the database at the beginning of their execution and remove it at the end.
From maven I've also added a RunListener to the maven-surefire-plugin and it works fine. And I've also added a system property variable named ismaven. When I execute the test from maven this variable is initialized but when I execute the tests from the Eclipse, this variable is null (I access to the variable with System.getProperty).
<configuration>
<properties>
<property>
<name>listener</name>
<value>com.mycompany.MyRunListener</value>
</property>
</properties>
<systemPropertyVariables>
<ismaven>true</ismaven>
</systemPropertyVariables>
</configuration>
All my database tests inherit from a class that has a #BeforeClass and an #AfterClass methods. These methods check if the test is being executed by Maven or by the Eclipse checking the value of the ismaven property. If the test is being executed by maven, the ismaven property has a value and they do anything. But is the test is being executed by the Eclipse, the ismaven variable is null and they starts (#BeforeClass) or stops (#AfterClass) the database:
#BeforeClass
public static void checkIfStartDatabase() {
String ismaven = System.getProperty("ismaven");
// If it is not maven, start the database
if (ismaven == null) {
startDatabase();
}
}
#AfterClass
public static void checkIfStopDatabase() {
String ismaven = System.getProperty("ismaven");
// If it is not maven, stop the database
if (ismaven == null) {
stopDatabase();
}
}
This solution doesn't solve 100% your problem but if you implement it you can execute (and debug) all the tests of one JUnit class using the Eclipse and you can also execute all the tests of your project using Maven with the guarantee that you will execute once a piece of code before or after the execution of all your tests.
Yes, it is possible. Basically you have to implement your own Runner and inside the run method, you can add a custom run listener. I figured this out based on this post, point 2.
Here is my listener
public class TestLogger extends RunListener
{
public void testFinished(Description description)
{
System.out.println("Successful " + description.getMethodName());
}
}
and here is my Runner
public class TestRunner extends BlockJUnit4ClassRunner
{
public TestRunner(Class<?> klass) throws InitializationError
{
super(klass);
}
#Override
public void run(RunNotifier notifier)
{
notifier.addListener(new TestLogger()); // THIS IS THE IMPORTANT LINE
super.run(notifier);
}
}
and here is my actual junit test
#RunWith(TestRunner.class) // THIS LINE IS ALSO IMPORTANT
public class MyTest1
{
#Test
public void Test1() throws Exception
{
if (Math.random() < .5) throw new Exception("ouch");
assertFalse(Math.random() < .5);
}
}
You can run MyTest1 or the Test1 method using the context menu in Eclipse and it will invoke the testLogger as you would expect.
I did some more reseatrch on this. As far as I can see now, there is no way to add a run listener too the JUnit runs in Eclipse.