Testing ejb with stub and openejb framework - java

I am trying to test an EJB that have another one injected in it.
For the tests purpose I want to use a stub for the injected EJB. I had use openEJB as framework for the EJB for the testing.
Here is the EJB :
#Stateless
#Local(IService.class)
public class Service implements IService {
#EJB
private IBean bean;
#Override
public String doService(String data) {
return bean.process(data);
}
}
The real injected EJB :
#Stateless
#Local(IBean.class)
public class Bean implements IBean {
private static Logger logger = Logger.getLogger(Bean.class);
#Override
public String process(String data) {
logger.info("Bean processing : " + data);
return "Bean processing : " + data;
}
}
The stub version of the EJB :
#Stateless
#Local(IBean.class)
public class BeanStub implements IBean {
private static Logger logger = Logger.getLogger(BeanStub.class);
#Override
public String process(String data) {
logger.info("Stub processing : " + data);
return "Stub processing : " + data;
}
}
And the JUnit test used :
public class ServiceTest {
private static Logger logger = Logger.getLogger(ServiceTest.class);
private static InitialContext context;
#BeforeClass
public static void setUpBeforeClass() throws Exception {
// openEJB
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,"org.apache.openejb.client.LocalInitialContextFactory");
p.put("openejb.altdd.prefix", "stub"); // use specific ejb-jar
p.put("openejb.descriptors.output", "true");
context = new InitialContext(p);
}
#Test
public void testServiceStub() {
try {
IService service = (IService) context.lookup("ServiceStubLocal");
assertNotNull(service);
String msg = service.doService("service");
assertEquals("Stub processing : service", msg);
} catch (NamingException e) {
logger.error(e);
fail(e.getMessage());
}
}
}
I had try to override the use of the real EJB by the stub one, using a specific ejb-jar (I want to use "BeanStub" instead of default "Bean" in my service) :
<ejb-jar>
<enterprise-beans>
<session id="ServiceStub">
<ejb-name>ServiceStub</ejb-name>
<ejb-class>tests.Service</ejb-class>
<ejb-local-ref>
<ejb-ref-name>tests.Service/bean</ejb-ref-name>
<ejb-link>BeanStub</ejb-link>
</ejb-local-ref>
</session>
</enterprise-beans>
</ejb-jar>
Unfortunatly I have a problem the EJB are declared :
Apache OpenEJB 3.1.4 build: 20101112-03:32
http://openejb.apache.org/
17:14:29,225 INFO startup:70 - openejb.home = D:\Workspace_Java\tests\testejb
17:14:29,225 INFO startup:70 - openejb.base = D:\Workspace_Java\tests\testejb
17:14:29,350 INFO config:70 - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service)
17:14:29,350 INFO config:70 - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager)
17:14:29,381 INFO config:70 - Found EjbModule in classpath: D:\Workspace_Java\tests\testejb\target\test-classes
17:14:29,412 INFO config:70 - Found EjbModule in classpath: D:\Workspace_Java\tests\testejb\target\classes
17:14:29,428 INFO config:70 - Beginning load: D:\Workspace_Java\tests\testejb\target\test-classes
17:14:29,428 INFO config:70 - AltDD ejb-jar.xml -> file:/D:/Workspace_Java/tests/testejb/target/test-classes/META-INF/stub.ejb-jar.xml
17:14:29,850 INFO config:70 - Beginning load: D:\Workspace_Java\tests\testejb\target\classes
17:14:29,850 INFO config:70 - AltDD ejb-jar.xml -> file:/D:/Workspace_Java/tests/testejb/target/classes/META-INF/stub.ejb-jar.xml
17:14:29,850 INFO config:70 - Configuring enterprise application: classpath.ear
17:14:29,912 INFO config:70 - Configuring Service(id=Default Stateless Container, type=Container, provider-id=Default Stateless Container)
17:14:29,912 INFO config:70 - Auto-creating a container for bean ServiceStub: Container(type=STATELESS, id=Default Stateless Container)
17:14:29,912 INFO options:70 - Using 'openejb.descriptors.output=true'
17:14:29,912 INFO options:70 - Using 'openejb.descriptors.output=true'
17:14:29,928 INFO config:70 - Dumping Generated ejb-jar.xml to: C:\TEMP\ejb-jar-6391test-classes.xml
17:14:29,959 INFO config:70 - Dumping Generated openejb-jar.xml to: C:\TEMP\openejb-jar-6392test-classes.xml
17:14:29,959 INFO options:70 - Using 'openejb.descriptors.output=true'
17:14:29,959 INFO config:70 - Dumping Generated ejb-jar.xml to: C:\TEMP\ejb-jar-6393classes.xml
17:14:29,975 INFO config:70 - Dumping Generated openejb-jar.xml to: C:\TEMP\openejb-jar-6394classes.xml
17:14:30,006 INFO config:70 - Enterprise application "classpath.ear" loaded.
17:14:30,084 INFO startup:70 - Assembling app: classpath.ear
17:14:30,131 INFO startup:70 - Jndi(name=ServiceStubLocal) --> Ejb(deployment-id=ServiceStub)
17:14:30,131 ERROR startup:46 - Jndi name could not be bound; it may be taken by another ejb. Jndi(name=openejb/Deployment/ServiceStub/tests.IService!Local)
17:14:30,131 INFO startup:70 - Undeploying app: classpath.ear
17:14:30,147 ERROR startup:50 - Application could not be deployed: classpath.ear
org.apache.openejb.OpenEJBException: Creating application failed: classpath.ear: Unable to bind business local interface for deployment ServiceStub
at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:679)
at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:450)
Is there something wrong in the approach, or in the way to write the ejb-jar ?

