For tests of some small JBoss enterprise apps I would like to use JUnit, and the Maven Cargo plugin. (I know that there is also JSFUnit but first I would like to take a closer look at Cargo.)
Is there a simple example available online which I could use as a reference for running a JUnit test which invokes a EJB operation using JBoss (4.2 or 5.1) using the Maven Cargo plugin? I have found some good introductions to the configuration, but I get error messages in the EJB lookup so it would be helpful to see how it should be used.
Here is the test code using InitialContext:
public void testEcho() {
assertEquals("Echo Echo", lookupEchoBeanRemote().Echo("Echo"));
}
private EchoBeanRemote lookupEchoBeanRemote() {
try {
Context c = new InitialContext();
return (EchoBeanRemote) c.lookup("EchoBean/remote");
} catch (NamingException ne) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
throw new RuntimeException(ne);
}
}
Which gives this error:
testEcho(de.betabeans.Echo2Test) Time elapsed: 0.885 sec <<< ERROR!
java.lang.reflect.UndeclaredThrowableException
at $Proxy3.Echo(Unknown Source)
at de.betabeans.Echo2Test.testEcho(Echo2Test.java:17)
Caused by: java.security.PrivilegedActionException: java.lang.reflect.InvocationTargetException
at java.security.AccessController.doPrivileged(Native Method)
at org.jboss.ejb3.security.client.SecurityActions.createSecurityContext(SecurityActions.java:657)
at org.jboss.ejb3.security.client.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:59)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:74)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.aspects.remoting.PojiProxy.invoke(PojiProxy.java:62)
at $Proxy4.invoke(Unknown Source)
at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:207)
at org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:164)
... 28 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.jboss.security.SecurityContextFactory.createSecurityContext(SecurityContextFactory.java:117)
at org.jboss.security.SecurityContextFactory.createSecurityContext(SecurityContextFactory.java:76)
at org.jboss.ejb3.security.client.SecurityActions$1.run(SecurityActions.java:662)
... 38 more
Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/security/jacc/PolicyContextException
at java.lang.ClassLoader.defineClass1(Native Method)
If I use the EJB annotation
@EJB(beanInterface=EchoBeanRemote.class,mappedName="EchoBean/remote")
private EchoBeanRemote newSessionBean;
public Echo3Test(String testName) {
super(testName);
}
public void testEcho() {
assertEquals("Echo Echo", newSessionBean.Echo("Echo"));
}
The test result is
testEcho(de.betabeans.Echo3Test) Time elapsed: 0.001 sec <<< ERROR!
java.lang.NullPointerException
at de.betabeans.Echo3Test.testEcho(Echo3Test.java:20)
jndi.properties is located in the EJB jar root folder and contains these lines:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
### The TimedSocketFactory connection timeout in milliseconds (0 == blocking)
jnp.timeout=0
### The TimedSocketFactory read timeout in milliseconds (0 == blocking)
jnp.sotimeout=0
The bean source code is
package de.betabeans;
import javax.ejb.Remote;
@Remote
public interface EchoBeanRemote {
String Echo(final String in);
}
package de.betabeans;
import javax.ejb.Stateless;
@Stateless
public class EchoBean implements EchoBeanRemote {
public String Echo(final String in) {
return in + " " + in;
}
}
I have also tested a web application which can call the EJB without problems - in both ways, with InitialContext or an annotation. A warning which I received in the deployment of the web application was
WARN [MappedReferenceMetaDataResolverDeployer] Unresolved references exist in JBossWebMetaData:[#web-app:AnnotatedEJBReferenceMetaData{name=de.betabeans.Echo3Servlet/echoBean,ejb-ref-type=null,link=null,ignore-dependecy=false,mapped/jndi-name=EchoBean/remote,resolved-jndi-name=null,beanInterface=interface de.betabeans.EchoBeanRemote}, #web-app:AnnotatedEJBReferenceMetaData{name=NewServlet/newSessionBean,ejb-ref-type=null,link=null,ignore-dependecy=false,mapped/jndi-name=NewSessionBean/remote,resolved-jndi-name=null,beanInterface=interface de.betabeans.NewSessionBeanRemote}] 12:26:11,770 INFO
All tests performed with JBoss 5.1.0.GA on two different build systems.
I have uploaded the complete Maven project now to http://www.mikejustin.com/download/JBossSimpleEJBApp-ejb-test.zip
EDIT: after added sources
First of all - my example works on JBoss 4.2.3.GA and Cargo 1.0 I did some refactoring of your code:
pom.xml file
<groupId>de.betabeans</groupId>
<artifactId>JBossSimpleEJBApp-ejb-test</artifactId>
<packaging>ejb</packaging>
<version>1.0-SNAPSHOT</version>
<name>JBossSimpleEJBApp-ejb JEE5 EJB Test</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
<version>3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jboss</groupId>
<artifactId>jboss-ejb3</artifactId>
<version>4.2.3.GA</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.client</groupId>
<artifactId>jbossall-client</artifactId>
<version>4.2.3.GA</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
<id>repository.jboss.com</id>
<name>Jboss Repository for Maven</name>
<url>http://repository.jboss.com/maven2/</url>
<layout>default</layout>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.1</version>
<configuration>
<ejbVersion>3.0</ejbVersion>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.0</version>
<configuration>
<container>
<containerId>jboss42x</containerId>
<home>${jboss.home}</home>
<append>false</append>
</container>
<configuration>
<type>existing</type>
<home>${jboss.home}/server/default</home>
<properties>
<cargo.jboss.configuration>default</cargo.jboss.configuration>
<cargo.rmi.port>1099</cargo.rmi.port>
<cargo.logging>high</cargo.logging>
</properties>
</configuration>
<wait>false</wait>
</configuration>
<executions>
<execution>
<id>start-container</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-container</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>surefire-it</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>false</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<finalName>JBossSimpleEJBApp-ejb-test</finalName>
</build>
I've changed your pom in following sections:
I've moved resources folder to test folder
jndi.properties file must be use by test (not beans) and can be as follows or that you have:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
The orher configuration files (jboss.xml, MANIFEST.MF) aren't necessary.
Configuration of server
The biggest problem with jboss 4.2.3.GA server and ejb.jar file is that it doesn't work by default! Description of the problem and workaround you can find here. (That was the hardest thing. In Jboss 5.0 server this problem doesn't exist but in maven-cargo-plugin this container is as experimental one)
That's all
Below I paste some links to references, If you'll have still problems I will send you my entire fixed project.
Great resource for you is this post from Carlos Sanchez blog. Maybe you can use Selenium instead JSFUnit too :)
To copy datasource file I use following configuration:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>copy-ds-context</id> <goals> <goal>copy-resources</goal> </goals> <phase>pre-integration-test</phase> <configuration> <outputDirectory>${jboss.deploy-ds.dir}</outputDirectory> <resources> <resource> <directory>${basedir}/src/main/webresources/META-INF</directory> <filtering>true</filtering> <includes> <include>context-ds.xml</include> </includes> </resource> </resources> </configuration> </execution> </executions> </plugin>