Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'Address already in use' when running tests using Spring LDAP embedded server

I am trying to use Spring LDAP in one of my Spring Boot projects but I am getting an 'Address already in use' error when running multiple tests.

I have cloned locally the sample project here: https://spring.io/guides/gs/authenticating-ldap/

...and just added the boilerplate test normally created by Spring Boot to verify that the Application Context loads correctly:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyApplicationTests {
    @Test
    public void contextLoads() {
    }
}

If run alone, this test passes. As soon as LdapAuthenticationTests and MyApplicationTests are run together, I get the error above for the latter.

After debugging a bit, I've found out that this happens because the system tries to spawn a second instance of the embedded server.

I am sure I am missing something very stupid in the configuration. How can I fix this problem?

like image 997
Zaphod Beeblebrox Avatar asked Nov 14 '17 17:11

Zaphod Beeblebrox


4 Answers

I had a similar problem, and it looks like you had a static port configured (as was in my case).

According to this article:

Spring Boot starts an embedded LDAP server for each application context. Logically, that means, it starts an embedded LDAP server for each test class. Practically, this is not always true since Spring Boot caches and reuses application contexts. However, you should always expect that there is more than one LDAP server running while executing your tests. For this reason, you may not declare a port for your LDAP server. In this way, it will automatically uses a free port. Otherwise, your tests will fail with “Address already in use”

Thus it might be a better idea not to define spring.ldap.embedded.port at all.

like image 53
AbstractVoid Avatar answered Nov 17 '22 09:11

AbstractVoid


I addressed the same issue. I solved it with an additional TestExecutionListener since you can get the InMemoryDirectoryServer bean.

/**
 * @author slemoine
 */
public class LdapExecutionListener implements TestExecutionListener {

    @Override
    public void afterTestClass(TestContext testContext) {
        InMemoryDirectoryServer ldapServer = testContext.getApplicationContext().getBean(InMemoryDirectoryServer.class);
        ldapServer.shutDown(true);
    }
}

And on each SpringBootTest (or only once in an abstract super class)

@RunWith(SpringRunner.class)
@SpringBootTest
@TestExecutionListeners(listeners = LdapExecutionListener.class,
        mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
public class MyTestClass {

...

}

also do not forget

mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS

to avoid disabling the whole @SpringBootTest auto configuration.

like image 36
slemoine Avatar answered Nov 17 '22 08:11

slemoine


Okay, I think I found a solution by adding a @DirtiesContext annotation to my test classes:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)

like image 4
Zaphod Beeblebrox Avatar answered Nov 17 '22 09:11

Zaphod Beeblebrox


If you are using spring embedded ldap, try to comment or remove port value from config file as below :

spring :
  ldap:
    embedded:
      base-dn: dc=example,dc=org
      credential:
        username: cn=admin,dc=example,dc=org
        password: admin
      ldif: classpath:test-schema.ldif
      # port: 12345
      validation:
        enabled: false
like image 1
Tomasz Avatar answered Nov 17 '22 09:11

Tomasz