I had similar problems and hurdles with OpenEJB. If you need stubbing and mocking for tests (who doesn't) have a look who I finally managed to handle it (with a great help from David - OpenEJB co-founder). In the latest version (3.1.4) OpenEJB works pretty much like Arquillian, allowing inner-class test driver, without ejb-jar.xml and classpath scanning.
I've described my hurdles here: http://jakub.marchwicki.pl/posts/2011/07/01/testing-ejb-application-openejb-without-classpath-scanning/. Have a look, maybe that will make your testing easier.

Why don't you simply use a mocking framework like EasyMock or Mockito to test this. You wouldn't need any deployment descriptor, EJB container, JNDI lookup, etc. Just this kind of code :
#Test
public void testDoService() {
IBean mockBean = EasyMock.createMock(IBean.class);
mockBean.process("data");
EasyMock.replay(mockBean);
Service serviceToTest = new Service(mockBean);
serviceTotest.doService("data");
EasyMock.verify(mockBean);
}
And it would certainly run much faster, too.

Related

import annotation based spring project in xml based project

I have two spring projects,
Project A: is built using xml bean confguration.
Project B : is built using Annotations;
and A depends on B;
how can I load B beans inside the A applicationContext.
I searched but I found how to load xml beans using annotations : #ImportResource
Is there a way to do so without having to create two application context :
ApplicationContext applicationContextA = new ClassPathXmlApplicationContext("classpath:/applicationContextA.xml");
ApplicationContext applicationContextB = new AnnotationConfigApplicationContext(BConfiguration.class);
Yes, You Can Use One Application Context
You can use a combination of both xml and annotation based configuration using either ApplicationContext implementation. So you can choose one and implement it using one of the following methods.
With ClassPathXmlApplicationContext
When using xml you want to activate package scanning in your xml file.
In the xml:
<context:component-scan base-package="com.yourdomain.packetstoscan"/>
<bean id="myXmlConfiguredBean" class="com.yourdomain.MyXmlConfiguredBean"/>
With AnnotationConfigApplicationContext
When using annotations you want to include the xml file with an annotation on your config class.
In your Java configuration class:
#Configuration
#ImportResource("classpath:yourContext.xml")
public class MyAnnotationConfiguredBean { }
Bean Creation Order
When testing this I noticed just one minor difference, which was the bean creation order. However, I do not think this should have any influence on your application. I'm just adding this for the sake of completeness.
For Xml based config:
INFO com.yourdomain.MyXmlApp - BEAN: myAnnotationConfiguredBean
INFO com.yourdomain.MyXmlApp - BEAN: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
INFO com.yourdomain.MyXmlApp - BEAN: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
INFO com.yourdomain.MyXmlApp - BEAN: org.springframework.context.event.internalEventListenerProcessor
INFO com.yourdomain.MyXmlApp - BEAN: org.springframework.context.event.internalEventListenerFactory
INFO com.yourdomain.MyXmlApp - BEAN: myXmlConfiguredBean
For Annotation based:
INFO com.yourdomain.MyApp - BEAN: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
INFO com.yourdomain.MyApp - BEAN: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
INFO com.yourdomain.MyApp - BEAN: org.springframework.context.event.internalEventListenerProcessor
INFO com.yourdomain.MyApp - BEAN: org.springframework.context.event.internalEventListenerFactory
INFO com.yourdomain.MyApp - BEAN: myAnnotationConfiguredBean
INFO com.yourdomain.MyApp - BEAN: myXmlConfiguredBean

Configure DataSource Using JNDI Using external Tomcat 9 Server: Spring Boot

I have a SpringBootApplication, packaged as war file:
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
on the application.properties:
spring.datasource.jndi-name=java:comp/env/jdbc/bonanza
but on the logs I see those messages when I deploy the war in the Tomcat 9:
Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].. Returning null.
the logs:
12:37:53.989 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [java:comp/env/spring.datasource.jndi-name]
12:37:53.989 [main] DEBUG o.s.jndi.JndiLocatorDelegate - Converted JNDI name [java:comp/env/spring.datasource.jndi-name] not found - trying original name [spring.datasource.jndi-name]. javax.naming.NameNotFoundException: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].
12:37:53.990 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [spring.datasource.jndi-name]
12:37:53.991 [main] DEBUG o.s.jndi.JndiPropertySource - JNDI lookup for name [spring.datasource.jndi-name] threw NamingException with message: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].. Returning null.
12:37:53.995 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [java:comp/env/spring.datasource.jndi-name]
12:37:53.996 [main] DEBUG o.s.jndi.JndiLocatorDelegate - Converted JNDI name [java:comp/env/spring.datasource.jndi-name] not found - trying original name [spring.datasource.jndi-name]. javax.naming.NameNotFoundException: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].
12:37:53.996 [main] DEBUG o.springframework.jndi.JndiTemplate - Looking up JNDI object with name [spring.datasource.jndi-name]
12:37:53.997 [main] DEBUG o.s.jndi.JndiPropertySource - JNDI lookup for name [spring.datasource.jndi-name] threw NamingException with message: Name [spring.datasource.jndi-name] is not bound in this Context. Unable to find [spring.datasource.jndi-name].. Returning null.
12:37:53.998 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Found key 'spring.datasource.jndi-name' in PropertySource 'configurationProperties' with value of type String
on my tomcat9/conf/context.xml:
<Resource name="jdbc/bonanza"
auth="Container"
type="javax.sql.DataSource"
maxTotal="100"
maxIdle="30"
maxWaitMillis="10000"
username="a_usr"
password="Mu*7gydlcdstg100#"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://172.175.77.55:3306/a_db"
/>
As the error suggests, spring boot cannot find the key in the JNDI lookup. JNDI is disabled in Spring boot's embedded Tomcat so you would need to enable it using Tomcat#enableNaming and once that is done you would need to create a lookup entry in JNDI. You can refer to the below code which I copied from one of the spring boot project maintainers repository GitHub repo JNDI-Tomcat
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
#Override
protected void postProcessContext(Context context) {
ContextResource resource = new ContextResource();
resource.setName("jdbc/bonanza");
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "your.db.Driver");
resource.setProperty("url", "jdbc:yourDb");
context.getNamingResources().addResource(resource);
}
};
}
[Edit]
As you are not using embedded tomcat server, you can configure JNDI by configuring it using tomcat config files:
In server.xml, create a Resource under <GlobalNamingResources>
<Resource auth="Container" driverClassName="..."
maxActive="..."
maxIdle="..."
maxWait="..."
name="jdbc/bonanza"
username="..."
password="..."
type="..."
url="..."/>
In Context.xml, you can link the resource
<context>
<ResourceLink auth="Container" name="jdbc/bonanza" global="jdbc/bonanza" type="javax.sql.DataSource" />
</context>
Also, make sure you are not starting the application using the spring-boot main method. You need to build the war file using maven/gradle and then deploy it to the tomcat and test it.

