11 Replies Latest reply on Aug 9, 2008 1:58 PM by alrubinger

    Which is the best place to write a test case for ejb3-test m

    jaikiran

      I have stumbled upon an issue in the ejb3 test framework (ejb3-test module). I have written a small test case to reproduce this. The test case currently resides in the ejb3-proxy module in my local workspace. I was planning to create a JIRA issue and attach this patch to it. Before doing that, i want to make sure that this test case is in the right module. Since this is related to the ejb3-test module, i decided to move it there. But the test case has dependencies on the ejb3-proxy component (imports classes from org.jboss.ejb3.test.proxy.common).

      So is it a right thing to add a dependency of ejb3-proxy in the pom of ejb3-test? In general, is it OK to add dependencies on ejb3 modules in the pom of ejb3-test?

        • 1. Re: Which is the best place to write a test case for ejb3-te
          alrubinger

          Nope. ;)

          EJB3 Test is a set of common test scaffolding/utilities that my be shared by the other components (think of it as EJB3 Common, but for testing dependencies only).

          So if you draw a dependency upon EJB3 Proxy to EJB3 Test, there will be a cyclic dependency.

          What exactly are you trying to do?

          S,
          ALR

          • 2. Re: Which is the best place to write a test case for ejb3-te
            jaikiran

             

            "ALRubinger" wrote:

            Nope. ;)

            EJB3 Test is a set of common test scaffolding/utilities that my be shared by the other components (think of it as EJB3 Common, but for testing dependencies only).

            So if you draw a dependency upon EJB3 Proxy to EJB3 Test, there will be a cyclic dependency.


            That's what i wanted to understand :) Thanks.


            "ALRubinger" wrote:

            What exactly are you trying to do?


            I'm actually trying to figure out the best place for the following testcase. Here's more details (actually we had discussed this sometime back through a mail, but at that time, i never got to the point of coming up with a reproducible testcase):

            public interface MySLSBLocal
            {
             void printObject(Object obj);
            
            }



            @Stateless
            @Local (MySLSBLocal.class)
            public class MySLSBean implements MySLSBLocal
            {
            
             public void printObject(Object obj)
             {
             System.out.println("Printing " + obj);
            
             }
            
            }



            And this is the testcase:
            .....
            import org.jboss.ejb3.test.proxy.common.Utils;
            import org.jboss.ejb3.test.proxy.common.container.SessionContainer;
            .....
            
            @Test
             public void testBeanMethodInvocation() throws Throwable
             {
             // create the SLSB container
             this.sessionContainer = Utils.createSlsb(MySLSBean.class);
            
             // bind to JNDI
             Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
            
             Context ctx = new InitialContext();
             // lookup the local bean
             MySLSBLocal local = (MySLSBLocal) ctx.lookup(getDefaultBusinessLocalJndiName(sessionContainer));
            
             assertNotNull("Local bean is null",local);
            
             //call the method
             String someString = new String("I am some string");
             local.printObject(someString);
            
             }



            This fails with:
            java.lang.reflect.UndeclaredThrowableException
             at $Proxy55.printObject(Unknown Source)
             at org.jboss.ejb3.test.proxy.jndiregistrar.unit.JndiSessionRegistrarBaseTestCase.testBeanMethodInvocation(JndiSessionRegistrarBaseTestCase.java:498)
             at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
             at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
             at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
             at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
             at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
             at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
             at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
             at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
             at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
             at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
             at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
             at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
             at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
             at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
             at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
             at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:165)
             at org.apache.maven.surefire.Surefire.run(Surefire.java:107)
             at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
             at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:289)
             at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:993)
            Caused by: java.lang.NoSuchMethodException: org.jboss.ejb3.test.proxy.jndiregistrar.MySLSBLocal.printObject(java.lang.String)
             at java.lang.Class.getDeclaredMethod(Class.java:1909)
             at org.jboss.ejb3.test.proxy.common.container.SessionContainer.invoke(SessionContainer.java:188)
             at org.jboss.ejb3.proxy.handler.session.SessionSpecProxyInvocationHandlerBase.invoke(SessionSpecProxyInvocationHandlerBase.java:120)
             ... 28 more
            


            The root cause is that i have a method in the bean with accepts a base class param (java.lang.Object) where as i am invoking the bean method by passing it a child class (java.lang.String). The issue is that the java reflection API used in SessionContainer.invoke looks for a exact match for the Method. The reflection APIs do not support a way to find the best match for a Method.

            • 3. Re: Which is the best place to write a test case for ejb3-te
              jaikiran

              Hmmm.... Just re-looked at the stacktrace:

              at org.jboss.ejb3.test.proxy.common.container.SessionContainer.invoke(SessionContainer.java:188)



              I'm actually trying to figure out the best place for the following testcase


              I think i got an answer to this question. The SessionContainer infact is part of the proxy. So the testcase too can go there. I don't know why, so far, i have been thinking that the problem was in the ejb3-test module :) (probably the package org.jboss.ejb3.test confused me).

              • 4. Re: Which is the best place to write a test case for ejb3-te
                alrubinger

                 

                "jaikiran" wrote:
                I think i got an answer to this question. The SessionContainer infact is part of the proxy. So the testcase too can go there. I don't know why, so far, i have been thinking that the problem was in the ejb3-test module :) (probably the package org.jboss.ejb3.test confused me).


                Looks like it.

                That SessionContainer is a mock container which is part of EJB3 Proxy (as Proxy knows nothing about the *real* containers in EJB3 Core). So SessionContainer there just implements InvokableContext.invoke(), and has its own handling.

                Go ahead and create an issue, commit the testcase for it, and try for a fix on the SessionContainer in proxy tests.

                S,
                ALR

                • 5. Re: Which is the best place to write a test case for ejb3-te
                  jaikiran
                  • 6. Re: Which is the best place to write a test case for ejb3-te
                    jaikiran

                    While testing the SessionContainer.invoke, i observed one other issue which was resulting in a NullPointerException:

                    @Stateless
                    @Local (MySLSBLocal.class)
                    public class MySLSBean implements MySLSBLocal
                    {
                    
                     public void printObject(Object obj)
                     {
                     // do nothing
                    
                     }
                    
                    }


                    Test case:

                    @Test
                     public void testBeanMethodInvocationForNullParams() throws Throwable
                     {
                     // create the SLSB container
                     this.sessionContainer = Utils.createSlsb(MySLSBean.class);
                    
                     // bind to JNDI
                     Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
                    
                     Context ctx = new InitialContext();
                     // lookup the local bean
                     MySLSBLocal local = (MySLSBLocal) ctx.lookup(getDefaultBusinessLocalJndiName(sessionContainer)
                    );
                    
                     assertNotNull("Local bean is null",local);
                    
                     // pass null to the method
                     local.printObject(null);
                    
                     }
                    
                    


                    This throws NPE:
                    testBeanMethodInvocationForNullParams(org.jboss.ejb3.test.proxy.common.container.unit.SessionContainerTestCase) Time elapsed: 0.031 sec <<< ERROR!
                    java.lang.NullPointerException
                     at org.jboss.ejb3.test.proxy.common.container.SessionContainer.invoke(SessionContainer.java:182)
                     at org.jboss.ejb3.proxy.handler.session.SessionSpecProxyInvocationHandlerBase.invoke(SessionSpecProxyInvocationHandlerBase.java:120)
                     at $Proxy37.printObject(Unknown Source)
                     at org.jboss.ejb3.test.proxy.common.container.unit.SessionContainerTestCase.testBeanMethodInvocationForNullParams(SessionContainerTestCase.java:149)
                     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                     at java.lang.reflect.Method.invoke(Method.java:585)
                     at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
                     at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
                     at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
                     at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
                     at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
                     at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
                     at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
                     at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
                     at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
                     at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
                     at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
                     at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
                     at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
                     at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
                     at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:165)
                     at org.apache.maven.surefire.Surefire.run(Surefire.java:107)
                     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                     at java.lang.reflect.Method.invoke(Method.java:585)
                     at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:289)
                     at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:993)


                    As part of fixing this and the earlier issue, i am changing the implementation of SessionContainer.invoke to do away with using Java Reflection APIs and instead use the toMethod() API of the SerializableMethod:
                    
                    Index: SessionContainer.java
                    ===================================================================
                    --- SessionContainer.java (revision 76706)
                    +++ SessionContainer.java (working copy)
                    @@ -25,9 +25,7 @@
                     import java.lang.reflect.InvocationHandler;
                     import java.lang.reflect.Method;
                     import java.lang.reflect.Proxy;
                    -import java.util.ArrayList;
                     import java.util.HashSet;
                    -import java.util.List;
                     import java.util.Map;
                     import java.util.Set;
                    
                    @@ -168,26 +166,9 @@
                     */
                     public Object invoke(Object proxy, SerializableMethod method, Object[] args) throws Throwable
                     {
                    - // Initialize
                    - Class<?>[] argTypes = new Class<?>[]
                    - {};
                    
                    - // Get the types from the arguments, if present
                    - if (args != null)
                    - {
                    - List<Class<?>> types = new ArrayList<Class<?>>();
                    - for (Object arg : args)
                    - {
                    - types.add(arg.getClass());
                    - }
                    - argTypes = types.toArray(new Class<?>[]
                    - {});
                    - }
                    + Method m = method.toMethod(this.getClassLoader());
                    
                    - // Obtain the method for invocation
                    - Method m = this.getClassLoader().loadClass(method.getDeclaringClassName()).getDeclaredMethod(method.getName(),
                    - argTypes);
                    -
                     // Invoke on the bean
                     return invokeBean(proxy, m, args);
                     }
                    


                    • 7. Re: Which is the best place to write a test case for ejb3-te
                      alrubinger

                      Could you put these test cases in a patch on the issue? :)

                      S,
                      ALR

                      • 8. Re: Which is the best place to write a test case for ejb3-te
                        jaikiran

                         

                        "ALRubinger" wrote:
                        Could you put these test cases in a patch on the issue? :)

                        S,
                        ALR


                        Done :)

                        The issue has been updated with a patch containing the testcase and another patch with the proposed fix.

                        • 9. Re: Which is the best place to write a test case for ejb3-te
                          alrubinger

                          Looks like the purpose of these unit tests are to test the mock container itself; correct assumption? If so, we might be approaching a level of coverage to match that of MC.

                          That said, there's absolutely a bug with the Mock SessionContainer in Proxy and your fix looks good. So green light for a commit on that piece at least.

                          Also:

                          * System.out.println == Bad. org.jboss.logging.Logger == Good (for these purposes anyway, it's a standard here, don't ask why another logging framework).

                          Good stuff, finding all the proper code for bootstrapping an embedded EJB environment. Say the word and I'll assign you some of my recent backlog of issues for Proxy.

                          S,
                          ALR



                          • 10. Re: Which is the best place to write a test case for ejb3-te
                            jaikiran

                             

                            "ALRubinger" wrote:
                            Looks like the purpose of these unit tests are to test the mock container itself; correct assumption?


                            Yes. Although, it wasn't my original intention to test the mock container. I was using the mock container to test the jndi binding of a bean when i happened to run into this issue.

                            "ALRubinger" wrote:


                            So green light for a commit on that piece at least.

                            Also:

                            * System.out.println == Bad. org.jboss.logging.Logger == Good (for these purposes anyway, it's a standard here, don't ask why another logging framework).



                            I understand :) I have incorporated this review comment and committed the fix and the test cases. SVN Revision: 76848

                            "ALRubinger" wrote:

                            Say the word and I'll assign you some of my recent backlog of issues for Proxy.



                            Sure. That way, i can keep myself busy in my spare time and also get to understand more about the codebase.


                            • 11. Re: Which is the best place to write a test case for ejb3-te
                              alrubinger

                               

                              "jaikiran" wrote:
                              Sure. That way, i can keep myself busy in my spare time and also get to understand more about the codebase.


                              Glutton for punishment:

                              http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4169734

                              S,
                              ALR