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 c6e725c2394d8757197211a3b132b65b7eaf822a Author: Tran Tien Duc <[email protected]> AuthorDate: Thu Feb 13 14:53:26 2020 +0700 JAMES-3056 Consistency test on failing creations --- .../CassandraMailboxManagerConsistencyTest.java | 168 ++++++++++++++++++++- 1 file changed, 165 insertions(+), 3 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 84c2ad3..bd6f93f 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 @@ -18,35 +18,68 @@ ****************************************************************/ 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.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; +import org.apache.james.mailbox.model.search.Wildcard; import org.apache.james.mailbox.store.PreDeletionHooks; +import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import 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"; + @RegisterExtension static CassandraClusterExtension cassandra = new CassandraClusterExtension(MailboxAggregateModule.MODULE_WITH_QUOTA); private CassandraMailboxManager testee; + private MailboxSession mailboxSession; + + private MailboxPath inboxPath; + 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(); - CassandraMailboxDAO mailboxDAO = spy(new CassandraMailboxDAO(session, typesProvider)); - CassandraMailboxPathDAOImpl mailboxPathDAO = spy(new CassandraMailboxPathDAOImpl(session, typesProvider)); - CassandraMailboxPathV2DAO mailboxPathV2DAO = spy(new CassandraMailboxPathV2DAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION)); + mailboxDAO = spy(new CassandraMailboxDAO(session, typesProvider)); + mailboxPathDAO = spy(new CassandraMailboxPathDAOImpl(session, typesProvider)); + mailboxPathV2DAO = spy(new CassandraMailboxPathV2DAO(session, CassandraUtils.WITH_DEFAULT_CONFIGURATION)); testee = CassandraMailboxManagerProvider.provideMailboxManager( session, @@ -55,5 +88,134 @@ class CassandraMailboxManagerConsistencyTest { binder -> binder.bind(CassandraMailboxDAO.class).toInstance(mailboxDAO), binder -> binder.bind(CassandraMailboxPathDAOImpl.class).toInstance(mailboxPathDAO), binder -> binder.bind(CassandraMailboxPathV2DAO.class).toInstance(mailboxPathV2DAO)); + + mailboxSession = testee.createSystemSession(USER); + + inboxPath = MailboxPath.forUser(USER, INBOX); + allMailboxesSearchQuery = MailboxQuery.builder() + .userAndNamespaceFrom(inboxPath) + .expression(Wildcard.INSTANCE) + .build() + .asUserBound(); + } + + @Nested + class FailsOnCreate { + + @Test + void createMailboxShouldBeConsistentWhenMailboxDaoFails() { + doReturn(Mono.error(new RuntimeException("mock exception"))) + .when(mailboxDAO) + .save(any(Mailbox.class)); + + doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession)); + + SoftAssertions.assertSoftly(Throwing.consumer(softly -> { + softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession)) + .isEmpty(); + softly.assertThat(testee.list(mailboxSession)) + .isEmpty(); + })); + } + + @Test + void createMailboxShouldBeConsistentWhenMailboxPathDaoFails() { + doReturn(Mono.error(new RuntimeException("mock exception"))) + .when(mailboxPathV2DAO) + .save(eq(inboxPath), isA(CassandraId.class)); + + doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession)); + + SoftAssertions.assertSoftly(Throwing.consumer(softly -> { + softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession)) + .isEmpty(); + softly.assertThat(testee.list(mailboxSession)) + .isEmpty(); + })); + } + + @Disabled("JAMES-3056 createMailbox() return an empty Optional") + @Test + void createMailboxAfterAFailedCreationShouldCreateTheMailboxWhenMailboxDaoFails() throws Exception { + doReturn(Mono.error(new RuntimeException("mock exception"))) + .doCallRealMethod() + .when(mailboxDAO) + .save(any(Mailbox.class)); + + doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession)); + + assertThat(testee.createMailbox(inboxPath, mailboxSession)) + .isNotEmpty(); + } + + @Test + void createMailboxAfterAFailedCreationShouldCreateTheMailboxWhenMailboxPathDaoFails() throws Exception { + doReturn(Mono.error(new RuntimeException("mock exception"))) + .doCallRealMethod() + .when(mailboxPathV2DAO) + .save(eq(inboxPath), isA(CassandraId.class)); + + doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession)); + + MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession) + .get(); + + SoftAssertions.assertSoftly(Throwing.consumer(softly -> { + softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession)) + .hasOnlyOneElementSatisfying(mailboxMetaData -> { + softly.assertThat(mailboxMetaData.getId()).isEqualTo(inboxId); + softly.assertThat(mailboxMetaData.getPath()).isEqualTo(inboxPath); + }); + softly.assertThat(testee.list(mailboxSession)) + .containsExactly(inboxPath); + })); + } + + @Disabled("JAMES-3056 createMailbox() return an empty Optional") + @Test + void createMailboxAfterDeletingShouldCreateTheMailboxWhenMailboxDaoFails() throws Exception { + doReturn(Mono.error(new RuntimeException("mock exception"))) + .doCallRealMethod() + .when(mailboxDAO) + .save(any(Mailbox.class)); + + doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession)); + doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession)); + + assertThat(testee.createMailbox(inboxPath, mailboxSession)) + .isNotEmpty(); + } + + @Test + void createMailboxAfterDeletingShouldCreateTheMailboxWhenMailboxPathDaoFails() throws Exception { + doReturn(Mono.error(new RuntimeException("mock exception"))) + .doCallRealMethod() + .when(mailboxPathV2DAO) + .save(eq(inboxPath), isA(CassandraId.class)); + + doQuietly(() -> testee.createMailbox(inboxPath, mailboxSession)); + doQuietly(() -> testee.deleteMailbox(inboxPath, mailboxSession)); + + MailboxId inboxId = testee.createMailbox(inboxPath, mailboxSession) + .get(); + + SoftAssertions.assertSoftly(Throwing.consumer(softly -> { + softly.assertThat(testee.search(allMailboxesSearchQuery, mailboxSession)) + .hasOnlyOneElementSatisfying(mailboxMetaData -> { + softly.assertThat(mailboxMetaData.getId()).isEqualTo(inboxId); + softly.assertThat(mailboxMetaData.getPath()).isEqualTo(inboxPath); + }); + softly.assertThat(testee.list(mailboxSession)) + .containsExactly(inboxPath); + })); + } + } + + private void doQuietly(ThrowingRunnable runnable) { + try { + runnable.run(); + } catch (Throwable th) { + // ignore + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