Spring application duplicating functionality because of ApplicationContext

I've got a Spring application with Hibernate integration, deployed on a JBoss server locally. I configured the app using annotations throughout and a Config.java class for configurations of Spring and Hibernate.
I'm getting this warning in my logs:
17:13:18,153 WARN spi.TypeConfiguration$Scope:273 - HHH000233:
Scoping types to session factory
org.hibernate.internal.SessionFactoryImpl#4945417e after already
scoped org.hibernate.internal.SessionFactoryImpl#4945417e
When I tried debugging throughout my program, I found out about the place in my program the log was coming from. In one of my servlets, I've got this:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
...
}
I've tried instead using
#Autowired
private ApplicationContext context;
in the class, but that breaks my application.
A little more verbose logging:
17:57:35,211 DEBUG internal.SessionFactoryImpl:292 - Instantiated session factory
17:57:35,211 DEBUG spi.TypeConfiguration:146 - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration#42990ff8] to SessionFactoryImpl [org.hibernate.internal.SessionFactoryImpl#494db1a3]
17:57:35,211 DEBUG spi.TypeConfiguration:148 - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration#42990ff8] to SessionFactory [org.hibernate.internal.SessionFactoryImpl#494db1a3]
17:57:35,211 WARN spi.TypeConfiguration$Scope:273 - HHH000233: Scoping types to session factory org.hibernate.internal.SessionFactoryImpl#494db1a3 after already scoped org.hibernate.internal.SessionFactoryImpl#494db1a3
17:57:35,225 TRACE internal.AbstractServiceRegistryImpl:228 - Initializing service [role=org.hibernate.persister.spi.PersisterFactory]
17:57:35,227 TRACE internal.AbstractServiceRegistryImpl:228 - Initializing service [role=org.hibernate.persister.spi.PersisterClassResolver]
What this all results in is all of my transactions taking place twice, both in my classes and in my database. Anyone have any ideas?

