You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/03/26 02:41:22 UTC

[james-project] branch master updated (1b7b36c -> c25a21c)

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.


    from 1b7b36c  JAMES-3124 Test and recommend upgrading to Tika 1.24
     new c68b8f3  JAMES-3088 remove mockito ReadOnlyUsersLDAPRepositoryTest
     new be27078  JAMES-3088 MemoryUsersRepository should use its parent boolean virtualHosting
     new 050b0ad  JAMES-3088 Migrating UserRepository tests to Junit 5 contract style
     new 82bf5be  JAMES-3088 Split AbstractUsersRepositoryTest into two contracts
     new 57d472b  JAMES-3088 Migrate CassandraUsersRepositoryTest
     new d994414  JAMES-3088 Migrate JpaUsersRepositoryTest
     new 154148d  JAMES-3088 s/AbstractUsersRepositoryTest/AbstractUsersRepositoryContract
     new 22e1166  JAMES-3088 Make LDAPUserRepository inherit AbstractUserRepository
     new d56e5ef  JAMES-3088 Apply contract tests to the LDAPUserRepository
     new e857819  JAMES-3088 Tests and fix for the missing domain checks
     new f82b46b  JAMES-3088 Add tests when empty LDAP
     new 1903ddb  JAMES-3087 Reactify MailboxMapper::findMailboxByPath
     new aa38053  JAMES-3087 Reactify MailboxManager::mailboxExist
     new 1bc8e36  JAMES-3078 Integration tests for CORS headers
     new 6ba3130  JAMES-3087 Sequentially process authentication strategies
     new c25a21c  [Build time] Comment to explain 'Speedup ComputeMessageFastViewProjectionListenerTest'

The 16 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/james/mailbox/MailboxManager.java   |   7 +-
 .../apache/james/mailbox/MailboxManagerTest.java   |  38 +-
 .../cassandra/mail/CassandraMailboxMapper.java     |   6 +-
 .../CassandraCombinationManagerTestSystem.java     |   5 +-
 .../cassandra/mail/CassandraMailboxMapperTest.java |  70 +-
 .../mail/migration/MailboxPathV2MigrationTest.java |   2 +-
 .../james/mailbox/jpa/mail/JPAMailboxMapper.java   |  21 +-
 .../mailbox/jpa/mail/JpaMailboxMapperTest.java     |   6 +-
 .../jpa/mail/TransactionalMailboxMapper.java       |   4 +-
 .../mailbox/maildir/mail/MaildirMailboxMapper.java |  11 +-
 .../inmemory/mail/InMemoryMailboxMapper.java       |  11 +-
 .../store/StoreMailboxAnnotationManager.java       |   2 +-
 .../james/mailbox/store/StoreMailboxManager.java   |  45 +-
 .../james/mailbox/store/StoreRightManager.java     |  10 +-
 .../james/mailbox/store/mail/MailboxMapper.java    |  19 +-
 .../AbstractMailboxManagerAttachmentTest.java      |   2 +-
 .../mailbox/store/MessageIdManagerTestSystem.java  |   2 +-
 .../store/StoreMailboxManagerAnnotationTest.java   |  21 +-
 .../mailbox/store/StoreMailboxManagerTest.java     |   4 +-
 .../james/mailbox/store/StoreRightManagerTest.java |   4 +-
 .../store/mail/model/MailboxMapperACLTest.java     |   1 +
 .../store/mail/model/MailboxMapperTest.java        |  14 +-
 .../imap/processor/AbstractAuthProcessor.java      |   4 +-
 .../processor/AbstractMessageRangeProcessor.java   |   4 +-
 .../james/imap/processor/RenameProcessor.java      |   4 +-
 .../james/imap/processor/CopyProcessorTest.java    |   8 +-
 .../james/imap/processor/MoveProcessorTest.java    |   8 +-
 .../org/apache/james/modules/MailboxProbeImpl.java |   7 +-
 .../adapter/mailbox/MailboxManagementTest.java     |   5 +-
 .../user/cassandra/CassandraUsersRepository.java   |   7 +-
 .../cassandra/CassandraUsersRepositoryTest.java    |  50 +-
 .../apache/james/user/jpa/JPAUsersRepository.java  |   6 +
 .../james/user/jpa/JpaUsersRepositoryTest.java     |  54 +-
 server/data/data-ldap/pom.xml                      |  10 +
 .../user/ldap/ReadOnlyUsersLDAPRepository.java     |  46 +-
 .../james/user/ldap/DockerLdapSingleton.java       |   2 +
 ... ReadOnlyUsersLDAPRepositoryEmptyListTest.java} |  81 ++-
 .../ReadOnlyUsersLDAPRepositoryInvalidDnTest.java  |   6 +-
 .../user/ldap/ReadOnlyUsersLDAPRepositoryTest.java | 250 ++++---
 .../src/test/resources/ldif-files/populate.ldif    |   4 +
 .../james/user/lib/AbstractUsersRepository.java    |  18 +-
 .../user/lib/AbstractUsersRepositoryContract.java  | 721 +++++++++++++++++++++
 .../user/lib/AbstractUsersRepositoryTest.java      | 542 ----------------
 .../james/user/memory/MemoryUsersRepository.java   |  21 +-
 .../user/memory/MemoryUsersRepositoryTest.java     | 141 ++--
 .../mailets/delivery/MailboxAppender.java          |   4 +-
 .../mailets/delivery/LocalDeliveryTest.java        |   3 +
 .../mailets/delivery/ToRecipientFolderTest.java    |   3 +
 .../apache/james/jmap/JMAPAuthenticationTest.java  |  14 +
 .../methods/integration/CorsHeaderAPITest.java     |  82 +++
 .../integration/cucumber/DownloadStepdefs.java     |   7 +
 .../test/resources/cucumber/DownloadGet.feature    |   6 +
 .../test/resources/cucumber/DownloadPost.feature   |   6 +
 ...ilingTest.java => MemoryCorsHeaderAPITest.java} |   5 +-
 .../jmap/http/AuthenticationReactiveFilter.java    |  11 +-
 .../http/DefaultMailboxesReactiveProvisioner.java  |  37 +-
 ...mputeMessageFastViewProjectionListenerTest.java |   2 +
 .../http/AuthenticationReactiveFilterTest.java     |  48 +-
 ...aultMailboxesReactiveProvisionerThreadTest.java |   4 +-
 .../hook/MailboxDeliverToRecipientHandler.java     |   4 +-
 .../james/pop3server/core/PassCmdHandler.java      |   4 +-
 .../apache/james/pop3server/POP3ServerTest.java    |  10 +-
 .../james/webadmin/routes/AliasRoutesTest.java     |   2 -
 .../james/webadmin/routes/ForwardRoutesTest.java   |   2 -
 .../routes/DeletedMessagesVaultRoutesTest.java     |   3 +-
 .../webadmin/service/UserMailboxesService.java     |   7 +-
 .../webadmin/routes/UserMailboxesRoutesTest.java   |   6 +-
 67 files changed, 1543 insertions(+), 1031 deletions(-)
 copy server/data/data-ldap/src/test/java/org/apache/james/user/ldap/{ReadOnlyUsersLDAPRepositoryInvalidDnTest.java => ReadOnlyUsersLDAPRepositoryEmptyListTest.java} (56%)
 create mode 100644 server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
 delete mode 100644 server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
 create mode 100644 server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/CorsHeaderAPITest.java
 copy server/protocols/jmap-draft-integration-testing/memory-jmap-draft-integration-testing/src/test/java/org/apache/james/jmap/memory/{MemoryQuotaMailingTest.java => MemoryCorsHeaderAPITest.java} (91%)


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 10/16: JAMES-3088 Tests and fix for the missing domain checks

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit e8578196791abf54b0d99ff577e81e6d68676d3f
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 15:03:24 2020 +0700

    JAMES-3088 Tests and fix for the missing domain checks
---
 .../user/cassandra/CassandraUsersRepository.java   |   7 +-
 .../apache/james/user/jpa/JPAUsersRepository.java  |   6 +
 .../user/ldap/ReadOnlyUsersLDAPRepository.java     |  23 +-
 .../ReadOnlyUsersLDAPRepositoryInvalidDnTest.java  |   2 +-
 .../user/ldap/ReadOnlyUsersLDAPRepositoryTest.java | 416 +---------
 .../james/user/lib/AbstractUsersRepository.java    |  18 +-
 .../user/lib/AbstractUsersRepositoryContract.java  | 873 ++++++++++++---------
 .../james/user/memory/MemoryUsersRepository.java   |   4 +
 .../user/memory/MemoryUsersRepositoryTest.java     |  11 +-
 .../james/webadmin/routes/AliasRoutesTest.java     |   2 -
 .../james/webadmin/routes/ForwardRoutesTest.java   |   2 -
 .../routes/DeletedMessagesVaultRoutesTest.java     |   3 +-
 12 files changed, 550 insertions(+), 817 deletions(-)

diff --git a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
index fe17614..a903f34 100644
--- a/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
+++ b/server/data/data-cassandra/src/main/java/org/apache/james/user/cassandra/CassandraUsersRepository.java
@@ -115,7 +115,7 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
     }
 
     @Override
