#AutoConfigureMockMvc fails integration tests with inifnite loop - integration-testing

We had an integration tests such as the one that follows that used to work:
#ActiveProfiles("local")
#WithMockUser("j_unit_user_http_test")
#RunWith(SpringRunner.class)
#SpringBootTest(
classes = { Application.class },
webEnvironment = RANDOM_PORT
)
#Transactional
#Rollback
#AutoConfigureMockMvc()
public abstract class HttpTest {
static {
//reads and sets a dependency related props
PropertiesReader propertiesReader = new PropertiesReader();
propertiesReader.readDependencyProperties().forEach(System::setProperty);
}
#Autowired
private MockMvc mockMvc;
#PersistenceContext
private EntityManager em;
#Test
public void createDashboard() {
// POST is a utility method that wraps "mockMvc.perform(post(url))", I've omitted it here for brevity.
var postResult = POST("/api/dashboards", Map.of("name", "wonderland"));
var newDashboard = extractJson(postResult);
assertTrue(newDashboard.get("id").isInt());
}
}
Among the changes we made the significant ones that seem to be causing the errors are:
Upgrading spring-boot from '2.3.0' to '2.5.6'
Setting the environment properties needed by some of our dependencies in the static void main class of our app:
public class Application {
public static void main(String[] args) {
// reads and sets dependency related props
PropertiesReader propertiesReader = new PropertiesReader();
propertiesReader.readDependencyProperties().forEach(System::setProperty);
}
}
The error we get is:
java.lang.StackOverflowError
at java.base/java.lang.Throwable.getOurStackTrace(Throwable.java:828)
at java.base/java.lang.Throwable.getStackTrace(Throwable.java:820)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:55)
at ch.qos.logback.classic.spi.ThrowableProxy.<init>(ThrowableProxy.java:60) // several frames of this follow
My guess is that the mockMvc is not getting configured correctly, because if I use it without #SpringBootTest and #AutoConfigureMvc, the tests work. Any idea what could be wrong?

The above issue has been fixed.
In the commit when the tests started failing, among other changes, the spring-boot version was changed from 2.3.x to 2.5.x
Turns out in version 2.4 spring-boot removed JUnit 5's vintage engine.
As pointed out in their release notes, ideally, i should migrate the tests to junit 5, but, in the meantime, adding the following in build.gradle helps:
testImplementation("org.junit.vintage:junit-vintage-engine") {
exclude group: "org.hamcrest", module: "hamcrest-core"
}
Equivalent changes in pom.xml would be:
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>

Related

Jackson JsonSerializer

I have simple serializer with Jaskcon
public class NullSerializer extends JsonSerializer<Object> {
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeString("");
}
}
After Compiling this code Java throws Error
Error:java: java.lang.StackOverflowError
I am using this dependency
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.1</version>
</dependency>
Any ideas ?
Works perfectly well for me:
public class Main {
static class NullSerializer extends JsonSerializer<Object> {
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeString("");
}
}
public static void main(String[] args) throws Exception {
ObjectMapper m = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Object.class, new NullSerializer());
m.registerModule(module);
System.out.println(m.writeValueAsString(
Arrays.asList(true, 1, "String", new HashMap())
)); //prints "", while without registerModule - [true,1,"String",{}]
}
}
I would look somewhere else.
For one, check your Xss for Maven. Should be at least -Xss256k, maybe you will need more, or even better, leave it default at 1MB, because compiler uses stack differently than Java and sometimes puts structures on the stack.
I hope you are not using GWT, because if your code got exposed to GWT compiler, it would be a typical response in this situation.
And the least likely event would be that you found a genuine bug in the compiler.
Try using --debug option with Maven, maybe it will show more info.

NullPointerException from LeakCanary when running Robolectric tests

Added LeakCanary (1.3) to my Application:
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
LeakCanary.install(this);
When I run the Robolectric test suite for my application I get a NullPointerException in LeakCanary.
Caused by: java.lang.NullPointerException
at com.squareup.leakcanary.LeakCanary.isInServiceProcess(LeakCanary.java:165)
at com.squareup.leakcanary.LeakCanary.isInAnalyzerProcess(LeakCanary.java:141)
at com.squareup.leakcanary.LeakCanary.install(LeakCanary.java:52)
at com.squareup.leakcanary.LeakCanary.install(LeakCanary.java:43)
at com.package.application.MyApplication.onCreate(MyApplication.java:50)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:131)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:431)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:224)
I added that Im using Crashlytics to point out that it (and other methods as well) receives the same Application but does not throw any Exceptions.
Wasn't sure if this should be here or on GitHub issues for LeakCanary. Anyone else experiencing this issue?
Converting my comment to the answer.
Robolectric provides way to deal with different initialisations and application test lifecycles through test application.
Here is your application class:
public class <YourAppplication> extends Application {
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
LeakCanary.install(this);
}
}
You should put in test sources in the same package as yours application next class:
public class Test<YourAppplication> extends <YourApplication> {
#Override
public void onCreate() {
}
}
Robolectric will load it instead of your application. As you can see I suppress all static initialisations from your application.
You can find more details here
A simple way to avoid the NullPointerException is to disable LeakCanary for unit tests by specifying the release (no-op) version in the testCompile directive in build.gradle. For instance:
dependencies {
...
testCompile (
'junit:junit:4.12',
'org.robolectric:robolectric:3.0',
'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
)
...
}

Jawr Spring Annotations Based Sample Configuration