Jboss AS 7.1.1 Final Local JNDI EJB Invocation

Using Jboss AS 7.1.1 Final, I'm trying to invoke a Local EJB(3.1) through JNDI.
My Local EJB is:
#Stateless(mappedName = "Services")
#LocalBean
public class Services implements ServicesLocal {
.....// scary stuffs here
}
My Interface Services is:
#Local
public interface ServicesLocal {
.... // Some powerfull stuffs here
}
I'm trying to invoke this EJB above like this:
private ServicesLocal getLocalEJB() throws NamingException {
log.info("\n\n\n\n\n\n\n\n ################## Getting the ServicesLocal");
InitialContext context = new InitialContext();
return (ServicesLocal) context.lookup("ejb:/global/docs/docs-ejb-0.1/Services!com.mycompany.docs.local.ServicesLocal");
}
This is the error I'm getting when invoking this code above:
############ Getting the ServicesLocal
15:36:10,437 INFO [org.jboss.ejb.client] (http-localhost-127.0.0.1-8080-1) JBoss EJB Client version 1.0.5.Final
15:36:10,456
ERROR [stderr] (http-localhost-127.0.0.1-8080-1) java.lang.IllegalStateException: No EJB receiver available for handling [appName:,modulename:global,distinctname:docs] combination for invocation context org.jboss.ejb.client.EJBClientInvocationContext#396f6a24
15:36:10,457
ERROR [stderr] (http-localhost-127.0.0.1-8080-1) ^Iat org.jboss.ejb.client.EJBClientContext.requireEJBReceiver(EJBClientContext.java:584)
And this is the JNDI log when the Jboss 7.1.1 Final boot. Having the EJB that I want to invoke:
15:07:07,975 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-7) JNDI bindings for session bean named Services in deployment unit subdeployment "docs-ejb-0.1.jar" of deployment "docs.ear" are as follows:
java:global/docs/docs-ejb-0.1/Services!com.mycompany.docs.local.ServicesLocal
java:app/docs-ejb-0.1/Services!com.mycompany.docs.local.ServicesLocal
java:module/Services!com.mycompany.docs.local.ServicesLocal
java:global/docs/docs-ejb-0.1/Services!com.mycompany.docs.services.Services
java:app/docs-ejb-0.1/Services!com.mycompany.docs.services.Services
java:module/Services!com.mycompany.docs.services.Services
I think my context.lookup("ejb:/global/docs/docs-ejb-0.1/Services!com.mycompany.docs.local.ServicesLocal") is wrong. What I can do to fix that and invoke my Local EJB with JNDI?
Have you tried to use what JBoss tells you?
context.lookup("java:global/docs/docs-ejb-0.1/Services!com.mycompany.docs.local.ServicesLocal")
Your EJB is stored in java namespace, not in ejb one.

