esanchezros / quickfixj-spring-boot-starter

Spring Boot Starter for QuickFIX/J
Apache License 2.0
125 stars 57 forks source link

InstanceAlreadyExistsException exception during integration tests #38

Closed raph1mm closed 4 years ago

raph1mm commented 4 years ago

Hello,

I'm having some issues during integration tests in Spring Boot.

I have app which uses Quickfix Client, here's my main class:

public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public Application clientApplication() {
        return new ApplicationAdapter();
    }

    @Bean()
    public Initiator clientInitiator(
            quickfix.Application clientApplication,
            MessageStoreFactory clientMessageStoreFactory,
            SessionSettings clientSessionSettings,
            LogFactory clientLogFactory,
            MessageFactory clientMessageFactory
    ) throws ConfigError {

        return new ThreadedSocketInitiator(
                clientApplication,
                clientMessageStoreFactory,
                clientSessionSettings,
                clientLogFactory,
                clientMessageFactory
        );
    }

}

I've got some integrations tests and during the second one (and next) I got this exception:

2020-04-22 10:14:12.117 ERROR 1466 --- [           main] o.s.boot.SpringApplication               : Application run failed
org.springframework.context.ApplicationContextException: Failed to start bean 'clientConnectionManager'; nested exception is java.lang.IllegalStateException: Could not start the connector
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:185) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:894) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:126) ~[spring-boot-test-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) ~[spring-test-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124) ~[spring-test-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123) ~[spring-test-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) ~[spring-test-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[spring-test-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43) ~[spring-boot-test-autoconfigure-2.2.6.RELEASE.jar:2.2.6.RELEASE]
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244) ~[spring-test-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98) ~[spring-test-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:337) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:342) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:337) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) ~[na:na]
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
    at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) ~[na:na]
    at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) ~[na:na]
    at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658) ~[na:na]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:336) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:259) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:252) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at java.base/java.util.Optional.orElseGet(Optional.java:369) ~[na:na]
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:251) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:29) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:106) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:105) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:107) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:107) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:75) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) ~[na:na]
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) ~[na:na]
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) ~[junit-platform-engine-1.5.2.jar:1.5.2]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128) ~[junit-platform-launcher-1.3.1.jar:1.3.1]
    at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invokeAllTests(JUnitPlatformProvider.java:150) ~[surefire-junit-platform-2.22.2.jar:2.22.2]
    at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.invoke(JUnitPlatformProvider.java:124) ~[surefire-junit-platform-2.22.2.jar:2.22.2]
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384) ~[surefire-booter-2.22.2.jar:2.22.2]
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345) ~[surefire-booter-2.22.2.jar:2.22.2]
    at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126) ~[surefire-booter-2.22.2.jar:2.22.2]
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418) ~[surefire-booter-2.22.2.jar:2.22.2]
Caused by: java.lang.IllegalStateException: Could not start the connector
    at io.allune.quickfixj.spring.boot.starter.connection.ConnectorManager.start(ConnectorManager.java:97) ~[quickfixj-spring-boot-starter-2.5.0.jar:2.5.0]
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182) ~[spring-context-5.2.5.RELEASE.jar:5.2.5.RELEASE]
    ... 80 common frames omitted
Caused by: org.quickfixj.QFJException: Connector MBean postregistration failed
    at org.quickfixj.jmx.mbean.connector.ConnectorAdmin.registerSessions(ConnectorAdmin.java:188) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at org.quickfixj.jmx.mbean.connector.ConnectorAdmin.lambda$postRegister$0(ConnectorAdmin.java:170) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at java.desktop/java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:341) ~[na:na]
    at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:333) ~[na:na]
    at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:266) ~[na:na]
    at quickfix.mina.SessionConnector.setSessions(SessionConnector.java:121) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at quickfix.mina.initiator.AbstractSocketInitiator.createSessions(AbstractSocketInitiator.java:204) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at quickfix.mina.initiator.AbstractSocketInitiator.createSessionInitiators(AbstractSocketInitiator.java:80) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at quickfix.ThreadedSocketInitiator.start(ThreadedSocketInitiator.java:105) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at io.allune.quickfixj.spring.boot.starter.connection.ConnectorManager.start(ConnectorManager.java:93) ~[quickfixj-spring-boot-starter-2.5.0.jar:2.5.0]
    ... 81 common frames omitted
