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/02/25 02:25:37 UTC

[james-project] branch master updated (a26903c -> 81be440)

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 a26903c  [Refactoring] changing EventDeadLetter::store
     new 82438a7  JAMES-3059 Allow Cassandra test suite to inject fault at the session level
     new 7de356a  JAMES-3058 Cassandra Testing Session: barrier synchronisation
     new 6e16c09  JAMES-3058 Concurrency test for CassandraAclMapper
     new 441fedb  [REFACTORING] Remove useless cast in CassandraMailboxMapper
     new 2c25783  [REFACTORING] Remove unused method
     new f4767c6  [REFACTORING] CassandraMailboxMapper Inline misnamed method
     new b1109e0  [REFACTORING] Extract condition in CassandraMailboxMapper::hasChildren
     new a2df8cc  [REFACTORING] Use Cassandra Session intrumentation in CassandraMailboxManagerConsistencyTest
     new 4af9ec9  [REFACTORING] Simplify providing a testing CassandraMailboxManager
     new 81be440  JAMES-3059 Retry Cassandra mailboxes operation leading to inconsistencies

The 10 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:
 .../james/backends/cassandra/CassandraCluster.java |   9 +-
 .../james/backends/cassandra/TestingSession.java   | 280 ++++++++++++++
 .../backends/cassandra/TestingSessionTest.java     | 232 ++++++++++++
 .../mailbox/cassandra/mail/CassandraACLMapper.java |  16 +-
 .../cassandra/mail/CassandraMailboxMapper.java     |  63 ++--
 .../CassandraMailboxManagerConsistencyTest.java    | 412 ++++++++++++---------
 .../cassandra/CassandraMailboxManagerProvider.java |  26 +-
 .../CassandraMailboxManagerStressTest.java         |   3 +-
 .../cassandra/CassandraMailboxManagerTest.java     |   3 +-
 .../cassandra/CassandraTestSystemFixture.java      |   5 +-
 .../TestCassandraMailboxSessionMapperFactory.java  |  12 +-
 .../cassandra/mail/CassandraACLMapperTest.java     |  37 +-
 .../CassandraMailboxManagerAttachmentTest.java     |   3 +-
 .../cassandra/mail/CassandraMailboxMapperTest.java | 291 +++++++++++----
 .../cassandra/mail/CassandraMapperProvider.java    |   3 +-
 .../mail/CassandraMessageIdMapperTest.java         |   3 +-
 .../tools/indexer/CassandraReIndexerImplTest.java  |   3 +-
 .../cassandra/host/CassandraHostSystem.java        |   4 +-
 18 files changed, 1062 insertions(+), 343 deletions(-)
 create mode 100644 backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
 create mode 100644 backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java


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


[james-project] 10/10: JAMES-3059 Retry Cassandra mailboxes operation leading to inconsistencies

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 81be4404d295826a715e54ba5c4299af790b1370
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Feb 18 16:11:35 2020 +0700

    JAMES-3059 Retry Cassandra mailboxes operation leading to inconsistencies
    
    Retries is a way to mitigate these inconsistencies by decreasing their
    probability of occurrence.
    
    Note: the testing strategy (spying mono) and triggering mockito 'next method'
    is achievable via "defer" to not retry the current mono but rely on mockito
    to regenerate it. It is a limitation of this change-set.
---
 .../cassandra/mail/CassandraMailboxMapper.java     |  28 +-
 .../cassandra/mail/CassandraMailboxMapperTest.java | 291 ++++++++++++++++-----
 2 files changed, 245 insertions(+), 74 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 7be9c1e..1c549db 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
@@ -19,6 +19,7 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
+import java.time.Duration;
 import java.util.List;
 
 import javax.inject.Inject;
@@ -49,7 +50,11 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraMailboxMapper implements MailboxMapper {
-    public static final Logger LOGGER = LoggerFactory.getLogger(CassandraMailboxMapper.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(CassandraMailboxMapper.class);
+
+    private static final int MAX_RETRY = 5;
+    private static final Duration MIN_RETRY_BACKOFF = Duration.ofMillis(10);
+    private static final Duration MAX_RETRY_BACKOFF = Duration.ofMillis(1000);
 
     private final CassandraMailboxDAO mailboxDAO;
     private final CassandraMailboxPathDAOImpl mailboxPathDAO;
@@ -72,7 +77,8 @@ public class CassandraMailboxMapper implements MailboxMapper {
         Flux.merge(
                 mailboxPathDAO.delete(mailbox.generateAssociatedPath()),
                 mailboxPathV2DAO.delete(mailbox.generateAssociatedPath()))
-            .thenEmpty(mailboxDAO.delete(mailboxId))
+            .thenEmpty(mailboxDAO.delete(mailboxId)
+                .retryBackoff(MAX_RETRY, MIN_RETRY_BACKOFF, MAX_RETRY_BACKOFF))
             .block();
     }
 
@@ -174,7 +180,7 @@ public class CassandraMailboxMapper implements MailboxMapper {
     private Mono<Boolean> tryCreate(Mailbox cassandraMailbox, CassandraId cassandraId) {
         return mailboxPathV2DAO.save(cassandraMailbox.generateAssociatedPath(), cassandraId)
             .filter(isCreated -> isCreated)
-            .flatMap(mailboxHasCreated -> mailboxDAO.save(cassandraMailbox)
+            .flatMap(mailboxHasCreated -> persistMailboxEntity(cassandraMailbox)
                 .thenReturn(true))
             .switchIfEmpty(Mono.just(false));
     }
@@ -197,17 +203,27 @@ public class CassandraMailboxMapper implements MailboxMapper {
         return cassandraId;
     }
 
-    private Mono<Boolean> tryRename(Mailbox cassandraMailbox, CassandraId cassandraId) throws MailboxException {
+    private Mono<Boolean> tryRename(Mailbox cassandraMailbox, CassandraId cassandraId) {
         return mailboxDAO.retrieveMailbox(cassandraId)
             .flatMap(mailbox -> mailboxPathV2DAO.save(cassandraMailbox.generateAssociatedPath(), cassandraId)
                 .filter(isCreated -> isCreated)
-                .flatMap(mailboxHasCreated -> mailboxPathV2DAO.delete(mailbox.generateAssociatedPath())
-                    .then(mailboxDAO.save(cassandraMailbox))
+                .flatMap(mailboxHasCreated -> deletePreviousMailboxPathReference(mailbox.generateAssociatedPath())
+                    .then(persistMailboxEntity(cassandraMailbox))
                     .thenReturn(true))
                 .switchIfEmpty(Mono.just(false)))
             .switchIfEmpty(Mono.error(() -> new MailboxNotFoundException(cassandraId)));
     }
 
+    private Mono<Void> persistMailboxEntity(Mailbox cassandraMailbox) {
+        return mailboxDAO.save(cassandraMailbox)
+            .retryBackoff(MAX_RETRY, MIN_RETRY_BACKOFF, MAX_RETRY_BACKOFF);
+    }
+
+    private Mono<Void> deletePreviousMailboxPathReference(MailboxPath mailboxPath) {
+        return mailboxPathV2DAO.delete(mailboxPath)
+            .retryBackoff(MAX_RETRY, MIN_RETRY_BACKOFF, MAX_RETRY_BACKOFF);
+    }
+
     @Override
     public boolean hasChildren(Mailbox mailbox, char delimiter) {
         return Flux.merge(
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 c2835a6..295f3b8 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
@@ -22,11 +22,6 @@ package org.apache.james.mailbox.cassandra.mail;
 import static org.apache.james.mailbox.model.MailboxAssertingTool.softly;
 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.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import java.util.List;
 
@@ -60,8 +55,6 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.runnable.ThrowingRunnable;
 
-import reactor.core.publisher.Mono;
-
 class CassandraMailboxMapperTest {
     private static final int UID_VALIDITY = 52;
     private static final Username USER = Username.of("user");
@@ -79,6 +72,7 @@ class CassandraMailboxMapperTest {
         CassandraMailboxModule.MODULE,
         CassandraSchemaVersionModule.MODULE,
         CassandraAclModule.MODULE);
+    private static final int TRY_COUNT_BEFORE_FAILURE = 6;
 
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(MODULES);
@@ -87,19 +81,18 @@ class CassandraMailboxMapperTest {
     private CassandraMailboxPathDAOImpl mailboxPathDAO;
     private CassandraMailboxPathV2DAO mailboxPathV2DAO;
     private CassandraMailboxMapper testee;
-    private CassandraACLMapper aclMapper;
 
     @BeforeEach
     void setUp() {
         CassandraCluster cassandra = cassandraCluster.getCassandraCluster();
-        mailboxDAO = spy(new CassandraMailboxDAO(cassandra.getConf(), cassandra.getTypesProvider()));
-        mailboxPathDAO = spy(new CassandraMailboxPathDAOImpl(cassandra.getConf(), cassandra.getTypesProvider()));
-        mailboxPathV2DAO = spy(new CassandraMailboxPathV2DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION));
+        mailboxDAO = new CassandraMailboxDAO(cassandra.getConf(), cassandra.getTypesProvider());
+        mailboxPathDAO = new CassandraMailboxPathDAOImpl(cassandra.getConf(), cassandra.getTypesProvider());
+        mailboxPathV2DAO = new CassandraMailboxPathV2DAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
         CassandraUserMailboxRightsDAO userMailboxRightsDAO = new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
-        aclMapper = spy(new CassandraACLMapper(
+        CassandraACLMapper aclMapper = new CassandraACLMapper(
             cassandra.getConf(),
             new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-            CassandraConfiguration.DEFAULT_CONFIGURATION));
+            CassandraConfiguration.DEFAULT_CONFIGURATION);
         testee = new CassandraMailboxMapper(
             mailboxDAO,
             mailboxPathDAO,
@@ -138,14 +131,131 @@ class CassandraMailboxMapperTest {
                 .asUserBound();
         }
 
+        @Nested
+        class Retries {
+            @Test
+            void renameShouldRetryFailedDeleteMailboxPath(CassandraCluster cassandra) throws Exception {
+                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
+                MailboxId inboxId = inbox.getMailboxId();
+                Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
+
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName;")
+                    .times(1)
+                    .setExecutionHook();
+
+                testee.rename(inboxRenamed);
+
+                cassandra.getConf().resetExecutionHook();
+
+                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                    softly(softly)
+                        .assertThat(testee.findMailboxById(inboxId))
+                        .isEqualTo(inboxRenamed);
+                    softly(softly)
+                        .assertThat(testee.findMailboxByPath(inboxPathRenamed))
+                        .isEqualTo(inboxRenamed);
+                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
+                        .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
+                            .assertThat(searchMailbox)
+                            .isEqualTo(inboxRenamed));
+                }));
+            }
+
+            @Test
+            void renameShouldRetryFailedMailboxSaving(CassandraCluster cassandra) throws Exception {
+                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
+                MailboxId inboxId = inbox.getMailboxId();
+                Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
+
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                    .times(1)
+                    .setExecutionHook();
+
+                testee.rename(inboxRenamed);
+
+                cassandra.getConf().resetExecutionHook();
+
+                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                    softly(softly)
+                        .assertThat(testee.findMailboxById(inboxId))
+                        .isEqualTo(inboxRenamed);
+                    softly(softly)
+                        .assertThat(testee.findMailboxByPath(inboxPathRenamed))
+                        .isEqualTo(inboxRenamed);
+                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
+                        .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
+                            .assertThat(searchMailbox)
+                            .isEqualTo(inboxRenamed));
+                }));
+            }
+
+            @Test
+            void createShouldRetryFailedMailboxSaving(CassandraCluster cassandra) throws Exception {
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                    .times(1)
+                    .setExecutionHook();
+
+                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
+
+                cassandra.getConf().resetExecutionHook();
+
+                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                    softly(softly)
+                        .assertThat(testee.findMailboxById(inbox.getMailboxId()))
+                        .isEqualTo(inbox);
+                    softly(softly)
+                        .assertThat(testee.findMailboxByPath(inboxPath))
+                        .isEqualTo(inbox);
+                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
+                        .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
+                            .assertThat(searchMailbox)
+                            .isEqualTo(inbox));
+                }));
+            }
+
+            @Test
+            void deleteShouldRetryFailedMailboxDeletion(CassandraCluster cassandra) throws Exception {
+                Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
+
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(1)
+                    .setExecutionHook();
+
+                testee.delete(inbox);
+
+                cassandra.getConf().resetExecutionHook();
+
+                SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                    assertThatThrownBy(() -> testee.findMailboxById(inbox.getMailboxId()))
+                        .isInstanceOf(MailboxNotFoundException.class);
+                    assertThatThrownBy(() -> testee.findMailboxByPath(inboxPath))
+                        .isInstanceOf(MailboxNotFoundException.class);
+                    softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
+                        .isEmpty();
+                }));
+            }
+        }
+
         @Test