Junit and spring websockets - after each test I get a weird exception

I am getting the following exception when my jUnit test is ending:
7 May 2014 18:06:29 INFO GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext#7b0133c2: startup date [Tue May 27 18:06:09 IDT 2014]; root of context hierarchy
27 May 2014 18:06:29 INFO DefaultLifecycleProcessor - Stopping beans in phase 2147483647
27 May 2014 18:06:29 INFO NettyTcpClient - CLOSED: [id: 0x09b0bb52, /127.0.0.1:56869 :> /127.0.0.1:61613]
27 May 2014 18:06:31 ERROR StompBrokerRelayMessageHandler - Error while shutting down TCP client
java.util.concurrent.TimeoutException
at org.springframework.messaging.tcp.reactor.AbstractPromiseToListenableFutureAdapter.get(AbstractPromiseToListenableFutureAdapter.java:84)
at org.springframework.messaging.simp.stomp.StompBrokerRelayMessageHandler.stopInternal(StompBrokerRelayMessageHandler.java:377)
at org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler.stop(AbstractBrokerMessageHandler.java:150)
at org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler.stop(AbstractBrokerMessageHandler.java:164)
at org.springframework.context.support.DefaultLifecycleProcessor.doStop(DefaultLifecycleProcessor.java:229)
at org.springframework.context.support.DefaultLifecycleProcessor.access$300(DefaultLifecycleProcessor.java:51)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.stop(DefaultLifecycleProcessor.java:363)
at org.springframework.context.support.DefaultLifecycleProcessor.stopBeans(DefaultLifecycleProcessor.java:202)
at org.springframework.context.support.DefaultLifecycleProcessor.onClose(DefaultLifecycleProcessor.java:118)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:888)
at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:809)
27 May 2014 18:06:31 INFO ThreadPoolTaskExecutor - Shutting down ExecutorService 'brokerChannelExecutor'
27 May 2014 18:06:31 INFO ThreadPoolTaskScheduler - Shutting down ExecutorService 'messageBrokerSockJsTaskScheduler'
27 May 2014 18:06:31 INFO ThreadPoolTaskExecutor - Shutting down ExecutorService 'clientOutboundChannelExecutor'
27 May 2014 18:06:31 INFO ThreadPoolTaskExecutor - Shutting down ExecutorService 'clientInboundChannelExecutor'
27 May 2014 18:06:31 INFO EhCacheManagerFactoryBean - Shutting down EhCache CacheManager
27 May 2014 18:06:31 INFO LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
27 May 2014 18:06:31 INFO DefaultContextLoadTimeWeaver - Removing all registered transformers for class loader: sun.misc.Launcher$AppClassLoader
Any ideas how to prevent that?
P.S - The tests are succeeding but I really hate to see that stack trace
EDIT -
my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/application-context.xml" })
public class EmptyTest{
/**
* Test (empty)
*/
#Test()
public void emptyTest() {
assertTrue(true);
}
}
And here is my config file for the broker:
#Configuration
#EnableWebSocketMessageBroker
#EnableScheduling
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableStompBrokerRelay(
"/topic",
"/queue/");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint(
"/wsdemo").withSockJS();
}
}
As I see it, you have a few options, depending on exactly what you want to achieve in your tests now, and what you might want to be able to do in the future.
1) If your test does not need the websocket configuration at all, change it to point at a custom context configuration that does not include the WebSocketConfig.
2) If your test needs the websocket config, but you don't need the broker relay (I can't see why it would be required in a test), you could add another Configuration for testing that uses registry.enableSimpleBroker("/topic", "/queue/") instead of enableStompBrokerRelay. Then there will be no TCP connection to the broker. The obvious disadvantage with this approach is that you are not testing your actual config, and that you are duplicating the destination prefixes.
3) Run an embedded STOMP broker for your tests. I'm not 100% certain such a thing exists - I know ActiveMQ has STOMP support and some support for running inside a VM, but I haven't tried this with STOMP. If possible, the advantage of this approach is that your tests would be testing something very close to the real code.
4) You could customise the STOMP broker relay to such an extent that you have full control over what your application receives from the broker. You can customise the StompBrokerRelayMessageHandler which manages the connection to the relay broker by adding a Configuration class that extends DelegatingWebSocketMessageBrokerConfiguration in order to override the stompBrokerRelayMessageHandler() method. For example, you can set the TCP client it uses to your own implementation of TcpOperations. Below is an example TCP client that simply does nothing, i.e. makes the Handler think it is connected, but cannot receive or send messages.
#Override
public AbstractBrokerMessageHandler stompBrokerRelayMessageHandler() {
AbstractBrokerMessageHandler handler = super.stompBrokerRelayMessageHandler();
if (handler instanceof StompBrokerRelayMessageHandler) {
StompBrokerRelayMessageHandler stompHandler = (StompBrokerRelayMessageHandler) handler;
stompHandler.setTcpClient(new TcpOperations<byte[]>() {
#Override
public ListenableFuture<Void> connect(TcpConnectionHandler<byte[]> connectionHandler) {
return new CompletedListenableFuture<>(null);
}
#Override
public ListenableFuture<Void> connect(TcpConnectionHandler<byte[]> connectionHandler, ReconnectStrategy reconnectStrategy) {
return new CompletedListenableFuture<>(null);
}
#Override
public ListenableFuture<Void> shutdown() {
return new CompletedListenableFuture<>(null);
}
});
}
return handler;
}
Note that CompletedListenableFuture is just an implementation of ListenableFuture that is done after construction, and immediately calls any callbacks passed to addCallback with the value passed into the constructor.
The point here is that you can easily customise the exact behaviour of the broker relay components, so you can control them better in your tests. I am not aware of any built-in support to make this kind of testing easier, but then again the websocket support is still pretty new. I would suggest that you look at Rossen Stoyanchev's excellent example project spring-websocket-portfolio, if you haven't done so already, as it includes several examples of how to test the websocket configuration at different levels (just one controller, loading the full context, running an embedded server, ...). Hopefully this is also helpful for deciding how you want to test your application, and what you might need to customise to do it.

Categories