1 2 Previous Next 16 Replies Latest reply on Nov 27, 2010 9:01 AM by aslak

    arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails

    jitend

      Hi All,

       

      I have set up Arquillian in my Eclipse. I have all the JARs (ALPHA4) required to run the test. I am using the below code to test Session Bean method.

       

      I am using @Run(RunModeType.IN_CONTAINER) and arquillian.xml file in classpath. Arquillian starts JBoss properly but not sure whether it deploys correctly. The code is something like this:

       

       

      package com.sonymusic;
      import java.util.ArrayList;
      import java.util.Collection;
      import javax.ejb.EJB;
      import org.jboss.arquillian.api.Deployment;
      import org.jboss.arquillian.junit.Arquillian;
      import org.jboss.arquillian.api.Run;
      import org.jboss.arquillian.api.RunModeType;
      import org.jboss.shrinkwrap.api.ShrinkWrap;
      import org.jboss.shrinkwrap.api.spec.JavaArchive;
      import org.junit.Assert;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import com.sonymusic.dx.ejb.interceptors.NullParameterInterceptor;
      import com.sonymusic.dx.ejb.utility.facades.MasterFacadeLocal;
      import com.sonymusic.dx.ejb.utility.facades.impl.MasterFacade;
      import com.sonymusic.dx.jpa.dx.enums.AssetPreviewType;
      @RunWith(Arquillian.class)
      @Run(RunModeType.IN_CONTAINER)
      public class TestMasterFacade {
           @Deployment
           public static JavaArchive createTestArchive() {
              return ShrinkWrap.create(JavaArchive.class, "test.jar")
                 .addClasses(MasterFacade.class, NullParameterInterceptor.class, MasterFacadeLocal.class,
                     AssetPreviewType.class).addManifestResource("persistence.xml");
           }
           @EJB
           private MasterFacadeLocal masterFacade;
           @Test
           public void shouldBeAbleToInjectEJB() throws Exception {
              Collection<String> masterIds = new ArrayList<String>();
              masterIds.add("");
              Assert.assertNotNull(masterFacade.getIconPreviewsForMasterIds(masterIds));
           }
      }

       

           @Deployment

           public static JavaArchive createTestArchive() {

              return ShrinkWrap.create(JavaArchive.class, "test.jar")

                 .addClasses(MasterFacade.class, NullParameterInterceptor.class, MasterFacadeLocal.class,

                     AssetPreviewType.class).addManifestResource("persistence.xml");

           }

       

       

           @EJB

           private MasterFacadeLocal masterFacade;

       

           @Test

           public void shouldBeAbleToInjectEJB() throws Exception {

              Collection<String> masterIds = new ArrayList<String>();

              masterIds.add("");

              Assert.assertNotNull(masterFacade.getIconPreviewsForMasterIds(masterIds));

           }

      }

      I get exception stack trace when running the test:
      org.jboss.arquillian.impl.event.FiredEventException: java.lang.RuntimeException: Could not inject members
      at org.jboss.arquillian.impl.event.MapEventManager.fire(MapEventManager.java:68)
      at org.jboss.arquillian.impl.context.AbstractEventContext.fire(AbstractEventContext.java:115)
      at org.jboss.arquillian.impl.EventTestRunnerAdaptor.before(EventTestRunnerAdaptor.java:127)
      at org.jboss.arquillian.junit.Arquillian$4.evaluate(Arquillian.java:206)
      at org.jboss.arquillian.junit.Arquillian$5$1.evaluate(Arquillian.java:225)
      at org.jboss.arquillian.junit.Arquillian$MultiStatementExecutor.execute(Arquillian.java:297)
      at org.jboss.arquillian.junit.Arquillian$5.evaluate(Arquillian.java:221)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
      at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
      at org.jboss.arquillian.junit.Arquillian$2.evaluate(Arquillian.java:163)
      at org.jboss.arquillian.junit.Arquillian$3$1.evaluate(Arquillian.java:186)
      at org.jboss.arquillian.junit.Arquillian$MultiStatementExecutor.execute(Arquillian.java:297)
      at org.jboss.arquillian.junit.Arquillian$3.evaluate(Arquillian.java:182)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
      at org.jboss.arquillian.junit.Arquillian.run(Arquillian.java:127)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
      at org.jboss.arquillian.junit.JUnitTestRunner.execute(JUnitTestRunner.java:69)
      at org.jboss.arquillian.protocol.servlet_2_5.ServletTestRunner.doGet(ServletTestRunner.java:84)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
      at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
      at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
      at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
      at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
      at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
      at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
      at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
      at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
      at java.lang.Thread.run(Unknown Source)
      Caused by: java.lang.RuntimeException: Could not inject members
      at org.jboss.arquillian.testenricher.ejb.EJBInjectionEnricher.injectClass(EJBInjectionEnricher.java:128)
      at org.jboss.arquillian.testenricher.ejb.EJBInjectionEnricher.enrich(EJBInjectionEnricher.java:50)
      at org.jboss.arquillian.impl.handler.TestCaseEnricher.callback(TestCaseEnricher.java:42)
      at org.jboss.arquillian.impl.handler.TestCaseEnricher.callback(TestCaseEnricher.java:32)
      at org.jboss.arquillian.impl.event.MapEventManager.fire(MapEventManager.java:63)
      ... 45 more
      Caused by: javax.naming.NamingException: No EJB found in JNDI, tried the following names: java:global/test.ear/test/MasterFacadeLocalBean, java:global/test.ear/test/MasterFacadeLocal, java:global/test/MasterFacadeLocal, java:global/test/MasterFacadeLocalBean, java:global/test/MasterFacadeLocal/no-interface, test/MasterFacadeLocalBean/local, test/MasterFacadeLocalBean/remote, test/MasterFacadeLocal/no-interface, MasterFacadeLocalBean/local, MasterFacadeLocalBean/remote, MasterFacadeLocal/no-interface,
      at org.jboss.arquillian.testenricher.ejb.EJBInjectionEnricher.lookupEJB(EJBInjectionEnricher.java:162)
      at org.jboss.arquillian.testenricher.ejb.EJBInjectionEnricher.injectClass(EJBInjectionEnricher.java:102)
      ... 49 more
      In same setting I am able to run Arquillian demo example GreetingManager session bean without any problem. Not sure what is missing in the above scenario where it is unable to do JNDI lookup. My guess is that it is not deploying EJB properly and that is why it is not able to inject. Any help will be appreciated.
      Regards,
      Jitendra

        • 1. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
          aslak

          Your hitting a limitation in the EJB enrichement, see  http://docs.jboss.org/arquillian/reference/latest/en-US/html_single/#d0e964

          • 2. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
            jitend

            Thanks Aslak! But how come sample Greetings EJB works fine. There also EJB injection. And I am sure the discovery mechanism for EJB injection would be same for both the cases (sample Greetings stuff and my code). Also, since Arquillian is deploying EJB before resolving injection in test class, it knows how (by which name) it has deployed EJB.

             

            I went thru EJB enrichment link that you have provided. The no. of combinations that EJB injection JNDI lookup happening, Arquillian should have been able to find my bean. Do you think there is something else (settings) that I am missing which is resulting in above mentioned error.

            • 3. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
              iapazmino

              Adding this lines to your arquillian.xml file you can get a copy of the packaged file trying to be deployed in your target folder. Mybe it helps to find the problem

               

              <engine>
                      <deploymentExportPath>./target</deploymentExportPath>
              </engine>

               

              I had a similar problem in a 5.1 container, and the problem was I used the name and mappedName attributes in the session bean annotation. I deleted them and worked fine.

              • 4. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                jitend

                Thanks Ivan!

                 

                I added what you suggested to arquillian.xml. I was able to inspect compiled EJB. I am not seeing any problem with it. And, I am not using mappedname attribute in my session bean. However I am using EntityManager (injected in Session Bean) inside Session Bean. If there was a way to just find out whether EJB is deployed to JBoss properly or not (arquillian shuts down JBoss as part of running JUnit test case). Because it might be possible that EJB is not getting deployed to JBoss in the very first place. At least, arquillian exception clearly says that it tried to lookup session bean using JNDI names and it could not find and therefore it could not inject EJB into to arquillian unit test class. Not sure what is wrong here.

                • 5. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                  aslak

                  It will try to find EJBs based on the Interface name following the patterns described in docs..

                   

                  so:

                  MasterFacadeLocal + [Bean] [/(local|remote)] etc

                   

                  Your bean is most likely bound to MasterFacade/MasterFacadeLocal or MasterFacade/(local/remote)

                  • 6. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                    jaikiran

                    Make sure the deployment that you are deploying, actually has the EJBs in them. Write out the Deployment archive to the filesystem and check its contents first.

                    • 7. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                      jitend

                      That is what Ivan in earlier post suggested and I did the same. I am able to see my session bean class and other associated classes are packaged inside test.jar.

                      • 8. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                        jitend

                        I checked JBoss log file and I can see EJB is deployed with below JNDI name:

                        16:28:30,078 INFO  [JBossASKernel] installing bean: jboss.j2ee:ear=test.ear,jar=test.jar,name=MasterFacade,service=EJB3
                        16:28:30,078 INFO  [JBossASKernel]   with dependencies:
                        16:28:30,078 INFO  [JBossASKernel]   and demands:
                        16:28:30,078 INFO  [JBossASKernel]     persistence.unit:unitName=test.ear/test.jar#DXPersistence
                        16:28:30,078 INFO  [JBossASKernel]     jboss.ejb:service=EJBTimerService
                        16:28:30,078 INFO  [JBossASKernel]   and supplies:
                        16:28:30,078 INFO  [JBossASKernel]     jndi:test/MasterFacade/local-com.sonymusic.dx.ejb.utility.facades.MasterFacadeLocal
                        16:28:30,078 INFO  [JBossASKernel]     Class:com.sonymusic.dx.ejb.utility.facades.MasterFacadeLocal
                        16:28:30,078 INFO  [JBossASKernel]     jndi:test/MasterFacade/local
                        16:28:30,078 INFO  [JBossASKernel]     jndi:test/MasterFacade/remote

                         

                         

                         

                        However, per Aslak, Arquillian will do lookup with the following pattern:

                        MasterFacadeLocal + [Bean] [/(local|remote)] etc

                         

                        And that is why Arquillian is unable to lookup. It is searching for test/MasterFacadeLocalBean/local

                         

                         

                        Aslak,

                        Can you guys please fix this in Arquillian. Our Session Beans do not following naming convention [Bean] at the end.

                        • 9. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                          henk53

                          If you look into the Arquillian source code, you'll find that it actually tries a dozen pattern to get the bean injected. However, the pattern that is used for JBoss AS 5.x is not there. This might be because the pattern is rather difficult. The class instance declaration uses the bean interface, but the JNDI entry is the actual implementation class.

                           

                          So anyone trying to deduct the JBoss AS 5.x JNDI name from the class instance variable name has to do some more work than just string concatenation. This is probably why JBoss AS 5.x is not supported by Arquillian for injection at the moment.

                          • 10. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                            aslak

                            henk de boer wrote:

                             

                            The class instance declaration uses the bean interface, but the JNDI entry is the actual implementation class.

                             

                            This goes for all JNDI names in all servers, and that's the basis of the issue. A InjectionPoint is based on the Interface while the JNDI name is based on the Impl name. There are no EE spec complaient APIs to get to a JNDI name for a EJB based on it's interface.

                             

                            For JBoss 6 and 7 we're working on a new internal SPI/API in the server that we can hand our Test instance to and it will handle all the injection of services it knows. This should give you the exact same injection support in the Test Case as you have in the whole server, across all specifications.. This API will not be ported to 5, but we have a couple of other options (mainly deploying a Arquillian Deployer so we can become a part of the Deployment chain and extract the information we need. Basically build up the Interface -> JNDIName mapping based on the raw internal deployment data).

                             

                            For non JBoss servers... hoping to get some joint effort on a similar Injection API/SPI. But have not approched any of them yet.

                            • 11. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                              henk53

                              Aslak Knutsen wrote:

                               

                              henk de boer wrote:

                               

                              The class instance declaration uses the bean interface, but the JNDI entry is the actual implementation class.

                               

                              This goes for all JNDI names in all servers, and that's the basis of the issue. A InjectionPoint is based on the Interface while the JNDI name is based on the Impl name. There are no EE spec complaient APIs to get to a JNDI name for a EJB based on it's interface.

                               

                              I see. I don't have the Arquillian source code ready at hand now, but in the code fragment I was glancing at earlier I saw a dozen or so patterns (among which the new Java EE portable global JNDI names), but not the JBoss AS 5.x patterns. Isn't injection in test cases thus also not working for the current versions of JBoss AS 6?

                               

                              One thing which might a kind of option is that the portable global JNDI names do contain the interface name. The full form is this:

                               

                              java:global/[<application-name>]/<module-name>/<bean-name>!<fully-qualified-bean-interface-name>
                              

                               

                              It might be possible to iterate through the entire java:global/[<application-name>]/<module-name>/ tree and match the last part of every name you encounter against the interface you're looking for.

                               

                              Or is this how JBoss AS 6 is currently supported?

                              • 12. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                                aslak

                                Currently all servers and versions use the same patterns. http://docs.jboss.org/arquillian/reference/latest/en-US/html_single/#d0e964

                                 

                                With OpenEJB we do that type of context loop, but it's still just a half solution. It's easier in OpenEJB since the context tree is very small compared to a full app server.

                                • 13. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                                  henk53

                                  Aslak Knutsen wrote:

                                   

                                  Currently all servers and versions use the same patterns. http://docs.jboss.org/arquillian/reference/latest/en-US/html_single/#d0e964

                                   

                                  Yes, these are the same patterns I saw in the code. Didn't realize they were mentioned in the docs as well.

                                   

                                  "java:global/test.ear/test/" + fieldType.getSimpleName() + "Bean",
                                  "java:global/test.ear/test/" + fieldType.getSimpleName(),
                                  "java:global/test/" + fieldType.getSimpleName(),
                                  "java:global/test/" + fieldType.getSimpleName() + "Bean",
                                  "java:global/test/" + fieldType.getSimpleName() + "/no-interface",
                                  "test/" + unqualified interface name + "Bean/local",
                                  "test/" + unqualified interface name + "Bean/remote",
                                  "test/" + unqualified interface name + "/no-interface",
                                  unqualified interface name + "Bean/local",
                                  unqualified interface name + "Bean/remote",
                                  unqualified interface name + "/no-interface"

                                   

                                   

                                   

                                  But I get it now, sorry for being so slow. You rely on naming conventions that people happen to use for EJB interfaces and the implementing EJB beans. If I tried to inject a bean with the interface CustomerDAO:

                                   

                                   

                                  @RunWith(Arquillian.class)
                                  public class CustomerDAOTest {
                                  
                                     @EJB
                                     CustomerDAO customerDAO;
                                  
                                  }
                                  

                                   

                                  Then you just guess that people would call the implementing EJB bean CustomerDAOBean, since that's a naming convention that's often used.

                                   

                                   

                                  With OpenEJB we do that type of context loop, but it's still just a half solution. It's easier in OpenEJB since the context tree is very small compared to a full app server.

                                   

                                  It is for the whole tree, but if you started the search in e.g. the "java:global/test.ear/test/" subtree, would there really be that many entries there? You wouldn't really need to go into any deeper subtrees of that tree and at least the actual String comparisons wouldn't be much of a performance problem of course. Even if you had to compare say 10000 Strings, this would still be nothing.

                                   

                                  Just some idea for another quick workaround. Runtime create and compile an EJB bean with the same @EJB injection as the test is using and with a getter for this instance. Add this bean to the shrinkwrap archive, and after the deployment retrieve the bean from JNDI (since we created this bean, we know the implementation name). Then we can retrieve the actual target instance from the getter and inject this into the test class.

                                  • 14. Re: arquillian EJB unit testing, JBoss 5.0.1 CR2 EAP, EJB JNDI lookup fails
                                    aslak

                                    henk de boer wrote:

                                    It is for the whole tree, but if you started the search in e.g. the "java:global/test.ear/test/" subtree, would there really be that many entries there? You wouldn't really need to go into any deeper subtrees of that tree and at least the actual String comparisons wouldn't be much of a performance problem of course. Even if you had to compare say 10000 Strings, this would still be nothing.

                                     

                                    For OpenEJB it's the whole tree yes. Another problem is that we don't really know "java:global/test.ear/test" from inside the deployment.

                                     

                                    henk de boer wrote:

                                     

                                    Just some idea for another quick workaround. Runtime create and compile an EJB bean with the same @EJB injection as the test is using and with a getter for this instance. Add this bean to the shrinkwrap archive, and after the deployment retrieve the bean from JNDI (since we created this bean, we know the implementation name). Then we can retrieve the actual target instance from the getter and inject this into the test class.

                                    Interesting idea. Should be doable, but still missing the application/module name part of the jndi name(ee6). This is why we're required to deploy as test.ear/test.jar with ejbs..

                                    1 2 Previous Next