-        void createShouldBeConsistentWhenFailToPersistMailbox() {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .when(mailboxDAO)
-                .save(any());
+        void createShouldBeConsistentWhenFailToPersistMailbox(CassandraCluster cassandra) {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(10)
+                .setExecutionHook();
 
             doQuietly(() -> testee.create(inboxPath, UID_VALIDITY));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(softly -> {
                 softly.assertThatThrownBy(() -> testee.findMailboxByPath(inboxPath))
                     .isInstanceOf(MailboxNotFoundException.class);
@@ -157,17 +267,21 @@ class CassandraMailboxMapperTest {
         }
 
         @Test
-        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindByInbox() throws Exception {
+        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindByInbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxDAO.retrieveMailbox(inboxId))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly(softly)
                     .assertThat(testee.findMailboxById(inboxId))
@@ -184,17 +298,21 @@ class CassandraMailboxMapperTest {
 
         @Disabled("JAMES-3056 returning two mailboxes with same name and id")
         @Test
-        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindAll() throws Exception {
+        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindAll(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxDAO.retrieveMailbox(inboxId))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThat(testee.findMailboxWithPathLike(allMailboxesSearchQuery))
                     .hasOnlyOneElementSatisfying(searchMailbox -> softly(softly)
@@ -205,17 +323,21 @@ class CassandraMailboxMapperTest {
 
         @Disabled("JAMES-3056 find by renamed name returns unexpected results")
         @Test
-        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindByRenamedInbox() throws Exception {
+        void renameThenFailToRetrieveMailboxShouldBeConsistentWhenFindByRenamedInbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxDAO.retrieveMailbox(inboxId))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThatThrownBy(() -> testee.findMailboxByPath(inboxPathRenamed))
                     .isInstanceOf(MailboxNotFoundException.class);
@@ -225,17 +347,21 @@ class CassandraMailboxMapperTest {
         }
 
         @Test
-        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindByInbox() throws Exception {
+        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindByInbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxPathV2DAO.delete(inboxPath))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly(softly)
                     .assertThat(testee.findMailboxById(inboxId))
@@ -252,14 +378,16 @@ class CassandraMailboxMapperTest {
 
         @Disabled("JAMES-3056 returning two mailboxes with same name and id")
         @Test
-        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindAll() throws Exception {
+        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindAll(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxPathV2DAO.delete(inboxPath))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
 
@@ -273,17 +401,21 @@ class CassandraMailboxMapperTest {
 
         @Disabled("JAMES-3056 find by renamed name returns unexpected results")
         @Test
-        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindByRenamedInbox() throws Exception {
+        void renameThenFailToDeleteMailboxPathShouldBeConsistentWhenFindByRenamedInbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxPathV2DAO.delete(inboxPath))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThatThrownBy(() -> testee.findMailboxByPath(inboxPathRenamed))
                     .isInstanceOf(MailboxNotFoundException.class);
@@ -294,16 +426,20 @@ class CassandraMailboxMapperTest {
 
         @Disabled("JAMES-3056 find by mailbox name returns unexpected results")
         @Test
-        void deleteShouldBeConsistentWhenFailToDeleteMailbox() throws Exception {
+        void deleteShouldBeConsistentWhenFailToDeleteMailbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
 
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .when(mailboxDAO)
-                .delete(inboxId);
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.delete(inbox));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThatCode(() -> testee.findMailboxById(inboxId))
                     .doesNotThrowAnyException();
@@ -341,13 +477,17 @@ class CassandraMailboxMapperTest {
 
         @Disabled("JAMES-3057 org.apache.james.mailbox.exception.MailboxNotFoundException: INBOX can not be found")
         @Test
-        void createAfterPreviousFailedCreateShouldCreateAMailbox() throws MailboxException {
-            when(mailboxDAO.save(any()))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+        void createAfterPreviousFailedCreateShouldCreateAMailbox(CassandraCluster cassandra) throws MailboxException {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.create(inboxPath, UID_VALIDITY));
 
+            cassandra.getConf().resetExecutionHook();
+
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
 
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
@@ -366,17 +506,17 @@ class CassandraMailboxMapperTest {
         }
 
         @Test
-        void createAfterPreviousDeleteOnFailedCreateShouldCreateAMailbox() throws MailboxException {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .when(mailboxDAO)
-                .save(any());
+        void createAfterPreviousDeleteOnFailedCreateShouldCreateAMailbox(CassandraCluster cassandra) throws MailboxException {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.create(inboxPath, UID_VALIDITY));
             doQuietly(() -> testee.delete(new Mailbox(inboxPath, UID_VALIDITY, CassandraId.timeBased())));
 
-            doCallRealMethod()
-                .when(mailboxDAO)
-                .save(any());
+            cassandra.getConf().resetExecutionHook();
 
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
 
@@ -396,15 +536,20 @@ class CassandraMailboxMapperTest {
         }
 
         @Test
-        void deleteAfterAFailedDeleteShouldDeleteTheMailbox() throws Exception {
+        void deleteAfterAFailedDeleteShouldDeleteTheMailbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
 
-            when(mailboxDAO.delete(inboxId))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.delete(inbox));
+
+            cassandra.getConf().resetExecutionHook();
+
             doQuietly(() -> testee.delete(inbox));
 
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
@@ -422,16 +567,21 @@ class CassandraMailboxMapperTest {
         @Disabled("JAMES-3056 mailbox name is not updated to INBOX_RENAMED).isEqualTo(" +
             "findMailboxWithPathLike() returns a list with two same mailboxes")
         @Test
-        void renameAfterRenameFailOnRetrieveMailboxShouldRenameTheMailbox() throws Exception {
+        void renameAfterRenameFailOnRetrieveMailboxShouldRenameTheMailbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxDAO.retrieveMailbox(inboxId))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("SELECT id,mailboxbase,uidvalidity,name FROM mailbox WHERE id=:id;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
+
+            cassandra.getConf().resetExecutionHook();
+
             doQuietly(() -> testee.rename(inboxRenamed));
 
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
@@ -456,16 +606,21 @@ class CassandraMailboxMapperTest {
 
         @Disabled("JAMES-3056 mailbox name is not updated to INBOX_RENAMED")
         @Test
-        void renameAfterRenameFailOnDeletePathShouldRenameTheMailbox() throws Exception {
+        void renameAfterRenameFailOnDeletePathShouldRenameTheMailbox(CassandraCluster cassandra) throws Exception {
             Mailbox inbox = testee.create(inboxPath, UID_VALIDITY);
             CassandraId inboxId = (CassandraId) inbox.getMailboxId();
             Mailbox inboxRenamed = createInboxRenamedMailbox(inboxId);
 
-            when(mailboxPathV2DAO.delete(inboxPath))
-                .thenReturn(Mono.error(new RuntimeException("mock exception")))
-                .thenCallRealMethod();
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2 WHERE namespace=:namespace AND user=:user AND mailboxName=:mailboxName;")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.rename(inboxRenamed));
+
+            cassandra.getConf().resetExecutionHook();
+
             doQuietly(() -> testee.rename(inboxRenamed));
 
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {


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


[james-project] 04/10: [REFACTORING] Remove useless cast in CassandraMailboxMapper

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 441fedb6efffe8221d3b5e7d043add26ee0e507d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Feb 18 14:04:32 2020 +0700

    [REFACTORING] Remove useless cast in CassandraMailboxMapper
---
 .../org/apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java | 2 --
 1 file changed, 2 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 a1c2271..f62c27b 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
@@ -228,7 +228,6 @@ public class CassandraMailboxMapper implements MailboxMapper {
     public List<Mailbox> list() {
         return mailboxDAO.retrieveAllMailboxes()
             .flatMap(this::toMailboxWithAcl)
-            .map(simpleMailboxes -> (Mailbox) simpleMailboxes)
             .collectList()
             .block();
     }
@@ -286,7 +285,6 @@ public class CassandraMailboxMapper implements MailboxMapper {
             .filter(mailboxId -> authorizedMailbox(mailboxId.getRight(), right))
             .map(Pair::getLeft)
             .flatMap(this::retrieveMailbox)
-            .map(simpleMailboxes -> (Mailbox) simpleMailboxes)
             .collectList()
             .block();
     }


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


[james-project] 01/10: JAMES-3059 Allow Cassandra test suite to inject fault at the session level

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 82438a76f99a620d08acfc712b2950e76f1c27a5
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Feb 21 12:59:10 2020 +0700

    JAMES-3059 Allow Cassandra test suite to inject fault at the session level
---
 .../james/backends/cassandra/CassandraCluster.java |   9 +-
 .../james/backends/cassandra/TestingSession.java   | 245 +++++++++++++++++++++
 .../backends/cassandra/TestingSessionTest.java     | 161 ++++++++++++++
 3 files changed, 411 insertions(+), 4 deletions(-)

diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
index f4be201..4b4854b 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/CassandraCluster.java
@@ -30,14 +30,13 @@ import org.apache.james.backends.cassandra.init.configuration.ClusterConfigurati
 import org.apache.james.util.Host;
 
 import com.datastax.driver.core.Cluster;
-import com.datastax.driver.core.Session;
 
 public final class CassandraCluster implements AutoCloseable {
     public static final String KEYSPACE = "testing";
 
     private static Optional<Exception> startStackTrace = Optional.empty();
     private final CassandraModule module;
-    private Session session;
+    private TestingSession session;
     private CassandraTypesProvider typesProvider;
     private Cluster cluster;
 
@@ -65,14 +64,15 @@ public final class CassandraCluster implements AutoCloseable {
                 .build();
             cluster = ClusterFactory.create(clusterConfiguration);
             KeyspaceFactory.createKeyspace(clusterConfiguration, cluster);
-            session = new SessionWithInitializedTablesFactory(clusterConfiguration, cluster, module).get();
+            session = new TestingSession(
+                new SessionWithInitializedTablesFactory(clusterConfiguration, cluster, module).get());
             typesProvider = new CassandraTypesProvider(module, session);
         } catch (Exception exception) {
             throw new RuntimeException(exception);
         }
     }
 
-    public Session getConf() {
+    public TestingSession getConf() {
         return session;
     }
 
@@ -82,6 +82,7 @@ public final class CassandraCluster implements AutoCloseable {
 
     @Override
     public void close() {
+        session.resetExecutionHook();
         if (!cluster.isClosed()) {
             clearTables();
             closeCluster();
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
new file mode 100644
index 0000000..5e0ad9d
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
@@ -0,0 +1,245 @@
+/****************************************************************
+ * 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.backends.cassandra;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+
+import com.datastax.driver.core.BoundStatement;
+import com.datastax.driver.core.CloseFuture;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.RegularStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.ResultSetFuture;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.Statement;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class TestingSession implements Session {
+    enum Behavior {
+        THROW((session, statement) -> {
+            RuntimeException injected_failure = new RuntimeException("Injected failure");
+            injected_failure.printStackTrace();
+            throw injected_failure;
+        }),
+        EXECUTE_NORMALLY(Session::executeAsync);
+
+        private final BiFunction<Session, Statement, ResultSetFuture> behaviour;
+
+        Behavior(BiFunction<Session, Statement, ResultSetFuture> behaviour) {
+            this.behaviour = behaviour;
+        }
+
+        ResultSetFuture execute(Session session, Statement statement) {
+            return behaviour.apply(session, statement);
+        }
+    }
+
+    @FunctionalInterface
+    interface StatementPredicate extends Predicate<Statement> {
+
+    }
+
+    static class BoundStatementStartingWith implements StatementPredicate {
+        private final String queryStringPrefix;
+
+        BoundStatementStartingWith(String queryStringPrefix) {
+            this.queryStringPrefix = queryStringPrefix;
+        }
+
+        @Override
+        public boolean test(Statement statement) {
+            if (statement instanceof BoundStatement) {
+                BoundStatement boundStatement = (BoundStatement) statement;
+                return boundStatement.preparedStatement()
+                    .getQueryString()
+                    .startsWith(queryStringPrefix);
+            }
+            return false;
+        }
+    }
+
+    @FunctionalInterface
+    public interface RequiresCondition {
+        RequiresApplyCount condition(StatementPredicate statementPredicate);
+
+        default RequiresApplyCount always() {
+            return condition(ALL_STATEMENTS);
+        }
+
+        default RequiresApplyCount whenBoundStatementStartsWith(String queryStringPrefix) {
+            return condition(new BoundStatementStartingWith(queryStringPrefix));
+        }
+    }
+
+    @FunctionalInterface
+    public interface RequiresApplyCount {
+        FinalStage times(int applyCount);
+    }
+
+    @FunctionalInterface
+    public interface FinalStage {
+        void setExecutionHook();
+    }
+
+    private static class ExecutionHook {
+        final StatementPredicate statementPredicate;
+        final Behavior behavior;
+        final AtomicInteger remaining;
+
+        private ExecutionHook(StatementPredicate statementPredicate, Behavior behavior, int applyCount) {
+            this.statementPredicate = statementPredicate;
+            this.behavior = behavior;
+            this.remaining = new AtomicInteger(applyCount);
+        }
+
+        ResultSetFuture execute(Session session, Statement statement) {
+            if (statementPredicate.test(statement)) {
+                int hookPosition = remaining.getAndDecrement();
+                if (hookPosition > 0) {
+                    return behavior.execute(session, statement);
+                }
+            }
+            return Behavior.EXECUTE_NORMALLY.execute(session, statement);
+        }
+    }
+
+    private static StatementPredicate ALL_STATEMENTS = statement -> true;
+    private static ExecutionHook NO_EXECUTION_HOOK = new ExecutionHook(ALL_STATEMENTS, Behavior.EXECUTE_NORMALLY, 0);
+
+    private final Session delegate;
+    private volatile ExecutionHook executionHook;
+
+    TestingSession(Session delegate) {
+        this.delegate = delegate;
+        this.executionHook = NO_EXECUTION_HOOK;
+    }
+
+    public RequiresCondition fail() {
+        return condition -> applyCount -> () -> executionHook = new ExecutionHook(condition, Behavior.THROW, applyCount);
+    }
+
+    public void resetExecutionHook() {
+        executionHook = NO_EXECUTION_HOOK;
+    }
+
+    @Override
+    public String getLoggedKeyspace() {
+        return delegate.getLoggedKeyspace();
+    }
+
+    @Override
+    public Session init() {
+        return delegate.init();
+    }
+
+    @Override
+    public ListenableFuture<Session> initAsync() {
+        return delegate.initAsync();
+    }
+
+    @Override
+    public ResultSet execute(String query) {
+        return delegate.execute(query);
+    }
+
+    @Override
+    public ResultSet execute(String query, Object... values) {
+        return delegate.execute(query, values);
+    }
+
+    @Override
+    public ResultSet execute(String query, Map<String, Object> values) {
+        return delegate.execute(query, values);
+    }
+
+    @Override
+    public ResultSet execute(Statement statement) {
+        return delegate.execute(statement);
+    }
+
+    @Override
+    public ResultSetFuture executeAsync(String query) {
+        return delegate.executeAsync(query);
+    }
+
+    @Override
+    public ResultSetFuture executeAsync(String query, Object... values) {
+        return delegate.executeAsync(query, values);
+    }
+
+    @Override
+    public ResultSetFuture executeAsync(String query, Map<String, Object> values) {
+        return delegate.executeAsync(query, values);
+    }
+
+    @Override
+    public ResultSetFuture executeAsync(Statement statement) {
+        return executionHook.execute(delegate, statement);
+    }
+
+    @Override
+    public PreparedStatement prepare(String query) {
+        return delegate.prepare(query);
+    }
+
+    @Override
+    public PreparedStatement prepare(RegularStatement statement) {
+        return delegate.prepare(statement);
+    }
+
+    @Override
+    public ListenableFuture<PreparedStatement> prepareAsync(String query) {
+        return delegate.prepareAsync(query);
+    }
+
+    @Override
+    public ListenableFuture<PreparedStatement> prepareAsync(RegularStatement statement) {
+        return delegate.prepareAsync(statement);
+    }
+
+    @Override
+    public CloseFuture closeAsync() {
+        return delegate.closeAsync();
+    }
+
+    @Override
+    public void close() {
+        delegate.close();
+    }
+
+    @Override
+    public boolean isClosed() {
+        return delegate.isClosed();
+    }
+
+    @Override
+    public Cluster getCluster() {
+        return delegate.getCluster();
+    }
+
+    @Override
+    public State getState() {
+        return delegate.getState();
+    }
+}
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java
new file mode 100644
index 0000000..1983e99
--- /dev/null
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java
@@ -0,0 +1,161 @@
+/****************************************************************
+ * 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.backends.cassandra;
+
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
+import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
+import org.apache.james.backends.cassandra.versions.SchemaVersion;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class TestingSessionTest {
+    @RegisterExtension
+    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraSchemaVersionModule.MODULE);
+
+    private CassandraSchemaVersionDAO dao;
+
+    @BeforeEach
+    void setUp(CassandraCluster cassandra) {
+        dao = new CassandraSchemaVersionDAO(cassandra.getConf());
+    }
+
+    @Test
+    void daoOperationShouldNotBeInstrumentedByDefault() {
+        assertThatCode(() -> dao.getCurrentSchemaVersion().block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void daoOperationShouldNotBeInstrumentedWhenNotMatching(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("non matching")
+            .times(1)
+            .setExecutionHook();
+
+        assertThatCode(() -> dao.getCurrentSchemaVersion().block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void daoOperationShouldNotBeInstrumentedWhenTimesIsZero(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("SELECT value FROM schemaVersion;")
+            .times(0)
+            .setExecutionHook();
+
+        assertThatCode(() -> dao.getCurrentSchemaVersion().block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void daoOperationShouldNotBeInstrumentedWhenTimesIsNegative(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("SELECT value FROM schemaVersion;")
+            .times(-1)
+            .setExecutionHook();
+
+        assertThatCode(() -> dao.getCurrentSchemaVersion().block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void daoOperationShouldFailWhenInstrumented(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("SELECT value FROM schemaVersion;")
+            .times(1)
+            .setExecutionHook();
+
+        assertThatThrownBy(() -> dao.getCurrentSchemaVersion().block())
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
+    void daoShouldNotBeInstrumentedWhenTimesIsExceeded(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("SELECT value FROM schemaVersion;")
+            .times(1)
+            .setExecutionHook();
+
+        try {
+            dao.getCurrentSchemaVersion().block();
+        } catch (Exception e) {
+            // discard expected exception
+        }
+
+        assertThatCode(() -> dao.getCurrentSchemaVersion().block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void timesShouldSpecifyExactlyTheFailureCount(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("SELECT value FROM schemaVersion;")
+            .times(2)
+            .setExecutionHook();
+
+        SoftAssertions.assertSoftly(softly -> {
+            assertThatThrownBy(() -> dao.getCurrentSchemaVersion().block())
+                .isInstanceOf(RuntimeException.class);
+            assertThatThrownBy(() -> dao.getCurrentSchemaVersion().block())
+                .isInstanceOf(RuntimeException.class);
+            assertThatCode(() -> dao.getCurrentSchemaVersion().block())
+                .doesNotThrowAnyException();
+        });
+    }
+
+    @Test
+    void resetExecutionHookShouldClearInstrumentation(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("SELECT value FROM schemaVersion;")
+            .times(1)
+            .setExecutionHook();
+
+        cassandra.getConf().resetExecutionHook();
+
+        assertThatCode(() -> dao.getCurrentSchemaVersion().block())
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void timesShouldBeTakenIntoAccountOnlyForMatchingStatements(CassandraCluster cassandra) {
+        cassandra.getConf()
+            .fail()
+            .whenBoundStatementStartsWith("SELECT value FROM schemaVersion;")
+            .times(1)
+            .setExecutionHook();
+
+        dao.updateVersion(new SchemaVersion(36)).block();
+
+        assertThatThrownBy(() -> dao.getCurrentSchemaVersion().block())
+            .isInstanceOf(RuntimeException.class);
+    }
+}


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


[james-project] 08/10: [REFACTORING] Use Cassandra Session intrumentation in CassandraMailboxManagerConsistencyTest

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 a2df8cc5230d2fb68228abed5ad789c95090529d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Feb 20 11:01:01 2020 +0700

    [REFACTORING] Use Cassandra Session intrumentation in CassandraMailboxManagerConsistencyTest
    
    This avoids relying on mocking
---
 .../CassandraMailboxManagerConsistencyTest.java    | 412 ++++++++++++---------
 1 file changed, 247 insertions(+), 165 deletions(-)

diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerConsistencyTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerConsistencyTest.java
index 5ec2154..184c0bf 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerConsistencyTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerConsistencyTest.java
@@ -19,23 +19,12 @@
 package org.apache.james.mailbox.cassandra;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isA;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
 
+import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
-import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.core.Username;
 import org.apache.james.mailbox.MailboxSession;
-import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.cassandra.mail.CassandraMailboxDAO;
-import org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathDAOImpl;
-import org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathV2DAO;
 import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
-import org.apache.james.mailbox.model.Mailbox;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.search.MailboxQuery;
@@ -48,17 +37,15 @@ import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.datastax.driver.core.Session;
 import com.github.fge.lambdas.Throwing;
 import com.github.fge.lambdas.runnable.ThrowingRunnable;
 
-import reactor.core.publisher.Mono;
-
 class CassandraMailboxManagerConsistencyTest {
 
     private static final Username USER = Username.of("user");
     private static final String INBOX = "INBOX";
     private static final String INBOX_RENAMED = "INBOX_RENAMED";
+    private static final int TRY_COUNT_BEFORE_FAILURE = 6;
 
     @RegisterExtension
     static CassandraClusterExtension cassandra = new CassandraClusterExtension(MailboxAggregateModule.MODULE_WITH_QUOTA);
@@ -70,26 +57,11 @@ class CassandraMailboxManagerConsistencyTest {
     private MailboxPath inboxPathRenamed;
     private MailboxQuery.UserBound allMailboxesSearchQuery;
 
-    private CassandraMailboxDAO mailboxDAO;
-    private CassandraMailboxPathDAOImpl mailboxPathDAO;
-    private CassandraMailboxPathV2DAO mailboxPathV2DAO;
-
     @BeforeEach
-    void setUp() {
-        Session session = cassandra.getCassandraCluster().getConf();
-        CassandraTypesProvider typesProvider = cassandra.getCassandraCluster().getTypesProvider();
-
-        mailboxDAO = spy(new CassandraMailboxDAO(session, typesProvider));
-        mailboxPathDAO = spy(new CassandraMailboxPathDAOImpl(session, typesProvider));
-        mailboxPathV2DAO = spy(new CassandraMailboxPathV2DAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION));
-
+    void setUp(CassandraCluster cassandra) {
         testee = CassandraMailboxManagerProvider.provideMailboxManager(
-            session,
-            typesProvider,
-            PreDeletionHooks.NO_PRE_DELETION_HOOK,
-            binder -> binder.bind(CassandraMailboxDAO.class).toInstance(mailboxDAO),
-            binder -> binder.bind(CassandraMailboxPathDAOImpl.class).toInstance(mailboxPathDAO),
-            binder -> binder.bind(CassandraMailboxPathV2DAO.class).toInstance(mailboxPathV2DAO));
+            cassandra,
+            PreDeletionHooks.NO_PRE_DELETION_HOOK);
 
         mailboxSession = testee.createSystemSession(USER);
 
@@ -106,13 +78,17 @@ class CassandraMailboxManagerConsistencyTest {
     class FailuresDuringCreation {
 
         @Test
-        void createMailboxShouldBeConsistentWhenMailboxDaoFails() {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .when(mailboxDAO)
-                .save(any(Mailbox.class));
+        void createMailboxShouldBeConsistentWhenMailboxDaoFails(CassandraCluster cassandra) {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                     .isEmpty();
@@ -122,13 +98,17 @@ class CassandraMailboxManagerConsistencyTest {
         }
 
         @Test
-        void createMailboxShouldBeConsistentWhenMailboxPathDaoFails() {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .when(mailboxPathV2DAO)
-                .save(eq(inboxPath), isA(CassandraId.class));
+        void createMailboxShouldBeConsistentWhenMailboxPathDaoFails(CassandraCluster cassandra) {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailboxPathV2")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                     .isEmpty();
@@ -139,11 +119,12 @@ class CassandraMailboxManagerConsistencyTest {
 
         @Disabled("JAMES-3056 createMailbox() doesn't return mailboxId while it's supposed to")
         @Test
-        void createMailboxAfterAFailedCreationShouldCreateTheMailboxWhenMailboxDaoFails() throws Exception {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxDAO)
-                .save(any(Mailbox.class));
+        void createMailboxAfterAFailedCreationShouldCreateTheMailboxWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession));
 
@@ -152,14 +133,17 @@ class CassandraMailboxManagerConsistencyTest {
         }
 
         @Test
-        void createMailboxAfterAFailedCreationShouldCreateTheMailboxWhenMailboxPathDaoFails() throws Exception {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxPathV2DAO)
-                .save(eq(inboxPath), isA(CassandraId.class));
+        void createMailboxAfterAFailedCreationShouldCreateTheMailboxWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailboxPathV2")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession));
 
+            cassandra.getConf().resetExecutionHook();
+
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                 .get();
 
@@ -176,13 +160,17 @@ class CassandraMailboxManagerConsistencyTest {
 
         @Disabled("JAMES-3056 createMailbox() doesn't return mailboxId while it's supposed to")
         @Test
-        void createMailboxAfterDeletingShouldCreateTheMailboxWhenMailboxDaoFails() throws Exception {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxDAO)
-                .save(any(Mailbox.class));
+        void createMailboxAfterDeletingShouldCreateTheMailboxWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession));
+
+            cassandra.getConf().resetExecutionHook();
+
             doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
 
             assertThat(testee.createMailbox(inboxPath, mailboxSession))
@@ -190,13 +178,17 @@ class CassandraMailboxManagerConsistencyTest {
         }
 
         @Test
-        void createMailboxAfterDeletingShouldCreateTheMailboxWhenMailboxPathDaoFails() throws Exception {
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxPathV2DAO)
-                .save(eq(inboxPath), isA(CassandraId.class));
+        void createMailboxAfterDeletingShouldCreateTheMailboxWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailboxPathV2")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession));
+
+            cassandra.getConf().resetExecutionHook();
+
             doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
 
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
@@ -218,16 +210,20 @@ class CassandraMailboxManagerConsistencyTest {
     class FailuresDuringRenaming {
 
         @Test
-        void renameShouldBeConsistentWhenMailboxDaoFails() throws Exception {
+        void renameShouldBeConsistentWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                 .get();
 
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .when(mailboxDAO)
-                .save(any(Mailbox.class));
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.renameMailbox(inboxPath, inboxPathRenamed, mailboxSession));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                     .hasOnlyOneElementSatisfying(mailboxMetaData -> {
@@ -240,16 +236,20 @@ class CassandraMailboxManagerConsistencyTest {
         }
 
         @Test
-        void renameShouldBeConsistentWhenMailboxPathDaoFails() throws Exception {
+        void renameShouldBeConsistentWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                 .get();
 
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .when(mailboxPathV2DAO)
-                .save(any(MailboxPath.class), any(CassandraId.class));
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailboxPathV2")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.renameMailbox(inboxPath, inboxPathRenamed, mailboxSession));
 
+            cassandra.getConf().resetExecutionHook();
+
             SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                 softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                     .hasOnlyOneElementSatisfying(mailboxMetaData -> {
@@ -263,16 +263,20 @@ class CassandraMailboxManagerConsistencyTest {
 
         @Disabled("JAMES-3056 cannot create a new mailbox because 'INBOX_RENAMED' already exists")
         @Test
-        void createNewMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxDaoFails() throws Exception {
+        void createNewMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                 .get();
 
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxDAO)
-                .save(any(Mailbox.class));
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.renameMailbox(inboxPath, inboxPathRenamed, mailboxSession));
+
+            cassandra.getConf().resetExecutionHook();
+
             MailboxId newMailboxId = testee.createMailbox(inboxPathRenamed, mailboxSession)
                 .get();
 
@@ -293,16 +297,20 @@ class CassandraMailboxManagerConsistencyTest {
         }
 
         @Test
-        void createNewMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxPathDaoFails() throws Exception {
+        void createNewMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                 .get();
 
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxPathV2DAO)
-                .save(any(MailboxPath.class), any(CassandraId.class));
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailboxPathV2")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.renameMailbox(inboxPath, inboxPathRenamed, mailboxSession));
+
+            cassandra.getConf().resetExecutionHook();
+
             MailboxId newMailboxId = testee.createMailbox(inboxPathRenamed, mailboxSession)
                 .get();
 
@@ -324,32 +332,40 @@ class CassandraMailboxManagerConsistencyTest {
 
         @Disabled("JAMES-3056 creating mailbox returns an empty Optional")
         @Test
-        void deleteMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxDaoFails() throws Exception {
+        void deleteMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                 .get();
 
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxDAO)
-                .save(any(Mailbox.class));
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailbox (id,name,uidvalidity,mailboxbase) VALUES (:id,:name,:uidvalidity,:mailboxbase);")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.renameMailbox(inboxPath, inboxPathRenamed, mailboxSession));
+
+            cassandra.getConf().resetExecutionHook();
+
             testee.deleteMailbox(inboxId, mailboxSession);
             assertThat(testee.createMailbox(inboxPathRenamed, mailboxSession))
                 .isNotEmpty();
         }
 
         @Test
-        void deleteMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxPathDaoFails() throws Exception {
+        void deleteMailboxAfterAFailedRenameShouldCreateThatMailboxWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
             MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                 .get();
 
-            doReturn(Mono.error(new RuntimeException("mock exception")))
-                .doCallRealMethod()
-                .when(mailboxPathV2DAO)
-                .save(any(MailboxPath.class), any(CassandraId.class));
+            cassandra.getConf()
+                .fail()
+                .whenBoundStatementStartsWith("INSERT INTO mailboxPathV2")
+                .times(TRY_COUNT_BEFORE_FAILURE)
+                .setExecutionHook();
 
             doQuietly(() -> testee.renameMailbox(inboxPath, inboxPathRenamed, mailboxSession));
+
+            cassandra.getConf().resetExecutionHook();
+
             testee.deleteMailbox(inboxId, mailboxSession);
             MailboxId newMailboxId = testee.createMailbox(inboxPathRenamed, mailboxSession)
                 .get();
@@ -373,16 +389,20 @@ class CassandraMailboxManagerConsistencyTest {
         class DeleteOnce {
             @Disabled("JAMES-3056 allMailboxesSearchQuery returns empty list")
             @Test
-            void deleteMailboxByPathShouldBeConsistentWhenMailboxDaoFails() throws Exception {
+            void deleteMailboxByPathShouldBeConsistentWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
 
+                cassandra.getConf().resetExecutionHook();
+
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                     softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                         .hasOnlyOneElementSatisfying(mailboxMetaData -> {
@@ -396,16 +416,20 @@ class CassandraMailboxManagerConsistencyTest {
 
             @Disabled("JAMES-3056 allMailboxesSearchQuery returns empty list")
             @Test
-            void deleteMailboxByIdShouldBeConsistentWhenMailboxDaoFails() throws Exception {
+            void deleteMailboxByIdShouldBeConsistentWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
 
+                cassandra.getConf().resetExecutionHook();
+
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                     softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                         .hasOnlyOneElementSatisfying(mailboxMetaData -> {
@@ -418,16 +442,20 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void deleteMailboxByPathShouldBeConsistentWhenMailboxPathDaoFails() throws Exception {
+            void deleteMailboxByPathShouldBeConsistentWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
 
+                cassandra.getConf().resetExecutionHook();
+
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                     softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                         .hasOnlyOneElementSatisfying(mailboxMetaData -> {
@@ -440,16 +468,20 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void deleteMailboxByIdShouldBeConsistentWhenMailboxPathDaoFails() throws Exception {
+            void deleteMailboxByIdShouldBeConsistentWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
 
+                cassandra.getConf().resetExecutionHook();
+
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                     softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                         .hasOnlyOneElementSatisfying(mailboxMetaData -> {
@@ -466,15 +498,19 @@ class CassandraMailboxManagerConsistencyTest {
         class DeleteOnceThenCreate {
 
             @Test
-            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteByPath() throws Exception {
+            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteByPath(CassandraCluster cassandra) throws Exception {
                 testee.createMailbox(inboxPath, mailboxSession);
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
@@ -490,16 +526,20 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteById() throws Exception {
+            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteById(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 MailboxId inboxNewId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
@@ -516,15 +556,19 @@ class CassandraMailboxManagerConsistencyTest {
 
             @Disabled("JAMES-3056 cannot create because mailbox already exists")
             @Test
-            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteByPath() throws Exception {
+            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteByPath(CassandraCluster cassandra) throws Exception {
                 testee.createMailbox(inboxPath, mailboxSession);
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 MailboxId inboxNewId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
@@ -541,16 +585,20 @@ class CassandraMailboxManagerConsistencyTest {
 
             @Disabled("JAMES-3056 cannot create because mailbox already exists")
             @Test
-            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteById() throws Exception {
+            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteById(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 MailboxId inboxNewId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
@@ -571,17 +619,23 @@ class CassandraMailboxManagerConsistencyTest {
 
             @Disabled("JAMES-3056 list() returns one element with inboxPath")
             @Test
-            void deleteMailboxByPathShouldDeleteWhenMailboxDaoFails() throws Exception {
+            void deleteMailboxByPathShouldDeleteWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
                 testee.createMailbox(inboxPath, mailboxSession);
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
 
+                cassandra.getConf().resetExecutionHook();
+
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
                     softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession))
                         .isEmpty();
@@ -591,16 +645,20 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void deleteMailboxByIdShouldDeleteWhenMailboxDaoFails() throws Exception {
+            void deleteMailboxByIdShouldDeleteWhenMailboxDaoFails(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
 
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
@@ -612,15 +670,19 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void deleteMailboxByPathShouldDeleteWhenMailboxPathDaoFails() throws Exception {
+            void deleteMailboxByPathShouldDeleteWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
                 testee.createMailbox(inboxPath, mailboxSession);
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
 
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
@@ -632,16 +694,20 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void deleteMailboxByIdShouldDeleteWhenMailboxPathDaoFails() throws Exception {
+            void deleteMailboxByIdShouldDeleteWhenMailboxPathDaoFails(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
 
                 SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
@@ -657,15 +723,19 @@ class CassandraMailboxManagerConsistencyTest {
         class DeleteTwiceThenCreate {
 
             @Test
-            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteByPath() throws Exception {
+            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteByPath(CassandraCluster cassandra) throws Exception {
                 testee.createMailbox(inboxPath, mailboxSession);
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
@@ -682,16 +752,20 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteById() throws Exception {
+            void createMailboxShouldCreateWhenMailboxDaoFailsOnDeleteById(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxDAO)
-                    .delete(any(CassandraId.class));
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailbox WHERE id=:id;")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
                 MailboxId inboxNewId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
@@ -708,15 +782,19 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteByPath() throws Exception {
+            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteByPath(CassandraCluster cassandra) throws Exception {
                 testee.createMailbox(inboxPath, mailboxSession);
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession));
                 MailboxId inboxNewId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
@@ -733,16 +811,20 @@ class CassandraMailboxManagerConsistencyTest {
             }
 
             @Test
-            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteById() throws Exception {
+            void createMailboxShouldCreateWhenMailboxPathDaoFailsOnDeleteById(CassandraCluster cassandra) throws Exception {
                 MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();
 
-                doReturn(Mono.error(new RuntimeException("mock exception")))
-                    .doCallRealMethod()
-                    .when(mailboxPathV2DAO)
-                    .delete(inboxPath);
+                cassandra.getConf()
+                    .fail()
+                    .whenBoundStatementStartsWith("DELETE FROM mailboxPathV2")
+                    .times(TRY_COUNT_BEFORE_FAILURE)
+                    .setExecutionHook();
 
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
+
+                cassandra.getConf().resetExecutionHook();
+
                 doQuietly(() -> testee.deleteMailbox(inboxId, mailboxSession));
                 MailboxId inboxNewId = testee.createMailbox(inboxPath, mailboxSession)
                     .get();


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


[james-project] 06/10: [REFACTORING] CassandraMailboxMapper Inline misnamed method

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 f4767c6bdf77d0a3cca35b1a447609a7f7a3a848
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Feb 18 14:08:39 2020 +0700

    [REFACTORING] CassandraMailboxMapper Inline misnamed method
    
    This method is called authorizedMailbox but do not act nor take decisions
    on a mailbox object.
    
    The inlined version seems easier to understand.
---
 .../james/mailbox/cassandra/mail/CassandraMailboxMapper.java       | 7 +------
 1 file changed, 1 insertion(+), 6 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 ed2573c..916b842 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
@@ -260,15 +260,10 @@ public class CassandraMailboxMapper implements MailboxMapper {
     @Override
     public List<Mailbox> findNonPersonalMailboxes(Username userName, Right right) {
         return userMailboxRightsDAO.listRightsForUser(userName)
-            .filter(mailboxId -> authorizedMailbox(mailboxId.getRight(), right))
+            .filter(mailboxId -> mailboxId.getRight().contains(right))
             .map(Pair::getLeft)
             .flatMap(this::retrieveMailbox)
             .collectList()
             .block();
     }
-
-    private boolean authorizedMailbox(MailboxACL.Rfc4314Rights rights, Right right) {
-        return rights.contains(right);
-    }
-
 }


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


[james-project] 05/10: [REFACTORING] Remove unused method

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 2c2578326b57c91a4a543b640284977e243dd1ea
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Feb 18 14:06:15 2020 +0700

    [REFACTORING] Remove unused method
    
    Mailbox matching is performed directly by mailboxQuery being now pushed
    to the mapper.
---
 .../cassandra/mail/CassandraMailboxMapper.java     | 22 ----------------------
 1 file changed, 22 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 f62c27b..ed2573c 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
@@ -19,11 +19,7 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
-import java.util.Collections;
 import java.util.List;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 
@@ -53,8 +49,6 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraMailboxMapper implements MailboxMapper {
-
-    private static final String WILDCARD = "%";
     public static final Logger LOGGER = LoggerFactory.getLogger(CassandraMailboxMapper.class);
 
     private final CassandraMailboxDAO mailboxDAO;
@@ -254,22 +248,6 @@ public class CassandraMailboxMapper implements MailboxMapper {
         // Do nothing
     }
 
-    private String constructEscapedRegexForMailboxNameMatching(MailboxPath path) {
-        return Collections
-            .list(new StringTokenizer(path.getName(), WILDCARD, true))
-            .stream()
-            .map(this::tokenToPatternPart)
-            .collect(Collectors.joining());
-    }
-
-    private String tokenToPatternPart(Object token) {
-        if (token.equals(WILDCARD)) {
-            return ".*";
-        } else {
-            return Pattern.quote((String) token);
-        }
-    }
-
     private Mono<Mailbox> toMailboxWithAcl(Mailbox mailbox) {
         CassandraId cassandraId = (CassandraId) mailbox.getMailboxId();
         return cassandraACLMapper.getACL(cassandraId)


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


[james-project] 07/10: [REFACTORING] Extract condition in CassandraMailboxMapper::hasChildren

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 b1109e0053e480d5f5f4f1c7bee575c88b7759a5
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Feb 18 14:12:24 2020 +0700

    [REFACTORING] Extract condition in CassandraMailboxMapper::hasChildren
    
    This complex condition deserves a proper name
---
 .../apache/james/mailbox/cassandra/mail/CassandraMailboxMapper.java | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

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 916b842..7be9c1e 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
@@ -213,11 +213,15 @@ public class CassandraMailboxMapper implements MailboxMapper {
         return Flux.merge(
                 mailboxPathDAO.listUserMailboxes(mailbox.getNamespace(), mailbox.getUser()),
                 mailboxPathV2DAO.listUserMailboxes(mailbox.getNamespace(), mailbox.getUser()))
-            .filter(idAndPath -> idAndPath.getMailboxPath().getName().startsWith(mailbox.getName() + String.valueOf(delimiter)))
+            .filter(idAndPath -> isPathChildOfMailbox(idAndPath, mailbox, delimiter))
             .hasElements()
             .block();
     }
 
+    private boolean isPathChildOfMailbox(CassandraIdAndPath idAndPath, Mailbox mailbox, char delimiter) {
+        return idAndPath.getMailboxPath().getName().startsWith(mailbox.getName() + String.valueOf(delimiter));
+    }
+
     @Override
     public List<Mailbox> list() {
         return mailboxDAO.retrieveAllMailboxes()


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


[james-project] 03/10: JAMES-3058 Concurrency test for CassandraAclMapper

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 6e16c097c1aa77374b056342036c8f2357f3e509
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Feb 20 16:52:00 2020 +0700

    JAMES-3058 Concurrency test for CassandraAclMapper
    
    This can be done without code injection in business logic thanks to
    Cassandra statement instrumentation.
---
 .../james/backends/cassandra/TestingSession.java   | 14 ++++++--
 .../mailbox/cassandra/mail/CassandraACLMapper.java | 16 ++--------
 .../cassandra/mail/CassandraACLMapperTest.java     | 37 +++++++++++++++++-----
 3 files changed, 42 insertions(+), 25 deletions(-)

diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
index 2e879c8..d102148 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
@@ -58,13 +58,21 @@ public class TestingSession implements Session {
 
     public static class Barrier {
         private final CountDownLatch callerLatch = new CountDownLatch(1);
-        private final CountDownLatch awaitCallerLatch = new CountDownLatch(1);
+        private final CountDownLatch awaitCallerLatch;
 
-        void awaitCaller() throws InterruptedException {
+        public Barrier() {
+            this(1);
+        }
+
+        public Barrier(int callerCount) {
+            awaitCallerLatch = new CountDownLatch(callerCount);
+        }
+
+        public void awaitCaller() throws InterruptedException {
             awaitCallerLatch.await();
         }
 
-        void releaseCaller() {
+        public void releaseCaller() {
             callerLatch.countDown();
         }
 
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
index c877d9a..4a2734b 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapper.java
@@ -58,14 +58,8 @@ public class CassandraACLMapper {
     private static final Logger LOG = LoggerFactory.getLogger(CassandraACLMapper.class);
     private static final String OLD_VERSION = "oldVersion";
 
-    @FunctionalInterface
-    public interface CodeInjector {
-        void inject();
-    }
-
     private final CassandraAsyncExecutor executor;
     private final int maxAclRetry;
-    private final CodeInjector codeInjector;
     private final CassandraUserMailboxRightsDAO userMailboxRightsDAO;
     private final PreparedStatement conditionalInsertStatement;
     private final PreparedStatement conditionalUpdateStatement;
@@ -73,13 +67,8 @@ public class CassandraACLMapper {
 
     @Inject
     public CassandraACLMapper(Session session, CassandraUserMailboxRightsDAO userMailboxRightsDAO, CassandraConfiguration cassandraConfiguration) {
-        this(session, userMailboxRightsDAO, cassandraConfiguration, () -> { });
-    }
-
-    public CassandraACLMapper(Session session, CassandraUserMailboxRightsDAO userMailboxRightsDAO, CassandraConfiguration cassandraConfiguration, CodeInjector codeInjector) {
         this.executor = new CassandraAsyncExecutor(session);
         this.maxAclRetry = cassandraConfiguration.getAclMaxRetry();
-        this.codeInjector = codeInjector;
         this.conditionalInsertStatement = prepareConditionalInsert(session);
         this.conditionalUpdateStatement = prepareConditionalUpdate(session);
         this.readStatement = prepareReadStatement(session);
@@ -139,9 +128,8 @@ public class CassandraACLMapper {
             .orElseThrow(() -> new MailboxException("Unable to update ACL"));
     }
 
-    private Mono<ACLDiff> updateAcl(CassandraId cassandraId, Function<ACLWithVersion, ACLWithVersion> aclTransformation, MailboxACL replacement) throws MailboxException {
-        return Mono.fromRunnable(() -> codeInjector.inject())
-            .then(Mono.defer(() -> getAclWithVersion(cassandraId)))
+    private Mono<ACLDiff> updateAcl(CassandraId cassandraId, Function<ACLWithVersion, ACLWithVersion> aclTransformation, MailboxACL replacement) {
+        return getAclWithVersion(cassandraId)
             .flatMap(aclWithVersion ->
                     updateStoredACL(cassandraId, aclTransformation.apply(aclWithVersion))
                             .map(newACL -> ACLDiff.computeDiff(aclWithVersion.mailboxACL, newACL)))
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
index d112645..025a41a 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraACLMapperTest.java
@@ -33,6 +33,7 @@ import java.util.concurrent.TimeoutException;
 
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.backends.cassandra.TestingSession.Barrier;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.backends.cassandra.utils.CassandraUtils;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
@@ -160,12 +161,22 @@ class CassandraACLMapperTest {
 
     @Test
     void twoConcurrentUpdatesWhenNoACLStoredShouldReturnACLWithTwoEntries(CassandraCluster cassandra) throws Exception {
-        CountDownLatch countDownLatch = new CountDownLatch(2);
+        Barrier barrier = new Barrier(2);
+        cassandra.getConf()
+            .awaitOn(barrier)
+            .whenBoundStatementStartsWith("SELECT acl,version FROM acl WHERE id=:id;")
+            .times(2)
+            .setExecutionHook();
+
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
-        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights, countDownLatch::countDown);
-        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights, countDownLatch::countDown);
+        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+
+        barrier.awaitCaller();
+        barrier.releaseCaller();
+
         awaitAll(future1, future2);
 
         assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
@@ -179,10 +190,21 @@ class CassandraACLMapperTest {
         MailboxACL.Rfc4314Rights rights = new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read);
         cassandraACLMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(keyBenwa).rights(rights).asAddition());
 
+        Barrier barrier = new Barrier(2);
+        cassandra.getConf()
+            .awaitOn(barrier)
+            .whenBoundStatementStartsWith("SELECT acl,version FROM acl WHERE id=:id;")
+            .times(2)
+            .setExecutionHook();
+
         MailboxACL.EntryKey keyBob = new MailboxACL.EntryKey("bob", MailboxACL.NameType.user, false);
         MailboxACL.EntryKey keyAlice = new MailboxACL.EntryKey("alice", MailboxACL.NameType.user, false);
-        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights, countDownLatch::countDown);
-        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights, countDownLatch::countDown);
+        Future<Boolean> future1 = performACLUpdateInExecutor(cassandra, executor, keyBob, rights);
+        Future<Boolean> future2 = performACLUpdateInExecutor(cassandra, executor, keyAlice, rights);
+
+        barrier.awaitCaller();
+        barrier.releaseCaller();
+
         awaitAll(future1, future2);
 
         assertThat(cassandraACLMapper.getACL(MAILBOX_ID).block())
@@ -196,13 +218,12 @@ class CassandraACLMapperTest {
         }
     }
 
-    private Future<Boolean> performACLUpdateInExecutor(CassandraCluster cassandra, ExecutorService executor, MailboxACL.EntryKey key, MailboxACL.Rfc4314Rights rights, CassandraACLMapper.CodeInjector runnable) {
+    private Future<Boolean> performACLUpdateInExecutor(CassandraCluster cassandra, ExecutorService executor, MailboxACL.EntryKey key, MailboxACL.Rfc4314Rights rights) {
         return executor.submit(() -> {
             CassandraACLMapper aclMapper = new CassandraACLMapper(
                 cassandra.getConf(),
                 new CassandraUserMailboxRightsDAO(cassandra.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION),
-                CassandraConfiguration.DEFAULT_CONFIGURATION,
-                runnable);
+                CassandraConfiguration.DEFAULT_CONFIGURATION);
             try {
                 aclMapper.updateACL(MAILBOX_ID, MailboxACL.command().key(key).rights(rights).asAddition());
             } catch (MailboxException exception) {


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


[james-project] 09/10: [REFACTORING] Simplify providing a testing CassandraMailboxManager

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 4af9ec97185d8832fe6fdc036c8d69d65e08716e
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Feb 20 11:01:45 2020 +0700

    [REFACTORING] Simplify providing a testing CassandraMailboxManager
    
    We no longer need to inject our DAOs
---
 .../cassandra/CassandraMailboxManagerProvider.java | 26 ++++------------------
 .../CassandraMailboxManagerStressTest.java         |  3 +--
 .../cassandra/CassandraMailboxManagerTest.java     |  3 +--
 .../cassandra/CassandraTestSystemFixture.java      |  5 +----
 .../TestCassandraMailboxSessionMapperFactory.java  | 12 +++++-----
 .../CassandraMailboxManagerAttachmentTest.java     |  3 +--
 .../cassandra/mail/CassandraMapperProvider.java    |  3 +--
 .../mail/CassandraMessageIdMapperTest.java         |  3 +--
 .../tools/indexer/CassandraReIndexerImplTest.java  |  3 +--
 .../cassandra/host/CassandraHostSystem.java        |  4 +---
 10 files changed, 17 insertions(+), 48 deletions(-)

diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
index 8e07ab4..1ccb948 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerProvider.java
@@ -19,14 +19,12 @@
 
 package org.apache.james.mailbox.cassandra;
 
-import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
-import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
+import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.mailbox.acl.GroupMembershipResolver;
 import org.apache.james.mailbox.acl.MailboxACLResolver;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
 import org.apache.james.mailbox.acl.UnionMailboxACLResolver;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
-import org.apache.james.mailbox.cassandra.mail.utils.GuiceUtils;
 import org.apache.james.mailbox.cassandra.quota.CassandraCurrentQuotaManager;
 import org.apache.james.mailbox.cassandra.quota.CassandraGlobalMaxQuotaDao;
 import org.apache.james.mailbox.cassandra.quota.CassandraPerDomainMaxQuotaDao;
@@ -56,36 +54,20 @@ import org.apache.james.mailbox.store.search.SimpleMessageSearchIndex;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
 
 import com.datastax.driver.core.Session;
-import com.google.inject.Module;
 
 public class CassandraMailboxManagerProvider {
     private static final int LIMIT_ANNOTATIONS = 3;
     private static final int LIMIT_ANNOTATION_SIZE = 30;
 
-    static CassandraMailboxManager provideMailboxManager(Session session, CassandraTypesProvider cassandraTypesProvider,
-                                                         PreDeletionHooks preDeletionHooks, Module... overriedGuiceModules) {
-        CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
-
-        CassandraMailboxSessionMapperFactory mapperFactory = GuiceUtils.testInjector(session,
-                cassandraTypesProvider,
-                messageIdFactory,
-                CassandraConfiguration.DEFAULT_CONFIGURATION,
-                overriedGuiceModules)
-            .getInstance(CassandraMailboxSessionMapperFactory.class);
-
-        return provideMailboxManager(session, preDeletionHooks, mapperFactory, messageIdFactory);
-    }
-
-    public static CassandraMailboxManager provideMailboxManager(Session session, CassandraTypesProvider cassandraTypesProvider,
+    public static CassandraMailboxManager provideMailboxManager(CassandraCluster cassandra,
                                                                 PreDeletionHooks preDeletionHooks) {
         CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
 
         CassandraMailboxSessionMapperFactory mapperFactory = TestCassandraMailboxSessionMapperFactory.forTests(
-            session,
-            cassandraTypesProvider,
+            cassandra,
             messageIdFactory);
 
-        return provideMailboxManager(session, preDeletionHooks, mapperFactory, messageIdFactory);
+        return provideMailboxManager(cassandra.getConf(), preDeletionHooks, mapperFactory, messageIdFactory);
     }
 
     private static CassandraMailboxManager provideMailboxManager(Session session,
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
index 8709413..6120bbd 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerStressTest.java
@@ -47,8 +47,7 @@ class CassandraMailboxManagerStressTest implements MailboxManagerStressContract<
     @BeforeEach
     void setUp() {
         this.mailboxManager = CassandraMailboxManagerProvider.provideMailboxManager(
-            cassandra.getCassandraCluster().getConf(),
-            cassandra.getCassandraCluster().getTypesProvider(),
+            cassandra.getCassandraCluster(),
             PreDeletionHooks.NO_PRE_DELETION_HOOK);
     }
 }
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
index 130cd7f..5cd44e3 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
@@ -33,8 +33,7 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
     @Override
     protected CassandraMailboxManager provideMailboxManager() {
         return CassandraMailboxManagerProvider.provideMailboxManager(
-            cassandra.getCassandraCluster().getConf(),
-            cassandra.getCassandraCluster().getTypesProvider(),
+            cassandra.getCassandraCluster(),
             new PreDeletionHooks(preDeletionHooks(), new RecordingMetricFactory()));
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
index c3aed62..ec3e121 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraTestSystemFixture.java
@@ -59,10 +59,7 @@ class CassandraTestSystemFixture {
     static CassandraMailboxSessionMapperFactory createMapperFactory(CassandraCluster cassandra) {
         CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
 
-        return TestCassandraMailboxSessionMapperFactory.forTests(
-            cassandra.getConf(),
-            cassandra.getTypesProvider(),
-            messageIdFactory);
+        return TestCassandraMailboxSessionMapperFactory.forTests(cassandra, messageIdFactory);
     }
 
     static CassandraMailboxManager createMailboxManager(CassandraMailboxSessionMapperFactory mapperFactory) {
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java
index 0c59550..d0fc733 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/TestCassandraMailboxSessionMapperFactory.java
@@ -19,24 +19,22 @@
 
 package org.apache.james.mailbox.cassandra;
 
-import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
+import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.utils.GuiceUtils;
 
-import com.datastax.driver.core.Session;
-
 public class TestCassandraMailboxSessionMapperFactory {
 
-    public static CassandraMailboxSessionMapperFactory forTests(Session session, CassandraTypesProvider typesProvider,
+    public static CassandraMailboxSessionMapperFactory forTests(CassandraCluster cassandra,
                                                                 CassandraMessageId.Factory factory) {
-        return forTests(session, typesProvider, factory, CassandraConfiguration.DEFAULT_CONFIGURATION);
+        return forTests(cassandra, factory, CassandraConfiguration.DEFAULT_CONFIGURATION);
     }
 
-    public static CassandraMailboxSessionMapperFactory forTests(Session session, CassandraTypesProvider typesProvider,
+    public static CassandraMailboxSessionMapperFactory forTests(CassandraCluster cassandra,
                                                                 CassandraMessageId.Factory factory, CassandraConfiguration cassandraConfiguration) {
 
-        return GuiceUtils.testInjector(session, typesProvider, factory, cassandraConfiguration)
+        return GuiceUtils.testInjector(cassandra.getConf(), cassandra.getTypesProvider(), factory, cassandraConfiguration)
             .getInstance(CassandraMailboxSessionMapperFactory.class);
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
index 1775767..05f39ff 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxManagerAttachmentTest.java
@@ -71,8 +71,7 @@ class CassandraMailboxManagerAttachmentTest extends AbstractMailboxManagerAttach
         CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
 
         mailboxSessionMapperFactory = TestCassandraMailboxSessionMapperFactory.forTests(
-            cassandraCluster.getCassandraCluster().getConf(),
-            cassandraCluster.getCassandraCluster().getTypesProvider(),
+            cassandraCluster.getCassandraCluster(),
             messageIdFactory);
         Authenticator noAuthenticator = null;
         Authorizator noAuthorizator = null;
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
index 8510f27..befae86 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMapperProvider.java
@@ -82,8 +82,7 @@ public class CassandraMapperProvider implements MapperProvider {
     }
 
     private CassandraMailboxSessionMapperFactory createMapperFactory() {
-        return TestCassandraMailboxSessionMapperFactory.forTests(cassandra.getConf(),
-            cassandra.getTypesProvider(),
+        return TestCassandraMailboxSessionMapperFactory.forTests(cassandra,
             new CassandraMessageId.Factory());
     }
 
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
index 5176f9d..98ef169 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapperTest.java
@@ -54,8 +54,7 @@ class CassandraMessageIdMapperTest extends MessageIdMapperTest {
     void findShouldReturnCorrectElementsWhenChunking() throws Exception {
         CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
         CassandraMailboxSessionMapperFactory mapperFactory = TestCassandraMailboxSessionMapperFactory.forTests(
-            cassandraCluster.getCassandraCluster().getConf(),
-            cassandraCluster.getCassandraCluster().getTypesProvider(),
+            cassandraCluster.getCassandraCluster(),
             messageIdFactory,
             CassandraConfiguration.builder()
                 .messageReadChunkSize(3)
diff --git a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java
index d397cef..2362609 100644
--- a/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java
+++ b/mailbox/tools/indexer/src/test/java/org/apache/mailbox/tools/indexer/CassandraReIndexerImplTest.java
@@ -64,8 +64,7 @@ public class CassandraReIndexerImplTest {
 
     @BeforeEach
     void setUp(CassandraCluster cassandra) {
-        mailboxManager = CassandraMailboxManagerProvider.provideMailboxManager(cassandra.getConf(), cassandra.getTypesProvider(),
-            PreDeletionHooks.NO_PRE_DELETION_HOOK);
+        mailboxManager = CassandraMailboxManagerProvider.provideMailboxManager(cassandra, PreDeletionHooks.NO_PRE_DELETION_HOOK);
         MailboxSessionMapperFactory mailboxSessionMapperFactory = mailboxManager.getMapperFactory();
         messageSearchIndex = mock(ListeningMessageSearchIndex.class);
         reIndexer = new ReIndexerImpl(new ReIndexerPerformer(mailboxManager, messageSearchIndex, mailboxSessionMapperFactory),
diff --git a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
index ba3d4a0..6027feb 100644
--- a/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
+++ b/mpt/impl/imap-mailbox/cassandra/src/test/java/org/apache/james/mpt/imapmailbox/cassandra/host/CassandraHostSystem.java
@@ -88,9 +88,7 @@ public class CassandraHostSystem extends JamesImapHostSystem {
         com.datastax.driver.core.Session session = cassandra.getConf();
         CassandraMessageId.Factory messageIdFactory = new CassandraMessageId.Factory();
         CassandraMailboxSessionMapperFactory mapperFactory = TestCassandraMailboxSessionMapperFactory.forTests(
-            cassandra.getConf(),
-            cassandra.getTypesProvider(),
-            messageIdFactory);
+            cassandra, messageIdFactory);
 
 
         InVMEventBus eventBus = new InVMEventBus(new InVmEventDelivery(new RecordingMetricFactory()));


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


[james-project] 02/10: JAMES-3058 Cassandra Testing Session: barrier synchronisation

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 7de356a4f2b4df51a0ff5114fe2c8c0943139329
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Feb 20 13:54:26 2020 +0700

    JAMES-3058 Cassandra Testing Session: barrier synchronisation
    
    This allow easy concurrency testing for Cassandra tests
---
 .../james/backends/cassandra/TestingSession.java   | 47 +++++++++++---
 .../backends/cassandra/TestingSessionTest.java     | 71 ++++++++++++++++++++++
 2 files changed, 108 insertions(+), 10 deletions(-)

diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
index 5e0ad9d..2e879c8 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSession.java
@@ -20,8 +20,8 @@
 package org.apache.james.backends.cassandra;
 
 import java.util.Map;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.BiFunction;
 import java.util.function.Predicate;
 
 import com.datastax.driver.core.BoundStatement;
@@ -36,22 +36,45 @@ import com.datastax.driver.core.Statement;
 import com.google.common.util.concurrent.ListenableFuture;
 
 public class TestingSession implements Session {
-    enum Behavior {
-        THROW((session, statement) -> {
+    @FunctionalInterface
+    interface Behavior {
+        Behavior THROW = (session, statement) -> {
             RuntimeException injected_failure = new RuntimeException("Injected failure");
             injected_failure.printStackTrace();
             throw injected_failure;
-        }),
-        EXECUTE_NORMALLY(Session::executeAsync);
+        };
 
-        private final BiFunction<Session, Statement, ResultSetFuture> behaviour;
+        Behavior EXECUTE_NORMALLY = Session::executeAsync;
 
-        Behavior(BiFunction<Session, Statement, ResultSetFuture> behaviour) {
-            this.behaviour = behaviour;
+        static Behavior awaitOn(Barrier barrier) {
+            return (session, statement) -> {
+                barrier.call();
+                return session.executeAsync(statement);
+            };
         }
 
-        ResultSetFuture execute(Session session, Statement statement) {
-            return behaviour.apply(session, statement);
+        ResultSetFuture execute(Session session, Statement statement);
+    }
+
+    public static class Barrier {
+        private final CountDownLatch callerLatch = new CountDownLatch(1);
+        private final CountDownLatch awaitCallerLatch = new CountDownLatch(1);
+
+        void awaitCaller() throws InterruptedException {
+            awaitCallerLatch.await();
+        }
+
+        void releaseCaller() {
+            callerLatch.countDown();
+        }
+
+        void call() {
+            awaitCallerLatch.countDown();
+            try {
+                callerLatch.await();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
         }
     }
 
@@ -139,6 +162,10 @@ public class TestingSession implements Session {
         return condition -> applyCount -> () -> executionHook = new ExecutionHook(condition, Behavior.THROW, applyCount);
     }
 
+    public RequiresCondition awaitOn(Barrier barrier) {
+        return condition -> applyCount -> () -> executionHook = new ExecutionHook(condition, Behavior.awaitOn(barrier), applyCount);
+    }
+
     public void resetExecutionHook() {
         executionHook = NO_EXECUTION_HOOK;
     }
diff --git a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java
index 1983e99..c044697 100644
--- a/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java
+++ b/backends-common/cassandra/src/test/java/org/apache/james/backends/cassandra/TestingSessionTest.java
@@ -19,9 +19,11 @@
 
 package org.apache.james.backends.cassandra;
 
+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 org.apache.james.backends.cassandra.TestingSession.Barrier;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionDAO;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
 import org.apache.james.backends.cassandra.versions.SchemaVersion;
@@ -30,6 +32,9 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
+
 class TestingSessionTest {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraSchemaVersionModule.MODULE);
@@ -158,4 +163,70 @@ class TestingSessionTest {
         assertThatThrownBy(() -> dao.getCurrentSchemaVersion().block())
             .isInstanceOf(RuntimeException.class);
     }
+
+    @Test
+    void statementShouldNotBeAppliedBeforeBarrierIsReleased(CassandraCluster cassandra) throws Exception {
+        SchemaVersion originalSchemaVersion = new SchemaVersion(32);
+        dao.updateVersion(originalSchemaVersion).block();
+        Barrier barrier = new Barrier();
+        cassandra.getConf()
+            .awaitOn(barrier)
+            .whenBoundStatementStartsWith("INSERT INTO schemaVersion")
+            .times(1)
+            .setExecutionHook();
+
+        dao.updateVersion(new SchemaVersion(36)).subscribeOn(Schedulers.elastic()).subscribe();
+
+        Thread.sleep(100);
+
+        assertThat(dao.getCurrentSchemaVersion().block())
+            .contains(originalSchemaVersion);
+    }
+
+    @Test
+    void statementShouldBeAppliedWhenBarrierIsReleased(CassandraCluster cassandra) throws Exception {
+        SchemaVersion originalSchemaVersion = new SchemaVersion(32);
+        SchemaVersion newVersion = new SchemaVersion(36);
+
+        dao.updateVersion(originalSchemaVersion).block();
+        Barrier barrier = new Barrier();
+        cassandra.getConf()
+            .awaitOn(barrier)
+            .whenBoundStatementStartsWith("INSERT INTO schemaVersion")
+            .times(1)
+            .setExecutionHook();
+
+        Mono<Void> operation = dao.updateVersion(newVersion).cache();
+
+        operation.subscribeOn(Schedulers.elastic()).subscribe();
+        barrier.releaseCaller();
+        operation.block();
+
+        assertThat(dao.getCurrentSchemaVersion().block())
+            .contains(newVersion);
+    }
+
+    @Test
+    void testShouldBeAbleToAwaitCaller(CassandraCluster cassandra) throws Exception {
+        SchemaVersion originalSchemaVersion = new SchemaVersion(32);
+        SchemaVersion newVersion = new SchemaVersion(36);
+
+        dao.updateVersion(originalSchemaVersion).block();
+        Barrier barrier = new Barrier();
+        cassandra.getConf()
+            .awaitOn(barrier)
+            .whenBoundStatementStartsWith("INSERT INTO schemaVersion")
+            .times(1)
+            .setExecutionHook();
+
+        Mono<Void> operation = dao.updateVersion(newVersion).cache();
+
+        operation.subscribeOn(Schedulers.elastic()).subscribe();
+        barrier.awaitCaller();
+        barrier.releaseCaller();
+        operation.block();
+
+        assertThat(dao.getCurrentSchemaVersion().block())
+            .contains(newVersion);
+    }
 }


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