Caused by: javax.management.InstanceAlreadyExistsException: org.quickfixj:type=Settings,beginString=FIX.4.2,senderCompID=XXX-XXXX-TEST,targetCompID=XXXX-XXXX-TEST
    at java.management/com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:436) ~[na:na]
    at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1855) ~[na:na]
    at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:955) ~[na:na]
    at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:890) ~[na:na]
    at java.management/com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:320) ~[na:na]
    at java.management/com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[na:na]
    at org.quickfixj.jmx.JmxExporter.registerMBean(JmxExporter.java:131) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at org.quickfixj.jmx.mbean.session.SessionJmxExporter.register(SessionJmxExporter.java:45) ~[quickfixj-core-2.1.0.jar:2.1.0]
    at org.quickfixj.jmx.mbean.connector.ConnectorAdmin.registerSessions(ConnectorAdmin.java:181) ~[quickfixj-core-2.1.0.jar:2.1.0]
    ... 90 common frames omitted

You can see "Caused by: javax.management.InstanceAlreadyExistsException" - it looks like the previous test didn't destroy bean related to Quickfix. What's the issue here?

I tried using "@DirtyContext" in tests but with no luck.

esanchezros commented 4 years ago

Hi raph1mm,

I will have a look but you can try setting quickfixj.client.jmx-enabled=false if you don't need the MBean for your tests.

esanchezros commented 4 years ago

Could you share your project in GitHub so I can have a look?

raph1mm commented 4 years ago

I will have a look but you can try setting quickfixj.client.jmx-enabled=false if you don't need the MBean for your tests.

I'm quite new to Java world, but I believe I need it - one of integration test I have is requesting my application using Rest Assured. I need complete application for this.

I've found not ideal solution. I can prevent reloading application context between test classes if all test classes have the same parent class, for example:

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public abstract class BaseTestApplication {
}
raph1mm commented 4 years ago

Could you share your project in GitHub so I can have a look?

I can't - because of NDA. :(

Maybe I can provide more information for you? What do you want to know?

esanchezros commented 4 years ago

I wanted to see the test classes and the spring boot test config. I will try to reproduce this issue

raph1mm commented 4 years ago

Ok. I'm preparing some code for you.

raph1mm commented 4 years ago

Ok. This code is not pretty, but it's only proof of concept for you:

I created this controller:

@RestController
public class MyController {
    @GetMapping(path = "/path1")
    public ResponseEntity<?> getPath1() throws SessionNotFound {
        QuoteRequest quoteRequest = createQuoteRequest(UUID.randomUUID());
        SessionID sessionID = new SessionID("FIX.4.2", "XXX-XXXX-TEST", "XXX-XXXX-TEST");

        Session.sendToTarget(quoteRequest, sessionID);

        return ResponseEntity.ok("OK");

    }

    @GetMapping(path = "/path2")
    public ResponseEntity<?> getPath2() throws SessionNotFound {
        QuoteRequest quoteRequest = createQuoteRequest(UUID.randomUUID());
        SessionID sessionID = new SessionID("FIX.4.2", "XXX-XXX-TEST", "XXX-XXXX-TEST");

        Session.sendToTarget(quoteRequest, sessionID);

        return ResponseEntity.ok("OK");

    }

    private QuoteRequest createQuoteRequest(
            UUID operationId) {
        QuoteRequest quoteRequest = new QuoteRequest(new QuoteReqID(operationId.toString()));
        return quoteRequest;
    }
}

