4 Replies Latest reply on Apr 11, 2013 9:52 AM by bmajsak

    Testing method validation on RestEasy endpoints using Arquillian

    tdziurko

      In our project we have Restful services deployed on JBoss 7. To get rid of some boilerplate code we've decided to add some method validations using JSR-303 annotations. Basic setup is working, standard validations are testable with some work, but at least they are working. Problem is with some more sophisticated custom made validators that needs something to be injected. For example: let's say I have annotation and its validator like below. On real server it works like a breeze, but I have problem with preparing setup using Arquillian to test it properly.

       

      I started adding more and more dependencies to @Deployment and so far I can not find the end of this Last two steps were to add in arquillian.xml:

       

      <property name="javaVmArguments">-Djava.util.logging.manager=org.jboss.logmanager.LogManager</property>

       

      as I was getting error on missing java.util.logging.manager propery and then UriBuilder.clas to @Depoyment. But after adding it thing went completely insane and my last stacktrace looks like follows:

       

      15:34:43,047 WARN  [org.jboss.modules] (http--127.0.0.1-8080-1) Failed to define class org.jboss.security.SecurityRolesAssociation in Module "org.picketbox:main"

      from local module loader @c9be79a (roots: /Users/tomek/work/softwaremill/jboss-as-7.1.1.Final/modules): java.lang.OutOfMemoryError: PermGen space

       

      Question is: Am i doing everything correctly? I ended with adding more and more strange classes to the test dependency and still wasn't able to have this setup working

       

       

       

      Source code I am using:

       

      validation annotation:

      @Target( { PARAMETER, FIELD })

      @Retention(RUNTIME)

      @Constraint(validatedBy = CustomerNotExistsConstraintValidator.class)

      @Documented

      public @interface CustomerNotExistsConstraint {

       

          String message() default "Customer with given name exists";

       

          Class<?>[] groups() default {};

       

          Class<? extends Payload>[] payload() default {};

      }

       

      and its validating class which needs CustomerService to be injected:

       

       

      public class CustomerNotExistsConstraintValidator implements ConstraintValidator<CustomerNotExistsConstraint, String> {

       

          @Inject

          private CustomerService customerService;

       

          @Override

          public void initialize(CustomerNotExistsConstraint constraintAnnotation) {

          }

       

          @Override

          public boolean isValid(String customerName, ConstraintValidatorContext context) {

              boolean customerExists = customerService.customerExists(customerName);

              return !customerExists;

          }

      }

       

       

       

      My files:

      arquillian.xml content:

       

      <defaultProtocol type="Servlet 3.0" />

      <container qualifier="jboss" default="true">

            <configuration>

               <property name="jbossHome">/Users/tomek/work/jboss-as-7.1.1.Final/</property>

                <property name="javaVmArguments">-Djava.util.logging.manager=org.jboss.logmanager.LogManager</property>

            </configuration>

      </container>

       

       

      test-validation.xml content:

       

      <constraint-validator-factory>

              org.jboss.seam.validation.InjectingConstraintValidatorFactory

          </constraint-validator-factory>

       

       

       

      and test class itself:

       

       

      package com.softwaremill.test;

       

       

       

       

      import com.google.common.base.CharMatcher;

      import com.softwaremill.beans.CustomerService;

      import com.softwaremill.constraints.CustomerNotExistsConstraint;

      import com.softwaremill.constraints.CustomerNotExistsConstraintValidator;

      import com.softwaremill.constraints.PhoneNumberConstraint;

      import com.softwaremill.constraints.PhoneNumberConstraintValidator;

      import com.softwaremill.model.Member;

      import com.softwaremill.rest.JaxRsActivator;

      import com.softwaremill.rest.MemberResource;

      import com.softwaremill.rest.MemberResourceRESTService;

      import com.softwaremill.rest.RestRequestStatus;

      import com.softwaremill.rest.RestResponse;

      import com.softwaremill.rest.ValidationExceptionMapper;

      import junit.framework.Assert;

      import org.apache.commons.lang3.StringUtils;

      import org.jboss.arquillian.container.test.api.Deployment;

      import org.jboss.arquillian.container.test.api.RunAsClient;

      import org.jboss.arquillian.junit.Arquillian;

      import org.jboss.arquillian.test.api.ArquillianResource;

      import org.jboss.logmanager.ExtHandler;

      import org.jboss.logmanager.Level;

      import org.jboss.logmanager.LogManager;

      import org.jboss.logmanager.log4j.handlers.Log4jAppenderHandler;

      import org.jboss.resteasy.client.ClientRequest;

      import org.jboss.resteasy.client.ClientResponse;

      import org.jboss.resteasy.client.ProxyFactory;

      import org.jboss.resteasy.plugins.providers.RegisterBuiltin;

      import org.jboss.resteasy.spi.ResteasyProviderFactory;

      import org.jboss.resteasy.spi.validation.ValidateRequest;

      import org.jboss.seam.validation.InjectingConstraintValidatorFactory;

      import org.jboss.shrinkwrap.api.ShrinkWrap;

      import org.jboss.shrinkwrap.api.asset.EmptyAsset;

      import org.jboss.shrinkwrap.api.spec.WebArchive;

      import org.jboss.solder.beanManager.BeanManagerAware;

      import org.jboss.solder.beanManager.BeanManagerLocator;

      import org.jboss.solder.beanManager.BeanManagerProvider;

      import org.jboss.solder.beanManager.BeanManagerUnavailableException;

      import org.jboss.solder.logging.Logger;

      import org.jboss.solder.logging.internal.BasicLogger;

      import org.jboss.solder.servlet.beanManager.ServletContextAttributeProvider;

      import org.jboss.solder.util.Sortable;

      import org.junit.BeforeClass;

      import org.junit.Ignore;

      import org.junit.Test;

      import org.junit.runner.RunWith;

      import org.jboss.resteasy.plugins.validation.hibernate.HibernateValidatorContextResolver;

       

       

      import javax.inject.Inject;

      import javax.validation.Validator;

      import javax.ws.rs.ApplicationPath;

      import javax.ws.rs.core.MediaType;

       

       

      import java.net.URL;

       

       

      import static org.junit.Assert.assertEquals;

      import static org.junit.Assert.assertNotNull;

       

       

      @RunWith(Arquillian.class)

      @RunAsClient

      public class MemberResourceRestTest {

       

          private static final String RESOURCE_PREFIX = JaxRsActivator.class.getAnnotation(ApplicationPath.class).value().substring(1);

       

          @Deployment

          public static WebArchive createDeployment() {

              return ShrinkWrap.create(WebArchive.class, "test.war")

                      .addClass(Member.class)

                      .addClass(MemberResourceRESTService.class)

                      .addClass(MemberResource.class)

                      .addClass(RestResponse.class)

                      .addClass(RestRequestStatus.class)

                      .addClass(CustomerService.class)

                      .addClass(JaxRsActivator.class)

                      .addClass(ValidateRequest.class)

                      .addClass(CustomerNotExistsConstraint.class)

                      .addClass(CustomerNotExistsConstraintValidator.class)

                      .addClass(PhoneNumberConstraint.class)

                      .addClass(PhoneNumberConstraintValidator.class)

                      .addPackage(HibernateValidatorContextResolver.class.getPackage())

                      .addClass(ValidationExceptionMapper.class)

                      .addPackage(CharMatcher.class.getPackage())

                      .addClass(StringUtils.class)

                      

                       // here I started adding stuff needed to use my custom made constraint validator but required stuff is getting stranger and stranger

                      .addClass(InjectingConstraintValidatorFactory.class)

                      .addClass(BeanManagerAware.class)

                      .addClass(BeanManagerLocator.class)

                      .addClass(BeanManagerUnavailableException.class)

                      .addClass(BeanManagerProvider.class)

                      .addClass(Sortable.class)

                      .addClass(org.jboss.solder.util.service.ServiceLoader.class)

                      .addClass(Logger.class)

                      .addPackage(org.jboss.solder.logging.internal.Logger.class.getPackage())

                      .addClass(LogManager.class)

                      .addPackage(Level.class.getPackage())

                      .addClass(ExtHandler.class)

                      .addClass(org.jboss.logmanager.handlers.FlushableCloseable.class)

                       .addClass(UriBuilder.class)

       

                       // standard stuff here

                      .addAsResource("META-INF/test-persistence.xml", "META-INF/persistence.xml")

                      .addAsResource("META-INF/test-validation.xml", "META-INF/validation.xml")

                      .addAsResource("import.sql")

                      .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")

                      .addAsWebInfResource("test-ds.xml", "test-ds.xml");

          }

       

       

          @ArquillianResource

          URL deploymentUrl;

       

       

          @BeforeClass

          public static void initResteasyClient() {

              RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

          }

       

       

          @Test

          public void should() {

              MemberResource client = ProxyFactory.create(MemberResource.class, deploymentUrl.toString() + RESOURCE_PREFIX);

              RestResponse response = client.createCustomerWithUser("contactName", "valid@email.com",

                      "user", "password", "customer", "reseller", "489999", "true");

       

              assertNotNull(response);

       

              // Then

              assertEquals(RestRequestStatus.OK.getStatusCode(), response.getStatus().intValue());

          }

         

      }

        • 1. Re: Testing method validation on RestEasy endpoints using Arquillian
          mmatloka

          Hello Tomasz,

           

          It seems that content of arquillian.xml wasn't included. What arq related dependencies (with versions) do you have in Your POM? Btw have you checked what would happen if you'd increate PermGen?

           

          Your test-validation.xml suggests that you're using seam validation. Included there class InjectingConstraintValidatorFactory is also the first one from Your "strange stuff list". You can use ShrinkWrap Resolvers to add this whole library to the deployment. I'm quessing that some of this "strange" classes might be its dependencies.

          1 of 1 people found this helpful
          • 2. Re: Testing method validation on RestEasy endpoints using Arquillian
            tdziurko

            Thanks Michał for answer.

             

             

            My arquillian.xml content:

               <defaultProtocol type="Servlet 3.0" />

             

               <container qualifier="jboss" default="true">

                  <configuration>

                     <property name="jbossHome">/Users/tomek/work/softwaremill/jboss-as-7.1.1.Final/</property>

                     <property name="javaVmArguments">-Djava.util.logging.manager=org.jboss.logmanager.LogManager</property>

                  </configuration>

               </container>

             

            I have added jar with seam-validation and indeed some of these classes are no longer needed. I've aldo increaded permgen in MAVEN_OPTS to 4GB, but PermGen still occurs:

             

            r @6b359c1b (roots: /Users/tomek/work/softwaremill/jboss-as-7.1.1.Final/modules): java.lang.OutOfMemoryError: PermGen space

                      at java.lang.ClassLoader.defineClass1(Native Method) [classes.jar:1.6.0_43]

                      at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) [classes.jar:1.6.0_43]

                      at java.lang.ClassLoader.defineClass(ClassLoader.java:615) [classes.jar:1.6.0_43]

                      at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) [classes.jar:1.6.0_43]

                      at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:327)

                      at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:391)

                      at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:243)

                      at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:73)

                      at org.jboss.modules.Module.loadModuleClass(Module.java:517)

                      at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:182)

                      at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468)

                      at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456)

                      at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:423)

                      at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)

                      at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120)

                      at org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:76) [resteasy-jaxrs-2.3.2.Final.jar:]

                      at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.init(ServletContainerDispatcher.java:67) [resteasy-jaxrs-2.3.2.Final.jar:]

                      at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.init(HttpServletDispatcher.java:36) [resteasy-jaxrs-2.3.2.Final.jar:]

                      at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1202) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:952) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:188) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]

                      at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]

                      at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]

                      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]

                      at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]

                      at java.lang.Thread.run(Thread.java:680) [classes.jar:1.6.0_43]

             

             

            11:17:05,819 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/test].[com.softwaremill.rest.JaxRsActivator]] (http--127.0.0.1-8080-1) Allocate exception for servlet com.softwaremill.rest.JaxRsActivator: java.lang.OutOfMemoryError: PermGen space

                      at java.lang.Class.getName0(Native Method) [classes.jar:1.6.0_43]

                      at java.lang.Class.getName(Class.java:554) [classes.jar:1.6.0_43]

                      at java.lang.Throwable.toString(Throwable.java:342) [classes.jar:1.6.0_43]

                      at java.lang.String.valueOf(String.java:2826) [classes.jar:1.6.0_43]

                      at java.lang.StringBuilder.append(StringBuilder.java:115) [classes.jar:1.6.0_43]

                      at org.jboss.logmanager.formatters.Formatters$12.renderCause(Formatters.java:606) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]

                      at org.jboss.logmanager.formatters.Formatters$12.renderRaw(Formatters.java:396) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]

                      at org.jboss.logmanager.formatters.Formatters$JustifyingFormatStep.render(Formatters.java:148) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]

                      at org.jboss.logmanager.formatters.MultistepFormatter.format(MultistepFormatter.java:86) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]

                      at org.jboss.logmanager.ExtFormatter.format(ExtFormatter.java:35) [classes:]

                      at org.jboss.logmanager.handlers.WriterHandler.doPublish(WriterHandler.java:49) [jboss-logmanager-1.2.2.GA.jar:1.2.2.GA]

                      at org.jboss.logmanager.ExtHandler.publish(ExtHandler.java:64) [classes:]

                      at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:283) [classes:]

                      at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [classes:]

                      at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [classes:]

                      at org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:291) [classes:]

             

            I have run out of ideas what might be wrong and currentlu I am willing to test this as an acceptance test on real application delpoyed on JBoss instead of fighting with this setup.

            • 3. Re: Testing method validation on RestEasy endpoints using Arquillian
              mmatloka

              I'm not sure if MAVEN_OPTS is in this case a proper place for perm gen settings or rather it should be jboss as settings in arquillian.xml. However it looks a bit like some type of reasteasy related memory leak.

              • 4. Re: Testing method validation on RestEasy endpoints using Arquillian
                bmajsak

                Hey, any update on this one?

                 

                I think you should increase memory settings in javaVmArguments as Michal mentioned. This will deffer PermGen at least. MVN_OPTS is not the right place, as jboss is run in seperated jvm process anyway, so I'm not really sure if that's propagated in such case.