-    public User getUserByName(Username name) {
+    public User getUserByName(Username name) throws UsersRepositoryException {
         return executor.executeSingleRow(
                 getUserStatement.bind()
                     .setString(NAME, name.asString()))
@@ -126,6 +126,7 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
 
     @Override
     public void updateUser(User user) throws UsersRepositoryException {
+        assertDomainPartValid(user.getUserName());
         Preconditions.checkArgument(user instanceof DefaultUser);
         DefaultUser defaultUser = (DefaultUser) user;
         boolean executed = executor.executeReturnApplied(
@@ -143,6 +144,8 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
 
     @Override
     public void removeUser(Username name) throws UsersRepositoryException {
+        assertDomainPartValid(name);
+
         boolean executed = executor.executeReturnApplied(
             removeUserStatement.bind()
                 .setString(NAME, name.asString()))
@@ -154,7 +157,7 @@ public class CassandraUsersRepository extends AbstractUsersRepository {
     }
 
     @Override
-    public boolean contains(Username name) {
+    public boolean contains(Username name) throws UsersRepositoryException {
         return getUserByName(name) != null;
     }
 
diff --git a/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java b/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java
index e949a52..3de0be5 100644
--- a/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java
+++ b/server/data/data-jpa/src/main/java/org/apache/james/user/jpa/JPAUsersRepository.java
@@ -46,6 +46,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Preconditions;
 
 /**
  * JPA based UserRepository
@@ -111,6 +112,9 @@ public class JPAUsersRepository extends AbstractUsersRepository {
      */
     @Override
     public void updateUser(User user) throws UsersRepositoryException {
+        Preconditions.checkNotNull(user);
+        assertDomainPartValid(user.getUserName());
+
         EntityManager entityManager = entityManagerFactory.createEntityManager();
 
         final EntityTransaction transaction = entityManager.getTransaction();
@@ -142,6 +146,8 @@ public class JPAUsersRepository extends AbstractUsersRepository {
      */
     @Override
     public void removeUser(Username name) throws UsersRepositoryException {
+        assertDomainPartValid(name);
+
         EntityManager entityManager = entityManagerFactory.createEntityManager();
 
         final EntityTransaction transaction = entityManager.getTransaction();
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java
index c1ec084..3889fb2 100644
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java
+++ b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java
@@ -628,9 +628,7 @@ public class ReadOnlyUsersLDAPRepository extends AbstractUsersRepository impleme
 
     @Override
     public void removeUser(Username name) throws UsersRepositoryException {
-        LOGGER.warn("This user-repository is read-only. Modifications are not permitted.");
-        throw new UsersRepositoryException(
-                "This user-repository is read-only. Modifications are not permitted.");
+        throw new UsersRepositoryException("This user-repository is read-only. Modifications are not permitted.");
 
     }
 
@@ -641,17 +639,8 @@ public class ReadOnlyUsersLDAPRepository extends AbstractUsersRepository impleme
     }
 
     @Override
-    public void addUser(Username username, String password) throws UsersRepositoryException {
-        LOGGER.error("This user-repository is read-only. Modifications are not permitted.");
-        throw new UsersRepositoryException(
-                "This user-repository is read-only. Modifications are not permitted.");
-    }
-
-    @Override
     public void updateUser(User user) throws UsersRepositoryException {
-        LOGGER.error("This user-repository is read-only. Modifications are not permitted.");
-        throw new UsersRepositoryException(
-                "This user-repository is read-only. Modifications are not permitted.");
+        throw new UsersRepositoryException("This user-repository is read-only. Modifications are not permitted.");
     }
 
     /**
@@ -664,13 +653,13 @@ public class ReadOnlyUsersLDAPRepository extends AbstractUsersRepository impleme
 
     @Override
     protected void doAddUser(Username username, String password) throws UsersRepositoryException {
-        LOGGER.error("This user-repository is read-only. Modifications are not permitted.");
-        throw new UsersRepositoryException(
-                "This user-repository is read-only. Modifications are not permitted.");
+        throw new UsersRepositoryException("This user-repository is read-only. Modifications are not permitted.");
     }
 
     @Override
-    public boolean isAdministrator(Username username) {
+    public boolean isAdministrator(Username username) throws UsersRepositoryException {
+        assertValid(username);
+
         if (ldapConfiguration.getAdministratorId().isPresent()) {
             return ldapConfiguration.getAdministratorId().get().equals(username);
         }
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java
index d558dd7..18f3c80 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java
@@ -53,7 +53,7 @@ class ReadOnlyUsersLDAPRepositoryInvalidDnTest {
 
     @AfterAll
     static void afterAll() {
-        ldapContainer.start();
+        ldapContainer.stop();
     }
 
     @BeforeEach
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
index 8fbaa63..44491b8 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
@@ -34,13 +34,11 @@ import org.apache.commons.configuration2.plist.PropertyListConfiguration;
 import org.apache.commons.configuration2.tree.ImmutableNode;
 import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.DomainList;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
 import org.apache.james.domainlist.api.mock.SimpleDomainList;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
 import org.apache.james.user.lib.AbstractUsersRepository;
 import org.apache.james.user.lib.AbstractUsersRepositoryContract;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Nested;
@@ -49,8 +47,6 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ImmutableList;
-
 class ReadOnlyUsersLDAPRepositoryTest {
 
     static final Logger LOGGER = LoggerFactory.getLogger(ReadOnlyUsersLDAPRepositoryTest.class);
@@ -70,11 +66,11 @@ class ReadOnlyUsersLDAPRepositoryTest {
 
     @AfterAll
     static void afterAll() {
-        ldapContainer.start();
+        ldapContainer.stop();
     }
 
     @Nested
-    class WhenEnableVirtualHosting implements AbstractUsersRepositoryContract.WithVirtualHostingContract {
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryContract.WithVirtualHostingReadOnlyContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
 
@@ -90,9 +86,8 @@ class ReadOnlyUsersLDAPRepositoryTest {
             return usersRepository;
         }
 
-        @Override
         @Test
-        public void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
+        void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
             assertThat(testee().isAdministrator(testSystem.getAdmin())).isTrue();
         }
 
@@ -122,11 +117,6 @@ class ReadOnlyUsersLDAPRepositoryTest {
         }
 
         @Test
-        void unknownUserShouldNotBeAbleToLogInWithVirtualHosting() throws Exception {
-            assertThat(usersRepository.test(UNKNOWN, BAD_PASSWORD)).isFalse();
-        }
-
-        @Test
         void unknownUserShouldNotBeAbleToLogInWhenPasswordIsCorrectWithVirtualHosting() throws Exception {
             assertThat(usersRepository.test(UNKNOWN, PASSWORD)).isFalse();
         }
@@ -143,219 +133,21 @@ class ReadOnlyUsersLDAPRepositoryTest {
             assertThat(usersRepository.contains(usersRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
         }
 
-        @Disabled("JAMES-3088 isAdministrator is case sensitive")
-        @Override
-        @Test
-        public void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void removeUserShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
         @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
         @Override
         @Test
         public void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) {
         }
 
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldDisableCaseVariation(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem){
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) {
-        }
-
         @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
         @Override
         @Test
         public void countUsersShouldReturnZeroWhenEmptyRepository() {
         }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void containsShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void containsShouldPreserveCaseVariation(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void listShouldReturnLowerCaseUser(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
-        }
     }
 
     @Nested
-    class WhenDisableVirtualHosting implements AbstractUsersRepositoryContract.WithOutVirtualHostingContract {
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryContract.WithOutVirtualHostingReadOnlyContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
 
@@ -396,216 +188,22 @@ class ReadOnlyUsersLDAPRepositoryTest {
             assertThat(usersRepository.contains(usersRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
         }
 
-        @Override
         @Test
-        public void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
+        void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
             assertThat(testee().isAdministrator(testSystem.getAdmin())).isTrue();
         }
 
-        @Disabled("JAMES-3088 isAdministrator is case sensitive")
-        @Override
-        @Test
-        public void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void removeUserShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
         @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
         @Override
         @Test
         public void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) {
         }
 
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldDisableCaseVariation(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem){
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) {
-        }
-
         @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
         @Override
         @Test
         public void countUsersShouldReturnZeroWhenEmptyRepository() {
         }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void containsShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void containsShouldPreserveCaseVariation(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void listShouldReturnLowerCaseUser(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) {
-        }
-
-        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
-        @Override
-        @Test
-        public void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
-        }
-
     }
 
     @Nested
diff --git a/server/data/data-library/src/main/java/org/apache/james/user/lib/AbstractUsersRepository.java b/server/data/data-library/src/main/java/org/apache/james/user/lib/AbstractUsersRepository.java
index b770ff1..3a25105 100644
--- a/server/data/data-library/src/main/java/org/apache/james/user/lib/AbstractUsersRepository.java
+++ b/server/data/data-library/src/main/java/org/apache/james/user/lib/AbstractUsersRepository.java
@@ -75,6 +75,11 @@ public abstract class AbstractUsersRepository implements UsersRepository, Config
 
     @Override
     public void assertValid(Username username) throws UsersRepositoryException {
+        assertDomainPartValid(username);
+        assertLocalPartValid(username);
+    }
+
+    protected void assertDomainPartValid(Username username) throws UsersRepositoryException {
         if (supportVirtualHosting()) {
             // need a @ in the username
             if (!username.hasDomainPart()) {
@@ -95,8 +100,12 @@ public abstract class AbstractUsersRepository implements UsersRepository, Config
                 throw new InvalidUsernameException("Given Username contains a @domainpart but virtualhosting support is disabled");
             }
         }
+    }
 
-        if (!isLocalPartValid(username)) {
+    private void assertLocalPartValid(Username username) throws InvalidUsernameException {
+        boolean isValid = CharMatcher.anyOf(ILLEGAL_USERNAME_CHARACTERS)
+            .matchesNoneOf(username.getLocalPart());
+        if (!isValid) {
             throw new InvalidUsernameException(String.format("Given Username '%s' should not contain any of those characters: %s",
                 username.asString(), ILLEGAL_USERNAME_CHARACTERS));
         }
@@ -135,6 +144,8 @@ public abstract class AbstractUsersRepository implements UsersRepository, Config
 
     @Override
     public boolean isAdministrator(Username username) throws UsersRepositoryException {
+        assertValid(username);
+
         return administratorId.map(id -> id.equals(username))
             .orElse(false);
     }
@@ -155,9 +166,4 @@ public abstract class AbstractUsersRepository implements UsersRepository, Config
             throw new UsersRepositoryException("Failed to compute mail address associated with the user", e);
         }
     }
-
-    private boolean isLocalPartValid(Username username) {
-        return CharMatcher.anyOf(ILLEGAL_USERNAME_CHARACTERS)
-            .matchesNoneOf(username.getLocalPart());
-    }
 }
diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
index 4780b02..557824f 100644
--- a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
+++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
@@ -19,10 +19,12 @@
 package org.apache.james.user.lib;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -34,6 +36,7 @@ import org.apache.james.user.api.AlreadyExistInUsersRepositoryException;
 import org.apache.james.user.api.InvalidUsernameException;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.api.model.User;
+import org.apache.james.user.lib.model.DefaultUser;
 import org.junit.jupiter.api.Assumptions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
@@ -89,6 +92,7 @@ public interface AbstractUsersRepositoryContract {
 
     class TestSystem {
         static final Domain DOMAIN = Domain.of("james.org");
+        static final Domain UNKNOW_DOMAIN = Domain.of("unknown.org");
 
         private final boolean supportVirtualHosting;
         private final SimpleDomainList domainList;
@@ -98,6 +102,8 @@ public interface AbstractUsersRepositoryContract {
         private final Username user3;
         private final Username admin;
         private final Username adminCaseVariation;
+        private final Username userWithUnknowDomain;
+        private final Username invalidUsername;
 
         TestSystem(boolean supportVirtualHosting) throws Exception {
             this.supportVirtualHosting = supportVirtualHosting;
@@ -108,14 +114,20 @@ public interface AbstractUsersRepositoryContract {
             user3 = toUsername("username3");
             user1CaseVariation = toUsername("uSeRnaMe");
             admin = toUsername("admin");
-            adminCaseVariation = toUsername("admin");
+            adminCaseVariation = toUsername("adMin");
+            userWithUnknowDomain = toUsername("unknown", UNKNOW_DOMAIN);
+            invalidUsername = toUsername("userContains)*(");
         }
 
         private Username toUsername(String login) {
+            return toUsername(login, DOMAIN);
+        }
+
+        private Username toUsername(String login, Domain domain) {
             if (supportVirtualHosting) {
-                return Username.of(login + '@' + DOMAIN.name());
+                return Username.fromLocalPartWithDomain(login, domain);
             } else {
-                return Username.of(login);
+                return Username.fromLocalPartWithoutDomain(login);
             }
         }
 
@@ -126,467 +138,584 @@ public interface AbstractUsersRepositoryContract {
         public Username getAdmin() {
             return admin;
         }
+
+        public Username getUserWithUnknowDomain() {
+            return userWithUnknowDomain;
+        }
     }
 
-    interface WithVirtualHostingContract extends AbstractUsersRepositoryContract {
+    AbstractUsersRepository testee();
 
+    interface ReadOnlyContract extends AbstractUsersRepositoryContract {
         @Test
-        default void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) throws Exception {
-            testSystem.domainList.addDomain(Domain.of("Domain.OrG"));
-            String username = "myuser";
-            String password = "password";
-            testee().addUser(Username.of(username + "@Domain.OrG"), password);
+        default void countUsersShouldReturnZeroWhenEmptyRepository() throws UsersRepositoryException {
+            //Given
+            int expected = 0;
+            //When
+            int actual = testee().countUsers();
+            //Then
+            assertThat(actual).isEqualTo(expected);
+        }
 
-            boolean actual = testee().test(Username.of(username + "@domain.org"), password);
+        @Test
+        default void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //When
+            Iterator<Username> actual = testee().list();
+            //Then
+            assertThat(actual)
+                .toIterable()
+                .isEmpty();
+        }
 
-            assertThat(actual).isTrue();
+        @Test
+        default void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
+            testee().setAdministratorId(Optional.of(testSystem.admin));
+            assertThat(testee().isAdministrator(testSystem.adminCaseVariation))
+                .isTrue();
         }
 
         @Test
-        default void virtualHostedUsersRepositoryShouldUseFullMailAddressAsUsername() throws Exception {
-            // Some implementations do not support changing virtual hosting value
-            Assumptions.assumeTrue(testee().supportVirtualHosting());
+        default void testShouldReturnFalseWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //When
+            boolean actual = testee().test(testSystem.user1, "password");
+            //Then
+            assertThat(actual).isFalse();
+        }
 
-            assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
+        @ParameterizedTest
+        @MethodSource("illegalCharacters")
+        default void assertValidShouldThrowWhenUsernameLocalPartWithIllegalCharacter(String illegalCharacter) {
+            assertThatThrownBy(() -> testee().assertValid(Username.of("a" + illegalCharacter + "a")))
+                .isInstanceOf(InvalidUsernameException.class);
+        }
+
+        static Stream<Arguments> illegalCharacters() {
+            return Stream.of(
+                "\"",
+                "(",
+                ")",
+                ",",
+                ":",
+                ";",
+                "<",
+                ">",
+                "@",
+                "[",
+                "\\",
+                "]",
+                " ")
+                .map(Arguments::of);
         }
+    }
+
+    interface ReadWriteContract extends AbstractUsersRepositoryContract {
 
         @Test
-        default void getMailAddressForShouldBeIdentityWhenVirtualHosting() throws Exception {
-            // Some implementations do not support changing virtual hosting value
-            Assumptions.assumeTrue(testee().supportVirtualHosting());
+        default void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            List<Username> keys = Arrays.asList(testSystem.user1, testSystem.user2, testSystem.user3);
+            for (Username username : keys) {
+                testee().addUser(username, username.asString());
+            }
+            //When
+            int actual = testee().countUsers();
+            //Then
+            assertThat(actual).isEqualTo(keys.size());
+        }
 
-            String username = "user@domain";
-            assertThat(testee().getMailAddressFor(Username.of(username)))
-                .isEqualTo(username);
+        @Test
+        default void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            List<Username> keys = Arrays.asList(testSystem.user1, testSystem.user2, testSystem.user3);
+            for (Username username : keys) {
+                testee().addUser(username, username.asString());
+            }
+            //When
+            Iterator<Username> actual = testee().list();
+            //Then
+            assertThat(actual)
+                .toIterable()
+                .containsOnly(testSystem.user1, testSystem.user2, testSystem.user3);
         }
 
         @Test
-        default void getUserShouldBeCaseInsensitive() throws Exception {
-            assertThat(testee().getUsername(new MailAddress("lowerUPPER", TestSystem.DOMAIN)))
-                .isEqualTo(Username.fromLocalPartWithDomain("lowerupper", TestSystem.DOMAIN));
+        default void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //When
+            testee().addUser(testSystem.user2, "password2");
+            //Then
+            assertThat(testee().contains(testSystem.user2)).isTrue();
         }
-    }
 
-    interface WithOutVirtualHostingContract extends AbstractUsersRepositoryContract {
         @Test
-        default void nonVirtualHostedUsersRepositoryShouldUseLocalPartAsUsername() throws Exception {
-            // Some implementations do not support changing virtual hosting value
-            Assumptions.assumeFalse(testee().supportVirtualHosting());
+        default void containsShouldPreserveCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1CaseVariation, "password2");
 
-            assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
+            assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
         }
 
         @Test
-        default void getMailAddressForShouldAppendDefaultDomainWhenNoVirtualHosting(TestSystem testSystem) throws Exception {
-            // Some implementations do not support changing virtual hosting value
-            Assumptions.assumeFalse(testee().supportVirtualHosting());
+        default void containsShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1CaseVariation, "password2");
 
-            String username = "user";
-            assertThat(testee().getMailAddressFor(Username.of(username)))
-                .isEqualTo(new MailAddress(username, testSystem.domainList.getDefaultDomain()));
+            assertThat(testee().contains(testSystem.user1)).isTrue();
         }
 
         @Test
-        default void getUserShouldBeCaseInsensitive() throws Exception {
-            assertThat(testee().getUsername(new MailAddress("lowerUPPER", TestSystem.DOMAIN)))
-                .isEqualTo(Username.fromLocalPartWithoutDomain("lowerupper"));
+        default void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1, "password2");
+
+            assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
         }
 
-    }
+        @Test
+        default void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1, "password2");
 
-    AbstractUsersRepository testee();
+            assertThatThrownBy(() -> testee().addUser(testSystem.user1CaseVariation, "pass"))
+                .isInstanceOf(UsersRepositoryException.class);
+        }
 
-    @Test
-    default void countUsersShouldReturnZeroWhenEmptyRepository() throws UsersRepositoryException {
-        //Given
-        int expected = 0;
-        //When
-        int actual = testee().countUsers();
-        //Then
-        assertThat(actual).isEqualTo(expected);
-    }
+        @Test
+        default void addUserShouldDisableCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1CaseVariation, "password2");
 
-    @Test
-    default void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        ArrayList<Username> keys = new ArrayList<>(3);
-        keys.add(testSystem.user1);
-        keys.add(testSystem.user2);
-        keys.add(testSystem.user3);
-        for (Username username : keys) {
-            testee().addUser(username, username.asString());
-        }
-        //When
-        int actual = testee().countUsers();
-        //Then
-        assertThat(actual).isEqualTo(keys.size());
-    }
+            assertThatThrownBy(() -> testee().addUser(testSystem.user1, "pass"))
+                .isInstanceOf(UsersRepositoryException.class);
+        }
 
-    @Test
-    default void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //When
-        Iterator<Username> actual = testee().list();
-        //Then
-        assertThat(actual)
-            .toIterable()
-            .isEmpty();
-    }
+        @Test
+        default void listShouldReturnLowerCaseUser(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1CaseVariation, "password2");
 
-    @Test
-    default void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        ArrayList<Username> keys = new ArrayList<>(3);
-        keys.add(testSystem.user1);
-        keys.add(testSystem.user2);
-        keys.add(testSystem.user3);
-        for (Username username : keys) {
-            testee().addUser(username, username.asString());
-        }
-        //When
-        Iterator<Username> actual = testee().list();
-        //Then
-        assertThat(actual)
-            .toIterable()
-            .containsOnly(testSystem.user1, testSystem.user2, testSystem.user3);
-    }
+            assertThat(testee().list())
+                .toIterable()
+                .containsExactly(testSystem.user1);
+        }
 
-    @Test
-    default void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //When
-        testee().addUser(testSystem.user2, "password2");
-        //Then
-        assertThat(testee().contains(testSystem.user2)).isTrue();
-    }
+        @Test
+        default void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1CaseVariation, "password2");
 
-    @Test
-    default void containsShouldPreserveCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1CaseVariation, "password2");
+            testee().removeUser(testSystem.user1);
 
-        assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
-    }
+            assertThat(testee().list())
+                .toIterable()
+                .isEmpty();
+        }
 
-    @Test
-    default void containsShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1CaseVariation, "password2");
+        @Test
+        default void removeUserShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1, "password2");
 
-        assertThat(testee().contains(testSystem.user1)).isTrue();
-    }
+            testee().removeUser(testSystem.user1CaseVariation);
 
-    @Test
-    default void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1, "password2");
+            assertThat(testee().list())
+                .toIterable()
+                .isEmpty();
+        }
 
-        assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
-    }
+        @Test
+        default void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1, "password2");
 
-    @Test
-    default void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1, "password2");
+            assertThat(testee().getUserByName(testSystem.user1CaseVariation).getUserName())
+                .isEqualTo(testSystem.user1);
+        }
 
-        assertThatThrownBy(() -> testee().addUser(testSystem.user1CaseVariation, "pass"))
-            .isInstanceOf(UsersRepositoryException.class);
-    }
+        @Test
+        default void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) throws UsersRepositoryException {
+            testee().addUser(testSystem.user1CaseVariation, "password2");
 
-    @Test
-    default void addUserShouldDisableCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1CaseVariation, "password2");
+            assertThat(testee().getUserByName(testSystem.user1).getUserName())
+                .isEqualTo(testSystem.user1);
+        }
 
-        assertThatThrownBy(() -> testee().addUser(testSystem.user1, "pass"))
-            .isInstanceOf(UsersRepositoryException.class);
-    }
 
-    @Test
-    default void listShouldReturnLowerCaseUser(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1CaseVariation, "password2");
+        @Test
+        default void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
+            String password = "password2";
+            testee().addUser(testSystem.user1CaseVariation, password);
 
-        assertThat(testee().list())
-            .toIterable()
-            .containsExactly(testSystem.user1);
-    }
+            assertThat(testee().test(testSystem.user1, password))
+                .isTrue();
+        }
 
-    @Test
-    default void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1CaseVariation, "password2");
+        @Test
+        default void testShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+            String password = "password2";
+            testee().addUser(testSystem.user1, password);
 
-        testee().removeUser(testSystem.user1);
+            assertThat(testee().test(testSystem.user1CaseVariation, password))
+                .isTrue();
+        }
 
-        assertThat(testee().list())
-            .toIterable()
-            .isEmpty();
-    }
+        @Test
+        default void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user2, "password2");
+            //When
+            testee().addUser(testSystem.user3, "password3");
+            //Then
+            assertThat(testee().contains(testSystem.user3)).isTrue();
+        }
 
-    @Test
-    default void removeUserShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1, "password2");
+        @Test
+        default void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.toUsername("myUsername"), "password");
+            //When
+            assertThatThrownBy(() -> testee().addUser(testSystem.toUsername("MyUsername"), "password"))
+                .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
+        }
 
-        testee().removeUser(testSystem.user1CaseVariation);
+        @Test
+        default void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            //When
+            assertThatThrownBy(() -> testee().addUser(testSystem.user1, "password2"))
+                .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
+        }
 
-        assertThat(testee().list())
-            .toIterable()
-            .isEmpty();
-    }
+        @Test
+        default void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            //When
+            User actual = testee().getUserByName(testSystem.user1);
+            //Then
+            assertThat(actual).isNotNull();
+            assertThat(actual.getUserName()).isEqualTo(testSystem.user1);
+        }
 
-    @Test
-    default void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1, "password2");
+        @Test
+        default void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.toUsername("username"), "password");
+            //When
+            User actual = testee().getUserByName(testSystem.toUsername("uSERNAMe"));
+            //Then
+            assertThat(actual).isNotNull();
+            assertThat(actual.getUserName()).isEqualTo(testSystem.user1);
+        }
 
-        assertThat(testee().getUserByName(testSystem.user1CaseVariation).getUserName())
-            .isEqualTo(testSystem.user1);
-    }
+        @Test
+        default void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            //When
+            boolean actual = testee().test(testSystem.user1, "password");
+            //Then
+            assertThat(actual).isTrue();
+        }
 
-    @Test
-    default void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) throws UsersRepositoryException {
-        testee().addUser(testSystem.user1CaseVariation, "password2");
+        @Test
+        default void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            //When
+            boolean actual = testee().test(testSystem.user1, "password2");
+            //Then
+            assertThat(actual).isFalse();
+        }
 
-        assertThat(testee().getUserByName(testSystem.user1).getUserName())
-            .isEqualTo(testSystem.user1);
-    }
+        @Test
+        default void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            //When
+            boolean actual = testee().test(testSystem.user1, "Password");
+            //Then
+            assertThat(actual).isFalse();
+        }
 
-    @Test
-    default void getUserShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
-        assertThat(testee().getUsername(testSystem.user1CaseVariation.asMailAddress()))
-            .isEqualTo(testSystem.user1);
-    }
+        @Test
+        default void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.toUsername("username"), "password");
+            //When
+            boolean actual = testee().test(testSystem.toUsername("username2"), "password");
+            //Then
+            assertThat(actual).isFalse();
+        }
 
-    @Test
-    default void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
-        testee().setAdministratorId(Optional.of(testSystem.admin));
-        assertThat(testee().isAdministrator(testSystem.adminCaseVariation))
-            .isTrue();
-    }
+        @Test
+        default void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.toUsername("username"), "password");
+            //When
+            boolean actual = testee().test(testSystem.toUsername("userName"), "password");
+            //Then
+            assertThat(actual).isTrue();
+        }
 
-    @Test
-    default void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
-        String password = "password2";
-        testee().addUser(testSystem.user1CaseVariation, password);
 
-        assertThat(testee().test(testSystem.user1, password))
-            .isTrue();
-    }
+        @Test
+        default void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            testee().removeUser(testSystem.user1);
+            //When
+            boolean actual = testee().test(testSystem.user1, "password");
+            //Then
+            assertThat(actual).isFalse();
+        }
 
-    @Test
-    default void testShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
-        String password = "password2";
-        testee().addUser(testSystem.user1, password);
+        @Test
+        default void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            //When
+            testee().removeUser(testSystem.user1);
+            //Then
+            assertThat(testee().contains(testSystem.user1)).isFalse();
+        }
 
-        assertThat(testee().test(testSystem.user1CaseVariation, password))
-            .isTrue();
-    }
+        @Test
+        default void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            User user = testee().getUserByName(testSystem.user1);
+            user.setPassword("newpass");
+            //When
+            testee().updateUser(user);
+            //Then
+            assertThat(testee().test(testSystem.user1, "newpass")).isTrue();
+        }
 
-    @Test
-    default void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user2, "password2");
-        //When
-        testee().addUser(testSystem.user3, "password3");
-        //Then
-        assertThat(testee().contains(testSystem.user3)).isTrue();
-    }
+        @Test
+        default void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            User user = testee().getUserByName(testSystem.user1);
+            user.setPassword("newpass");
+            //When
+            testee().updateUser(user);
+            //Then
+            assertThat(testee().test(testSystem.user1, "password")).isFalse();
+        }
 
-    @Test
-    default void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.toUsername("myUsername"), "password");
-        //When
-        assertThatThrownBy(() -> testee().addUser(testSystem.toUsername("MyUsername"), "password"))
-            .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
-    }
+        @Test
+        default void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) throws UsersRepositoryException {
+            //Given
+            testee().addUser(testSystem.user1, "password");
+            User user = testee().getUserByName(testSystem.user1);
+            testee().removeUser(testSystem.user1);
+            //When
+            assertThatThrownBy(() -> testee().updateUser(user))
+                .isInstanceOf(UsersRepositoryException.class);
+        }
 
-    @Test
-    default void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        //When
-        assertThatThrownBy(() -> testee().addUser(testSystem.user1, "password2"))
-            .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
-    }
+        @Test
+        default void removeUserShouldThrowWhenUserNotInRepository(TestSystem testSystem) {
+            //When
+            assertThatThrownBy(() -> testee().removeUser(testSystem.user1))
+                .isInstanceOf(UsersRepositoryException.class);
+        }
 
-    @Test
-    default void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        //When
-        User actual = testee().getUserByName(testSystem.user1);
-        //Then
-        assertThat(actual).isNotNull();
-        assertThat(actual.getUserName()).isEqualTo(testSystem.user1);
-    }
+        @Test
+        default void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
+            testee().setAdministratorId(Optional.empty());
 
-    @Test
-    default void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.toUsername("username"), "password");
-        //When
-        User actual = testee().getUserByName(testSystem.toUsername("uSERNAMe"));
-        //Then
-        assertThat(actual).isNotNull();
-        assertThat(actual.getUserName()).isEqualTo(testSystem.user1);
-    }
+            assertThat(testee().isAdministrator(testSystem.admin)).isFalse();
+        }
 
-    @Test
-    default void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        //When
-        boolean actual = testee().test(testSystem.user1, "password");
-        //Then
-        assertThat(actual).isTrue();
-    }
+        @Test
+        default void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
+            testee().setAdministratorId(Optional.of(testSystem.admin));
 
-    @Test
-    default void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        //When
-        boolean actual = testee().test(testSystem.user1, "password2");
-        //Then
-        assertThat(actual).isFalse();
-    }
+            assertThat(testee().isAdministrator(testSystem.admin)).isTrue();
+        }
 
-    @Test
-    default void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        //When
-        boolean actual = testee().test(testSystem.user1, "Password");
-        //Then
-        assertThat(actual).isFalse();
-    }
+        @Test
+        default void isAdministratorShouldReturnFalseWhenConfiguredAndUserIsNotAdmin(TestSystem testSystem) throws Exception {
+            testee().setAdministratorId(Optional.of(testSystem.admin));
 
-    @Test
-    default void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.toUsername("username"), "password");
-        //When
-        boolean actual = testee().test(testSystem.toUsername("username2"), "password");
-        //Then
-        assertThat(actual).isFalse();
+            assertThat(testee().isAdministrator(testSystem.user1)).isFalse();
+        }
     }
 
-    @Test
-    default void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.toUsername("username"), "password");
-        //When
-        boolean actual = testee().test(testSystem.toUsername("userName"), "password");
-        //Then
-        assertThat(actual).isTrue();
-    }
+    interface WithVirtualHostingReadWriteContract extends ReadWriteContract {
 
-    @Test
-    default void testShouldReturnFalseWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //When
-        boolean actual = testee().test(testSystem.user1, "password");
-        //Then
-        assertThat(actual).isFalse();
-    }
+        @Test
+        default void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) throws Exception {
+            testSystem.domainList.addDomain(Domain.of("Domain.OrG"));
+            String username = "myuser";
+            String password = "password";
+            testee().addUser(Username.of(username + "@Domain.OrG"), password);
 
-    @Test
-    default void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        testee().removeUser(testSystem.user1);
-        //When
-        boolean actual = testee().test(testSystem.user1, "password");
-        //Then
-        assertThat(actual).isFalse();
-    }
+            boolean actual = testee().test(Username.of(username + "@domain.org"), password);
 
-    @Test
-    default void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        //When
-        testee().removeUser(testSystem.user1);
-        //Then
-        assertThat(testee().contains(testSystem.user1)).isFalse();
-    }
+            assertThat(actual).isTrue();
+        }
 
-    @Test
-    default void removeUserShouldThrowWhenUserNotInRepository(TestSystem testSystem) {
-        //When
-        assertThatThrownBy(() -> testee().removeUser(testSystem.user1))
-            .isInstanceOf(UsersRepositoryException.class);
-    }
+        @Test
+        default void addUserShouldThrowWhenUserDoesNotBelongToDomainList(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().addUser(testSystem.userWithUnknowDomain, "password"))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessage("Domain does not exist in DomainList");
+        }
 
-    @Test
-    default void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        User user = testee().getUserByName(testSystem.user1);
-        user.setPassword("newpass");
-        //When
-        testee().updateUser(user);
-        //Then
-        assertThat(testee().test(testSystem.user1, "newpass")).isTrue();
-    }
+        @Test
+        default void addUserShouldThrowWhenInvalidUser(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().addUser(testSystem.invalidUsername, "password"))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessageContaining("should not contain any of those characters");
+        }
 
-    @Test
-    default void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        User user = testee().getUserByName(testSystem.user1);
-        user.setPassword("newpass");
-        //When
-        testee().updateUser(user);
-        //Then
-        assertThat(testee().test(testSystem.user1, "password")).isFalse();
-    }
+        @Test
+        default void updateUserShouldThrowWhenUserDoesNotBelongToDomainList(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().updateUser(new DefaultUser(testSystem.userWithUnknowDomain, "hasAlg")))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessage("Domain does not exist in DomainList");
+        }
 
-    @Test
-    default void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) throws UsersRepositoryException {
-        //Given
-        testee().addUser(testSystem.user1, "password");
-        User user = testee().getUserByName(testSystem.user1);
-        testee().removeUser(testSystem.user1);
-        //When
-        assertThatThrownBy(() -> testee().updateUser(user))
-            .isInstanceOf(UsersRepositoryException.class);
-    }
+        @Test
+        default void updateUserShouldNotThrowInvalidUsernameExceptionWhenInvalidUser(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().updateUser(new DefaultUser(testSystem.invalidUsername, "hasAlg")))
+                .isNotInstanceOf(InvalidUsernameException.class);
+        }
 
-    @Test
-    default void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
-        testee().setAdministratorId(Optional.empty());
+        @Test
+        default void removeUserShouldThrowWhenUserDoesNotBelongToDomainList(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().removeUser(testSystem.userWithUnknowDomain))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessage("Domain does not exist in DomainList");
+        }
 
-        assertThat(testee().isAdministrator(testSystem.admin)).isFalse();
+        @Test
+        default void removeUserShouldNotThrowInvalidUsernameExceptionWhenInvalidUser(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().removeUser(testSystem.invalidUsername))
+                .isNotInstanceOf(InvalidUsernameException.class);
+        }
     }
 
-    @Test
-    default void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
-        testee().setAdministratorId(Optional.of(testSystem.admin));
+    interface WithVirtualHostingReadOnlyContract extends ReadOnlyContract {
+
+        @Test
+        default void getUserByNameShouldNotThrowWhenUserDoesNotBelongToDomainList(TestSystem testSystem) {
+            assertThatCode(() -> testee().getUserByName(testSystem.userWithUnknowDomain))
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void containsShouldNotThrowWhenUserDoesNotBelongToDomainList(TestSystem testSystem) {
+            assertThatCode(() -> testee().contains(testSystem.userWithUnknowDomain))
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void testShouldNotThrowWhenUserDoesNotBelongToDomainList(TestSystem testSystem) {
+            assertThatCode(() -> testee().test(testSystem.userWithUnknowDomain, "password"))
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        default void isAdministratorShouldThrowWhenUserDoesNotBelongToDomainList(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().isAdministrator(testSystem.userWithUnknowDomain))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessage("Domain does not exist in DomainList");
+        }
+
+        @Test
+        default void virtualHostedUsersRepositoryShouldUseFullMailAddressAsUsername() throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeTrue(testee().supportVirtualHosting());
+
+            assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
+        }
+
+        @Test
+        default void getMailAddressForShouldBeIdentityWhenVirtualHosting() throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeTrue(testee().supportVirtualHosting());
+
+            String username = "user@domain";
+            assertThat(testee().getMailAddressFor(Username.of(username)))
+                .isEqualTo(username);
+        }
+
+        @Test
+        default void getUserShouldBeCaseInsensitive() throws Exception {
+            assertThat(testee().getUsername(new MailAddress("lowerUPPER", TestSystem.DOMAIN)))
+                .isEqualTo(Username.fromLocalPartWithDomain("lowerupper", TestSystem.DOMAIN));
+        }
+
+        @Test
+        default void assertDomainPartValidShouldThrowWhenDomainPartIsMissing() throws Exception {
+            Username withoutDomainPart = Username.fromLocalPartWithoutDomain("localPartOnly");
+
+            assertThatThrownBy(() -> testee().assertDomainPartValid(withoutDomainPart))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessage("Given Username needs to contain a @domainpart");
+        }
+
+        @Test
+        default void assertDomainPartValidShouldThrowWhenDomainPartIsNotManaged(TestSystem testSystem) {
+            assertThatThrownBy(() -> testee().assertDomainPartValid(testSystem.userWithUnknowDomain))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessage("Domain does not exist in DomainList");
+        }
+
+        @Test
+        default void assertDomainPartValidShouldNotThrowWhenDomainPartIsManaged() {
+            Username userWithManagedDomain = Username.fromLocalPartWithDomain(
+                "localPart",
+                TestSystem.DOMAIN);
 
-        assertThat(testee().isAdministrator(testSystem.admin)).isTrue();
+            assertThatCode(() -> testee().assertDomainPartValid(userWithManagedDomain))
+                .doesNotThrowAnyException();
+        }
     }
 
-    @Test
-    default void isAdministratorShouldReturnFalseWhenConfiguredAndUserIsNotAdmin(TestSystem testSystem) throws Exception {
-        testee().setAdministratorId(Optional.of(testSystem.admin));
+    interface WithOutVirtualHostingReadOnlyContract extends ReadOnlyContract {
+        @Test
+        default void nonVirtualHostedUsersRepositoryShouldUseLocalPartAsUsername() throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeFalse(testee().supportVirtualHosting());
+
+            assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
+        }
+
+        @Test
+        default void getMailAddressForShouldAppendDefaultDomainWhenNoVirtualHosting(TestSystem testSystem) throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeFalse(testee().supportVirtualHosting());
+
+            String username = "user";
+            assertThat(testee().getMailAddressFor(Username.of(username)))
+                .isEqualTo(new MailAddress(username, testSystem.domainList.getDefaultDomain()));
+        }
+
+        @Test
+        default void getUserShouldBeCaseInsensitive() throws Exception {
+            assertThat(testee().getUsername(new MailAddress("lowerUPPER", TestSystem.DOMAIN)))
+                .isEqualTo(Username.fromLocalPartWithoutDomain("lowerupper"));
+        }
+
+        @Test
+        default void assertDomainPartValidShouldThrowWhenDomainPartIsPresent() {
+            Username withDomainPart = Username.fromLocalPartWithDomain(
+                "localPart",
+                TestSystem.DOMAIN);
+
+            assertThatThrownBy(() -> testee().assertDomainPartValid(withDomainPart))
+                .isInstanceOf(InvalidUsernameException.class)
+                .hasMessage("Given Username contains a @domainpart but virtualhosting support is disabled");
+        }
 
-        assertThat(testee().isAdministrator(testSystem.user1)).isFalse();
+        @Test
+        default void assertDomainPartValidShouldNotThrowWhenDomainPartIsMissing() {
+            Username withOutDomainPart = Username.fromLocalPartWithoutDomain("localPartOnly");
+
+            assertThatCode(() -> testee().assertDomainPartValid(withOutDomainPart))
+                .doesNotThrowAnyException();
+        }
     }
 
-    @ParameterizedTest
-    @MethodSource("illegalCharacters")
-    default void assertValidShouldThrowWhenUsernameLocalPartWithIllegalCharacter(String illegalCharacter) {
-        assertThatThrownBy(() -> testee().assertValid(Username.of("a" + illegalCharacter + "a")))
-            .isInstanceOf(InvalidUsernameException.class);
+    interface WithVirtualHostingContract extends WithVirtualHostingReadOnlyContract, WithVirtualHostingReadWriteContract {
     }
 
-    static Stream<Arguments> illegalCharacters() {
-        return Stream.of(
-            "\"",
-            "(",
-            ")",
-            ",",
-            ":",
-            ";",
-            "<",
-            ">",
-            "@",
-            "[",
-            "\\",
-            "]",
-            " ")
-            .map(Arguments::of);
+    interface WithOutVirtualHostingContract extends WithOutVirtualHostingReadOnlyContract, ReadWriteContract {
     }
 }
diff --git a/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java b/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java
index 2853514..b80c387 100644
--- a/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java
+++ b/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java
@@ -81,6 +81,8 @@ public class MemoryUsersRepository extends AbstractUsersRepository {
 
     @Override
     public void updateUser(User user) throws UsersRepositoryException {
+        assertDomainPartValid(user.getUserName());
+
         User existingUser = getUserByName(user.getUserName());
         if (existingUser == null) {
             throw new UsersRepositoryException("Please provide an existing user to update");
@@ -90,6 +92,8 @@ public class MemoryUsersRepository extends AbstractUsersRepository {
 
     @Override
     public void removeUser(Username name) throws UsersRepositoryException {
+        assertDomainPartValid(name);
+
         if (userByName.remove(name.asString()) == null) {
             throw new UsersRepositoryException("unable to remove unknown user " + name.asString());
         }
diff --git a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
index cbae5da..894f7b4 100644
--- a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
+++ b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
@@ -36,6 +36,9 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 
 class MemoryUsersRepositoryTest {
 
+    private static final String LOCALHOST = "localhost";
+    private static final String LOCALHOST_ADDRESS = "127.0.0.1";
+
     @Nested
     class WhenEnableVirtualHosting implements AbstractUsersRepositoryContract.WithVirtualHostingContract {
         @RegisterExtension
@@ -62,8 +65,8 @@ class MemoryUsersRepositoryTest {
         @Test
         void assertValidShouldNotThrowWhenDomainPartAndVirtualHosting() throws Exception {
             MemoryDomainList domainList = new MemoryDomainList(new InMemoryDNSService()
-                .registerMxRecord("localhost", "127.0.0.1")
-                .registerMxRecord("127.0.0.1", "127.0.0.1"));
+                .registerMxRecord(LOCALHOST, LOCALHOST_ADDRESS)
+                .registerMxRecord(LOCALHOST_ADDRESS, LOCALHOST_ADDRESS));
             domainList.setAutoDetect(false);
             domainList.setAutoDetectIP(false);
             domainList.addDomain(Domain.of("domain.tld"));
@@ -77,8 +80,8 @@ class MemoryUsersRepositoryTest {
         @Test
         void assertValidShouldNotThrowWhenDomainPartAndDomainNotFound() throws Exception {
             MemoryDomainList domainList = new MemoryDomainList(new InMemoryDNSService()
-                .registerMxRecord("localhost", "127.0.0.1")
-                .registerMxRecord("127.0.0.1", "127.0.0.1"));
+                .registerMxRecord(LOCALHOST, LOCALHOST_ADDRESS)
+                .registerMxRecord(LOCALHOST_ADDRESS, LOCALHOST_ADDRESS));
             domainList.setAutoDetect(false);
             domainList.setAutoDetectIP(false);
 
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/AliasRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/AliasRoutesTest.java
index 2d29cfd..d17afd2 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/AliasRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/AliasRoutesTest.java
@@ -35,7 +35,6 @@ import static org.mockito.Mockito.spy;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.core.Domain;
 import org.apache.james.core.Username;
 import org.apache.james.dnsservice.api.DNSService;
@@ -119,7 +118,6 @@ class AliasRoutesTest {
             memoryRecipientRewriteTable.setDomainList(domainList);
 
             usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
-            usersRepository.configure(new BaseHierarchicalConfiguration());
 
             usersRepository.addUser(Username.of(BOB), BOB_PASSWORD);
             usersRepository.addUser(Username.of(BOB_WITH_SLASH), BOB_WITH_SLASH_PASSWORD);
diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/ForwardRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/ForwardRoutesTest.java
index bcecf27..8425f92 100644
--- a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/ForwardRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/ForwardRoutesTest.java
@@ -36,7 +36,6 @@ import static org.mockito.Mockito.spy;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.core.Domain;
 import org.apache.james.core.Username;
 import org.apache.james.dnsservice.api.DNSService;
@@ -118,7 +117,6 @@ class ForwardRoutesTest {
             MappingSourceModule mappingSourceModule = new MappingSourceModule();
 
             usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
-            usersRepository.configure(new BaseHierarchicalConfiguration());
 
             usersRepository.addUser(Username.of(BOB), BOB_PASSWORD);
             usersRepository.addUser(Username.of(ALICE), ALICE_PASSWORD);
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java
index 50a0cec..5990161 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/test/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutesTest.java
@@ -71,7 +71,6 @@ import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
 
-import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.blob.api.BlobId;
 import org.apache.james.blob.api.BucketName;
 import org.apache.james.blob.api.HashBlobId;
@@ -129,6 +128,7 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 
 import com.google.common.collect.ImmutableList;
+
 import io.restassured.RestAssured;
 import io.restassured.filter.log.LogDetail;
 import reactor.core.publisher.Flux;
@@ -211,7 +211,6 @@ class DeletedMessagesVaultRoutesTest {
         domainList.addDomain(DOMAIN);
 
         MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
-        usersRepository.configure(new BaseHierarchicalConfiguration());
 
         usersRepository.addUser(USERNAME, "userPassword");
 


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 06/16: JAMES-3088 Migrate JpaUsersRepositoryTest

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit d9944148fb5f473cbe733e6cd6f4a18aba37b08b
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 11:55:36 2020 +0700

    JAMES-3088 Migrate JpaUsersRepositoryTest
---
 .../james/user/jpa/JpaUsersRepositoryTest.java     | 52 +++++++++++++++++-----
 1 file changed, 42 insertions(+), 10 deletions(-)

diff --git a/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java b/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
index 6c44c6e..b912d30 100644
--- a/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
+++ b/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
@@ -20,33 +20,65 @@ package org.apache.james.user.jpa;
 
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.backends.jpa.JpaTestCluster;
+import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.user.jpa.model.JPAUser;
 import org.apache.james.user.lib.AbstractUsersRepository;
 import org.apache.james.user.lib.AbstractUsersRepositoryTest;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-class JpaUsersRepositoryTest extends AbstractUsersRepositoryTest {
+class JpaUsersRepositoryTest {
 
-    static final JpaTestCluster JPA_TEST_CLUSTER = JpaTestCluster.create(JPAUser.class);
+    private static final JpaTestCluster JPA_TEST_CLUSTER = JpaTestCluster.create(JPAUser.class);
 
-    @BeforeEach
-    void setup() throws Exception {
-        super.setUp();
+    @Nested
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryTest.WithVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
+
+        private JPAUsersRepository usersRepository;
+
+        @BeforeEach
+        void setUp(TestSystem testSystem) throws Exception {
+            usersRepository = getUsersRepository(testSystem.getDomainList(), extension.isSupportVirtualHosting());
+        }
+
+        @Override
+        public AbstractUsersRepository testee() {
+            return usersRepository;
+        }
+    }
+
+    @Nested
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryTest.WithOutVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
+
+        private JPAUsersRepository usersRepository;
+
+        @BeforeEach
+        void setUp(TestSystem testSystem) throws Exception {
+            usersRepository = getUsersRepository(testSystem.getDomainList(), extension.isSupportVirtualHosting());
+        }
+
+        @Override
+        public AbstractUsersRepository testee() {
+            return usersRepository;
+        }
     }
 
     @AfterEach
-    void teardown() throws Exception {
-        super.tearDown();
+    void tearDown() {
         JPA_TEST_CLUSTER.clear("JAMES_USER");
     }
 
-    @Override
-    protected AbstractUsersRepository getUsersRepository() throws Exception {
+    private static JPAUsersRepository getUsersRepository(DomainList domainList, boolean enableVirtualHosting) throws Exception {
         JPAUsersRepository repos = new JPAUsersRepository(domainList);
         repos.setEntityManagerFactory(JPA_TEST_CLUSTER.getEntityManagerFactory());
         BaseHierarchicalConfiguration configuration = new BaseHierarchicalConfiguration();
-        configuration.addProperty("enableVirtualHosting", "true");
+        configuration.addProperty("enableVirtualHosting", String.valueOf(enableVirtualHosting));
         repos.configure(configuration);
         return repos;
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 13/16: JAMES-3087 Reactify MailboxManager::mailboxExist

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit aa380531071d6b6149ad06af625b41886f5c2e35
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Mar 22 17:46:02 2020 +0700

    JAMES-3087 Reactify MailboxManager::mailboxExist
    
    The happy path scenario of DefaultMailboxesReactiveProvisioner is then
    fully reactive.
---
 .../org/apache/james/mailbox/MailboxManager.java   |  7 ++--
 .../apache/james/mailbox/MailboxManagerTest.java   | 38 +++++++++++-----------
 .../james/mailbox/store/StoreMailboxManager.java   | 15 +++++----
 .../imap/processor/AbstractAuthProcessor.java      |  4 ++-
 .../processor/AbstractMessageRangeProcessor.java   |  4 ++-
 .../james/imap/processor/RenameProcessor.java      |  4 ++-
 .../james/imap/processor/CopyProcessorTest.java    |  8 +++--
 .../james/imap/processor/MoveProcessorTest.java    |  8 +++--
 .../mailets/delivery/MailboxAppender.java          |  4 ++-
 .../mailets/delivery/LocalDeliveryTest.java        |  3 ++
 .../mailets/delivery/ToRecipientFolderTest.java    |  3 ++
 .../http/DefaultMailboxesReactiveProvisioner.java  | 37 ++++++++++-----------
 ...aultMailboxesReactiveProvisionerThreadTest.java |  4 ++-
 .../hook/MailboxDeliverToRecipientHandler.java     |  4 ++-
 .../james/pop3server/core/PassCmdHandler.java      |  4 ++-
 .../apache/james/pop3server/POP3ServerTest.java    | 10 +++---
 .../webadmin/service/UserMailboxesService.java     |  7 ++--
 .../webadmin/routes/UserMailboxesRoutesTest.java   |  6 ++--
 18 files changed, 100 insertions(+), 70 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
index 782aeb1..6b83d9f 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
@@ -34,6 +34,7 @@ import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.MessageRange;
 import org.apache.james.mailbox.model.MultimailboxesSearchQuery;
 import org.apache.james.mailbox.model.search.MailboxQuery;
+import org.reactivestreams.Publisher;
 
 /**
  * <p>
@@ -259,10 +260,10 @@ public interface MailboxManager extends RequestAware, RightManager, MailboxAnnot
      *            not null
      * @param session
      *            the context for this call, not null
-     * @return true when the mailbox exists and is accessible for the given
+     * @return A publisher holding true when the mailbox exists and is accessible for the given
      *            user, false otherwise
      */
-    boolean mailboxExists(MailboxPath mailboxPath, MailboxSession session) throws MailboxException;
+    Publisher<Boolean> mailboxExists(MailboxPath mailboxPath, MailboxSession session) throws MailboxException;
 
     /**
      * Does the user INBOX exist?
@@ -272,7 +273,7 @@ public interface MailboxManager extends RequestAware, RightManager, MailboxAnnot
      * @return true when the INBOX exists and is accessible for the given
      *            user, false otherwise
      */
-    default boolean hasInbox(MailboxSession session) throws MailboxException {
+    default Publisher<Boolean> hasInbox(MailboxSession session) throws MailboxException {
         return mailboxExists(MailboxPath.inbox(session), session);
     }
 
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index 04f7918..5397ed9 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -182,7 +182,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             session = mailboxManager.createSystemSession(USER_1);
             mailboxManager.startProcessingRequest(session);
 
-            assertThat(mailboxManager.hasInbox(session)).isFalse();
+            assertThat(Mono.from(mailboxManager.hasInbox(session)).block()).isFalse();
         }
 
         @Test
@@ -194,7 +194,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath, session);
             MessageManager retrievedMailbox = mailboxManager.getMailbox(mailboxPath, session);
 
-            assertThat(mailboxManager.hasInbox(session)).isTrue();
+            assertThat(Mono.from(mailboxManager.hasInbox(session)).block()).isTrue();
             assertThat(mailboxId.get()).isEqualTo(retrievedMailbox.getId());
         }
 
@@ -206,7 +206,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             Optional<MailboxId> mailboxId = mailboxManager.createMailbox(MailboxPath.forUser(USER_1, "iNbOx"), session);
             MessageManager retrievedMailbox = mailboxManager.getMailbox(MailboxPath.inbox(session), session);
 
-            assertThat(mailboxManager.hasInbox(session)).isTrue();
+            assertThat(Mono.from(mailboxManager.hasInbox(session)).block()).isTrue();
             assertThat(mailboxId.get()).isEqualTo(retrievedMailbox.getId());
         }
 
@@ -242,7 +242,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             Optional<MailboxId> mailboxId = mailboxManager.createMailbox(MailboxPath.forUser(USER_1, "iNbOx.submailbox"), session);
             MessageManager retrievedMailbox = mailboxManager.getMailbox(MailboxPath.inbox(session), session);
 
-            assertThat(mailboxManager.hasInbox(session)).isTrue();
+            assertThat(Mono.from(mailboxManager.hasInbox(session)).block()).isTrue();
         }
 
         @Test
@@ -254,7 +254,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             Optional<MailboxId> mailboxId = mailboxManager.createMailbox(childPath, session);
             MessageManager retrievedMailbox = mailboxManager.getMailbox(childPath, session);
 
-            assertThat(mailboxManager.hasInbox(session)).isTrue();
+            assertThat(Mono.from(mailboxManager.hasInbox(session)).block()).isTrue();
             assertThat(mailboxId.get()).isEqualTo(retrievedMailbox.getId());
         }
     }
@@ -1524,7 +1524,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             mailboxManager.startProcessingRequest(session);
 
             MailboxPath inbox = MailboxPath.inbox(session);
-            assertThat(mailboxManager.mailboxExists(inbox, session)).isFalse();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inbox, session)).block()).isFalse();
         }
 
         @Test