and some tests (tests have no addiotional setup - only via annotations):

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class MyController1IntegrationTest {

    @Test
    public void canGetPath1() {
        given()
            .contentType("application/json")
        .when()
            .get("/myapp/path1")
        .then()
            .assertThat()
                .statusCode(200);
    }
}
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class MyController2IntegrationTest {

    @Test
    public void canGetPath2() {
        given()
            .contentType("application/json")
        .when()
            .get("/myapp/path2")
        .then()
            .assertThat()
                .statusCode(200);
    }
}
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class QuoteRepositoryTest {
    @Autowired
    private QuoteRepository repository;

    @Test
    public void someRepoStuff() {
        repository.findByQuoteId("123");
    }
}

I had to use @DirtiesContext in the last one to enforce situation with application reloading (in my orginal code it reloads context without it).

When I run:

mvn clean test

InstanceAlreadyExistsException happen.

To make sure that happen, you should see

image

at least twice.

esanchezros commented 4 years ago

Hi @raph1mm

I just added a branch with your code and tests and everything worked fine (https://github.com/esanchezros/quickfixj-spring-boot-starter-examples/tree/add-spring-integration-test - See simple-server-sender)

Just a thought, could you check if you have another instance of the app running elsewhere? It could be that you already have a server running and that, having quickfixj.server.jmx-enabled=true, will cause the issue described.

raph1mm commented 4 years ago

Hi @esanchezros

Thank you for checking. :)

I ran your'e example. Please add

@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)

before every test class. Then you can see Spring Boot logo twice during tests - but even then - your example works fine.

I noticed that your setup is different. For example - I cannot see "ThreadedSocketInitiator" bean. Maybe here is something wrong?

esanchezros commented 4 years ago

Hi @raph1mm

I changed the tests (pushed it to examples) and added the @DirtiesContext on every class, plus added the config as in the original post, still everything built fine.

Before running any tests, could you run jconsole from the command line and see if there is already a local process running?

Thanks

raph1mm commented 4 years ago

Hi,

I only see this:

image

esanchezros commented 4 years ago

Hi @raph1mm,

I'm still curious to see why you were getting this error. Did you get to the bottom of it?

Thanks

esanchezros commented 4 years ago

Hi @raph1mm

tl;dr

I managed to reproduced your issue and found the root cause.

Full explanation

The spring starter register two beans, serverAcceptorMBean and clientInitiatorMBean, that create a JmxExporter. The object needs REGISTRATION_REPLACE_EXISTING set in registration behaviour to override the existing MBean. This comment is in theJmxExporter javadoc:

 * Actually register the MBean with the server. The behaviour when encountering
 * an existing MBean can be configured using the registrationBehaviour constructor or {@link #setRegistrationBehavior(int)}.
 * This design (and also code) was unashamedly cribbed from Spring's
 * <a href="http://static.springframework.org/spring/docs/2.0.x/api/org/springframework/jmx/support/MBeanRegistrationSupport.html">MBeanRegistrationSupport</a>
 * class. Thanks Spring team!
 *
 * @see #REGISTRATION_FAIL_ON_EXISTING
 * @see #REGISTRATION_IGNORE_EXISTING
 * @see #REGISTRATION_REPLACE_EXISTING

The default behaviour is set to REGISTRATION_FAIL_ON_EXISTING, hence when reloading the Spring context the MBean registration fails.

A workaround for this issue is to set quickfixj.server.jmx-enabled=false which will prevent the bean from registering the `MBean.

I will fix this and release a new version shortly.

raph1mm commented 4 years ago

Hi @esanchezros

I wanted to reply that I haven't found other solution than common parent class for all tests.

I'll try your workaround. :)

raph1mm commented 4 years ago

This setup works for me:

quickfixj:
  client:
    config: ${QUIICKFIXJ_CLIENT_CONFIG_FILE:classpath:barxfx.cfg}
    jmx-enabled: false
  server:
    jmx-enabled: false

Anyway - thank you very much for your time and helping me with this. :)

esanchezros commented 4 years ago

Hi @raph1mm

I've release version 2.5.2 with a fix for this issue. Could you update your version and try with @DirtiesContext on separate classes?

Thanks

raph1mm commented 4 years ago

I've just tested it. It works just fine. :)

Thank you, again.