I wanted to implement Jawr for minification and obfuscation of CSS and JS resources. I am using a Spring MVC project where the configurations are done using Java code using annotations and XML is not used. Now able to find a documentation for the same. Can some one suggest me the configuration or a reference link.
jawr dependencies to your pom:
<dependency>
<groupId>net.jawr</groupId>
<artifactId>jawr-core</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>net.jawr.extensions</groupId>
<artifactId>jawr-spring-extension</artifactId>
<version>3.6</version>
</dependency>
Build a controller like this:
#Controller
public class JsController extends JawrSpringController
{
public JsController ()
{
setType("js");
setConfigLocation("/jawr.properties");
}
#RequestMapping("/js/**")
public void javascript ( HttpServletRequest request, HttpServletResponse response ) throws Exception
{
handleRequest(request, response);
}
}

CDI WELD #ConversationScoped #Stateful EJB conversation.end() & #Remove SFSB

currently i am trying to remove a ConversationScoped Stateful Session Bean (SFSB). The ConversationScope is managed by the CDI Container and the lifecycle of the SFSB is managed by the EJB Container. Is this correct?
In my Controller i'm trying to end the conversation by calling a method of the SFSB and to call the #Remove annotated method to destroy the SFSB.
The conversation can be end without any problems but i am not able to destroy the SFSB.
A Code example from Weld Reference Guide (WELD Conversation Scope):
#ConversationScoped #Stateful
public class OrderBuilder {
private Order order;
private #Inject Conversation conversation;
private #PersistenceContext(type = EXTENDED) EntityManager em;
#Produces public Order getOrder() {
return order;
}
public Order createOrder() {
order = new Order();
conversation.begin();
return order;
}
public void addLineItem(Product product, int quantity) {
order.add(new LineItem(product, quantity));
}
public void saveOrder(Order order) {
em.persist(order);
conversation.end();
}
#Remove
public void destroy() {}
}
The controller:
#Named
#SessionScoped
public class TestController implements Serializable{
#Inject
private OrderBuilder orderBuilder;
...
public String checkout(Order order){
orderBuilder.saveOrder(order);
orderBuilder.destroy();
return "success";
}
}
After i have called testController.checkout(order), i'am getting this exception:
javax.servlet.ServletException:
java.lang.reflect.InvocationTargetException
javax.faces.webapp.FacesServlet.service(FacesServlet.java:321)
org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67)
root cause
javax.faces.el.EvaluationException:
java.lang.reflect.InvocationTargetException
javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:98)
com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:98)
javax.faces.component.UICommand.broadcast(UICommand.java:311)
javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:781)
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1246)
com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:77)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:308)
org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67)
Any ideas?
THX
You should end the CDI conversation and CDI will call the #Remove method.
Have a look in Weld documentation :
"
Stateful session beans may define a remove method, annotated #Remove, that is used by the application to indicate that an instance should be destroyed. However, for a contextual instance of the bean—an instance under the control of CDI—this method may only be called by the application if the bean has scope #Dependent. For beans with other scopes, the application must let the container destroy the bean.
"
JSF 1.2 or 2.0 does not support expression like methods with parameter
obj.method(parameter)
JSF supoorts only method without parameter like
obj.method()
Seam 2,3 build in supports this kind of expreesions but if you are using only weld (CDI support of seam, core of seam) without other seam jars, you can not have this ability.
But it is possible to give this kind of ability to JSF.
Adding this to jar project you can use methods with parameters. If you are using maven u can use code below or. Download jars manually in lib folder.
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>el-impl</artifactId>
<version>2.2</version>
</dependency>
Additionally, I tested it with tomcat worked fine, but in jetty some conflicts happen with the other jars. May be it is about my project.
Add this to web xml
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>

AspectJ AOP not working as expected

I am working on AspectJ AOP implementation on spring MVC application. I have written Aspect java class where I am trying to intercept join points for all the methods of one of the packages say com.xyz.services. But AOP always failed to interecept the methods of that package. Aspect is defined as follows -
#Pointcut("execution(* com.xyz.services..*.*(..))")
public void logBefore() {
}
#Before("logBefore()")
public void logHere(JoinPoint joinPoint) {
System.out.println("In logHere ....");
logger.info("logBefore is running ....");
logger.info("hijacked ::::" + joinPoint.getSignature().getName());
logger.info("joinPoint.getSignature().getDeclaringTypeName() ::::"
+ joinPoint.getSignature().getDeclaringTypeName());
logger.info("joinPoint.getSignature().getModifiers() ::::"
+ joinPoint.getSignature().getModifiers());
logger.info("******************************************************");
}
I have enabled AOP in application-context.xml as follows -
<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name='loggingAspect' />
</aop:aspectj-autoproxy>
When ever I am calling webservice the methods in the com.xyz.services get called but the Aspect method never get called.
I tried with different pointcuts but the aspect code never did not execute.
#Pointcut("execution(public * com.xyz.services.ManagerServiceImpl.*(..))")
public void logBefore() {
System.out.println("In Logbefore");}
#Pointcut("execution(public * com.xyz.services.*.*(..))")
public void logBefore() {
System.out.println("In Logbefore");
}
I have added cglib dependency on pom.xml to enable cglib based proxies.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
Can anyone help me out why this aspects are not working as expected?
have you configured correctly the class with the annotation ?
#EnableAspectJAutoProxy(proxyTargetClass = true)

Resources