@@ -1535,7 +1535,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             MailboxPath inbox = MailboxPath.inbox(session);
             mailboxManager.createMailbox(inbox, session);
 
-            assertThat(mailboxManager.mailboxExists(inbox, session)).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inbox, session)).block()).isTrue();
         }
 
         @Test
@@ -1661,7 +1661,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             MailboxPath inbox = MailboxPath.inbox(session);
             mailboxManager.createMailbox(inbox, session);
 
-            assertThat(mailboxManager.mailboxExists(new MailboxPath(inbox, "INBOX.Test"), session)).isFalse();
+            assertThat(Mono.from(mailboxManager.mailboxExists(new MailboxPath(inbox, "INBOX.Test"), session)).block()).isFalse();
         }
 
         @Test
@@ -1674,7 +1674,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             MailboxPath inboxSubMailbox = new MailboxPath(inbox, "INBOX.Test");
             mailboxManager.createMailbox(inboxSubMailbox, session);
 
-            assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inboxSubMailbox, session)).block()).isTrue();
         }
 
         @Test
@@ -1689,8 +1689,8 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
 
             mailboxManager.deleteMailbox(inbox, session);
 
-            assertThat(mailboxManager.mailboxExists(inbox, session)).isFalse();
-            assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inbox, session)).block()).isFalse();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inboxSubMailbox, session)).block()).isTrue();
         }
 
 
@@ -1706,8 +1706,8 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
 
             mailboxManager.deleteMailbox(inboxId, session);
 
-            assertThat(mailboxManager.mailboxExists(inbox, session)).isFalse();
-            assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inbox, session)).block()).isFalse();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inboxSubMailbox, session)).block()).isTrue();
         }
 
         @Test
@@ -1747,8 +1747,8 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
 
             mailboxManager.deleteMailbox(inboxSubMailbox, session);
 
-            assertThat(mailboxManager.mailboxExists(inbox, session)).isTrue();
-            assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isFalse();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inbox, session)).block()).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inboxSubMailbox, session)).block()).isFalse();
         }
 
         @Test
@@ -1763,8 +1763,8 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
 
             mailboxManager.deleteMailbox(inboxSubMailboxId, session);
 
-            assertThat(mailboxManager.mailboxExists(inbox, session)).isTrue();
-            assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isFalse();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inbox, session)).block()).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(inboxSubMailbox, session)).block()).isFalse();
         }
 
         @Test
@@ -1791,7 +1791,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             MailboxPath trash = MailboxPath.forUser(USER_2, "Trash");
             mailboxManager.createMailbox(trash, session);
 
-            assertThat(mailboxManager.mailboxExists(trash, session)).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(trash, session)).block()).isTrue();
         }
 
         @Test
@@ -1800,7 +1800,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
             MailboxPath nestedFolder = MailboxPath.forUser(USER_2, "INBOX.testfolder");
             mailboxManager.createMailbox(nestedFolder, session);
 
-            assertThat(mailboxManager.mailboxExists(nestedFolder, session)).isTrue();
+            assertThat(Mono.from(mailboxManager.mailboxExists(nestedFolder, session)).block()).isTrue();
             mailboxManager.getMailbox(MailboxPath.inbox(session), session)
                 .appendMessage(AppendCommand.from(message), session);
         }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index 2854449..6cb08a8 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -93,6 +93,8 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
+import reactor.core.publisher.Mono;
+
 /**
  * This base class of an {@link MailboxManager} implementation provides a high-level api for writing your own
  * {@link MailboxManager} implementation. If you plan to write your own {@link MailboxManager} its most times so easiest
@@ -318,7 +320,7 @@ public class StoreMailboxManager implements MailboxManager {
             MailboxPath sanitizedMailboxPath = mailboxPath.sanitize(mailboxSession.getPathDelimiter());
             sanitizedMailboxPath.assertAcceptable(mailboxSession.getPathDelimiter());
 
-            if (mailboxExists(sanitizedMailboxPath, mailboxSession)) {
+            if (mailboxExists(sanitizedMailboxPath, mailboxSession).block()) {
                 throw new MailboxExistsException(sanitizedMailboxPath.asString());
             }
 
@@ -346,7 +348,7 @@ public class StoreMailboxManager implements MailboxManager {
 
     private Stream<MailboxId> manageMailboxCreation(MailboxSession mailboxSession, boolean isRootPath, MailboxPath mailboxPath) throws MailboxException {
         if (mailboxPath.isInbox()) {
-            if (hasInbox(mailboxSession)) {
+            if (Mono.from(hasInbox(mailboxSession)).block()) {
                 return duplicatedINBOXCreation(isRootPath, mailboxPath);
             }
 
@@ -368,7 +370,7 @@ public class StoreMailboxManager implements MailboxManager {
     private List<MailboxId> performConcurrentMailboxCreation(MailboxSession mailboxSession, MailboxPath mailboxPath) throws MailboxException {
         List<MailboxId> mailboxIds = new ArrayList<>();
         locker.executeWithLock(mailboxPath, (LockAwareExecution<Void>) () -> {
-            if (!mailboxExists(mailboxPath, mailboxSession)) {
+            if (!mailboxExists(mailboxPath, mailboxSession).block()) {
                 MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession);
                 try {
                     mapper.execute(Mapper.toTransaction(() -> {
@@ -494,7 +496,7 @@ public class StoreMailboxManager implements MailboxManager {
     }
 
     private void validateDestinationPath(MailboxPath newMailboxPath, MailboxSession session) throws MailboxException {
-        if (mailboxExists(newMailboxPath, session)) {
+        if (mailboxExists(newMailboxPath, session).block()) {
             throw new MailboxExistsException(newMailboxPath.toString());
         }
         assertIsOwner(session, newMailboxPath);
@@ -695,11 +697,10 @@ public class StoreMailboxManager implements MailboxManager {
     }
 
     @Override
-    public boolean mailboxExists(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
+    public Mono<Boolean> mailboxExists(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
         return mapper.findMailboxByPath(mailboxPath)
-            .blockOptional()
-            .isPresent();
+            .hasElement();
     }
 
     /**
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractAuthProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractAuthProcessor.java
index 35eac0b..198b101 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractAuthProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractAuthProcessor.java
@@ -44,6 +44,8 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 
+import reactor.core.publisher.Mono;
+
 public abstract class AbstractAuthProcessor<R extends ImapRequest> extends AbstractMailboxProcessor<R> {
     private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAuthProcessor.class);
 
@@ -124,7 +126,7 @@ public abstract class AbstractAuthProcessor<R extends ImapRequest> extends Abstr
 
     private void provisionInbox(ImapSession session, MailboxManager mailboxManager, MailboxSession mailboxSession) throws MailboxException {
         final MailboxPath inboxPath = PathConverter.forSession(session).buildFullPath(MailboxConstants.INBOX);
-        if (mailboxManager.mailboxExists(inboxPath, mailboxSession)) {
+        if (Mono.from(mailboxManager.mailboxExists(inboxPath, mailboxSession)).block()) {
             LOGGER.debug("INBOX exists. No need to create it.");
         } else {
             try {
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMessageRangeProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMessageRangeProcessor.java
index 0d3e1f3..9e7a1c8 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMessageRangeProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMessageRangeProcessor.java
@@ -48,6 +48,8 @@ import org.slf4j.LoggerFactory;
 import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 
+import reactor.core.publisher.Mono;
+
 public abstract class AbstractMessageRangeProcessor<R extends AbstractMessageRangeRequest> extends AbstractMailboxProcessor<R> {
     private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMessageRangeProcessor.class);
 
@@ -70,7 +72,7 @@ public abstract class AbstractMessageRangeProcessor<R extends AbstractMessageRan
         try {
             MailboxSession mailboxSession = session.getMailboxSession();
 
-            if (!getMailboxManager().mailboxExists(targetMailbox, mailboxSession)) {
+            if (!Mono.from(getMailboxManager().mailboxExists(targetMailbox, mailboxSession)).block()) {
                 no(request, responder, HumanReadableText.FAILURE_NO_SUCH_MAILBOX, StatusResponse.ResponseCode.tryCreate());
             } else {
                 StatusResponse.ResponseCode code = handleRanges(request, session, targetMailbox, mailboxSession);
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/RenameProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/RenameProcessor.java
index 27de839..a6795e9 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/RenameProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/RenameProcessor.java
@@ -40,6 +40,8 @@ import org.apache.james.util.MDCBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import reactor.core.publisher.Mono;
+
 public class RenameProcessor extends AbstractMailboxProcessor<RenameRequest> {
     private static final Logger LOGGER = LoggerFactory.getLogger(RenameProcessor.class);
 
@@ -58,7 +60,7 @@ public class RenameProcessor extends AbstractMailboxProcessor<RenameRequest> {
             MailboxSession mailboxsession = session.getMailboxSession();
             mailboxManager.renameMailbox(existingPath, newPath, mailboxsession);
 
-            if (existingPath.getName().equalsIgnoreCase(ImapConstants.INBOX_NAME) && !mailboxManager.mailboxExists(existingPath, mailboxsession)) {
+            if (existingPath.getName().equalsIgnoreCase(ImapConstants.INBOX_NAME) && !Mono.from(mailboxManager.mailboxExists(existingPath, mailboxsession)).block()) {
                 mailboxManager.createMailbox(existingPath, mailboxsession);
             }
             okComplete(request, responder);
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/CopyProcessorTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/CopyProcessorTest.java
index 2b4bb63..0e6a6b6 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/CopyProcessorTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/CopyProcessorTest.java
@@ -57,6 +57,8 @@ import org.junit.Test;
 
 import com.google.common.collect.Lists;
 
+import reactor.core.publisher.Mono;
+
 public class CopyProcessorTest {
     private static final Username USERNAME = Username.of("username");
     private static final MailboxPath INBOX = MailboxPath.inbox(USERNAME);
@@ -95,7 +97,7 @@ public class CopyProcessorTest {
         when(selectedMailbox.existsCount()).thenReturn(8L);
         when(selectedMailbox.getPath()).thenReturn(selected);
         imapSession.selected(selectedMailbox);
-        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(true);
+        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(Mono.just(true));
         MessageManager targetMessageManager = mock(MessageManager.class);
         when(mockMailboxManager.getMailbox(INBOX, mailboxSession)).thenReturn(targetMessageManager);
         Mailbox mailbox = mock(Mailbox.class);
@@ -128,7 +130,7 @@ public class CopyProcessorTest {
         when(selectedMailbox.existsCount()).thenReturn(8L);
         when(selectedMailbox.getPath()).thenReturn(selected);
         imapSession.selected(selectedMailbox);
-        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(true);
+        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(Mono.just(true));
         MessageManager targetMessageManager = mock(MessageManager.class);
         when(mockMailboxManager.getMailbox(INBOX, mailboxSession)).thenReturn(targetMessageManager);
         Mailbox mailbox = mock(Mailbox.class);
@@ -160,7 +162,7 @@ public class CopyProcessorTest {
         when(selectedMailbox.existsCount()).thenReturn(8L);
         when(selectedMailbox.getPath()).thenReturn(selected);
         imapSession.selected(selectedMailbox);
-        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(false);
+        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(Mono.just(false));
 
         StatusResponse noResponse = mock(StatusResponse.class);
         when(mockStatusResponseFactory.taggedNo(any(Tag.class), any(ImapCommand.class), any(HumanReadableText.class), any(StatusResponse.ResponseCode.class))).thenReturn(noResponse);
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/MoveProcessorTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/MoveProcessorTest.java
index 7837f48..4dcf048 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/MoveProcessorTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/MoveProcessorTest.java
@@ -60,6 +60,8 @@ import org.junit.Test;
 
 import com.google.common.collect.Lists;
 
+import reactor.core.publisher.Mono;
+
 public class MoveProcessorTest {
     private static final Username USERNAME = Username.of("username");
     private static final MailboxPath INBOX = MailboxPath.inbox(USERNAME);
@@ -111,7 +113,7 @@ public class MoveProcessorTest {
         when(selectedMailbox.existsCount()).thenReturn(8L);
         when(selectedMailbox.getPath()).thenReturn(selected);
         imapSession.selected(selectedMailbox);
-        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(true);
+        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(Mono.just(true));
         MessageManager targetMessageManager = mock(MessageManager.class);
         when(mockMailboxManager.getMailbox(INBOX, mailboxSession)).thenReturn(targetMessageManager);
         Mailbox mailbox = mock(Mailbox.class);
@@ -144,7 +146,7 @@ public class MoveProcessorTest {
         when(selectedMailbox.existsCount()).thenReturn(8L);
         when(selectedMailbox.getPath()).thenReturn(selected);
         imapSession.selected(selectedMailbox);
-        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(true);
+        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(Mono.just(true));
         MessageManager targetMessageManager = mock(MessageManager.class);
         when(mockMailboxManager.getMailbox(INBOX, mailboxSession)).thenReturn(targetMessageManager);
         Mailbox mailbox = mock(Mailbox.class);
@@ -175,7 +177,7 @@ public class MoveProcessorTest {
         when(selectedMailbox.existsCount()).thenReturn(8L);
         when(selectedMailbox.getPath()).thenReturn(selected);
         imapSession.selected(selectedMailbox);
-        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(false);
+        when(mockMailboxManager.mailboxExists(INBOX, mailboxSession)).thenReturn(Mono.just(false));
 
         StatusResponse noResponse = mock(StatusResponse.class);
         when(mockStatusResponseFactory.taggedNo(any(Tag.class), any(ImapCommand.class), any(HumanReadableText.class), any(StatusResponse.ResponseCode.class))).thenReturn(noResponse);
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java
index 7719039..9722c19 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java
@@ -36,6 +36,8 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Strings;
 
+import reactor.core.publisher.Mono;
+
 public class MailboxAppender {
     private static final Logger LOGGER = LoggerFactory.getLogger(MailboxAppender.class);
 
@@ -86,7 +88,7 @@ public class MailboxAppender {
     }
 
     private void createMailboxIfNotExist(MailboxSession session, MailboxPath path) throws MailboxException {
-        if (!mailboxManager.mailboxExists(path, session)) {
+        if (!Mono.from(mailboxManager.mailboxExists(path, session)).block()) {
             try {
                 mailboxManager.createMailbox(path, session);
             } catch (MailboxExistsException e) {
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java
index 9c546ed..601a78d 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java
@@ -49,6 +49,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.Logger;
 
+import reactor.core.publisher.Mono;
+
 public class LocalDeliveryTest {
 
     public static final String RECEIVER_DOMAIN_COM = "receiver@domain.com";
@@ -69,6 +71,7 @@ public class LocalDeliveryTest {
         session = mock(MailboxSession.class);
         when(session.getPathDelimiter()).thenReturn('.');
         when(mailboxManager.createSystemSession(any(Username.class))).thenReturn(session);
+        when(mailboxManager.mailboxExists(any(), any())).thenReturn(Mono.just(true));
 
 
         config = FakeMailetConfig.builder()
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java
index 00c6d9b..7108eb6 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java
@@ -50,6 +50,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.Logger;
 
+import reactor.core.publisher.Mono;
+
 @Deprecated
 public class ToRecipientFolderTest {
 
@@ -83,6 +85,7 @@ public class ToRecipientFolderTest {
         session = mock(MailboxSession.class);
         when(session.getPathDelimiter()).thenReturn('.');
         when(mailboxManager.createSystemSession(any(Username.class))).thenReturn(session);
+        when(mailboxManager.mailboxExists(any(), any())).thenReturn(Mono.just(true));
         when(session.getUser()).thenReturn(Username.of(USER));
     }
 
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisioner.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisioner.java
index 7b0568d..9f6c9e6 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisioner.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisioner.java
@@ -33,15 +33,16 @@ import org.apache.james.mailbox.exception.MailboxExistsException;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.metrics.api.MetricFactory;
-import org.apache.james.metrics.api.TimeMetric;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 
+import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
 
-public class DefaultMailboxesReactiveProvisioner {
+class DefaultMailboxesReactiveProvisioner {
     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultMailboxesReactiveProvisioner.class);
     private final MailboxManager mailboxManager;
     private final SubscriptionManager subscriptionManager;
@@ -57,31 +58,29 @@ public class DefaultMailboxesReactiveProvisioner {
         this.metricFactory = metricFactory;
     }
 
-    public Mono<Void> createMailboxesIfNeeded(MailboxSession session) {
-        return Mono.fromRunnable(() -> {
-            TimeMetric timeMetric = metricFactory.timer("JMAP-mailboxes-provisioning");
-            try {
+    Mono<Void> createMailboxesIfNeeded(MailboxSession session) {
+        return metricFactory.runPublishingTimerMetric("JMAP-mailboxes-provisioning",
+            () -> {
                 Username username = session.getUser();
-                createDefaultMailboxes(username);
-            } catch (MailboxException e) {
-                throw new RuntimeException(e);
-            } finally {
-                timeMetric.stopAndPublish();
-            }
-        });
+                return createDefaultMailboxes(username);
+            });
     }
 
-    private void createDefaultMailboxes(Username username) throws MailboxException {
+    private Mono<Void> createDefaultMailboxes(Username username) {
         MailboxSession session = mailboxManager.createSystemSession(username);
-        DefaultMailboxes.DEFAULT_MAILBOXES.stream()
+
+        return Flux.fromIterable(DefaultMailboxes.DEFAULT_MAILBOXES)
             .map(toMailboxPath(session))
-            .filter(mailboxPath -> mailboxDoesntExist(mailboxPath, session))
-            .forEach(mailboxPath -> createMailbox(mailboxPath, session));
+            .filterWhen(mailboxPath -> mailboxDoesntExist(mailboxPath, session))
+            .concatMap(mailboxPath -> Mono.fromRunnable(() -> createMailbox(mailboxPath, session))
+                .subscribeOn(Schedulers.elastic()))
+            .then();
     }
 
-    private boolean mailboxDoesntExist(MailboxPath mailboxPath, MailboxSession session) {
+    private Mono<Boolean> mailboxDoesntExist(MailboxPath mailboxPath, MailboxSession session) {
         try {
-            return !mailboxManager.mailboxExists(mailboxPath, session);
+            return Mono.from(mailboxManager.mailboxExists(mailboxPath, session))
+                .map(x -> !x);
         } catch (MailboxException e) {
             throw new RuntimeException(e);
         }
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisionerThreadTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisionerThreadTest.java
index d0a5904..3e59213 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisionerThreadTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/DefaultMailboxesReactiveProvisionerThreadTest.java
@@ -40,6 +40,8 @@ import org.apache.james.util.concurrency.ConcurrentTestRunner;
 import org.junit.Before;
 import org.junit.Test;
 
+import reactor.core.publisher.Mono;
+
 public class DefaultMailboxesReactiveProvisionerThreadTest {
 
     private static final Username USERNAME = Username.of("username");
@@ -62,7 +64,7 @@ public class DefaultMailboxesReactiveProvisionerThreadTest {
         doNothing().when(subscriptionManager).subscribe(eq(session), anyString());
 
         when(mailboxManager.createMailbox(any(MailboxPath.class), eq(session))).thenReturn(Optional.of(TestId.of(18L)));
-        when(mailboxManager.mailboxExists(any(MailboxPath.class), eq(session))).thenReturn(false);
+        when(mailboxManager.mailboxExists(any(MailboxPath.class), eq(session))).thenReturn(Mono.just(false));
         when(mailboxManager.createSystemSession(USERNAME)).thenReturn(session);
 
         ConcurrentTestRunner
diff --git a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java
index e1bc470..038321a 100644
--- a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java
+++ b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java
@@ -45,6 +45,8 @@ import org.apache.james.user.api.UsersRepositoryException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import reactor.core.publisher.Mono;
+
 /**
  * {@link DeliverToRecipientHook} which deliver the message directly to the recipients mailbox.
  */
@@ -71,7 +73,7 @@ public class MailboxDeliverToRecipientHandler implements DeliverToRecipientHook
             mailboxManager.startProcessingRequest(mailboxSession);
 
             // create inbox if not exist
-            if (!mailboxManager.mailboxExists(inbox, mailboxSession)) {
+            if (!Mono.from(mailboxManager.mailboxExists(inbox, mailboxSession)).block()) {
                 Optional<MailboxId> mailboxId = mailboxManager.createMailbox(inbox, mailboxSession);
                 LOGGER.info("Provisioning INBOX. {} created.", mailboxId);
             }
diff --git a/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java b/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java
index 4c04fa5..47a1945 100644
--- a/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java
+++ b/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/core/PassCmdHandler.java
@@ -43,6 +43,8 @@ import org.apache.james.protocols.pop3.mailbox.Mailbox;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import reactor.core.publisher.Mono;
+
 /**
  * {@link PassCmdHandler} which also handles POP3 Before SMTP
  * 
@@ -76,7 +78,7 @@ public class PassCmdHandler extends AbstractPassCmdHandler  {
             MailboxPath inbox = MailboxPath.inbox(mSession);
             
             // check if the mailbox exists, if not create it
-            if (!manager.mailboxExists(inbox, mSession)) {
+            if (!Mono.from(manager.mailboxExists(inbox, mSession)).block()) {
                 Optional<MailboxId> mailboxId = manager.createMailbox(inbox, mSession);
                 LOGGER.info("Provisioning INBOX. {} created.", mailboxId);
             }
diff --git a/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java b/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java
index affc673..bc3b7f3 100644
--- a/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java
+++ b/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java
@@ -210,7 +210,7 @@ public class POP3ServerTest {
         pop3Client.disconnect();
         MailboxPath mailboxPath = MailboxPath.inbox(username);
         MailboxSession session = mailboxManager.login(username, "bar");
-        if (!mailboxManager.mailboxExists(mailboxPath, session)) {
+        if (!mailboxManager.mailboxExists(mailboxPath, session).block()) {
             mailboxManager.createMailbox(mailboxPath, session);
         }
         setupTestMails(session, mailboxManager.getMailbox(mailboxPath, session));
@@ -297,7 +297,7 @@ public class POP3ServerTest {
         MailboxPath mailboxPath = MailboxPath.inbox(username);
         MailboxSession session = mailboxManager.login(username, "bar2");
 
-        if (!mailboxManager.mailboxExists(mailboxPath, session)) {
+        if (!mailboxManager.mailboxExists(mailboxPath, session).block()) {
             mailboxManager.createMailbox(mailboxPath, session);
         }
 
@@ -387,7 +387,7 @@ public class POP3ServerTest {
         MailboxPath mailboxPath = MailboxPath.inbox(username);
         MailboxSession session = mailboxManager.login(username, "bar2");
 
-        if (!mailboxManager.mailboxExists(mailboxPath, session)) {
+        if (!mailboxManager.mailboxExists(mailboxPath, session).block()) {
             mailboxManager.createMailbox(mailboxPath, session);
         }
 
@@ -441,7 +441,7 @@ public class POP3ServerTest {
         MailboxPath mailboxPath = MailboxPath.inbox(username);
         MailboxSession session = mailboxManager.login(username, "bar2");
 
-        if (!mailboxManager.mailboxExists(mailboxPath, session)) {
+        if (!mailboxManager.mailboxExists(mailboxPath, session).block()) {
             mailboxManager.createMailbox(mailboxPath, session);
         }
 
@@ -653,7 +653,7 @@ public class POP3ServerTest {
         MailboxPath mailboxPath = MailboxPath.inbox(username);
 
         mailboxManager.startProcessingRequest(session);
-        if (!mailboxManager.mailboxExists(mailboxPath, session)) {
+        if (!mailboxManager.mailboxExists(mailboxPath, session).block()) {
             mailboxManager.createMailbox(mailboxPath, session);
         }
 
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
index 7b25ba1..003220f 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserMailboxesService.java
@@ -45,6 +45,8 @@ import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
 
+import reactor.core.publisher.Mono;
+
 
 public class UserMailboxesService {
     private static final Logger LOGGER = LoggerFactory.getLogger(UserMailboxesService.class);
@@ -89,9 +91,10 @@ public class UserMailboxesService {
     public boolean testMailboxExists(Username username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException {
         usernamePreconditions(username);
         MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
-        return mailboxManager.mailboxExists(
+        return Mono.from(mailboxManager.mailboxExists(
             MailboxPath.forUser(username, mailboxName.asString()),
-            mailboxSession);
+            mailboxSession))
+            .block();
     }
 
     public void deleteMailbox(Username username, MailboxName mailboxName) throws MailboxException, UsersRepositoryException, MailboxHaveChildrenException {
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
index 2dc0a3b..6f52c47 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserMailboxesRoutesTest.java
@@ -29,6 +29,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -83,6 +84,7 @@ import com.google.common.collect.ImmutableSet;
 
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import reactor.core.publisher.Mono;
 
 class UserMailboxesRoutesTest {
     private static final Username USERNAME = Username.of("username");
@@ -942,7 +944,7 @@ class UserMailboxesRoutesTest {
 
         @Test
         void getShouldGenerateInternalErrorOnUnknownException() throws Exception {
-            doThrow(new RuntimeException()).when(mailboxManager).mailboxExists(any(), any());
+            doReturn(Mono.error(new RuntimeException())).when(mailboxManager).mailboxExists(any(), any());
 
             when()
                 .get(MAILBOX_NAME)
@@ -952,7 +954,7 @@ class UserMailboxesRoutesTest {
 
         @Test
         void getShouldGenerateInternalErrorOnUnknownMailboxException() throws Exception {
-            doThrow(new MailboxException()).when(mailboxManager).mailboxExists(any(), any());
+            doReturn(Mono.error(new MailboxException())).when(mailboxManager).mailboxExists(any(), any());
 
             when()
                 .get(MAILBOX_NAME)


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 03/16: JAMES-3088 Migrating UserRepository tests to Junit 5 contract style

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 050b0adcd4aafc79ec43ff2de2baa69bb639f070
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 11:04:59 2020 +0700

    JAMES-3088 Migrating UserRepository tests to Junit 5 contract style
    
    This is a `have to` step in order to test every method with and without
    virtualHosting. It requires to have separated contracts implementing
    the common one. The different is only about virtualHosting support.
    
    Otherwise, with the incoming number of tests regarding this issue.
    The test code will be really messy. And we cannot easy to test the LDAP
    version because it doesn't implement the abstract test right now
    
    Memory version go first
---
 .../user/lib/AbstractUsersRepositoryTest.java      | 416 +++++++++++----------
 .../user/memory/MemoryUsersRepositoryTest.java     |  28 +-
 2 files changed, 237 insertions(+), 207 deletions(-)

diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
index a5f056c..fe9e664 100644
--- a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
+++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
@@ -30,13 +30,17 @@ import org.apache.james.core.Domain;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.mock.SimpleDomainList;
-import org.apache.james.lifecycle.api.LifecycleUtil;
 import org.apache.james.user.api.AlreadyExistInUsersRepositoryException;
 import org.apache.james.user.api.InvalidUsernameException;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.api.model.User;
 import org.junit.jupiter.api.Assumptions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -44,80 +48,100 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 public abstract class AbstractUsersRepositoryTest {
 
-    static final Domain DOMAIN = Domain.of("domain");
-
-    protected AbstractUsersRepository usersRepository;
-    protected SimpleDomainList domainList;
-
-    /**
-     * Create the repository to be tested.
-     *
-     * @return the user repository
-     * @throws Exception
-     */
-    protected abstract AbstractUsersRepository getUsersRepository() throws Exception;
-
-    Username user1;
-    Username user1CaseVariation;
-    Username user2;
-    Username user3;
-    Username admin;
-    Username adminCaseVariation;
-
-    protected void setUp() throws Exception {
-        domainList = new SimpleDomainList();
-        domainList.addDomain(DOMAIN);
-        this.usersRepository = getUsersRepository();
-        user1 = login("username");
-        user2 = login("username2");
-        user3 = login("username3");
-        user1CaseVariation = login("uSeRnaMe");
-        admin = login("admin");
-        adminCaseVariation = login("adMin");
-    }
-
-    protected void tearDown() throws Exception {
-        LifecycleUtil.dispose(this.usersRepository);
+    protected static class UserRepositoryExtension implements BeforeEachCallback, ParameterResolver {
+
+        private final boolean supportVirtualHosting;
+        private TestSystem testSystem;
+
+        public UserRepositoryExtension(boolean supportVirtualHosting) {
+            this.supportVirtualHosting = supportVirtualHosting;
+        }
+
+        @Override
+        public void beforeEach(ExtensionContext extensionContext) throws Exception {
+            testSystem = new TestSystem(supportVirtualHosting);
+        }
+
+        @Override
+        public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+            return parameterContext.getParameter().getType() == TestSystem.class;
+        }
+
+        @Override
+        public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+            return testSystem;
+        }
     }
-    
-    private Username login(String login) {
-        if (usersRepository.supportVirtualHosting()) {
-            return Username.of(login + '@' + DOMAIN.name());
-        } else {
-            return Username.of(login);
+
+    protected static class TestSystem {
+        static final Domain DOMAIN = Domain.of("domain");
+
+        private final boolean supportVirtualHosting;
+        private final SimpleDomainList domainList;
+        private final Username user1;
+        private final Username user1CaseVariation;
+        private final Username user2;
+        private final Username user3;
+        private final Username admin;
+        private final Username adminCaseVariation;
+
+        TestSystem(boolean supportVirtualHosting) throws Exception {
+            this.supportVirtualHosting = supportVirtualHosting;
+            domainList = new SimpleDomainList();
+            domainList.addDomain(DOMAIN);
+            user1 = toUsername("username");
+            user2 = toUsername("username2");
+            user3 = toUsername("username3");
+            user1CaseVariation = toUsername("uSeRnaMe");
+            admin = toUsername("testSystem.admin");
+            adminCaseVariation = toUsername("testSystem.admin");
+        }
+
+        private Username toUsername(String login) {
+            if (supportVirtualHosting) {
+                return Username.of(login + '@' + DOMAIN.name());
+            } else {
+                return Username.of(login);
+            }
+        }
+
+        public SimpleDomainList getDomainList() {
+            return domainList;
         }
     }
+
+    protected abstract AbstractUsersRepository testee();
     
     @Test
     void countUsersShouldReturnZeroWhenEmptyRepository() throws UsersRepositoryException {
         //Given
         int expected = 0;
         //When
-        int actual = usersRepository.countUsers();
+        int actual = testee().countUsers();
         //Then
         assertThat(actual).isEqualTo(expected);
     }
     
     @Test
-    void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository() throws UsersRepositoryException {
+    void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         ArrayList<Username> keys = new ArrayList<>(3);
-        keys.add(user1);
-        keys.add(user2);
-        keys.add(user3);
+        keys.add(testSystem.user1);
+        keys.add(testSystem.user2);
+        keys.add(testSystem.user3);
         for (Username username : keys) {
-            usersRepository.addUser(username, username.asString());
+            testee().addUser(username, username.asString());
         }
         //When
-        int actual = usersRepository.countUsers();
+        int actual = testee().countUsers();
         //Then
         assertThat(actual).isEqualTo(keys.size());
     }
     
     @Test
-    void listShouldReturnEmptyIteratorWhenEmptyRepository() throws UsersRepositoryException {
+    void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //When
-        Iterator<Username> actual = usersRepository.list();
+        Iterator<Username> actual = testee().list();
         //Then
         assertThat(actual)
             .toIterable()
@@ -125,400 +149,400 @@ public abstract class AbstractUsersRepositoryTest {
     }
     
     @Test
-    void listShouldReturnExactlyUsersInRepository() throws UsersRepositoryException {
+    void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         ArrayList<Username> keys = new ArrayList<>(3);
-        keys.add(user1);
-        keys.add(user2);
-        keys.add(user3);
+        keys.add(testSystem.user1);
+        keys.add(testSystem.user2);
+        keys.add(testSystem.user3);
         for (Username username : keys) {
-            usersRepository.addUser(username, username.asString());
+            testee().addUser(username, username.asString());
         }
         //When
-        Iterator<Username> actual = usersRepository.list();
+        Iterator<Username> actual = testee().list();
         //Then
         assertThat(actual)
             .toIterable()
-            .containsOnly(user1, user2, user3);
+            .containsOnly(testSystem.user1, testSystem.user2, testSystem.user3);
     }
     
     @Test
-    void addUserShouldAddAUserWhenEmptyRepository() throws UsersRepositoryException {
+    void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //When
-        usersRepository.addUser(user2, "password2");
+        testee().addUser(testSystem.user2, "password2");
         //Then
-        assertThat(usersRepository.contains(user2)).isTrue();
+        assertThat(testee().contains(testSystem.user2)).isTrue();
     }
 
     @Test
-    void containsShouldPreserveCaseVariation() throws UsersRepositoryException {
-        usersRepository.addUser(user1CaseVariation, "password2");
+    void containsShouldPreserveCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1CaseVariation, "password2");
 
-        assertThat(usersRepository.contains(user1CaseVariation)).isTrue();
+        assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
     }
 
     @Test
-    void containsShouldBeCaseInsentive() throws UsersRepositoryException {
-        usersRepository.addUser(user1CaseVariation, "password2");
+    void containsShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1CaseVariation, "password2");
 
-        assertThat(usersRepository.contains(user1)).isTrue();
+        assertThat(testee().contains(testSystem.user1)).isTrue();
     }
 
     @Test
-    void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased() throws UsersRepositoryException {
-        usersRepository.addUser(user1, "password2");
+    void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1, "password2");
 
-        assertThat(usersRepository.contains(user1CaseVariation)).isTrue();
+        assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
     }
 
     @Test
-    void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased() throws UsersRepositoryException {
-        usersRepository.addUser(user1, "password2");
+    void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1, "password2");
 
-        assertThatThrownBy(() -> usersRepository.addUser(user1CaseVariation, "pass"))
+        assertThatThrownBy(() -> testee().addUser(testSystem.user1CaseVariation, "pass"))
             .isInstanceOf(UsersRepositoryException.class);
     }
 
     @Test
-    void addUserShouldDisableCaseVariation() throws UsersRepositoryException {
-        usersRepository.addUser(user1CaseVariation, "password2");
+    void addUserShouldDisableCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1CaseVariation, "password2");
 
-        assertThatThrownBy(() -> usersRepository.addUser(user1, "pass"))
+        assertThatThrownBy(() -> testee().addUser(testSystem.user1, "pass"))
             .isInstanceOf(UsersRepositoryException.class);
     }
 
     @Test
-    void listShouldReturnLowerCaseUser() throws UsersRepositoryException {
-        usersRepository.addUser(user1CaseVariation, "password2");
+    void listShouldReturnLowerCaseUser(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1CaseVariation, "password2");
 
-        assertThat(usersRepository.list())
+        assertThat(testee().list())
             .toIterable()
-            .containsExactly(user1);
+            .containsExactly(testSystem.user1);
     }
 
     @Test
-    void removeUserShouldBeCaseInsentiveOnCaseVariationUser() throws UsersRepositoryException {
-        usersRepository.addUser(user1CaseVariation, "password2");
+    void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1CaseVariation, "password2");
 
-        usersRepository.removeUser(user1);
+        testee().removeUser(testSystem.user1);
 
-        assertThat(usersRepository.list())
+        assertThat(testee().list())
             .toIterable()
             .isEmpty();
     }
 
     @Test
-    void removeUserShouldBeCaseInsentive() throws UsersRepositoryException {
-        usersRepository.addUser(user1, "password2");
+    void removeUserShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1, "password2");
 
-        usersRepository.removeUser(user1CaseVariation);
+        testee().removeUser(testSystem.user1CaseVariation);
 
-        assertThat(usersRepository.list())
+        assertThat(testee().list())
             .toIterable()
             .isEmpty();
     }
 
     @Test
-    void getUserByNameShouldBeCaseInsentive() throws UsersRepositoryException {
-        usersRepository.addUser(user1, "password2");
+    void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1, "password2");
 
-        assertThat(usersRepository.getUserByName(user1CaseVariation).getUserName())
-            .isEqualTo(user1);
+        assertThat(testee().getUserByName(testSystem.user1CaseVariation).getUserName())
+            .isEqualTo(testSystem.user1);
     }
 
     @Test
-    void getUserByNameShouldReturnLowerCaseAddedUser() throws UsersRepositoryException {
-        usersRepository.addUser(user1CaseVariation, "password2");
+    void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) throws UsersRepositoryException {
+        testee().addUser(testSystem.user1CaseVariation, "password2");
 
-        assertThat(usersRepository.getUserByName(user1).getUserName())
-            .isEqualTo(user1);
+        assertThat(testee().getUserByName(testSystem.user1).getUserName())
+            .isEqualTo(testSystem.user1);
     }
 
     @Test
-    void getUserShouldBeCaseInsentive() throws Exception {
-        assertThat(usersRepository.getUsername(user1CaseVariation.asMailAddress()))
-            .isEqualTo(user1);
+    void getUserShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
+        assertThat(testee().getUsername(testSystem.user1CaseVariation.asMailAddress()))
+            .isEqualTo(testSystem.user1);
     }
 
     @Test
-    void isAdministratorShouldBeCaseInsentive() throws Exception {
-        usersRepository.setAdministratorId(Optional.of(admin));
-        assertThat(usersRepository.isAdministrator(adminCaseVariation))
+    void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
+        testee().setAdministratorId(Optional.of(testSystem.admin));
+        assertThat(testee().isAdministrator(testSystem.adminCaseVariation))
             .isTrue();
     }
 
     @Test
-    void testShouldBeCaseInsentiveOnCaseVariationUser() throws UsersRepositoryException {
+    void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
         String password = "password2";
-        usersRepository.addUser(user1CaseVariation, password);
+        testee().addUser(testSystem.user1CaseVariation, password);
 
-        assertThat(usersRepository.test(user1, password))
+        assertThat(testee().test(testSystem.user1, password))
             .isTrue();
     }
 
     @Test
-    void testShouldBeCaseInsentive() throws UsersRepositoryException {
+    void testShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
         String password = "password2";
-        usersRepository.addUser(user1, password);
+        testee().addUser(testSystem.user1, password);
 
-        assertThat(usersRepository.test(user1CaseVariation, password))
+        assertThat(testee().test(testSystem.user1CaseVariation, password))
             .isTrue();
     }
     
     @Test 
-    void addUserShouldAddAUserWhenNotEmptyRepository() throws UsersRepositoryException {
+    void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user2, "password2");
+        testee().addUser(testSystem.user2, "password2");
         //When
-        usersRepository.addUser(user3, "password3");
+        testee().addUser(testSystem.user3, "password3");
         //Then
-        assertThat(usersRepository.contains(user3)).isTrue();
+        assertThat(testee().contains(testSystem.user3)).isTrue();
     }
     
     @Test
-    void addUserShouldThrowWhenSameUsernameWithDifferentCase() throws UsersRepositoryException {
+    void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(login("myUsername"), "password");
+        testee().addUser(testSystem.toUsername("myUsername"), "password");
         //When
-        assertThatThrownBy(() -> usersRepository.addUser(login("MyUsername"), "password"))
+        assertThatThrownBy(() -> testee().addUser(testSystem.toUsername("MyUsername"), "password"))
             .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
     }
     
     @Test
-    void addUserShouldThrowWhenUserAlreadyPresentInRepository() throws UsersRepositoryException {
+    void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
+        testee().addUser(testSystem.user1, "password");
         //When
-        assertThatThrownBy(() -> usersRepository.addUser(user1, "password2"))
+        assertThatThrownBy(() -> testee().addUser(testSystem.user1, "password2"))
             .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
     }
     
     @Test
-    void getUserByNameShouldReturnAUserWhenContainedInRepository() throws UsersRepositoryException {
+    void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
+        testee().addUser(testSystem.user1, "password");
         //When
-        User actual = usersRepository.getUserByName(user1);
+        User actual = testee().getUserByName(testSystem.user1);
         //Then
         assertThat(actual).isNotNull();
-        assertThat(actual.getUserName()).isEqualTo(user1);
+        assertThat(actual.getUserName()).isEqualTo(testSystem.user1);
     }
 
     @Test
-    void getUserByNameShouldReturnUserWhenDifferentCase() throws UsersRepositoryException {
+    void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(login("username"), "password");
+        testee().addUser(testSystem.toUsername("username"), "password");
         //When
-        User actual = usersRepository.getUserByName(login("uSERNAMe"));
+        User actual = testee().getUserByName(testSystem.toUsername("uSERNAMe"));
         //Then
         assertThat(actual).isNotNull();
-        assertThat(actual.getUserName()).isEqualTo(user1);
+        assertThat(actual.getUserName()).isEqualTo(testSystem.user1);
     }
    
     @Test
-    void testShouldReturnTrueWhenAUserHasACorrectPassword() throws UsersRepositoryException { 
+    void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
+        testee().addUser(testSystem.user1, "password");
         //When
-        boolean actual = usersRepository.test(user1, "password");
+        boolean actual = testee().test(testSystem.user1, "password");
         //Then
         assertThat(actual).isTrue();
     }
     
     @Test
-    void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain() throws Exception { 
-        usersRepository.setEnableVirtualHosting(true);
+    void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) throws Exception {
+        testee().setEnableVirtualHosting(true);
 
-        domainList.addDomain(Domain.of("jAmEs.oRg"));
+        testSystem.domainList.addDomain(Domain.of("jAmEs.oRg"));
         String username = "myuser";
         String password = "password";
-        usersRepository.addUser(Username.of(username + "@jAmEs.oRg"), password);
+        testee().addUser(Username.of(username + "@jAmEs.oRg"), password);
 
-        boolean actual = usersRepository.test(Username.of(username + "@james.org"), password);
+        boolean actual = testee().test(Username.of(username + "@james.org"), password);
 
         assertThat(actual).isTrue();
     }
 
     @Test
-    void testShouldReturnFalseWhenAUserHasAnIncorrectPassword() throws UsersRepositoryException { 
+    void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
+        testee().addUser(testSystem.user1, "password");
         //When
-        boolean actual = usersRepository.test(user1, "password2");
+        boolean actual = testee().test(testSystem.user1, "password2");
         //Then
         assertThat(actual).isFalse();
     }
     
     @Test
-    void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword() throws UsersRepositoryException { 
+    void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
+        testee().addUser(testSystem.user1, "password");
         //When
-        boolean actual = usersRepository.test(user1, "Password");
+        boolean actual = testee().test(testSystem.user1, "Password");
         //Then
         assertThat(actual).isFalse();
     }
     
     @Test
-    void testShouldReturnFalseWhenAUserIsNotInRepository() throws UsersRepositoryException { 
+    void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(login("username"), "password");
+        testee().addUser(testSystem.toUsername("username"), "password");
         //When
-        boolean actual = usersRepository.test(login("username2"), "password"); 
+        boolean actual = testee().test(testSystem.toUsername("username2"), "password");
         //Then
         assertThat(actual).isFalse();
     }
 
     @Test
-    void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName() throws UsersRepositoryException {
+    void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(login("username"), "password");
+        testee().addUser(testSystem.toUsername("username"), "password");
         //When
-        boolean actual = usersRepository.test(login("userName"), "password");
+        boolean actual = testee().test(testSystem.toUsername("userName"), "password");
         //Then
         assertThat(actual).isTrue();
     }
 
     @Test
-    void testShouldReturnFalseWhenEmptyRepository() throws UsersRepositoryException {
+    void testShouldReturnFalseWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //When
-        boolean actual = usersRepository.test(user1, "password");
+        boolean actual = testee().test(testSystem.user1, "password");
         //Then
         assertThat(actual).isFalse();
     }
 
     @Test
-    void testShouldReturnFalseWhenAUserIsRemovedFromRepository() throws UsersRepositoryException {
+    void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
-        usersRepository.removeUser(user1);
+        testee().addUser(testSystem.user1, "password");
+        testee().removeUser(testSystem.user1);
         //When
-        boolean actual = usersRepository.test(user1, "password");
+        boolean actual = testee().test(testSystem.user1, "password");
         //Then
         assertThat(actual).isFalse();
     }
     
     @Test
-    void removeUserShouldRemoveAUserWhenPresentInRepository() throws UsersRepositoryException {
+    void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
+        testee().addUser(testSystem.user1, "password");
         //When
-        usersRepository.removeUser(user1);
+        testee().removeUser(testSystem.user1);
         //Then
-        assertThat(usersRepository.contains(user1)).isFalse();
+        assertThat(testee().contains(testSystem.user1)).isFalse();
     }
     
     @Test
-    void removeUserShouldThrowWhenUserNotInRepository() {
+    void removeUserShouldThrowWhenUserNotInRepository(TestSystem testSystem) {
         //When
-        assertThatThrownBy(() -> usersRepository.removeUser(user1))
+        assertThatThrownBy(() -> testee().removeUser(testSystem.user1))
             .isInstanceOf(UsersRepositoryException.class);
     }
     
     @Test
-    void updateUserShouldAllowToAuthenticateWithNewPassword() throws UsersRepositoryException { 
+    void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
-        User user = usersRepository.getUserByName(user1);
+        testee().addUser(testSystem.user1, "password");
+        User user = testee().getUserByName(testSystem.user1);
         user.setPassword("newpass");
         //When
-        usersRepository.updateUser(user);
+        testee().updateUser(user);
         //Then
-        assertThat(usersRepository.test(user1, "newpass")).isTrue();
+        assertThat(testee().test(testSystem.user1, "newpass")).isTrue();
     }
    
     @Test
-    void updateUserShouldNotAllowToAuthenticateWithOldPassword() throws UsersRepositoryException {
+    void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
-        User user = usersRepository.getUserByName(user1);
+        testee().addUser(testSystem.user1, "password");
+        User user = testee().getUserByName(testSystem.user1);
         user.setPassword("newpass");
         //When
-        usersRepository.updateUser(user);
+        testee().updateUser(user);
         //Then
-        assertThat(usersRepository.test(user1, "password")).isFalse();
+        assertThat(testee().test(testSystem.user1, "password")).isFalse();
     }
     
     @Test
-    void updateUserShouldThrowWhenAUserIsNoMoreInRepository() throws UsersRepositoryException {
+    void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
-        usersRepository.addUser(user1, "password");
-        User user = usersRepository.getUserByName(user1);
-        usersRepository.removeUser(user1);
+        testee().addUser(testSystem.user1, "password");
+        User user = testee().getUserByName(testSystem.user1);
+        testee().removeUser(testSystem.user1);
         //When
-        assertThatThrownBy(() -> usersRepository.updateUser(user))
+        assertThatThrownBy(() -> testee().updateUser(user))
             .isInstanceOf(UsersRepositoryException.class);
     }
 
     @Test
     void virtualHostedUsersRepositoryShouldUseFullMailAddressAsUsername() throws Exception {
-        usersRepository.setEnableVirtualHosting(true);
+        testee().setEnableVirtualHosting(true);
 
         // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeTrue(usersRepository.supportVirtualHosting());
+        Assumptions.assumeTrue(testee().supportVirtualHosting());
 
-        assertThat(usersRepository.getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
+        assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
     }
 
     @Test
     void nonVirtualHostedUsersRepositoryShouldUseLocalPartAsUsername() throws Exception {
-        usersRepository.setEnableVirtualHosting(false);
+        testee().setEnableVirtualHosting(false);
 
         // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeFalse(usersRepository.supportVirtualHosting());
+        Assumptions.assumeFalse(testee().supportVirtualHosting());
 
-        assertThat(usersRepository.getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
+        assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
     }
 
     @Test
-    void isAdministratorShouldReturnFalseWhenNotConfigured() throws Exception {
-        usersRepository.setAdministratorId(Optional.empty());
+    void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
+        testee().setAdministratorId(Optional.empty());
 
-        assertThat(usersRepository.isAdministrator(admin)).isFalse();
+        assertThat(testee().isAdministrator(testSystem.admin)).isFalse();
     }
 
     @Test
-    void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin() throws Exception {
-        usersRepository.setAdministratorId(Optional.of(admin));
+    void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
+        testee().setAdministratorId(Optional.of(testSystem.admin));
 
-        assertThat(usersRepository.isAdministrator(admin)).isTrue();
+        assertThat(testee().isAdministrator(testSystem.admin)).isTrue();
     }
 
     @Test
-    void isAdministratorShouldReturnFalseWhenConfiguredAndUserIsNotAdmin() throws Exception {
-        usersRepository.setAdministratorId(Optional.of(admin));
+    void isAdministratorShouldReturnFalseWhenConfiguredAndUserIsNotAdmin(TestSystem testSystem) throws Exception {
+        testee().setAdministratorId(Optional.of(testSystem.admin));
 
-        assertThat(usersRepository.isAdministrator(user1)).isFalse();
+        assertThat(testee().isAdministrator(testSystem.user1)).isFalse();
     }
 
     @Test
     void getMailAddressForShouldBeIdentityWhenVirtualHosting() throws Exception {
-        usersRepository.setEnableVirtualHosting(true);
+        testee().setEnableVirtualHosting(true);
 
         // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeTrue(usersRepository.supportVirtualHosting());
+        Assumptions.assumeTrue(testee().supportVirtualHosting());
 
         String username = "user@domain";
-        assertThat(usersRepository.getMailAddressFor(Username.of(username)))
+        assertThat(testee().getMailAddressFor(Username.of(username)))
             .isEqualTo(username);
     }
 
     @Test
-    void getMailAddressForShouldAppendDefaultDomainWhenNoVirtualHosting() throws Exception {
-        usersRepository.setEnableVirtualHosting(false);
+    void getMailAddressForShouldAppendDefaultDomainWhenNoVirtualHosting(TestSystem testSystem) throws Exception {
+        testee().setEnableVirtualHosting(false);
 
         // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeFalse(usersRepository.supportVirtualHosting());
+        Assumptions.assumeFalse(testee().supportVirtualHosting());
 
         String username = "user";
-        assertThat(usersRepository.getMailAddressFor(Username.of(username)))
-            .isEqualTo(new MailAddress(username, domainList.getDefaultDomain()));
+        assertThat(testee().getMailAddressFor(Username.of(username)))
+            .isEqualTo(new MailAddress(username, testSystem.domainList.getDefaultDomain()));
     }
 
     @ParameterizedTest
     @MethodSource("illegalCharacters")
     void assertValidShouldThrowWhenUsernameLocalPartWithIllegalCharacter(String illegalCharacter) {
-        assertThatThrownBy(() -> usersRepository.assertValid(Username.of("a" + illegalCharacter + "a")))
+        assertThatThrownBy(() -> testee().assertValid(Username.of("a" + illegalCharacter + "a")))
             .isInstanceOf(InvalidUsernameException.class);
     }
 
diff --git a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
index 6cd6c4f..54ddc17 100644
--- a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
+++ b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
@@ -31,30 +31,36 @@ import org.apache.james.user.lib.AbstractUsersRepository;
 import org.apache.james.user.lib.AbstractUsersRepositoryTest;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 class MemoryUsersRepositoryTest extends AbstractUsersRepositoryTest {
 
+    @RegisterExtension
+    static UserRepositoryExtension extension = new UserRepositoryExtension(true);
+
+    private MemoryUsersRepository memoryUsersRepository;
+
     @BeforeEach
-    void setup() throws Exception {
-        super.setUp();
+    void setUp(TestSystem testSystem) {
+        memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(testSystem.getDomainList());
     }
-    
+
     @Override
-    protected AbstractUsersRepository getUsersRepository() {
-        return MemoryUsersRepository.withVirtualHosting(domainList);
+    protected AbstractUsersRepository testee() {
+        return memoryUsersRepository;
     }
 
     @Test
-    void assertValidShouldThrowWhenDomainPartAndNoVirtualHosting() {
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(domainList);
+    void assertValidShouldThrowWhenDomainPartAndNoVirtualHosting(TestSystem testSystem) {
+        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(testSystem.getDomainList());
 
         assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user@domain.tld")))
             .isInstanceOf(UsersRepositoryException.class);
     }
 
     @Test
-    void assertValidShouldThrowWhenNoDomainPartAndVirtualHosting() {
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+    void assertValidShouldThrowWhenNoDomainPartAndVirtualHosting(TestSystem testSystem) {
+        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(testSystem.getDomainList());
 
         assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user")))
             .isInstanceOf(UsersRepositoryException.class);
@@ -90,8 +96,8 @@ class MemoryUsersRepositoryTest extends AbstractUsersRepositoryTest {
     }
 
     @Test
-    void assertValidShouldNotThrowWhenNoDomainPartAndNoVirtualHosting() {
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(domainList);
+    void assertValidShouldNotThrowWhenNoDomainPartAndNoVirtualHosting(TestSystem testSystem) {
+        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(testSystem.getDomainList());
 
         assertThatCode(() -> memoryUsersRepository.assertValid(Username.of("user")))
             .doesNotThrowAnyException();


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 16/16: [Build time] Comment to explain 'Speedup ComputeMessageFastViewProjectionListenerTest'

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit c25a21c7a187e6f4e499a750d23b16cfa7d9a9c4
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Mar 24 14:49:39 2020 +0700

    [Build time] Comment to explain 'Speedup ComputeMessageFastViewProjectionListenerTest'
---
 .../james/jmap/event/ComputeMessageFastViewProjectionListenerTest.java  | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/ComputeMessageFastViewProjectionListenerTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/ComputeMessageFastViewProjectionListenerTest.java
index 1194d0c..5a22e2d 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/ComputeMessageFastViewProjectionListenerTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/event/ComputeMessageFastViewProjectionListenerTest.java
@@ -103,6 +103,8 @@ class ComputeMessageFastViewProjectionListenerTest {
     @BeforeEach
     void setup() throws Exception {
         eventDeadLetters = new MemoryEventDeadLetters();
+        // Default RetryBackoffConfiguration leads each events to be re-executed for 30s which is too long
+        // Reducing the wait time for the event bus allow a faster test suite execution without harming test correctness
         RetryBackoffConfiguration backoffConfiguration = RetryBackoffConfiguration.builder()
             .maxRetries(2)
             .firstBackoff(Duration.ofMillis(1))


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 14/16: JAMES-3078 Integration tests for CORS headers

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 1bc8e367df50c557c9a4a6c71e0daebe9227723b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Mar 23 15:48:01 2020 +0700

    JAMES-3078 Integration tests for CORS headers
---
 .../apache/james/jmap/JMAPAuthenticationTest.java  | 14 ++++
 .../methods/integration/CorsHeaderAPITest.java     | 82 ++++++++++++++++++++++
 .../integration/cucumber/DownloadStepdefs.java     |  7 ++
 .../test/resources/cucumber/DownloadGet.feature    |  6 ++
 .../test/resources/cucumber/DownloadPost.feature   |  6 ++
 .../james/jmap/memory/MemoryCorsHeaderAPITest.java | 37 ++++++++++
 6 files changed, 152 insertions(+)

diff --git a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java
index 08018db..184bc13 100644
--- a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java
+++ b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/JMAPAuthenticationTest.java
@@ -165,6 +165,20 @@ public abstract class JMAPAuthenticationTest {
     }
 
     @Test
+    public void mustPositionCorsHeaders() throws Exception {
+        given()
+            .contentType(ContentType.JSON)
+            .accept(ContentType.JSON)
+            .body("{\"username\": \"" + userCredentials.getUsername() + "\", \"clientName\": \"Mozilla Thunderbird\", \"clientVersion\": \"42.0\", \"deviceName\": \"Joe Blogg’s iPhone\"}")
+        .when()
+            .post("/authentication")
+        .then()
+            .header("Access-Control-Allow-Origin", "*")
+            .header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
+            .header("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
+    }
+
+    @Test
     public void mustReturnJsonResponse() throws Exception {
         given()
             .contentType(ContentType.JSON)
diff --git a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/CorsHeaderAPITest.java b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/CorsHeaderAPITest.java
new file mode 100644
index 0000000..c942c69
--- /dev/null
+++ b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/CorsHeaderAPITest.java
@@ -0,0 +1,82 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.draft.methods.integration;
+
+import static io.restassured.RestAssured.given;
+import static org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
+import static org.apache.james.jmap.JMAPTestingConstants.ALICE;
+import static org.apache.james.jmap.JMAPTestingConstants.ALICE_PASSWORD;
+import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
+import static org.apache.james.jmap.JMAPTestingConstants.jmapRequestSpecBuilder;
+import static org.apache.james.jmap.JmapURIBuilder.baseUri;
+
+import java.io.IOException;
+
+import org.apache.james.GuiceJamesServer;
+import org.apache.james.jmap.AccessToken;
+import org.apache.james.jmap.draft.JmapGuiceProbe;
+import org.apache.james.probe.DataProbe;
+import org.apache.james.utils.DataProbeImpl;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.restassured.RestAssured;
+
+public abstract class CorsHeaderAPITest {
+    protected abstract GuiceJamesServer createJmapServer() throws IOException;
+
+    private AccessToken accessToken;
+    private GuiceJamesServer jmapServer;
+    
+    @Before
+    public void setup() throws Throwable {
+        jmapServer = createJmapServer();
+        jmapServer.start();
+
+        RestAssured.requestSpecification = jmapRequestSpecBuilder
+                .setPort(jmapServer.getProbe(JmapGuiceProbe.class).getJmapPort().getValue())
+                .build();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+
+        DataProbe dataProbe = jmapServer.getProbe(DataProbeImpl.class);
+        dataProbe.addDomain(DOMAIN);
+        dataProbe.addUser(ALICE.asString(), ALICE_PASSWORD);
+        accessToken = authenticateJamesUser(baseUri(jmapServer), ALICE, ALICE_PASSWORD);
+    }
+
+    @After
+    public void teardown() {
+        jmapServer.stop();
+    }
+    
+    @Test
+    public void apiShouldPositionCorsHeaders() {
+        given()
+            .header("Authorization", accessToken.asString())
+            .body("[[\"getMailboxes\", {\"accountId\": \"1\"}, \"#0\"]]")
+        .when()
+            .post("/jmap")
+        .then()
+            .header("Access-Control-Allow-Origin", "*")
+            .header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
+            .header("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
+    }
+}
diff --git a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/cucumber/DownloadStepdefs.java b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/cucumber/DownloadStepdefs.java
index eb1e05f..41a8fe1 100644
--- a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/cucumber/DownloadStepdefs.java
+++ b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/cucumber/DownloadStepdefs.java
@@ -490,6 +490,13 @@ public class DownloadStepdefs {
         assertThat(response.getFirstHeader("Content-Length").getValue()).isEqualTo(String.valueOf(size));
     }
 
+    @Then("^CORS headers are positioned$")
+    public void assertCorsHeader() {
+        assertThat(response.getFirstHeader("Access-Control-Allow-Origin").getValue()).isEqualTo("*");
+        assertThat(response.getFirstHeader("Access-Control-Allow-Methods").getValue()).isEqualTo("GET, POST, DELETE, PUT");
+        assertThat(response.getFirstHeader("Access-Control-Allow-Headers").getValue()).isEqualTo("Content-Type, Authorization, Accept");
+    }
+
     @Then("^the Content-Type is \"([^\"]*)\"$")
     public void assertContentType(String contentType) {
         assertThat(response.getFirstHeader("Content-Type").getValue()).isEqualTo(contentType);
diff --git a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
index 2639d86..5132a5f 100644
--- a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
+++ b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
@@ -75,6 +75,12 @@ Feature: Download GET
     Then she can read that blob
     And the blob size is 36
 
+  Scenario: Position CORS headers
+    Given "alice@domain.tld" mailbox "INBOX" contains a message "1"
+    When "alice@domain.tld" downloads "1"
+    Then she can read that blob
+    And CORS headers are positioned
+
   Scenario: Deleted message should revoke attachment blob download rights
     Given "alice@domain.tld" mailbox "INBOX" contains a message "1" with an attachment "2"
     And "alice@domain.tld" delete mailbox "INBOX"
diff --git a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadPost.feature b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadPost.feature
index e6f09ab..13270a1 100644
--- a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadPost.feature
+++ b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/resources/cucumber/DownloadPost.feature
@@ -35,3 +35,9 @@ Feature: Alternative authentication mechanism for getting attachment via a POST
     Given "username@domain.tld" mailbox "INBOX" contains a message "1" with an attachment "2"
     When "username@domain.tld" asks for a token for attachment "2"
     Then the user should receive an attachment access token
+
+  Scenario: Position CORS headers
+    Given "username@domain.tld" mailbox "INBOX" contains a message "1" with an attachment "2"
+    When "username@domain.tld" asks for a token for attachment "2"
+    Then the user should receive an attachment access token
+    And CORS headers are positioned
\ No newline at end of file
diff --git a/server/protocols/jmap-draft-integration-testing/memory-jmap-draft-integration-testing/src/test/java/org/apache/james/jmap/memory/MemoryCorsHeaderAPITest.java b/server/protocols/jmap-draft-integration-testing/memory-jmap-draft-integration-testing/src/test/java/org/apache/james/jmap/memory/MemoryCorsHeaderAPITest.java
new file mode 100644
index 0000000..2b422c0
--- /dev/null
+++ b/server/protocols/jmap-draft-integration-testing/memory-jmap-draft-integration-testing/src/test/java/org/apache/james/jmap/memory/MemoryCorsHeaderAPITest.java
@@ -0,0 +1,37 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.memory;
+
+import java.io.IOException;
+
+import org.apache.james.GuiceJamesServer;
+import org.apache.james.MemoryJmapTestRule;
+import org.apache.james.jmap.draft.methods.integration.CorsHeaderAPITest;
+import org.junit.Rule;
+
+public class MemoryCorsHeaderAPITest extends CorsHeaderAPITest {
+    @Rule
+    public MemoryJmapTestRule memoryJmap = new MemoryJmapTestRule();
+
+    @Override
+    protected GuiceJamesServer createJmapServer() throws IOException {
+        return memoryJmap.jmapServer();
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 02/16: JAMES-3088 MemoryUsersRepository should use its parent boolean virtualHosting

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit be27078b5e42a06f588b82f28349670efa2b3491
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 10:28:24 2020 +0700

    JAMES-3088 MemoryUsersRepository should use its parent boolean virtualHosting
---
 .../apache/james/user/memory/MemoryUsersRepository.java | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java b/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java
index d7c7d53..2853514 100644
--- a/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java
+++ b/server/data/data-memory/src/main/java/org/apache/james/user/memory/MemoryUsersRepository.java
@@ -37,22 +37,24 @@ import org.apache.james.user.lib.model.DefaultUser;
 public class MemoryUsersRepository extends AbstractUsersRepository {
 
     public static MemoryUsersRepository withVirtualHosting(DomainList domainList) {
-        return new MemoryUsersRepository(domainList, true);
+         MemoryUsersRepository userRepository = new MemoryUsersRepository(domainList);
+         userRepository.setEnableVirtualHosting(true);
+         return userRepository;
     }
 
     public static MemoryUsersRepository withoutVirtualHosting(DomainList domainList) {
-        return new MemoryUsersRepository(domainList, false);
+        MemoryUsersRepository userRepository = new MemoryUsersRepository(domainList);
+        userRepository.setEnableVirtualHosting(false);
+        return userRepository;
     }
     
     private final Map<String, User> userByName;
-    private final boolean supportVirtualHosting;
     private String algo;
 
-    private MemoryUsersRepository(DomainList domainList, boolean supportVirtualHosting) {
+    private MemoryUsersRepository(DomainList domainList) {
         super(domainList);
         this.userByName = new HashMap<>();
         this.algo = "MD5";
-        this.supportVirtualHosting = supportVirtualHosting;
     }
 
     public void clear() {
@@ -60,11 +62,6 @@ public class MemoryUsersRepository extends AbstractUsersRepository {
     }
 
     @Override
-    public boolean supportVirtualHosting() {
-        return supportVirtualHosting;
-    }
-
-    @Override
     public void doConfigure(HierarchicalConfiguration<ImmutableNode> config) throws ConfigurationException {
         algo = config.getString("algorithm", "MD5");
         super.doConfigure(config);


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 01/16: JAMES-3088 remove mockito ReadOnlyUsersLDAPRepositoryTest

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit c68b8f36480527402cd58d14572aca2ae1c2dfea
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 10:13:33 2020 +0700

    JAMES-3088 remove mockito ReadOnlyUsersLDAPRepositoryTest
---
 server/data/data-ldap/pom.xml                                       | 6 ++++++
 .../org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java | 6 ++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/server/data/data-ldap/pom.xml b/server/data/data-ldap/pom.xml
index 3a01707..1e0ccfc 100644
--- a/server/data/data-ldap/pom.xml
+++ b/server/data/data-ldap/pom.xml
@@ -39,6 +39,12 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-data-library</artifactId>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-lifecycle-api</artifactId>
         </dependency>
         <dependency>
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
index 8d0fd20..9b09f06 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
@@ -25,7 +25,6 @@ import static org.apache.james.user.ldap.DockerLdapSingleton.JAMES_USER;
 import static org.apache.james.user.ldap.DockerLdapSingleton.PASSWORD;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.mock;
 
 import org.apache.commons.configuration2.HierarchicalConfiguration;
 import org.apache.commons.configuration2.ex.ConversionException;
@@ -35,6 +34,9 @@ import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.DomainList;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
+import org.apache.james.domainlist.api.mock.SimpleDomainList;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -69,7 +71,7 @@ class ReadOnlyUsersLDAPRepositoryTest {
 
     @BeforeEach
     void setUp() {
-        domainList = mock(DomainList.class);
+        domainList = new SimpleDomainList();
     }
 
     @Nested


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 09/16: JAMES-3088 Apply contract tests to the LDAPUserRepository

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit d56e5ef944d6084068410debd0ff674e6e0550c6
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 13:22:19 2020 +0700

    JAMES-3088 Apply contract tests to the LDAPUserRepository
---
 .../james/user/ldap/DockerLdapSingleton.java       |   2 +
 .../ReadOnlyUsersLDAPRepositoryInvalidDnTest.java  |   4 -
 .../user/ldap/ReadOnlyUsersLDAPRepositoryTest.java | 628 +++++++++++++++++----
 .../user/lib/AbstractUsersRepositoryContract.java  |  12 +-
 4 files changed, 542 insertions(+), 104 deletions(-)

diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/DockerLdapSingleton.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/DockerLdapSingleton.java
index 1a61bd9..9de0fa7 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/DockerLdapSingleton.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/DockerLdapSingleton.java
@@ -26,6 +26,8 @@ public class DockerLdapSingleton {
     public static final String PASSWORD = "secret";
     public static final String DOMAIN = "james.org";
     public static final String ADMIN_PASSWORD = "mysecretpassword";
+    public static final String ADMIN_LOCAL_PART = "admin";
+    public static final Username ADMIN = Username.fromLocalPartWithDomain(ADMIN_LOCAL_PART, DOMAIN);
 
     public static final LdapGenericContainer ldapContainer = LdapGenericContainer.builder()
         .domain(DOMAIN)
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java
index 33fd239..d558dd7 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryInvalidDnTest.java
@@ -27,16 +27,12 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
 import org.apache.commons.configuration2.HierarchicalConfiguration;
-import org.apache.commons.configuration2.plist.PropertyListConfiguration;
 import org.apache.commons.configuration2.tree.ImmutableNode;
-import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.DomainList;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.ImmutableList;
 
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
index 9b09f06..8fbaa63 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.user.ldap;
 
+import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN;
+import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN_LOCAL_PART;
 import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN_PASSWORD;
 import static org.apache.james.user.ldap.DockerLdapSingleton.DOMAIN;
 import static org.apache.james.user.ldap.DockerLdapSingleton.JAMES_USER;
@@ -37,9 +39,13 @@ import org.junit.jupiter.api.BeforeAll;
 import org.apache.james.domainlist.api.mock.SimpleDomainList;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
+import org.apache.james.user.lib.AbstractUsersRepository;
+import org.apache.james.user.lib.AbstractUsersRepositoryContract;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,8 +63,6 @@ class ReadOnlyUsersLDAPRepositoryTest {
         .password(ADMIN_PASSWORD)
         .build();
 
-    DomainList domainList;
-
     @BeforeAll
     static void setUpAll() {
         ldapContainer.start();
@@ -69,188 +73,620 @@ class ReadOnlyUsersLDAPRepositoryTest {
         ldapContainer.start();
     }
 
-    @BeforeEach
-    void setUp() {
-        domainList = new SimpleDomainList();
-    }
-
     @Nested
-    class SupportVirtualHosting {
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryContract.WithVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
+
+        private ReadOnlyUsersLDAPRepository usersRepository;
 
+        @BeforeEach
+        void setUp(TestSystem testSystem) throws Exception {
+            usersRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer), testSystem.getDomainList());
+        }
+
+        @Override
+        public AbstractUsersRepository testee() {
+            return usersRepository;
+        }
+
+        @Override
         @Test
-        void supportVirtualHostingShouldReturnFalseByDefault() throws Exception {
-            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(domainList);
-            usersLDAPRepository.configure(ldapRepositoryConfiguration(ldapContainer));
+        public void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
+            assertThat(testee().isAdministrator(testSystem.getAdmin())).isTrue();
+        }
 
-            assertThat(usersLDAPRepository.supportVirtualHosting()).isFalse();
+        @Test
+        void knownUserShouldBeAbleToLogInWhenPasswordIsCorrectWithVirtualHosting() throws Exception {
+            assertThat(usersRepository.test(JAMES_USER_MAIL, PASSWORD)).isTrue();
         }
 
         @Test
-        void supportVirtualHostingShouldReturnTrueWhenReportedInConfig() throws Exception {
-            HierarchicalConfiguration<ImmutableNode> configuration = ldapRepositoryConfiguration(ldapContainer);
-            configuration.addProperty(ReadOnlyUsersLDAPRepository.SUPPORTS_VIRTUAL_HOSTING, "true");
+        void testShouldStillWorkAfterRestartingLDAP() throws Exception {
+            usersRepository.test(JAMES_USER_MAIL, PASSWORD);
 
-            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(domainList);
-            usersLDAPRepository.configure(configuration);
+            DockerLdapSingleton.ldapContainer.pause();
+            try {
+                usersRepository.test(JAMES_USER_MAIL, PASSWORD);
+            } catch (Exception e) {
+                LOGGER.info("This exception is expected as we shut down the LDAP and forced its use", e);
+            }
+            DockerLdapSingleton.ldapContainer.unpause();
 
-            assertThat(usersLDAPRepository.supportVirtualHosting()).isTrue();
+            assertThat(usersRepository.test(JAMES_USER_MAIL, PASSWORD)).isTrue();
         }
 
         @Test
-        void supportVirtualHostingShouldReturnFalseWhenReportedInConfig() throws Exception {
-            HierarchicalConfiguration<ImmutableNode> configuration = ldapRepositoryConfiguration(ldapContainer);
-            configuration.addProperty(ReadOnlyUsersLDAPRepository.SUPPORTS_VIRTUAL_HOSTING, "false");
+        void knownUserShouldNotBeAbleToLogInWhenPasswordIsNotCorrectWithVirtualHosting() throws Exception {
+            assertThat(usersRepository.test(JAMES_USER, BAD_PASSWORD)).isFalse();
+        }
 
-            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(domainList);
-            usersLDAPRepository.configure(configuration);
+        @Test
+        void unknownUserShouldNotBeAbleToLogInWithVirtualHosting() throws Exception {
+            assertThat(usersRepository.test(UNKNOWN, BAD_PASSWORD)).isFalse();
+        }
 
-            assertThat(usersLDAPRepository.supportVirtualHosting()).isFalse();
+        @Test
+        void unknownUserShouldNotBeAbleToLogInWhenPasswordIsCorrectWithVirtualHosting() throws Exception {
+            assertThat(usersRepository.test(UNKNOWN, PASSWORD)).isFalse();
         }
 
         @Test
-        void configureShouldThrowOnNonBooleanValueForSupportsVirtualHosting() {
-            HierarchicalConfiguration<ImmutableNode> configuration = ldapRepositoryConfiguration(ldapContainer);
-            configuration.addProperty(ReadOnlyUsersLDAPRepository.SUPPORTS_VIRTUAL_HOSTING, "bad");
+        void specialCharacterInUserInputShouldBeSanitized() throws Exception {
+            Username patternMatchingMultipleUsers = Username.of("j*");
 
-            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(domainList);
+            assertThat(usersRepository.test(patternMatchingMultipleUsers, PASSWORD)).isFalse();
+        }
 
-            assertThatThrownBy(() -> usersLDAPRepository.configure(configuration))
-                .isInstanceOf(ConversionException.class);
+        @Test
+        void containsWithGetUserShouldBeTrueWithVirtualHosting() throws Exception {
+            assertThat(usersRepository.contains(usersRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
+        }
+
+        @Disabled("JAMES-3088 isAdministrator is case sensitive")
+        @Override
+        @Test
+        public void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void removeUserShouldBeCaseInsentive(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Override
+        @Test
+        public void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldDisableCaseVariation(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem){
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Override
+        @Test
+        public void countUsersShouldReturnZeroWhenEmptyRepository() {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldBeCaseInsentive(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void containsShouldBeCaseInsentive(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void containsShouldPreserveCaseVariation(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void listShouldReturnLowerCaseUser(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
         }
     }
 
     @Nested
-    class TestUser {
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryContract.WithOutVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
+
+        private ReadOnlyUsersLDAPRepository usersRepository;
+
+        @BeforeEach
+        void setUp(TestSystem testSystem) throws Exception {
+            usersRepository = startUsersRepository(ldapRepositoryConfiguration(ldapContainer), testSystem.getDomainList());
+        }
+
+        @Override
+        public AbstractUsersRepository testee() {
+            return usersRepository;
+        }
 
         @Test
         void knownUserShouldBeAbleToLogInWhenPasswordIsCorrect() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfiguration(ldapContainer));
-            assertThat(ldapRepository.test(JAMES_USER, PASSWORD)).isTrue();
+            assertThat(usersRepository.test(JAMES_USER, PASSWORD)).isTrue();
         }
 
         @Test
         void knownUserShouldNotBeAbleToLogInWhenPasswordIsNotCorrect() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfiguration(ldapContainer));
-            assertThat(ldapRepository.test(JAMES_USER, BAD_PASSWORD)).isFalse();
+            assertThat(usersRepository.test(JAMES_USER, BAD_PASSWORD)).isFalse();
         }
 
         @Test
         void unknownUserShouldNotBeAbleToLogIn() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfiguration(ldapContainer));
-            assertThat(ldapRepository.test(UNKNOWN, BAD_PASSWORD)).isFalse();
+            assertThat(usersRepository.test(UNKNOWN, BAD_PASSWORD)).isFalse();
         }
 
         @Test
         void unknownUserShouldNotBeAbleToLogInWhenPasswordIsCorrect() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfiguration(ldapContainer));
-            assertThat(ldapRepository.test(UNKNOWN, PASSWORD)).isFalse();
+            assertThat(usersRepository.test(UNKNOWN, PASSWORD)).isFalse();
         }
 
         @Test
-        void knownUserShouldBeAbleToLogInWhenPasswordIsCorrectWithVirtualHosting() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ldapRepository.test(JAMES_USER_MAIL, PASSWORD)).isTrue();
+        void containsWithGetUserShouldBeTrue() throws Exception {
+            assertThat(usersRepository.contains(usersRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
         }
 
+        @Override
         @Test
-        void testShouldListUsers() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ImmutableList.copyOf(ldapRepository.list()))
-                .containsOnly(JAMES_USER_MAIL);
+        public void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
+            assertThat(testee().isAdministrator(testSystem.getAdmin())).isTrue();
         }
 
+        @Disabled("JAMES-3088 isAdministrator is case sensitive")
+        @Override
         @Test
-        void testShouldStillWorkAfterRestartingLDAP() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            ldapRepository.test(JAMES_USER_MAIL, PASSWORD);
+        public void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
+        }
 
-            DockerLdapSingleton.ldapContainer.pause();
-            try {
-                ldapRepository.test(JAMES_USER_MAIL, PASSWORD);
-            } catch (Exception e) {
-                LOGGER.info("This exception is expected as we shut down the LDAP and forced its use", e);
-            }
-            DockerLdapSingleton.ldapContainer.unpause();
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
+        }
 
-            assertThat(ldapRepository.test(JAMES_USER_MAIL, PASSWORD)).isTrue();
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) {
         }
 
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
         @Test
-        void knownUserShouldNotBeAbleToLogInWhenPasswordIsNotCorrectWithVirtualHosting() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ldapRepository.test(JAMES_USER, BAD_PASSWORD)).isFalse();
+        public void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) {
         }
 
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
         @Test
-        void unknownUserShouldNotBeAbleToLogInWithVirtualHosting() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ldapRepository.test(UNKNOWN, BAD_PASSWORD)).isFalse();
+        public void removeUserShouldBeCaseInsentive(TestSystem testSystem) {
         }
 
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Override
         @Test
-        void unknownUserShouldNotBeAbleToLogInWhenPasswordIsCorrectWithVirtualHosting() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ldapRepository.test(UNKNOWN, PASSWORD)).isFalse();
+        public void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) {
         }
 
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
         @Test
-        void specialCharacterInUserInputShouldBeSanitized() throws Exception {
-            Username patternMatchingMultipleUsers = Username.of("j*");
+        public void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) {
+        }
 
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ldapRepository.test(patternMatchingMultipleUsers, PASSWORD)).isFalse();
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldDisableCaseVariation(TestSystem testSystem) {
         }
 
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
         @Test
-        void containsWithGetUserShouldBeTrue() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfiguration(ldapContainer));
-            assertThat(ldapRepository.contains(ldapRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
+        public void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem){
         }
 
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
         @Test
-        void containsWithGetUserShouldBeTrueWithVirtualHosting() throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ldapRepository.contains(ldapRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
+        public void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) {
         }
 
-        private ReadOnlyUsersLDAPRepository startUsersRepository(HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration) throws Exception {
-            ReadOnlyUsersLDAPRepository ldapRepository = new ReadOnlyUsersLDAPRepository(domainList);
-            ldapRepository.configure(ldapRepositoryConfiguration);
-            ldapRepository.init();
-            return ldapRepository;
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Override
+        @Test
+        public void countUsersShouldReturnZeroWhenEmptyRepository() {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldBeCaseInsentive(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void containsShouldBeCaseInsentive(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void containsShouldPreserveCaseVariation(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
         }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void listShouldReturnLowerCaseUser(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) {
+        }
+
+        @Disabled("JAMES-3088 This user-repository is read-only. Modifications are not permitted.")
+        @Override
+        @Test
+        public void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) {
+        }
+
     }
 
-    private HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration(LdapGenericContainer ldapContainer) {
-        PropertyListConfiguration configuration = new PropertyListConfiguration();
-        configuration.addProperty("[@ldapHost]", ldapContainer.getLdapHost());
-        configuration.addProperty("[@principal]", "cn=admin,dc=james,dc=org");
-        configuration.addProperty("[@credentials]", ADMIN_PASSWORD);
-        configuration.addProperty("[@userBase]", "ou=People,dc=james,dc=org");
+    @Nested
+    class SupportVirtualHosting {
+
+        @Test
+        void supportVirtualHostingShouldReturnFalseByDefault() throws Exception {
+            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(new SimpleDomainList());
+            usersLDAPRepository.configure(ldapRepositoryConfiguration(ldapContainer));
+
+            assertThat(usersLDAPRepository.supportVirtualHosting()).isFalse();
+        }
+
+        @Test
+        void supportVirtualHostingShouldReturnTrueWhenReportedInConfig() throws Exception {
+            HierarchicalConfiguration<ImmutableNode> configuration = ldapRepositoryConfiguration(ldapContainer);
+            configuration.addProperty(ReadOnlyUsersLDAPRepository.SUPPORTS_VIRTUAL_HOSTING, "true");
+
+            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(new SimpleDomainList());
+            usersLDAPRepository.configure(configuration);
+
+            assertThat(usersLDAPRepository.supportVirtualHosting()).isTrue();
+        }
+
+        @Test
+        void supportVirtualHostingShouldReturnFalseWhenReportedInConfig() throws Exception {
+            HierarchicalConfiguration<ImmutableNode> configuration = ldapRepositoryConfiguration(ldapContainer);
+            configuration.addProperty(ReadOnlyUsersLDAPRepository.SUPPORTS_VIRTUAL_HOSTING, "false");
+
+            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(new SimpleDomainList());
+            usersLDAPRepository.configure(configuration);
+
+            assertThat(usersLDAPRepository.supportVirtualHosting()).isFalse();
+        }
+
+        @Test
+        void configureShouldThrowOnNonBooleanValueForSupportsVirtualHosting() {
+            HierarchicalConfiguration<ImmutableNode> configuration = ldapRepositoryConfiguration(ldapContainer);
+            configuration.addProperty(ReadOnlyUsersLDAPRepository.SUPPORTS_VIRTUAL_HOSTING, "bad");
+
+            ReadOnlyUsersLDAPRepository usersLDAPRepository = new ReadOnlyUsersLDAPRepository(new SimpleDomainList());
+
+            assertThatThrownBy(() -> usersLDAPRepository.configure(configuration))
+                .isInstanceOf(ConversionException.class);
+        }
+    }
+
+    private static ReadOnlyUsersLDAPRepository startUsersRepository(HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration,
+                                                             DomainList domainList) throws Exception {
+        ReadOnlyUsersLDAPRepository ldapRepository = new ReadOnlyUsersLDAPRepository(domainList);
+        ldapRepository.configure(ldapRepositoryConfiguration);
+        ldapRepository.init();
+        return ldapRepository;
+    }
+
+    private static HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration(LdapGenericContainer ldapContainer) {
+        PropertyListConfiguration configuration = baseConfiguration(ldapContainer);
         configuration.addProperty("[@userIdAttribute]", "uid");
-        configuration.addProperty("[@userObjectClass]", "inetOrgPerson");
-        configuration.addProperty("[@maxRetries]", "1");
-        configuration.addProperty("[@retryStartInterval]", "0");
-        configuration.addProperty("[@retryMaxInterval]", "2");
-        configuration.addProperty("[@retryIntervalScale]", "100");
-        configuration.addProperty("[@connectionTimeout]", "100");
-        configuration.addProperty("[@readTimeout]", "100");
+        configuration.addProperty("[@administratorId]", ADMIN_LOCAL_PART);
         return configuration;
     }
 
     static HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfigurationWithVirtualHosting(LdapGenericContainer ldapContainer) {
+        PropertyListConfiguration configuration = baseConfiguration(ldapContainer);
+        configuration.addProperty("[@userIdAttribute]", "mail");
+        configuration.addProperty("supportsVirtualHosting", true);
+        configuration.addProperty("[@administratorId]", ADMIN.asString());
+        return configuration;
+    }
+
+    private static PropertyListConfiguration baseConfiguration(LdapGenericContainer ldapContainer) {
         PropertyListConfiguration configuration = new PropertyListConfiguration();
         configuration.addProperty("[@ldapHost]", ldapContainer.getLdapHost());
         configuration.addProperty("[@principal]", "cn=admin,dc=james,dc=org");
         configuration.addProperty("[@credentials]", ADMIN_PASSWORD);
         configuration.addProperty("[@userBase]", "ou=People,dc=james,dc=org");
-        configuration.addProperty("[@userIdAttribute]", "mail");
         configuration.addProperty("[@userObjectClass]", "inetOrgPerson");
         configuration.addProperty("[@maxRetries]", "1");
         configuration.addProperty("[@retryStartInterval]", "0");
         configuration.addProperty("[@retryMaxInterval]", "2");
         configuration.addProperty("[@retryIntervalScale]", "100");
-        configuration.addProperty("supportsVirtualHosting", true);
         configuration.addProperty("[@connectionTimeout]", "100");
         configuration.addProperty("[@readTimeout]", "100");
         return configuration;
diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
index 6c0fd3b..4780b02 100644
--- a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
+++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
@@ -88,7 +88,7 @@ public interface AbstractUsersRepositoryContract {
     }
 
     class TestSystem {
-        static final Domain DOMAIN = Domain.of("domain");
+        static final Domain DOMAIN = Domain.of("james.org");
 
         private final boolean supportVirtualHosting;
         private final SimpleDomainList domainList;
@@ -122,18 +122,22 @@ public interface AbstractUsersRepositoryContract {
         public SimpleDomainList getDomainList() {
             return domainList;
         }
+
+        public Username getAdmin() {
+            return admin;
+        }
     }
 
     interface WithVirtualHostingContract extends AbstractUsersRepositoryContract {
 
         @Test
         default void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) throws Exception {
-            testSystem.domainList.addDomain(Domain.of("jAmEs.oRg"));
+            testSystem.domainList.addDomain(Domain.of("Domain.OrG"));
             String username = "myuser";
             String password = "password";
-            testee().addUser(Username.of(username + "@jAmEs.oRg"), password);
+            testee().addUser(Username.of(username + "@Domain.OrG"), password);
 
-            boolean actual = testee().test(Username.of(username + "@james.org"), password);
+            boolean actual = testee().test(Username.of(username + "@domain.org"), password);
 
             assertThat(actual).isTrue();
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 08/16: JAMES-3088 Make LDAPUserRepository inherit AbstractUserRepository

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 22e116647e705ea4f5b3ffa69ee76cbeb444053b
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 12:27:16 2020 +0700

    JAMES-3088 Make LDAPUserRepository inherit AbstractUserRepository
    
    Reasons:
     - AbstractUserRepository and LDAPUserRepository all carry the information
     of domainList
     - getMailAddressFor() is 100% same in both classes, can get rid of
     that duplication
     - reuse the well implemented `assertValid(Username)` in AbstractUserRepository
     in the future to serve this JAMES-XXXX
     - inherit the rich Contract from AbstractUserRepository
---
 server/data/data-ldap/pom.xml                      |  4 +++
 .../user/ldap/ReadOnlyUsersLDAPRepository.java     | 29 ++++++++--------------
 2 files changed, 14 insertions(+), 19 deletions(-)

diff --git a/server/data/data-ldap/pom.xml b/server/data/data-ldap/pom.xml
index 1e0ccfc..6eb5460 100644
--- a/server/data/data-ldap/pom.xml
+++ b/server/data/data-ldap/pom.xml
@@ -45,6 +45,10 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-data-library</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-server-lifecycle-api</artifactId>
         </dependency>
         <dependency>
diff --git a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java
index e9af7ac..c1ec084 100644
--- a/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java
+++ b/server/data/data-ldap/src/main/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepository.java
@@ -46,14 +46,13 @@ import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.commons.configuration2.tree.ImmutableNode;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.directory.api.ldap.model.filter.FilterEncoder;
-import org.apache.james.core.MailAddress;
 import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.lifecycle.api.Configurable;
-import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.api.model.User;
 import org.apache.james.user.ldap.api.LdapConstants;
+import org.apache.james.user.lib.AbstractUsersRepository;
 import org.apache.james.util.OptionalUtils;
 import org.apache.james.util.retry.DoublingRetrySchedule;
 import org.apache.james.util.retry.api.RetrySchedule;
@@ -243,7 +242,7 @@ import com.google.common.base.Strings;
  * @see ReadOnlyLDAPGroupRestriction
  *
  */
-public class ReadOnlyUsersLDAPRepository implements UsersRepository, Configurable {
+public class ReadOnlyUsersLDAPRepository extends AbstractUsersRepository implements Configurable {
     private static final Logger LOGGER = LoggerFactory.getLogger(ReadOnlyUsersLDAPRepository.class);
 
     // The name of the factory class which creates the initial context
@@ -264,13 +263,11 @@ public class ReadOnlyUsersLDAPRepository implements UsersRepository, Configurabl
     // The schedule for retry attempts
     private RetrySchedule schedule = null;
 
-    private final DomainList domainList;
     private LdapRepositoryConfiguration ldapConfiguration;
 
     @Inject
     public ReadOnlyUsersLDAPRepository(DomainList domainList) {
-        super();
-        this.domainList = domainList;
+        super(domainList);
     }
 
     /**
@@ -666,6 +663,13 @@ public class ReadOnlyUsersLDAPRepository implements UsersRepository, Configurabl
     }
 
     @Override
+    protected void doAddUser(Username username, String password) throws UsersRepositoryException {
+        LOGGER.error("This user-repository is read-only. Modifications are not permitted.");
+        throw new UsersRepositoryException(
+                "This user-repository is read-only. Modifications are not permitted.");
+    }
+
+    @Override
     public boolean isAdministrator(Username username) {
         if (ldapConfiguration.getAdministratorId().isPresent()) {
             return ldapConfiguration.getAdministratorId().get().equals(username);
@@ -677,17 +681,4 @@ public class ReadOnlyUsersLDAPRepository implements UsersRepository, Configurabl
     public boolean isReadOnly() {
         return true;
     }
-
-
-    @Override
-    public MailAddress getMailAddressFor(Username username) throws UsersRepositoryException {
-        try {
-            if (supportVirtualHosting()) {
-                return new MailAddress(username.asString());
-            }
-            return new MailAddress(username.getLocalPart(), domainList.getDefaultDomain());
-        } catch (Exception e) {
-            throw new UsersRepositoryException("Failed to compute mail address associated with the user", e);
-        }
-    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 15/16: JAMES-3087 Sequentially process authentication strategies

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 6ba313032776098da7e265c96fc26ca9c7ab57d6
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Mar 24 14:38:11 2020 +0700

    JAMES-3087 Sequentially process authentication strategies
    
    Solutions relying on JWT were also execution standard JMAP authentication
    
    This is because flatMap is eager.
    
    Sequentially processing avoids verbose logs of invalid access token format.
---
 .../jmap/http/AuthenticationReactiveFilter.java    | 11 +++--
 .../http/AuthenticationReactiveFilterTest.java     | 48 +++++++++++-----------
 2 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/AuthenticationReactiveFilter.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/AuthenticationReactiveFilter.java
index 2a68298..4955bc5 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/AuthenticationReactiveFilter.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/http/AuthenticationReactiveFilter.java
@@ -29,6 +29,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
 
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
@@ -37,6 +38,10 @@ import reactor.netty.http.server.HttpServerRequest;
 public class AuthenticationReactiveFilter {
     private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationReactiveFilter.class);
 
+    static AuthenticationReactiveFilter of(MetricFactory metricFactory, AuthenticationStrategy... authenticationStrategies) {
+        return new AuthenticationReactiveFilter(ImmutableList.copyOf(authenticationStrategies), metricFactory);
+    }
+
     private final List<AuthenticationStrategy> authMethods;
     private final MetricFactory metricFactory;
 
@@ -49,10 +54,10 @@ public class AuthenticationReactiveFilter {
 
     public Mono<MailboxSession> authenticate(HttpServerRequest request) {
         return Mono.from(metricFactory.runPublishingTimerMetric("JMAP-authentication-filter",
-            Flux.fromStream(authMethods.stream())
-                .flatMap(auth -> auth.createMailboxSession(request))
+            Flux.fromIterable(authMethods)
+                .concatMap(auth -> auth.createMailboxSession(request))
                 .onErrorContinue((throwable, nothing) -> LOGGER.error("Error while trying to authenticate with JMAP", throwable))
-                .singleOrEmpty()
+                .next()
                 .switchIfEmpty(Mono.error(new UnauthorizedException()))));
     }
 }
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticationReactiveFilterTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticationReactiveFilterTest.java
index b236aa8..16041b9 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticationReactiveFilterTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/http/AuthenticationReactiveFilterTest.java
@@ -18,13 +18,14 @@
  ****************************************************************/
 package org.apache.james.jmap.http;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.james.core.Username;
 import org.apache.james.jmap.api.access.AccessToken;
@@ -45,11 +46,13 @@ import reactor.core.publisher.Mono;
 import reactor.netty.http.server.HttpServerRequest;
 
 public class AuthenticationReactiveFilterTest {
-    private static final boolean AUTHORIZED = true;
     private static final String TOKEN = "df991d2a-1c5a-4910-a90f-808b6eda133e";
     private static final String AUTHORIZATION_HEADERS = "Authorization";
     private static final Username USERNAME = Username.of("user@domain.tld");
 
+    private static final AuthenticationStrategy DENY = httpRequest -> Mono.error(new MailboxSessionCreationException(null));
+    private static final AuthenticationStrategy ALLOW = httpRequest -> Mono.just(mock(MailboxSession.class));
+
     private HttpServerRequest mockedRequest;
     private HttpHeaders mockedHeaders;
     private AccessTokenRepository accessTokenRepository;
@@ -68,9 +71,7 @@ public class AuthenticationReactiveFilterTest {
         when(mockedRequest.requestHeaders())
             .thenReturn(mockedHeaders);
 
-        List<AuthenticationStrategy> fakeAuthenticationStrategies = ImmutableList.of(new FakeAuthenticationStrategy(!AUTHORIZED));
-
-        testee = new AuthenticationReactiveFilter(fakeAuthenticationStrategies, new RecordingMetricFactory());
+        testee = AuthenticationReactiveFilter.of(new RecordingMetricFactory(), DENY);
     }
 
     @Test
@@ -81,7 +82,21 @@ public class AuthenticationReactiveFilterTest {
         assertThatThrownBy(() -> testee.authenticate(mockedRequest).block())
             .isInstanceOf(UnauthorizedException.class);
     }
-    
+
+    @Test
+    public void authenticationStrategiesShouldNotBeEagerlySubScribed() {
+        AtomicBoolean called = new AtomicBoolean(false);
+
+        testee = AuthenticationReactiveFilter.of(new RecordingMetricFactory(),
+            ALLOW,
+            req -> Mono.fromRunnable(() -> called.set(true)));
+        assertThat(called.get()).isFalse();
+
+        testee.authenticate(mockedRequest).block();
+
+        assertThat(called.get()).isFalse();
+    }
+
     @Test
     public void filterShouldReturnUnauthorizedOnInvalidAuthorizationHeader() {
         when(mockedHeaders.get(AUTHORIZATION_HEADERS))
@@ -118,7 +133,7 @@ public class AuthenticationReactiveFilterTest {
 
         accessTokenRepository.addToken(USERNAME, token).block();
 
-        AuthenticationReactiveFilter authFilter = new AuthenticationReactiveFilter(ImmutableList.of(new FakeAuthenticationStrategy(AUTHORIZED)), new RecordingMetricFactory());
+        AuthenticationReactiveFilter authFilter = AuthenticationReactiveFilter.of(new RecordingMetricFactory(), ALLOW);
 
         assertThatCode(() -> authFilter.authenticate(mockedRequest).block())
             .doesNotThrowAnyException();
@@ -132,26 +147,9 @@ public class AuthenticationReactiveFilterTest {
 
         accessTokenRepository.addToken(USERNAME, token).block();
 
-        AuthenticationReactiveFilter authFilter = new AuthenticationReactiveFilter(ImmutableList.of(new FakeAuthenticationStrategy(!AUTHORIZED), new FakeAuthenticationStrategy(AUTHORIZED)), new RecordingMetricFactory());
+        AuthenticationReactiveFilter authFilter = AuthenticationReactiveFilter.of(new RecordingMetricFactory(), DENY, ALLOW);
 
         assertThatCode(() -> authFilter.authenticate(mockedRequest).block())
             .doesNotThrowAnyException();
     }
-
-    private static class FakeAuthenticationStrategy implements AuthenticationStrategy {
-
-        private final boolean isAuthorized;
-
-        private FakeAuthenticationStrategy(boolean isAuthorized) {
-            this.isAuthorized = isAuthorized;
-        }
-
-        @Override
-        public Mono<MailboxSession> createMailboxSession(HttpServerRequest httpRequest) {
-            if (!isAuthorized) {
-                return Mono.error(new MailboxSessionCreationException(null));
-            }
-            return Mono.just(mock(MailboxSession.class));
-        }
-    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 07/16: JAMES-3088 s/AbstractUsersRepositoryTest/AbstractUsersRepositoryContract

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 154148decba06b2d60b4ef72620bf8aa6e70e6b4
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 12:33:13 2020 +0700

    JAMES-3088 s/AbstractUsersRepositoryTest/AbstractUsersRepositoryContract
---
 .../james/user/cassandra/CassandraUsersRepositoryTest.java     |  6 +++---
 .../java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java |  6 +++---
 ...epositoryTest.java => AbstractUsersRepositoryContract.java} | 10 +++++-----
 .../apache/james/user/memory/MemoryUsersRepositoryTest.java    |  6 +++---
 4 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java
index c039679..6c2adee 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java
@@ -23,7 +23,7 @@ import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.user.lib.AbstractUsersRepository;
-import org.apache.james.user.lib.AbstractUsersRepositoryTest;
+import org.apache.james.user.lib.AbstractUsersRepositoryContract;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -34,7 +34,7 @@ class CassandraUsersRepositoryTest {
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraUsersRepositoryModule.MODULE);
 
     @Nested
-    class WhenEnableVirtualHosting implements AbstractUsersRepositoryTest.WithVirtualHostingContract {
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryContract.WithVirtualHostingContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
 
@@ -52,7 +52,7 @@ class CassandraUsersRepositoryTest {
     }
 
     @Nested
-    class WhenDisableVirtualHosting implements AbstractUsersRepositoryTest.WithOutVirtualHostingContract {
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryContract.WithOutVirtualHostingContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
 
diff --git a/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java b/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
index b912d30..02a2ebb 100644
--- a/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
+++ b/server/data/data-jpa/src/test/java/org/apache/james/user/jpa/JpaUsersRepositoryTest.java
@@ -23,7 +23,7 @@ import org.apache.james.backends.jpa.JpaTestCluster;
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.user.jpa.model.JPAUser;
 import org.apache.james.user.lib.AbstractUsersRepository;
-import org.apache.james.user.lib.AbstractUsersRepositoryTest;
+import org.apache.james.user.lib.AbstractUsersRepositoryContract;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -34,7 +34,7 @@ class JpaUsersRepositoryTest {
     private static final JpaTestCluster JPA_TEST_CLUSTER = JpaTestCluster.create(JPAUser.class);
 
     @Nested
-    class WhenEnableVirtualHosting implements AbstractUsersRepositoryTest.WithVirtualHostingContract {
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryContract.WithVirtualHostingContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
 
@@ -52,7 +52,7 @@ class JpaUsersRepositoryTest {
     }
 
     @Nested
-    class WhenDisableVirtualHosting implements AbstractUsersRepositoryTest.WithOutVirtualHostingContract {
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryContract.WithOutVirtualHostingContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
 
diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
similarity index 99%
rename from server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
rename to server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
index 93a20a8..6c0fd3b 100644
--- a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
+++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryContract.java
@@ -45,7 +45,7 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
-public interface AbstractUsersRepositoryTest {
+public interface AbstractUsersRepositoryContract {
 
     class UserRepositoryExtension implements BeforeEachCallback, ParameterResolver {
 
@@ -107,8 +107,8 @@ public interface AbstractUsersRepositoryTest {
             user2 = toUsername("username2");
             user3 = toUsername("username3");
             user1CaseVariation = toUsername("uSeRnaMe");
-            admin = toUsername("testSystem.admin");
-            adminCaseVariation = toUsername("testSystem.admin");
+            admin = toUsername("admin");
+            adminCaseVariation = toUsername("admin");
         }
 
         private Username toUsername(String login) {
@@ -124,7 +124,7 @@ public interface AbstractUsersRepositoryTest {
         }
     }
 
-    interface WithVirtualHostingContract extends AbstractUsersRepositoryTest {
+    interface WithVirtualHostingContract extends AbstractUsersRepositoryContract {
 
         @Test
         default void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) throws Exception {
@@ -163,7 +163,7 @@ public interface AbstractUsersRepositoryTest {
         }
     }
 
-    interface WithOutVirtualHostingContract extends AbstractUsersRepositoryTest {
+    interface WithOutVirtualHostingContract extends AbstractUsersRepositoryContract {
         @Test
         default void nonVirtualHostedUsersRepositoryShouldUseLocalPartAsUsername() throws Exception {
             // Some implementations do not support changing virtual hosting value
diff --git a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
index 51cc61e..cbae5da 100644
--- a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
+++ b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
@@ -28,7 +28,7 @@ import org.apache.james.dnsservice.api.InMemoryDNSService;
 import org.apache.james.domainlist.memory.MemoryDomainList;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.lib.AbstractUsersRepository;
-import org.apache.james.user.lib.AbstractUsersRepositoryTest;
+import org.apache.james.user.lib.AbstractUsersRepositoryContract;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -37,7 +37,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 class MemoryUsersRepositoryTest {
 
     @Nested
-    class WhenEnableVirtualHosting implements AbstractUsersRepositoryTest.WithVirtualHostingContract {
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryContract.WithVirtualHostingContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
 
@@ -90,7 +90,7 @@ class MemoryUsersRepositoryTest {
     }
 
     @Nested
-    class WhenDisableVirtualHosting implements AbstractUsersRepositoryTest.WithOutVirtualHostingContract {
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryContract.WithOutVirtualHostingContract {
         @RegisterExtension
         UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
 


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 12/16: JAMES-3087 Reactify MailboxMapper::findMailboxByPath

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 1903ddb442cc36bda117667c2e6ef91f881c81d4
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sun Mar 22 13:38:09 2020 +0700

    JAMES-3087 Reactify MailboxMapper::findMailboxByPath
---
 .../cassandra/mail/CassandraMailboxMapper.java     |  6 +-
 .../CassandraCombinationManagerTestSystem.java     |  5 +-
 .../cassandra/mail/CassandraMailboxMapperTest.java | 70 +++++++++++-----------
 .../mail/migration/MailboxPathV2MigrationTest.java |  2 +-
 .../james/mailbox/jpa/mail/JPAMailboxMapper.java   | 21 ++++---
 .../mailbox/jpa/mail/JpaMailboxMapperTest.java     |  6 +-
 .../jpa/mail/TransactionalMailboxMapper.java       |  4 +-
 .../mailbox/maildir/mail/MaildirMailboxMapper.java | 11 +++-
 .../inmemory/mail/InMemoryMailboxMapper.java       | 11 ++--
 .../store/StoreMailboxAnnotationManager.java       |  2 +-
 .../james/mailbox/store/StoreMailboxManager.java   | 34 ++++-------
 .../james/mailbox/store/StoreRightManager.java     | 10 ++--
 .../james/mailbox/store/mail/MailboxMapper.java    | 19 +++++-
 .../AbstractMailboxManagerAttachmentTest.java      |  2 +-
 .../mailbox/store/MessageIdManagerTestSystem.java  |  2 +-
 .../store/StoreMailboxManagerAnnotationTest.java   | 21 ++++---
 .../mailbox/store/StoreMailboxManagerTest.java     |  4 +-
 .../james/mailbox/store/StoreRightManagerTest.java |  4 +-
 .../store/mail/model/MailboxMapperACLTest.java     |  1 +
 .../store/mail/model/MailboxMapperTest.java        | 14 ++---
 .../org/apache/james/modules/MailboxProbeImpl.java |  7 ++-
 .../adapter/mailbox/MailboxManagementTest.java     |  5 +-
 22 files changed, 145 insertions(+), 116 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
index daf71ce..0f0244f 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java
@@ -82,13 +82,11 @@ public class CassandraMailboxMapper implements MailboxMapper {
     }
 
     @Override
-    public Mailbox findMailboxByPath(MailboxPath path) throws MailboxException {
+    public Mono<Mailbox> findMailboxByPath(MailboxPath path) {
         return mailboxPathV2DAO.retrieveId(path)
             .map(CassandraIdAndPath::getCassandraId)
             .flatMap(this::retrieveMailbox)
-            .switchIfEmpty(fromPreviousTable(path))
-            .blockOptional()
-            .orElseThrow(() -> new MailboxNotFoundException(path));
+            .switchIfEmpty(fromPreviousTable(path));
     }
 
     private Mono<Mailbox> fromPreviousTable(MailboxPath path) {
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java
index e2cc7d1..1e0c20e 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraCombinationManagerTestSystem.java
@@ -26,6 +26,7 @@ import org.apache.james.mailbox.MessageIdManager;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.quota.QuotaManager;
@@ -54,7 +55,9 @@ public class CassandraCombinationManagerTestSystem extends CombinationManagerTes
     @Override
     public Mailbox createMailbox(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
         cassandraMailboxManager.createMailbox(mailboxPath, session);
-        return mapperFactory.getMailboxMapper(session).findMailboxByPath(mailboxPath);
+        return mapperFactory.getMailboxMapper(session).findMailboxByPath(mailboxPath)
+            .blockOptional()
+            .orElseThrow(() -> new MailboxNotFoundException(mailboxPath));
     }
 
     @Override
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
index d16a079..1675f44 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapperTest.java
@@ -157,7 +157,7 @@ class CassandraMailboxMapperTest {
                         .assertThat(testee.findMailboxById(inboxId))
                         .isEqualTo(inboxRenamed);
                     softly(softly)
-                        .assertThat(testee.findMailboxByPath(inboxPathRenamed))
+                        .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
                         .isEqualTo(inboxRenamed);
                     softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
                         .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -184,7 +184,7 @@ class CassandraMailboxMapperTest {
                         .assertThat(testee.findMailboxById(inboxId))
                         .isEqualTo(inboxRenamed);
                     softly(softly)
-                        .assertThat(testee.findMailboxByPath(inboxPathRenamed))
+                        .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
                         .isEqualTo(inboxRenamed);
                     softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
                         .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -207,7 +207,7 @@ class CassandraMailboxMapperTest {
                         .assertThat(testee.findMailboxById(inbox.getMailboxId()))
                         .isEqualTo(inbox);
                     softly(softly)
-                        .assertThat(testee.findMailboxByPath(inboxPath))
+                        .assertThat(testee.findMailboxByPath(inboxPath).block())
                         .isEqualTo(inbox);
                     softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
                         .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -228,10 +228,10 @@ class CassandraMailboxMapperTest {
                 testee.delete(inbox);
 
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
-                    assertThatThrownBy(() -> testee.findMailboxById(inbox.getMailboxId()))
-                        .isInstanceOf(MailboxNotFoundException.class);
-                    assertThatThrownBy(() -> testee.findMailboxByPath(inboxPath))
+                    softly.assertThatThrownBy(() -> testee.findMailboxById(inbox.getMailboxId()))
                         .isInstanceOf(MailboxNotFoundException.class);
+                    softly.assertThat(testee.findMailboxByPath(inboxPath).blockOptional())
+                        .isEmpty();
                     softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
                         .isEmpty();
                 }));
@@ -248,8 +248,8 @@ class CassandraMailboxMapperTest {
             doQuietly(() -> testee.create(inboxPath, UID_VALIDITY));
 
             SoftAssertions.assertSoftly(softly -> {
-                softly.assertThatThrownBy(() -> testee.findMailboxByPath(inboxPath))
-                    .isInstanceOf(MailboxNotFoundException.class);
+                softly.assertThat(testee.findMailboxByPath(inboxPath).blockOptional())
+                    .isEmpty();
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .isEmpty();
                 softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
@@ -277,7 +277,7 @@ class CassandraMailboxMapperTest {
                     .assertThat(testee.findMailboxById(inboxId))
                     .isEqualTo(inbox);
                 softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath))
+                    .assertThat(testee.findMailboxByPath(inboxPath).block())
                     .isEqualTo(inbox);
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -348,7 +348,7 @@ class CassandraMailboxMapperTest {
                     .assertThat(testee.findMailboxById(inboxId))
                     .isEqualTo(inbox);
                 softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath))
+                    .assertThat(testee.findMailboxByPath(inboxPath).block())
                     .isEqualTo(inbox);
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -463,7 +463,7 @@ class CassandraMailboxMapperTest {
 
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath))
+                    .assertThat(testee.findMailboxByPath(inboxPath).block())
                     .isEqualTo(inbox);
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -490,7 +490,7 @@ class CassandraMailboxMapperTest {
 
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPath))
+                    .assertThat(testee.findMailboxByPath(inboxPath).block())
                     .isEqualTo(inbox);
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -520,8 +520,8 @@ class CassandraMailboxMapperTest {
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThatThrownBy(() -> testee.findMailboxById(inboxId))
                     .isInstanceOf(MailboxNotFoundException.class);
-                softly.assertThatThrownBy(() -> testee.findMailboxByPath(inboxPath))
-                    .isInstanceOf(MailboxNotFoundException.class);
+                    softly.assertThat(testee.findMailboxByPath(inboxPath).blockOptional())
+                        .isEmpty();
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .isEmpty();
                 softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
@@ -551,7 +551,7 @@ class CassandraMailboxMapperTest {
                     .assertThat(testee.findMailboxById(inboxId))
                     .isEqualTo(inboxRenamed);
                 softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPathRenamed))
+                    .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
                     .isEqualTo(inboxRenamed);
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .isEmpty();
@@ -587,7 +587,7 @@ class CassandraMailboxMapperTest {
                     .assertThat(testee.findMailboxById(inboxId))
                     .isEqualTo(inboxRenamed);
                 softly(softly)
-                    .assertThat(testee.findMailboxByPath(inboxPathRenamed))
+                    .assertThat(testee.findMailboxByPath(inboxPathRenamed).block())
                     .isEqualTo(inboxRenamed);
                 softly.assertThat(testee.findMailboxWithPathLike(inboxSearchQuery))
                     .isEmpty();
@@ -620,7 +620,7 @@ class CassandraMailboxMapperTest {
     @Test
     void renameShouldNotRemoveOldMailboxPathWhenCreatingTheNewMailboxPathFails() throws Exception {
         testee.create(MAILBOX_PATH, UID_VALIDITY);
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH);
+        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
 
         Mailbox newMailbox = new Mailbox(tooLongMailboxPath(mailbox.generateAssociatedPath()), UID_VALIDITY, mailbox.getMailboxId());
         assertThatThrownBy(() -> testee.rename(newMailbox))
@@ -643,8 +643,8 @@ class CassandraMailboxMapperTest {
 
         testee.delete(MAILBOX);
 
-        assertThatThrownBy(() -> testee.findMailboxByPath(MAILBOX_PATH))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
+            .isEmpty();
     }
 
     @Test
@@ -656,36 +656,36 @@ class CassandraMailboxMapperTest {
 
         testee.delete(MAILBOX);
 
-        assertThatThrownBy(() -> testee.findMailboxByPath(MAILBOX_PATH))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
+            .isEmpty();
     }
 
     @Test
-    void findMailboxByPathShouldReturnMailboxWhenExistsInV1Table() throws Exception {
+    void findMailboxByPathShouldReturnMailboxWhenExistsInV1Table() {
         mailboxDAO.save(MAILBOX)
             .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
             .block();
 
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH);
+        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
 
         assertThat(mailbox.generateAssociatedPath()).isEqualTo(MAILBOX_PATH);
     }
 
     @Test
-    void findMailboxByPathShouldReturnMailboxWhenExistsInV2Table() throws Exception {
+    void findMailboxByPathShouldReturnMailboxWhenExistsInV2Table() {
         mailboxDAO.save(MAILBOX)
             .block();
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
             .block();
 
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH);
+        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
 
         assertThat(mailbox.generateAssociatedPath()).isEqualTo(MAILBOX_PATH);
     }
 
     @Test
-    void findMailboxByPathShouldReturnMailboxWhenExistsInBothTables() throws Exception {
+    void findMailboxByPathShouldReturnMailboxWhenExistsInBothTables() {
         mailboxDAO.save(MAILBOX)
             .block();
         mailboxPathDAO.save(MAILBOX_PATH, MAILBOX_ID)
@@ -693,7 +693,7 @@ class CassandraMailboxMapperTest {
         mailboxPathV2DAO.save(MAILBOX_PATH, MAILBOX_ID)
             .block();
 
-        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH);
+        Mailbox mailbox = testee.findMailboxByPath(MAILBOX_PATH).block();
 
         assertThat(mailbox.generateAssociatedPath()).isEqualTo(MAILBOX_PATH);
     }
@@ -709,8 +709,8 @@ class CassandraMailboxMapperTest {
 
         testee.delete(MAILBOX);
 
-        assertThatThrownBy(() -> testee.findMailboxByPath(MAILBOX_PATH))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
+            .isEmpty();
     }
 
     @Test
@@ -722,8 +722,8 @@ class CassandraMailboxMapperTest {
 
         testee.delete(MAILBOX);
 
-        assertThatThrownBy(() -> testee.findMailboxByPath(MAILBOX_PATH))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
+            .isEmpty();
     }
 
     @Test
@@ -735,8 +735,8 @@ class CassandraMailboxMapperTest {
 
         testee.delete(MAILBOX);
 
-        assertThatThrownBy(() -> testee.findMailboxByPath(MAILBOX_PATH))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
+            .isEmpty();
     }
 
     @Test
@@ -744,8 +744,8 @@ class CassandraMailboxMapperTest {
         mailboxDAO.save(MAILBOX)
             .block();
 
-        assertThatThrownBy(() -> testee.findMailboxByPath(MAILBOX_PATH))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(testee.findMailboxByPath(MAILBOX_PATH).blockOptional())
+            .isEmpty();
     }
 
     @Test
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
index 82ee289..81bab1c 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/migration/MailboxPathV2MigrationTest.java
@@ -110,7 +110,7 @@ class MailboxPathV2MigrationTest {
         daoV1.save(MAILBOX_PATH_1, MAILBOX_ID_1).block();
         mailboxDAO.save(mailbox).block();
 
-        mailboxMapper.findMailboxByPath(MAILBOX_PATH_1);
+        mailboxMapper.findMailboxByPath(MAILBOX_PATH_1).block();
 
         SoftAssertions softly = new SoftAssertions();
         softly.assertThat(daoV1.retrieveId(MAILBOX_PATH_1).blockOptional()).isEmpty();
diff --git a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMailboxMapper.java b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMailboxMapper.java
index 966101a..1601631 100644
--- a/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMailboxMapper.java
+++ b/mailbox/jpa/src/main/java/org/apache/james/mailbox/jpa/mail/JPAMailboxMapper.java
@@ -50,6 +50,8 @@ import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
+import reactor.core.publisher.Mono;
+
 /**
  * Data access management for mailbox.
  */
@@ -129,27 +131,24 @@ public class JPAMailboxMapper extends JPATransactionalMapper implements MailboxM
     }
 
     private boolean isPathAlreadyUsedByAnotherMailbox(MailboxPath mailboxPath) throws MailboxException {
-        try {
-            findMailboxByPath(mailboxPath);
-            return true;
-        } catch (MailboxNotFoundException e) {
-            return false;
-        }
+        return findMailboxByPath(mailboxPath)
+            .blockOptional()
+            .isPresent();
     }
 
     @Override
-    public Mailbox findMailboxByPath(MailboxPath mailboxPath) throws MailboxException, MailboxNotFoundException {
+    public Mono<Mailbox> findMailboxByPath(MailboxPath mailboxPath)  {
         try {
-            return getEntityManager().createNamedQuery("findMailboxByNameWithUser", JPAMailbox.class)
+            return Mono.just(getEntityManager().createNamedQuery("findMailboxByNameWithUser", JPAMailbox.class)
                 .setParameter("nameParam", mailboxPath.getName())
                 .setParameter("namespaceParam", mailboxPath.getNamespace())
                 .setParameter("userParam", mailboxPath.getUser().asString())
                 .getSingleResult()
-                .toMailbox();
+                .toMailbox());
         } catch (NoResultException e) {
-            throw new MailboxNotFoundException(mailboxPath);
+            return Mono.empty();
         } catch (PersistenceException e) {
-            throw new MailboxException("Search of mailbox " + mailboxPath + " failed", e);
+            return Mono.error(new MailboxException("Exception upon JPA execution", e));
         }
     }
 
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMailboxMapperTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMailboxMapperTest.java
index 9be8ff1..32aec06 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMailboxMapperTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/JpaMailboxMapperTest.java
@@ -67,7 +67,7 @@ class JpaMailboxMapperTest extends MailboxMapperTest {
         entityManager.persist(jpaMailbox);
         entityManager.getTransaction().commit();
 
-        Mailbox readMailbox = mailboxMapper.findMailboxByPath(benwaInboxPath);
+        Mailbox readMailbox = mailboxMapper.findMailboxByPath(benwaInboxPath).block();
 
         assertThat(readMailbox.getUidValidity().isValid()).isTrue();
     }
@@ -82,8 +82,8 @@ class JpaMailboxMapperTest extends MailboxMapperTest {
         entityManager.persist(jpaMailbox);
         entityManager.getTransaction().commit();
 
-        Mailbox readMailbox1 = mailboxMapper.findMailboxByPath(benwaInboxPath);
-        Mailbox readMailbox2 = mailboxMapper.findMailboxByPath(benwaInboxPath);
+        Mailbox readMailbox1 = mailboxMapper.findMailboxByPath(benwaInboxPath).block();
+        Mailbox readMailbox2 = mailboxMapper.findMailboxByPath(benwaInboxPath).block();
 
         assertThat(readMailbox1.getUidValidity()).isEqualTo(readMailbox2.getUidValidity());
     }
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/TransactionalMailboxMapper.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/TransactionalMailboxMapper.java
index a40e189..30b4da7 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/TransactionalMailboxMapper.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/mail/TransactionalMailboxMapper.java
@@ -36,6 +36,8 @@ import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.store.mail.MailboxMapper;
 import org.apache.james.mailbox.store.transaction.Mapper;
 
+import reactor.core.publisher.Mono;
+
 public class TransactionalMailboxMapper implements MailboxMapper {
     private final JPAMailboxMapper wrapped;
 
@@ -69,7 +71,7 @@ public class TransactionalMailboxMapper implements MailboxMapper {
     }
 
     @Override
-    public Mailbox findMailboxByPath(MailboxPath mailboxPath) throws MailboxException, MailboxNotFoundException {
+    public Mono<Mailbox> findMailboxByPath(MailboxPath mailboxPath) {
         return wrapped.findMailboxByPath(mailboxPath);
     }
 
diff --git a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java
index f6e8195..d9b5c0d 100644
--- a/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java
+++ b/mailbox/maildir/src/main/java/org/apache/james/mailbox/maildir/mail/MaildirMailboxMapper.java
@@ -54,6 +54,8 @@ import org.slf4j.LoggerFactory;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.ImmutableList;
 
+import reactor.core.publisher.Mono;
+
 public class MaildirMailboxMapper extends NonTransactionalMapper implements MailboxMapper {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(MaildirMailboxMapper.class);
@@ -106,9 +108,12 @@ public class MaildirMailboxMapper extends NonTransactionalMapper implements Mail
     }
    
     @Override
-    public Mailbox findMailboxByPath(MailboxPath mailboxPath)
-            throws MailboxException, MailboxNotFoundException {      
-        return maildirStore.loadMailbox(session, mailboxPath);
+    public Mono<Mailbox> findMailboxByPath(MailboxPath mailboxPath) {
+        try {
+            return Mono.just(maildirStore.loadMailbox(session, mailboxPath));
+        } catch (MailboxException e) {
+            return Mono.empty();
+        }
     }
     
     @Override
diff --git a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxMapper.java b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxMapper.java
index c990f48..fc55302 100644
--- a/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxMapper.java
+++ b/mailbox/memory/src/main/java/org/apache/james/mailbox/inmemory/mail/InMemoryMailboxMapper.java
@@ -44,6 +44,8 @@ import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 
+import reactor.core.publisher.Mono;
+
 public class InMemoryMailboxMapper implements MailboxMapper {
     
     private static final int INITIAL_SIZE = 128;
@@ -64,13 +66,10 @@ public class InMemoryMailboxMapper implements MailboxMapper {
     }
 
     @Override
-    public synchronized Mailbox findMailboxByPath(MailboxPath path) throws MailboxException {
+    public synchronized Mono<Mailbox> findMailboxByPath(MailboxPath path) {
         Mailbox result = mailboxesByPath.get(path);
-        if (result == null) {
-            throw new MailboxNotFoundException(path);
-        } else {
-            return new Mailbox(result);
-        }
+        return Mono.justOrEmpty(result)
+            .map(Mailbox::new);
     }
 
     @Override
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxAnnotationManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxAnnotationManager.java
index 7bc3a95..2b1a52f 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxAnnotationManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxAnnotationManager.java
@@ -69,7 +69,7 @@ public class StoreMailboxAnnotationManager implements MailboxAnnotationManager {
 
     public MailboxId checkThenGetMailboxId(MailboxPath path, MailboxSession session) throws MailboxException {
         MailboxMapper mailboxMapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailbox = mailboxMapper.findMailboxByPath(path);
+        Mailbox mailbox = mailboxMapper.findMailboxByPathBlocking(path);
         if (!rightManager.hasRight(mailbox, Right.Read, session)) {
             throw new InsufficientRightsException("Not enough rights on " + path);
         }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index e9ad7a4..2854449 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -255,13 +255,12 @@ public class StoreMailboxManager implements MailboxManager {
     public MessageManager getMailbox(MailboxPath mailboxPath, MailboxSession session)
             throws MailboxException {
         final MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailboxRow = mapper.findMailboxByPath(mailboxPath);
-
-        if (mailboxRow == null) {
-            LOGGER.info("Mailbox '{}' not found.", mailboxPath);
-            throw new MailboxNotFoundException(mailboxPath);
-
-        }
+        Mailbox mailboxRow = mapper.findMailboxByPath(mailboxPath)
+            .blockOptional()
+            .orElseThrow(() -> {
+                LOGGER.info("Mailbox '{}' not found.", mailboxPath);
+                return new MailboxNotFoundException(mailboxPath);
+            });
 
         if (!assertUserHasAccessTo(mailboxRow, session)) {
             LOGGER.info("Mailbox '{}' does not belong to user '{}' but to '{}'", mailboxPath, session.getUser(), mailboxRow.getUser());
@@ -409,10 +408,7 @@ public class StoreMailboxManager implements MailboxManager {
         MailboxMapper mailboxMapper = mailboxSessionMapperFactory.getMailboxMapper(session);
 
         mailboxMapper.execute(() -> {
-            Mailbox mailbox = mailboxMapper.findMailboxByPath(mailboxPath);
-            if (mailbox == null) {
-                throw new MailboxNotFoundException(mailboxPath);
-            }
+            Mailbox mailbox = mailboxMapper.findMailboxByPathBlocking(mailboxPath);
             return doDeleteMailbox(mailboxMapper, mailbox, session);
         });
     }
@@ -476,8 +472,7 @@ public class StoreMailboxManager implements MailboxManager {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
 
         mapper.execute(Mapper.toTransaction(() -> {
-            Mailbox mailbox = Optional.ofNullable(mapper.findMailboxByPath(from))
-                .orElseThrow(() -> new MailboxNotFoundException(from));
+            Mailbox mailbox = mapper.findMailboxByPathBlocking(from);
             doRenameMailbox(mailbox, sanitizedMailboxPath, session, mapper);
         }));
     }
@@ -701,13 +696,10 @@ public class StoreMailboxManager implements MailboxManager {
 
     @Override
     public boolean mailboxExists(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
-        try {
-            final MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-            mapper.findMailboxByPath(mailboxPath);
-            return true;
-        } catch (MailboxNotFoundException e) {
-            return false;
-        }
+        MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
+        return mapper.findMailboxByPath(mailboxPath)
+            .blockOptional()
+            .isPresent();
     }
 
     /**
@@ -819,7 +811,7 @@ public class StoreMailboxManager implements MailboxManager {
     @Override
     public boolean hasChildren(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailbox = mapper.findMailboxByPath(mailboxPath);
+        Mailbox mailbox = mapper.findMailboxByPathBlocking(mailboxPath);
         return mapper.hasChildren(mailbox, session.getPathDelimiter());
     }
 
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java
index 7db8dba..5707f15 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreRightManager.java
@@ -89,7 +89,7 @@ public class StoreRightManager implements RightManager {
     @Override
     public Rfc4314Rights myRights(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailbox = mapper.findMailboxByPath(mailboxPath);
+        Mailbox mailbox = mapper.findMailboxByPathBlocking(mailboxPath);
         return myRights(mailbox, session);
     }
 
@@ -118,7 +118,7 @@ public class StoreRightManager implements RightManager {
     @Override
     public Rfc4314Rights[] listRights(MailboxPath mailboxPath, EntryKey key, MailboxSession session) throws MailboxException {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailbox = mapper.findMailboxByPath(mailboxPath);
+        Mailbox mailbox = mapper.findMailboxByPathBlocking(mailboxPath);
 
         return aclResolver.listRights(key,
             groupMembershipResolver,
@@ -129,7 +129,7 @@ public class StoreRightManager implements RightManager {
     @Override
     public MailboxACL listRights(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailbox = mapper.findMailboxByPath(mailboxPath);
+        Mailbox mailbox = mapper.findMailboxByPathBlocking(mailboxPath);
         return mailbox.getACL();
     }
 
@@ -137,7 +137,7 @@ public class StoreRightManager implements RightManager {
     public void applyRightsCommand(MailboxPath mailboxPath, ACLCommand mailboxACLCommand, MailboxSession session) throws MailboxException {
         assertSharesBelongsToUserDomain(mailboxPath.getUser(), mailboxACLCommand);
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailbox = mapper.findMailboxByPath(mailboxPath);
+        Mailbox mailbox = mapper.findMailboxByPathBlocking(mailboxPath);
         ACLDiff aclDiff = mapper.updateACL(mailbox, mailboxACLCommand);
 
         eventBus.dispatch(EventFactory.aclUpdated()
@@ -200,7 +200,7 @@ public class StoreRightManager implements RightManager {
     public void setRights(MailboxPath mailboxPath, MailboxACL mailboxACL, MailboxSession session) throws MailboxException {
         assertSharesBelongsToUserDomain(mailboxPath.getUser(), mailboxACL.getEntries());
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
-        Mailbox mailbox = mapper.findMailboxByPath(mailboxPath);
+        Mailbox mailbox = mapper.findMailboxByPathBlocking(mailboxPath);
 
         setRights(mailboxACL, mapper, mailbox, session);
     }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java
index 9973d8f..f0df8d1 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MailboxMapper.java
@@ -33,6 +33,8 @@ import org.apache.james.mailbox.model.UidValidity;
 import org.apache.james.mailbox.model.search.MailboxQuery;
 import org.apache.james.mailbox.store.transaction.Mapper;
 
+import reactor.core.publisher.Mono;
+
 /**
  * Mapper for {@link Mailbox} actions. A {@link MailboxMapper} has a lifecycle from the start of a request 
  * to the end of the request.
@@ -59,8 +61,21 @@ public interface MailboxMapper extends Mapper {
     /**
      * Return the {@link Mailbox} for the given name
      */
-    Mailbox findMailboxByPath(MailboxPath mailboxName)
-            throws MailboxException, MailboxNotFoundException;
+    Mono<Mailbox> findMailboxByPath(MailboxPath mailboxName);
+
+    default Mailbox findMailboxByPathBlocking(MailboxPath mailboxPath) throws MailboxException, MailboxNotFoundException {
+        try {
+            return findMailboxByPath(mailboxPath)
+                .blockOptional()
+                .orElseThrow(() -> new MailboxNotFoundException(mailboxPath));
+        } catch (Exception e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof MailboxException) {
+                throw (MailboxException) cause;
+            }
+            throw e;
+        }
+    }
 
     /**
      * Return the {@link Mailbox} for the given name
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java
index a2a09d8..a55deae 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMailboxManagerAttachmentTest.java
@@ -77,7 +77,7 @@ public abstract class AbstractMailboxManagerAttachmentTest {
         inboxPath = MailboxPath.forUser(USERNAME, "INBOX");
         mailboxManager = getMailboxManager();
         mailboxManager.createMailbox(inboxPath, mailboxSession);
-        inbox = mailboxMapper.findMailboxByPath(inboxPath);
+        inbox = mailboxMapper.findMailboxByPath(inboxPath).block();
         inboxMessageManager = mailboxManager.getMailbox(inboxPath, mailboxSession);
         attachmentMapper = getAttachmentMapperFactory().createAttachmentMapper(mailboxSession);
     }
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageIdManagerTestSystem.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageIdManagerTestSystem.java
index ecbcbd8..420e94a 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageIdManagerTestSystem.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/MessageIdManagerTestSystem.java
@@ -78,7 +78,7 @@ public class MessageIdManagerTestSystem {
 
     public Mailbox createMailbox(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
         mailboxManager.createMailbox(mailboxPath, session);
-        return mapperFactory.getMailboxMapper(session).findMailboxByPath(mailboxPath);
+        return mapperFactory.getMailboxMapper(session).findMailboxByPath(mailboxPath).block();
     }
 
     public MessageId persist(MailboxId mailboxId, MessageUid uid, Flags flags, MailboxSession mailboxSession) {
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerAnnotationTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerAnnotationTest.java
index 85e3670..ee73f44 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerAnnotationTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerAnnotationTest.java
@@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -54,6 +55,8 @@ import org.mockito.MockitoAnnotations;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
+import reactor.core.publisher.Mono;
+
 class StoreMailboxManagerAnnotationTest {
     static final MailboxAnnotationKey PRIVATE_KEY = new MailboxAnnotationKey("/private/comment");
     static final MailboxAnnotationKey SHARED_KEY = new MailboxAnnotationKey("/shared/comment");
@@ -86,7 +89,7 @@ class StoreMailboxManagerAnnotationTest {
         when(mailboxSessionMapperFactory.getMailboxMapper(eq(session))).thenReturn(mailboxMapper);
         when(mailboxSessionMapperFactory.getAnnotationMapper(eq(session))).thenReturn(annotationMapper);
         when(mailbox.getMailboxId()).thenReturn(mailboxId);
-        when(mailboxMapper.findMailboxByPath(eq(mailboxPath))).thenReturn(mailbox);
+        when(mailboxMapper.findMailboxByPath(eq(mailboxPath))).thenReturn(Mono.just(mailbox));
         when(annotationMapper.execute(any(Mapper.Transaction.class)))
             .thenAnswer(invocationOnMock -> {
                 Mapper.Transaction<?> transaction = (Mapper.Transaction<?>) invocationOnMock.getArguments()[0];
@@ -101,7 +104,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void updateAnnotationsShouldThrowExceptionWhenDoesNotLookupMailbox() throws Exception {
-        doThrow(MailboxException.class).when(mailboxMapper).findMailboxByPath(eq(mailboxPath));
+        doThrow(MailboxException.class).when(mailboxMapper).findMailboxByPathBlocking(eq(mailboxPath));
 
         assertThatThrownBy(() -> annotationManager.updateAnnotations(mailboxPath, session, ImmutableList.of(PRIVATE_ANNOTATION)))
             .isInstanceOf(MailboxException.class);
@@ -109,7 +112,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void updateAnnotationsShouldCallAnnotationMapperToInsertAnnotation() throws Exception {
-        when(mailboxMapper.findMailboxByPath(eq(mailboxPath))).thenReturn(mailbox);
+        when(mailboxMapper.findMailboxByPathBlocking(eq(mailboxPath))).thenReturn(mailbox);
         annotationManager.updateAnnotations(mailboxPath, session, ANNOTATIONS);
 
         verify(annotationMapper, times(2)).insertAnnotation(eq(mailboxId), any(MailboxAnnotation.class));
@@ -117,7 +120,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void updateAnnotationsShouldCallAnnotationMapperToDeleteAnnotation() throws Exception {
-        when(mailboxMapper.findMailboxByPath(eq(mailboxPath))).thenReturn(mailbox);
+        when(mailboxMapper.findMailboxByPathBlocking(eq(mailboxPath))).thenReturn(mailbox);
         annotationManager.updateAnnotations(mailboxPath, session, ANNOTATIONS_WITH_NIL_ENTRY);
 
         verify(annotationMapper, times(1)).insertAnnotation(eq(mailboxId), eq(PRIVATE_ANNOTATION));
@@ -126,7 +129,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void getAllAnnotationsShouldThrowExceptionWhenDoesNotLookupMailbox() throws Exception {
-        doThrow(MailboxException.class).when(mailboxMapper).findMailboxByPath(eq(mailboxPath));
+        doThrow(MailboxException.class).when(mailboxMapper).findMailboxByPathBlocking(eq(mailboxPath));
 
         assertThatThrownBy(() -> annotationManager.getAllAnnotations(mailboxPath, session))
             .isInstanceOf(MailboxException.class);
@@ -134,7 +137,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void getAllAnnotationsShouldReturnEmptyForNonStoredAnnotation() throws Exception {
-        when(mailboxMapper.findMailboxByPath(eq(mailboxPath))).thenReturn(mailbox);
+        when(mailboxMapper.findMailboxByPathBlocking(eq(mailboxPath))).thenReturn(mailbox);
         when(annotationMapper.getAllAnnotations(eq(mailboxId))).thenReturn(Collections.<MailboxAnnotation>emptyList());
 
         assertThat(annotationManager.getAllAnnotations(mailboxPath, session)).isEmpty();
@@ -142,7 +145,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void getAllAnnotationsShouldReturnStoredAnnotation() throws Exception {
-        when(mailboxMapper.findMailboxByPath(eq(mailboxPath))).thenReturn(mailbox);
+        when(mailboxMapper.findMailboxByPathBlocking(eq(mailboxPath))).thenReturn(mailbox);
         when(annotationMapper.getAllAnnotations(eq(mailboxId))).thenReturn(ANNOTATIONS);
 
         assertThat(annotationManager.getAllAnnotations(mailboxPath, session)).isEqualTo(ANNOTATIONS);
@@ -150,7 +153,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void getAnnotationsByKeysShouldThrowExceptionWhenDoesNotLookupMailbox() throws Exception {
-        doThrow(MailboxException.class).when(mailboxMapper).findMailboxByPath(eq(mailboxPath));
+        doThrow(MailboxException.class).when(mailboxMapper).findMailboxByPathBlocking(eq(mailboxPath));
 
         assertThatThrownBy(() -> annotationManager.getAnnotationsByKeys(mailboxPath, session, KEYS))
             .isInstanceOf(MailboxException.class);
@@ -158,7 +161,7 @@ class StoreMailboxManagerAnnotationTest {
 
     @Test
     void getAnnotationsByKeysShouldRetrieveStoreAnnotationsByKey() throws Exception {
-        when(mailboxMapper.findMailboxByPath(eq(mailboxPath))).thenReturn(mailbox);
+        when(mailboxMapper.findMailboxByPathBlocking(eq(mailboxPath))).thenReturn(mailbox);
         when(annotationMapper.getAnnotationsByKeys(eq(mailboxId), eq(KEYS))).thenReturn(ANNOTATIONS);
 
         assertThat(annotationManager.getAnnotationsByKeys(mailboxPath, session, KEYS)).isEqualTo(ANNOTATIONS);
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
index 6280122..9ffdee2 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreMailboxManagerTest.java
@@ -60,6 +60,8 @@ import org.apache.james.metrics.tests.RecordingMetricFactory;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import reactor.core.publisher.Mono;
+
 class StoreMailboxManagerTest {
     static final Username CURRENT_USER = Username.of("user");
     static final String CURRENT_USER_PASSWORD = "secret";
@@ -146,7 +148,7 @@ class StoreMailboxManagerTest {
         when(mockedMailbox.getMailboxId()).thenReturn(MAILBOX_ID);
         when(mockedMailbox.getUser()).thenReturn(otherUser);
         when(mockedMailboxMapper.findMailboxById(MAILBOX_ID)).thenReturn(mockedMailbox);
-        when(mockedMailboxMapper.findMailboxByPath(any())).thenReturn(mockedMailbox);
+        when(mockedMailboxMapper.findMailboxByPath(any())).thenReturn(Mono.just(mockedMailbox));
 
         assertThatThrownBy(() -> storeMailboxManager.getMailbox(MAILBOX_ID, mockedMailboxSession))
             .isInstanceOf(MailboxNotFoundException.class);
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java
index 7aa4a76..a880c3a 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/StoreRightManagerTest.java
@@ -56,6 +56,8 @@ import org.apache.james.mailbox.store.mail.MailboxMapper;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import reactor.core.publisher.Mono;
+
 class StoreRightManagerTest {
 
     static final MailboxId MAILBOX_ID = TestId.of(42);
@@ -84,7 +86,7 @@ class StoreRightManagerTest {
     @Test
     void hasRightShouldThrowMailboxNotFoundExceptionWhenMailboxDoesNotExist() throws MailboxException {
         MailboxPath mailboxPath = MailboxPath.forUser(MailboxFixture.ALICE, "unexisting mailbox");
-        when(mockedMailboxMapper.findMailboxByPath(mailboxPath))
+        when(mockedMailboxMapper.findMailboxByPathBlocking(mailboxPath))
             .thenThrow(new MailboxNotFoundException(""));
 
         assertThatThrownBy(() ->
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperACLTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperACLTest.java
index 744892f..d4dfaec 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperACLTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperACLTest.java
@@ -396,6 +396,7 @@ public abstract class MailboxMapperACLTest {
 
         assertThat(
             mailboxMapper.findMailboxByPath(benwaInboxMailbox.generateAssociatedPath())
+                .block()
                 .getACL()
                 .getEntries())
             .hasSize(1)
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperTest.java
index 98bf41a..026e402 100644
--- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperTest.java
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MailboxMapperTest.java
@@ -82,15 +82,15 @@ public abstract class MailboxMapperTest {
 
     @Test
     void findMailboxByPathWhenAbsentShouldFail() {
-        assertThatThrownBy(() -> mailboxMapper.findMailboxByPath(MailboxPath.forUser(BENWA, "INBOX")))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(mailboxMapper.findMailboxByPath(MailboxPath.forUser(BENWA, "INBOX")).blockOptional())
+            .isEmpty();
     }
 
     @Test
     void createShouldPersistTheMailbox() throws MailboxException {
         benwaInboxMailbox = createMailbox(benwaInboxPath);
 
-        assertThat(mailboxMapper.findMailboxByPath(benwaInboxPath)).isEqualTo(benwaInboxMailbox);
+        assertThat(mailboxMapper.findMailboxByPath(benwaInboxPath).blockOptional()).contains(benwaInboxMailbox);
         assertThat(mailboxMapper.findMailboxById(benwaInboxMailbox.getMailboxId())).isEqualTo(benwaInboxMailbox);
     }
 
@@ -149,8 +149,8 @@ public abstract class MailboxMapperTest {
         benwaWorkMailbox = new Mailbox(benwaWorkPath, UID_VALIDITY, mailboxId);
         mailboxMapper.rename(benwaWorkMailbox);
 
-        assertThatThrownBy(() -> mailboxMapper.findMailboxByPath(benwaInboxPath))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(mailboxMapper.findMailboxByPath(benwaInboxPath).blockOptional())
+            .isEmpty();
     }
 
     @Test
@@ -200,8 +200,8 @@ public abstract class MailboxMapperTest {
         createAll();
         mailboxMapper.delete(benwaInboxMailbox);
 
-        assertThatThrownBy(() -> mailboxMapper.findMailboxByPath(benwaInboxPath))
-            .isInstanceOf(MailboxNotFoundException.class);
+        assertThat(mailboxMapper.findMailboxByPath(benwaInboxPath).blockOptional())
+            .isEmpty();
     }
 
     @Test
diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
index d8cb4e8..f112583 100644
--- a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
+++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java
@@ -34,6 +34,7 @@ import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxMetaData;
@@ -84,7 +85,11 @@ public class MailboxProbeImpl implements GuiceProbe, MailboxProbe {
         try {
             mailboxSession = mailboxManager.createSystemSession(username);
             MailboxMapper mailboxMapper = mailboxMapperFactory.getMailboxMapper(mailboxSession);
-            return mailboxMapper.findMailboxByPath(new MailboxPath(namespace, username, name)).getMailboxId();
+            MailboxPath path = new MailboxPath(namespace, username, name);
+            return mailboxMapper.findMailboxByPath(path)
+                .blockOptional()
+                .orElseThrow(() -> new MailboxNotFoundException(path.asString()))
+                .getMailboxId();
         } catch (MailboxException e) {
             throw new RuntimeException(e);
         } finally {
diff --git a/server/container/mailbox-jmx/src/test/java/org/apache/james/adapter/mailbox/MailboxManagementTest.java b/server/container/mailbox-jmx/src/test/java/org/apache/james/adapter/mailbox/MailboxManagementTest.java
index 21c33c7..9cf51e8 100644
--- a/server/container/mailbox-jmx/src/test/java/org/apache/james/adapter/mailbox/MailboxManagementTest.java
+++ b/server/container/mailbox-jmx/src/test/java/org/apache/james/adapter/mailbox/MailboxManagementTest.java
@@ -132,7 +132,10 @@ public class MailboxManagementTest {
     void createMailboxShouldCreateAMailbox() throws Exception {
         mailboxManagerManagement.createMailbox(MailboxConstants.USER_NAMESPACE, USER.asString(), "name");
         assertThat(mapperFactory.createMailboxMapper(session).list()).hasSize(1);
-        assertThat(mapperFactory.createMailboxMapper(session).findMailboxByPath(MailboxPath.forUser(USER, "name"))).isNotNull();
+        assertThat(mapperFactory.createMailboxMapper(session)
+                .findMailboxByPath(MailboxPath.forUser(USER, "name"))
+                .blockOptional())
+            .isPresent();
     }
 
     @Test


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 05/16: JAMES-3088 Migrate CassandraUsersRepositoryTest

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 57d472b72282eaf087d3a4b1492243c008ea6204
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 11:52:26 2020 +0700

    JAMES-3088 Migrate CassandraUsersRepositoryTest
---
 .../cassandra/CassandraUsersRepositoryTest.java    | 48 +++++++++++++++++-----
 .../user/lib/AbstractUsersRepositoryTest.java      |  4 ++
 2 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java b/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java
index 8781f71..c039679 100644
--- a/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java
+++ b/server/data/data-cassandra/src/test/java/org/apache/james/user/cassandra/CassandraUsersRepositoryTest.java
@@ -21,32 +21,58 @@ package org.apache.james.user.cassandra;
 
 import org.apache.commons.configuration2.BaseHierarchicalConfiguration;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.user.lib.AbstractUsersRepository;
 import org.apache.james.user.lib.AbstractUsersRepositoryTest;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class CassandraUsersRepositoryTest extends AbstractUsersRepositoryTest {
+class CassandraUsersRepositoryTest {
 
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraUsersRepositoryModule.MODULE);
 
-    @BeforeEach
-    void setup() throws Exception {
-        super.setUp();
+    @Nested
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryTest.WithVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
+
+        private CassandraUsersRepository usersRepository;
+
+        @BeforeEach
+        void setUp(TestSystem testSystem) throws Exception {
+            usersRepository = getUsersRepository(testSystem.getDomainList(), extension.isSupportVirtualHosting());
+        }
+
+        @Override
+        public AbstractUsersRepository testee() {
+            return usersRepository;
+        }
     }
 
-    @AfterEach
-    void teardown() throws Exception {
-        super.tearDown();
+    @Nested
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryTest.WithOutVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
+
+        private CassandraUsersRepository usersRepository;
+
+        @BeforeEach
+        void setUp(TestSystem testSystem) throws Exception {
+            usersRepository = getUsersRepository(testSystem.getDomainList(), extension.isSupportVirtualHosting());
+        }
+
+        @Override
+        public AbstractUsersRepository testee() {
+            return usersRepository;
+        }
     }
 
-    @Override
-    protected AbstractUsersRepository getUsersRepository() throws Exception {
+    private static CassandraUsersRepository getUsersRepository(DomainList domainList, boolean enableVirtualHosting) throws Exception {
         CassandraUsersRepository cassandraUsersRepository = new CassandraUsersRepository(domainList, cassandraCluster.getCassandraCluster().getConf());
         BaseHierarchicalConfiguration configuration = new BaseHierarchicalConfiguration();
-        configuration.addProperty("enableVirtualHosting", "true");
+        configuration.addProperty("enableVirtualHosting", String.valueOf(enableVirtualHosting));
         cassandraUsersRepository.configure(configuration);
         return cassandraUsersRepository;
     }
diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
index d959987..93a20a8 100644
--- a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
+++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
@@ -81,6 +81,10 @@ public interface AbstractUsersRepositoryTest {
         public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
             return testSystem;
         }
+
+        public boolean isSupportVirtualHosting() {
+            return supportVirtualHosting;
+        }
     }
 
     class TestSystem {


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 11/16: JAMES-3088 Add tests when empty LDAP

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit f82b46b8d0fff2a25a92f50031c850e327e25721
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Mar 25 11:42:20 2020 +0700

    JAMES-3088 Add tests when empty LDAP
---
 .../ReadOnlyUsersLDAPRepositoryEmptyListTest.java  | 121 +++++++++++++++++++++
 .../user/ldap/ReadOnlyUsersLDAPRepositoryTest.java |  14 ++-
 .../src/test/resources/ldif-files/populate.ldif    |   4 +
 3 files changed, 134 insertions(+), 5 deletions(-)

diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryEmptyListTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryEmptyListTest.java
new file mode 100644
index 0000000..0f9e17c
--- /dev/null
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryEmptyListTest.java
@@ -0,0 +1,121 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.user.ldap;
+
+import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN_PASSWORD;
+import static org.apache.james.user.ldap.DockerLdapSingleton.DOMAIN;
+import static org.apache.james.user.ldap.ReadOnlyUsersLDAPRepositoryTest.ldapRepositoryConfiguration;
+import static org.apache.james.user.ldap.ReadOnlyUsersLDAPRepositoryTest.ldapRepositoryConfigurationWithVirtualHosting;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.apache.commons.configuration2.HierarchicalConfiguration;
+import org.apache.commons.configuration2.tree.ImmutableNode;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+class ReadOnlyUsersLDAPRepositoryEmptyListTest {
+    static LdapGenericContainer ldapContainer = LdapGenericContainer.builder()
+        .domain(DOMAIN)
+        .password(ADMIN_PASSWORD)
+        .build();
+
+    DomainList domainList;
+    private ReadOnlyUsersLDAPRepository ldapRepository;
+
+    @BeforeAll
+    static void setUpAll() {
+        ldapContainer.start();
+    }
+
+    @AfterAll
+    static void afterAll() {
+        ldapContainer.stop();
+    }
+
+    @Nested
+    class WhenDisableVirtualHosting {
+
+        @BeforeEach
+        void setUp() throws Exception {
+            domainList = mock(DomainList.class);
+            HierarchicalConfiguration<ImmutableNode> config = ldapRepositoryConfiguration(ldapContainer);
+            config.setProperty("[@userBase]", "ou=empty,dc=james,dc=org");
+            ldapRepository = startUsersRepository(config);
+        }
+
+        @Test
+        void listShouldReturnEmptyWhenNoEntity() throws Exception {
+            assertThat(ImmutableList.copyOf(ldapRepository.list()))
+                .isEmpty();
+        }
+
+        @Test
+        void countUsersShouldReturnZeroWhenEmptyRepository() throws UsersRepositoryException {
+            //Given
+            int expected = 0;
+            //When
+            int actual = ldapRepository.countUsers();
+            //Then
+            assertThat(actual).isEqualTo(expected);
+        }
+    }
+
+    @Nested
+    class SupportVirtualHosting {
+        @BeforeEach
+        void setUp() throws Exception {
+            domainList = mock(DomainList.class);
+            HierarchicalConfiguration<ImmutableNode> config = ldapRepositoryConfigurationWithVirtualHosting(ldapContainer);
+            config.setProperty("[@userBase]", "ou=empty,dc=james,dc=org");
+            ldapRepository = startUsersRepository(config);
+        }
+
+        @Test
+        void listShouldReturnEmptyWhenNoEntity() throws Exception {
+            assertThat(ImmutableList.copyOf(ldapRepository.list()))
+                .isEmpty();
+        }
+
+        @Test
+        void countUsersShouldReturnZeroWhenEmptyRepository() throws UsersRepositoryException {
+            //Given
+            int expected = 0;
+            //When
+            int actual = ldapRepository.countUsers();
+            //Then
+            assertThat(actual).isEqualTo(expected);
+        }
+    }
+
+    private ReadOnlyUsersLDAPRepository startUsersRepository(HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration) throws Exception {
+        ReadOnlyUsersLDAPRepository ldapRepository = new ReadOnlyUsersLDAPRepository(domainList);
+        ldapRepository.configure(ldapRepositoryConfiguration);
+        ldapRepository.init();
+        return ldapRepository;
+    }
+}
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
index 44491b8..4ce4d74 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
@@ -133,13 +133,15 @@ class ReadOnlyUsersLDAPRepositoryTest {
             assertThat(usersRepository.contains(usersRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
         }
 
-        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case," +
+            "See @link{ReadOnlyUsersLDAPRepositoryEmptyListTest}")
         @Override
         @Test
         public void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) {
         }
 
-        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case," +
+            "See @link{ReadOnlyUsersLDAPRepositoryEmptyListTest}")
         @Override
         @Test
         public void countUsersShouldReturnZeroWhenEmptyRepository() {
@@ -193,13 +195,15 @@ class ReadOnlyUsersLDAPRepositoryTest {
             assertThat(testee().isAdministrator(testSystem.getAdmin())).isTrue();
         }
 
-        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case," +
+            "See @link{ReadOnlyUsersLDAPRepositoryEmptyListTest}")
         @Override
         @Test
         public void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) {
         }
 
-        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case")
+        @Disabled("JAMES-3088 Users are provisioned by default from Dockerfile, cannot setup this test case," +
+            "See @link{ReadOnlyUsersLDAPRepositoryEmptyListTest}")
         @Override
         @Test
         public void countUsersShouldReturnZeroWhenEmptyRepository() {
@@ -259,7 +263,7 @@ class ReadOnlyUsersLDAPRepositoryTest {
         return ldapRepository;
     }
 
-    private static HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration(LdapGenericContainer ldapContainer) {
+    static HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration(LdapGenericContainer ldapContainer) {
         PropertyListConfiguration configuration = baseConfiguration(ldapContainer);
         configuration.addProperty("[@userIdAttribute]", "uid");
         configuration.addProperty("[@administratorId]", ADMIN_LOCAL_PART);
diff --git a/server/data/data-ldap/src/test/resources/ldif-files/populate.ldif b/server/data/data-ldap/src/test/resources/ldif-files/populate.ldif
index 95f3391..586125d 100644
--- a/server/data/data-ldap/src/test/resources/ldif-files/populate.ldif
+++ b/server/data/data-ldap/src/test/resources/ldif-files/populate.ldif
@@ -2,6 +2,10 @@ dn: ou=people, dc=james,dc=org
 ou: people
 objectClass: organizationalUnit
 
+dn: ou=empty, dc=james,dc=org
+ou: empty
+objectClass: organizationalUnit
+
 dn: uid=james-user, ou=people, dc=james,dc=org
 objectClass: inetOrgPerson
 uid: james-user


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 04/16: JAMES-3088 Split AbstractUsersRepositoryTest into two contracts

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 82bf5be86345c63829e7c6316dcb1f7379b23b6c
Author: Tran Tien Duc <dt...@linagora.com>
AuthorDate: Thu Mar 5 11:40:18 2020 +0700

    JAMES-3088 Split AbstractUsersRepositoryTest into two contracts
---
 .../user/lib/AbstractUsersRepositoryTest.java      | 262 +++++++++++----------
 .../user/memory/MemoryUsersRepositoryTest.java     | 138 ++++++-----
 2 files changed, 219 insertions(+), 181 deletions(-)

diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
index fe9e664..d959987 100644
--- a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
+++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
@@ -45,15 +45,25 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
+public interface AbstractUsersRepositoryTest {
 
-public abstract class AbstractUsersRepositoryTest {
+    class UserRepositoryExtension implements BeforeEachCallback, ParameterResolver {
 
-    protected static class UserRepositoryExtension implements BeforeEachCallback, ParameterResolver {
+        private static final boolean ENABLE_VIRTUAL_HOSTING = true;
+        private static final boolean DISABLE_VIRTUAL_HOSTING = !ENABLE_VIRTUAL_HOSTING;
+
+        public static UserRepositoryExtension withVirtualHost() {
+            return new UserRepositoryExtension(ENABLE_VIRTUAL_HOSTING);
+        }
+
+        public static UserRepositoryExtension withoutVirtualHosting() {
+            return new UserRepositoryExtension(DISABLE_VIRTUAL_HOSTING);
+        }
 
         private final boolean supportVirtualHosting;
         private TestSystem testSystem;
 
-        public UserRepositoryExtension(boolean supportVirtualHosting) {
+        private UserRepositoryExtension(boolean supportVirtualHosting) {
             this.supportVirtualHosting = supportVirtualHosting;
         }
 
@@ -73,7 +83,7 @@ public abstract class AbstractUsersRepositoryTest {
         }
     }
 
-    protected static class TestSystem {
+    class TestSystem {
         static final Domain DOMAIN = Domain.of("domain");
 
         private final boolean supportVirtualHosting;
@@ -110,10 +120,76 @@ public abstract class AbstractUsersRepositoryTest {
         }
     }
 
-    protected abstract AbstractUsersRepository testee();
-    
+    interface WithVirtualHostingContract extends AbstractUsersRepositoryTest {
+
+        @Test
+        default void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) throws Exception {
+            testSystem.domainList.addDomain(Domain.of("jAmEs.oRg"));
+            String username = "myuser";
+            String password = "password";
+            testee().addUser(Username.of(username + "@jAmEs.oRg"), password);
+
+            boolean actual = testee().test(Username.of(username + "@james.org"), password);
+
+            assertThat(actual).isTrue();
+        }
+
+        @Test
+        default void virtualHostedUsersRepositoryShouldUseFullMailAddressAsUsername() throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeTrue(testee().supportVirtualHosting());
+
+            assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
+        }
+
+        @Test
+        default void getMailAddressForShouldBeIdentityWhenVirtualHosting() throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeTrue(testee().supportVirtualHosting());
+
+            String username = "user@domain";
+            assertThat(testee().getMailAddressFor(Username.of(username)))
+                .isEqualTo(username);
+        }
+
+        @Test
+        default void getUserShouldBeCaseInsensitive() throws Exception {
+            assertThat(testee().getUsername(new MailAddress("lowerUPPER", TestSystem.DOMAIN)))
+                .isEqualTo(Username.fromLocalPartWithDomain("lowerupper", TestSystem.DOMAIN));
+        }
+    }
+
+    interface WithOutVirtualHostingContract extends AbstractUsersRepositoryTest {
+        @Test
+        default void nonVirtualHostedUsersRepositoryShouldUseLocalPartAsUsername() throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeFalse(testee().supportVirtualHosting());
+
+            assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
+        }
+
+        @Test
+        default void getMailAddressForShouldAppendDefaultDomainWhenNoVirtualHosting(TestSystem testSystem) throws Exception {
+            // Some implementations do not support changing virtual hosting value
+            Assumptions.assumeFalse(testee().supportVirtualHosting());
+
+            String username = "user";
+            assertThat(testee().getMailAddressFor(Username.of(username)))
+                .isEqualTo(new MailAddress(username, testSystem.domainList.getDefaultDomain()));
+        }
+
+        @Test
+        default void getUserShouldBeCaseInsensitive() throws Exception {
+            assertThat(testee().getUsername(new MailAddress("lowerUPPER", TestSystem.DOMAIN)))
+                .isEqualTo(Username.fromLocalPartWithoutDomain("lowerupper"));
+        }
+
+    }
+
+    AbstractUsersRepository testee();
+
     @Test
-    void countUsersShouldReturnZeroWhenEmptyRepository() throws UsersRepositoryException {
+    default void countUsersShouldReturnZeroWhenEmptyRepository() throws UsersRepositoryException {
         //Given
         int expected = 0;
         //When
@@ -121,9 +197,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(actual).isEqualTo(expected);
     }
-    
+
     @Test
-    void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void countUsersShouldReturnNumberOfUsersWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         ArrayList<Username> keys = new ArrayList<>(3);
         keys.add(testSystem.user1);
@@ -137,9 +213,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(actual).isEqualTo(keys.size());
     }
-    
+
     @Test
-    void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void listShouldReturnEmptyIteratorWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //When
         Iterator<Username> actual = testee().list();
         //Then
@@ -147,9 +223,9 @@ public abstract class AbstractUsersRepositoryTest {
             .toIterable()
             .isEmpty();
     }
-    
+
     @Test
-    void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void listShouldReturnExactlyUsersInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         ArrayList<Username> keys = new ArrayList<>(3);
         keys.add(testSystem.user1);
@@ -165,9 +241,9 @@ public abstract class AbstractUsersRepositoryTest {
             .toIterable()
             .containsOnly(testSystem.user1, testSystem.user2, testSystem.user3);
     }
-    
+
     @Test
-    void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void addUserShouldAddAUserWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //When
         testee().addUser(testSystem.user2, "password2");
         //Then
@@ -175,28 +251,28 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void containsShouldPreserveCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
+    default void containsShouldPreserveCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1CaseVariation, "password2");
 
         assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
     }
 
     @Test
-    void containsShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+    default void containsShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1CaseVariation, "password2");
 
         assertThat(testee().contains(testSystem.user1)).isTrue();
     }
 
     @Test
-    void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
+    default void containsShouldBeCaseInsentiveWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1, "password2");
 
         assertThat(testee().contains(testSystem.user1CaseVariation)).isTrue();
     }
 
     @Test
-    void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
+    default void addUserShouldDisableCaseVariationWhenOriginalValueLowerCased(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1, "password2");
 
         assertThatThrownBy(() -> testee().addUser(testSystem.user1CaseVariation, "pass"))
@@ -204,7 +280,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void addUserShouldDisableCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
+    default void addUserShouldDisableCaseVariation(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1CaseVariation, "password2");
 
         assertThatThrownBy(() -> testee().addUser(testSystem.user1, "pass"))
@@ -212,7 +288,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void listShouldReturnLowerCaseUser(TestSystem testSystem) throws UsersRepositoryException {
+    default void listShouldReturnLowerCaseUser(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1CaseVariation, "password2");
 
         assertThat(testee().list())
@@ -221,7 +297,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
+    default void removeUserShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1CaseVariation, "password2");
 
         testee().removeUser(testSystem.user1);
@@ -232,7 +308,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void removeUserShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+    default void removeUserShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1, "password2");
 
         testee().removeUser(testSystem.user1CaseVariation);
@@ -243,7 +319,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+    default void getUserByNameShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1, "password2");
 
         assertThat(testee().getUserByName(testSystem.user1CaseVariation).getUserName())
@@ -251,7 +327,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) throws UsersRepositoryException {
+    default void getUserByNameShouldReturnLowerCaseAddedUser(TestSystem testSystem) throws UsersRepositoryException {
         testee().addUser(testSystem.user1CaseVariation, "password2");
 
         assertThat(testee().getUserByName(testSystem.user1).getUserName())
@@ -259,20 +335,20 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void getUserShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
+    default void getUserShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
         assertThat(testee().getUsername(testSystem.user1CaseVariation.asMailAddress()))
             .isEqualTo(testSystem.user1);
     }
 
     @Test
-    void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
+    default void isAdministratorShouldBeCaseInsentive(TestSystem testSystem) throws Exception {
         testee().setAdministratorId(Optional.of(testSystem.admin));
         assertThat(testee().isAdministrator(testSystem.adminCaseVariation))
             .isTrue();
     }
 
     @Test
-    void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldBeCaseInsentiveOnCaseVariationUser(TestSystem testSystem) throws UsersRepositoryException {
         String password = "password2";
         testee().addUser(testSystem.user1CaseVariation, password);
 
@@ -281,16 +357,16 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void testShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldBeCaseInsentive(TestSystem testSystem) throws UsersRepositoryException {
         String password = "password2";
         testee().addUser(testSystem.user1, password);
 
         assertThat(testee().test(testSystem.user1CaseVariation, password))
             .isTrue();
     }
-    
-    @Test 
-    void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+
+    @Test
+    default void addUserShouldAddAUserWhenNotEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user2, "password2");
         //When
@@ -298,27 +374,27 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(testee().contains(testSystem.user3)).isTrue();
     }
-    
+
     @Test
-    void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
+    default void addUserShouldThrowWhenSameUsernameWithDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.toUsername("myUsername"), "password");
         //When
         assertThatThrownBy(() -> testee().addUser(testSystem.toUsername("MyUsername"), "password"))
             .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
     }
-    
+
     @Test
-    void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void addUserShouldThrowWhenUserAlreadyPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         //When
         assertThatThrownBy(() -> testee().addUser(testSystem.user1, "password2"))
             .isInstanceOf(AlreadyExistInUsersRepositoryException.class);
     }
-    
+
     @Test
-    void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void getUserByNameShouldReturnAUserWhenContainedInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         //When
@@ -329,7 +405,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
+    default void getUserByNameShouldReturnUserWhenDifferentCase(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.toUsername("username"), "password");
         //When
@@ -338,9 +414,9 @@ public abstract class AbstractUsersRepositoryTest {
         assertThat(actual).isNotNull();
         assertThat(actual.getUserName()).isEqualTo(testSystem.user1);
     }
-   
+
     @Test
-    void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldReturnTrueWhenAUserHasACorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         //When
@@ -348,23 +424,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(actual).isTrue();
     }
-    
-    @Test
-    void testShouldReturnTrueWhenAUserHasACorrectPasswordAndOtherCaseInDomain(TestSystem testSystem) throws Exception {
-        testee().setEnableVirtualHosting(true);
-
-        testSystem.domainList.addDomain(Domain.of("jAmEs.oRg"));
-        String username = "myuser";
-        String password = "password";
-        testee().addUser(Username.of(username + "@jAmEs.oRg"), password);
-
-        boolean actual = testee().test(Username.of(username + "@james.org"), password);
-
-        assertThat(actual).isTrue();
-    }
 
     @Test
-    void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldReturnFalseWhenAUserHasAnIncorrectPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         //When
@@ -372,9 +434,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(actual).isFalse();
     }
-    
+
     @Test
-    void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldReturnFalseWhenAUserHasAnIncorrectCasePassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         //When
@@ -382,9 +444,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(actual).isFalse();
     }
-    
+
     @Test
-    void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldReturnFalseWhenAUserIsNotInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.toUsername("username"), "password");
         //When
@@ -394,7 +456,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldReturnTrueWhenAUserHasAnIncorrectCaseName(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.toUsername("username"), "password");
         //When
@@ -404,7 +466,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void testShouldReturnFalseWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldReturnFalseWhenEmptyRepository(TestSystem testSystem) throws UsersRepositoryException {
         //When
         boolean actual = testee().test(testSystem.user1, "password");
         //Then
@@ -412,7 +474,7 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void testShouldReturnFalseWhenAUserIsRemovedFromRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         testee().removeUser(testSystem.user1);
@@ -421,9 +483,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(actual).isFalse();
     }
-    
+
     @Test
-    void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void removeUserShouldRemoveAUserWhenPresentInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         //When
@@ -431,16 +493,16 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(testee().contains(testSystem.user1)).isFalse();
     }
-    
+
     @Test
-    void removeUserShouldThrowWhenUserNotInRepository(TestSystem testSystem) {
+    default void removeUserShouldThrowWhenUserNotInRepository(TestSystem testSystem) {
         //When
         assertThatThrownBy(() -> testee().removeUser(testSystem.user1))
             .isInstanceOf(UsersRepositoryException.class);
     }
-    
+
     @Test
-    void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem) throws UsersRepositoryException {
+    default void updateUserShouldAllowToAuthenticateWithNewPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         User user = testee().getUserByName(testSystem.user1);
@@ -450,9 +512,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(testee().test(testSystem.user1, "newpass")).isTrue();
     }
-   
+
     @Test
-    void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) throws UsersRepositoryException {
+    default void updateUserShouldNotAllowToAuthenticateWithOldPassword(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         User user = testee().getUserByName(testSystem.user1);
@@ -462,9 +524,9 @@ public abstract class AbstractUsersRepositoryTest {
         //Then
         assertThat(testee().test(testSystem.user1, "password")).isFalse();
     }
-    
+
     @Test
-    void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) throws UsersRepositoryException {
+    default void updateUserShouldThrowWhenAUserIsNoMoreInRepository(TestSystem testSystem) throws UsersRepositoryException {
         //Given
         testee().addUser(testSystem.user1, "password");
         User user = testee().getUserByName(testSystem.user1);
@@ -475,78 +537,34 @@ public abstract class AbstractUsersRepositoryTest {
     }
 
     @Test
-    void virtualHostedUsersRepositoryShouldUseFullMailAddressAsUsername() throws Exception {
-        testee().setEnableVirtualHosting(true);
-
-        // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeTrue(testee().supportVirtualHosting());
-
-        assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
-    }
-
-    @Test
-    void nonVirtualHostedUsersRepositoryShouldUseLocalPartAsUsername() throws Exception {
-        testee().setEnableVirtualHosting(false);
-
-        // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeFalse(testee().supportVirtualHosting());
-
-        assertThat(testee().getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
-    }
-
-    @Test
-    void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
+    default void isAdministratorShouldReturnFalseWhenNotConfigured(TestSystem testSystem) throws Exception {
         testee().setAdministratorId(Optional.empty());
 
         assertThat(testee().isAdministrator(testSystem.admin)).isFalse();
     }
 
     @Test
-    void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
+    default void isAdministratorShouldReturnTrueWhenConfiguredAndUserIsAdmin(TestSystem testSystem) throws Exception {
         testee().setAdministratorId(Optional.of(testSystem.admin));
 
         assertThat(testee().isAdministrator(testSystem.admin)).isTrue();
     }
 
     @Test
-    void isAdministratorShouldReturnFalseWhenConfiguredAndUserIsNotAdmin(TestSystem testSystem) throws Exception {
+    default void isAdministratorShouldReturnFalseWhenConfiguredAndUserIsNotAdmin(TestSystem testSystem) throws Exception {
         testee().setAdministratorId(Optional.of(testSystem.admin));
 
         assertThat(testee().isAdministrator(testSystem.user1)).isFalse();
     }
 
-    @Test
-    void getMailAddressForShouldBeIdentityWhenVirtualHosting() throws Exception {
-        testee().setEnableVirtualHosting(true);
-
-        // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeTrue(testee().supportVirtualHosting());
-
-        String username = "user@domain";
-        assertThat(testee().getMailAddressFor(Username.of(username)))
-            .isEqualTo(username);
-    }
-
-    @Test
-    void getMailAddressForShouldAppendDefaultDomainWhenNoVirtualHosting(TestSystem testSystem) throws Exception {
-        testee().setEnableVirtualHosting(false);
-
-        // Some implementations do not support changing virtual hosting value
-        Assumptions.assumeFalse(testee().supportVirtualHosting());
-
-        String username = "user";
-        assertThat(testee().getMailAddressFor(Username.of(username)))
-            .isEqualTo(new MailAddress(username, testSystem.domainList.getDefaultDomain()));
-    }
-
     @ParameterizedTest
     @MethodSource("illegalCharacters")
-    void assertValidShouldThrowWhenUsernameLocalPartWithIllegalCharacter(String illegalCharacter) {
+    default void assertValidShouldThrowWhenUsernameLocalPartWithIllegalCharacter(String illegalCharacter) {
         assertThatThrownBy(() -> testee().assertValid(Username.of("a" + illegalCharacter + "a")))
             .isInstanceOf(InvalidUsernameException.class);
     }
 
-    private static Stream<Arguments> illegalCharacters() {
+    static Stream<Arguments> illegalCharacters() {
         return Stream.of(
             "\"",
             "(",
diff --git a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
index 54ddc17..51cc61e 100644
--- a/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
+++ b/server/data/data-memory/src/test/java/org/apache/james/user/memory/MemoryUsersRepositoryTest.java
@@ -30,76 +30,96 @@ import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.lib.AbstractUsersRepository;
 import org.apache.james.user.lib.AbstractUsersRepositoryTest;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-class MemoryUsersRepositoryTest extends AbstractUsersRepositoryTest {
-
-    @RegisterExtension
-    static UserRepositoryExtension extension = new UserRepositoryExtension(true);
-
-    private MemoryUsersRepository memoryUsersRepository;
-
-    @BeforeEach
-    void setUp(TestSystem testSystem) {
-        memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(testSystem.getDomainList());
+class MemoryUsersRepositoryTest {
+
+    @Nested
+    class WhenEnableVirtualHosting implements AbstractUsersRepositoryTest.WithVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withVirtualHost();
+
+        private MemoryUsersRepository memoryUsersRepository;
+
+        @BeforeEach
+        void setUp(TestSystem testSystem) {
+            memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(testSystem.getDomainList());
+        }
+
+        @Override
+        public AbstractUsersRepository testee() {
+            return memoryUsersRepository;
+        }
+
+        @Test
+        void assertValidShouldThrowWhenNoDomainPartAndVirtualHosting() {
+            assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user")))
+                .isInstanceOf(UsersRepositoryException.class);
+        }
+
+        @Test
+        void assertValidShouldNotThrowWhenDomainPartAndVirtualHosting() throws Exception {
+            MemoryDomainList domainList = new MemoryDomainList(new InMemoryDNSService()
+                .registerMxRecord("localhost", "127.0.0.1")
+                .registerMxRecord("127.0.0.1", "127.0.0.1"));
+            domainList.setAutoDetect(false);
+            domainList.setAutoDetectIP(false);
+            domainList.addDomain(Domain.of("domain.tld"));
+
+            MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+
+            assertThatCode(() -> memoryUsersRepository.assertValid(Username.of("user@domain.tld")))
+                .doesNotThrowAnyException();
+        }
+
+        @Test
+        void assertValidShouldNotThrowWhenDomainPartAndDomainNotFound() throws Exception {
+            MemoryDomainList domainList = new MemoryDomainList(new InMemoryDNSService()
+                .registerMxRecord("localhost", "127.0.0.1")
+                .registerMxRecord("127.0.0.1", "127.0.0.1"));
+            domainList.setAutoDetect(false);
+            domainList.setAutoDetectIP(false);
+
+            MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
+
+            assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user@domain.tld")))
+                .isInstanceOf(UsersRepositoryException.class);
+        }
     }
 
-    @Override
-    protected AbstractUsersRepository testee() {
-        return memoryUsersRepository;
-    }
+    @Nested
+    class WhenDisableVirtualHosting implements AbstractUsersRepositoryTest.WithOutVirtualHostingContract {
+        @RegisterExtension
+        UserRepositoryExtension extension = UserRepositoryExtension.withoutVirtualHosting();
 
-    @Test
-    void assertValidShouldThrowWhenDomainPartAndNoVirtualHosting(TestSystem testSystem) {
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(testSystem.getDomainList());
+        private MemoryUsersRepository memoryUsersRepository;
 
-        assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user@domain.tld")))
-            .isInstanceOf(UsersRepositoryException.class);
-    }
-
-    @Test
-    void assertValidShouldThrowWhenNoDomainPartAndVirtualHosting(TestSystem testSystem) {
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(testSystem.getDomainList());
+        @BeforeEach
+        void setUp(TestSystem testSystem) {
+            memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(testSystem.getDomainList());
+        }
 
-        assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user")))
-            .isInstanceOf(UsersRepositoryException.class);
-    }
+        @Override
+        public AbstractUsersRepository testee() {
+            return memoryUsersRepository;
+        }
 
-    @Test
-    void assertValidShouldNotThrowWhenDomainPartAndVirtualHosting() throws Exception {
-        MemoryDomainList domainList = new MemoryDomainList(new InMemoryDNSService()
-            .registerMxRecord("localhost", "127.0.0.1")
-            .registerMxRecord("127.0.0.1", "127.0.0.1"));
-        domainList.setAutoDetect(false);
-        domainList.setAutoDetectIP(false);
-        domainList.addDomain(Domain.of("domain.tld"));
+        @Test
+        void assertValidShouldThrowWhenDomainPartAndNoVirtualHosting(TestSystem testSystem) {
+            MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(testSystem.getDomainList());
 
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
-
-        assertThatCode(() -> memoryUsersRepository.assertValid(Username.of("user@domain.tld")))
-            .doesNotThrowAnyException();
-    }
-
-    @Test
-    void assertValidShouldNotThrowWhenDomainPartAndDomainNotFound() throws Exception {
-        MemoryDomainList domainList = new MemoryDomainList(new InMemoryDNSService()
-            .registerMxRecord("localhost", "127.0.0.1")
-            .registerMxRecord("127.0.0.1", "127.0.0.1"));
-        domainList.setAutoDetect(false);
-        domainList.setAutoDetectIP(false);
-
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
-
-        assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user@domain.tld")))
-            .isInstanceOf(UsersRepositoryException.class);
-    }
+            assertThatThrownBy(() -> memoryUsersRepository.assertValid(Username.of("user@domain.tld")))
+                .isInstanceOf(UsersRepositoryException.class);
+        }
 
-    @Test
-    void assertValidShouldNotThrowWhenNoDomainPartAndNoVirtualHosting(TestSystem testSystem) {
-        MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(testSystem.getDomainList());
+        @Test
+        void assertValidShouldNotThrowWhenNoDomainPartAndNoVirtualHosting(TestSystem testSystem) {
+            MemoryUsersRepository memoryUsersRepository = MemoryUsersRepository.withoutVirtualHosting(testSystem.getDomainList());
 
-        assertThatCode(() -> memoryUsersRepository.assertValid(Username.of("user")))
-            .doesNotThrowAnyException();
+            assertThatCode(() -> memoryUsersRepository.assertValid(Username.of("user")))
+                .doesNotThrowAnyException();
+        }
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org