JAMES-1925 Introduce CassandraMailboxPathDAO and its tests

Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/422209ea
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/422209ea
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/422209ea

Branch: refs/heads/master
Commit: 422209ea46ae7b48b933b8165f7ad5e66dfc5b0f
Parents: 6cee136
Author: Benoit Tellier <[email protected]>
Authored: Tue Feb 14 09:28:39 2017 +0700
Committer: Antoine Duprat <[email protected]>
Committed: Wed Feb 15 13:12:38 2017 +0100

----------------------------------------------------------------------
 .../cassandra/mail/CassandraMailboxPathDAO.java | 172 +++++++++++++++++++
 .../table/CassandraMailboxPathTable.java        |   2 +
 .../mail/CassandraMailboxPathDAOTest.java       | 138 +++++++++++++++
 3 files changed, 312 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/422209ea/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
----------------------------------------------------------------------
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
new file mode 100644
index 0000000..552e010
--- /dev/null
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAO.java
@@ -0,0 +1,172 @@
+/****************************************************************
+ * 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.mailbox.cassandra.mail;
+
+import static com.datastax.driver.core.querybuilder.QueryBuilder.bindMarker;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.insertInto;
+import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
+import static 
org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.FIELDS;
+import static 
org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.MAILBOX_ID;
+import static 
org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.MAILBOX_NAME;
+import static 
org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.NAMESPACE_AND_USER;
+import static 
org.apache.james.mailbox.cassandra.table.CassandraMailboxPathTable.TABLE_NAME;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Stream;
+
+import javax.inject.Inject;
+
+import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
+import org.apache.james.backends.cassandra.utils.CassandraAsyncExecutor;
+import org.apache.james.backends.cassandra.utils.CassandraUtils;
+import org.apache.james.mailbox.cassandra.CassandraId;
+import org.apache.james.mailbox.cassandra.mail.utils.MailboxBaseTupleUtil;
+import org.apache.james.mailbox.cassandra.table.CassandraMailboxTable;
+import org.apache.james.mailbox.model.MailboxPath;
+
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.google.common.base.Objects;
+
+public class CassandraMailboxPathDAO {
+
+    public static class CassandraIdAndPath {
+        private final CassandraId cassandraId;
+        private final MailboxPath mailboxPath;
+
+        public CassandraIdAndPath(CassandraId cassandraId, MailboxPath 
mailboxPath) {
+            this.cassandraId = cassandraId;
+            this.mailboxPath = mailboxPath;
+        }
+
+        public CassandraId getCassandraId() {
+            return cassandraId;
+        }
+
+        public MailboxPath getMailboxPath() {
+            return mailboxPath;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof CassandraIdAndPath) {
+                CassandraIdAndPath that = (CassandraIdAndPath) o;
+
+                return Objects.equal(this.cassandraId, that.cassandraId)
+                    && Objects.equal(this.mailboxPath, that.mailboxPath);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hashCode(cassandraId, mailboxPath);
+        }
+    }
+
+    private final CassandraAsyncExecutor cassandraAsyncExecutor;
+    private final MailboxBaseTupleUtil mailboxBaseTupleUtil;
+    private final PreparedStatement delete;
+    private final PreparedStatement insert;
+    private final PreparedStatement select;
+    private final PreparedStatement selectAll;
+
+    @Inject
+    public CassandraMailboxPathDAO(Session session, CassandraTypesProvider 
typesProvider) {
+        this.cassandraAsyncExecutor = new CassandraAsyncExecutor(session);
+        this.mailboxBaseTupleUtil = new MailboxBaseTupleUtil(typesProvider);
+        this.insert = prepareInsert(session);
+        this.delete = prepareDelete(session);
+        this.select = prepareSelect(session);
+        this.selectAll = prepareSelectAll(session);
+    }
+
+    private PreparedStatement prepareDelete(Session session) {
+        return session.prepare(QueryBuilder.delete()
+            .from(TABLE_NAME)
+            .where(eq(NAMESPACE_AND_USER, bindMarker(NAMESPACE_AND_USER)))
+            .and(eq(MAILBOX_NAME, bindMarker(MAILBOX_NAME))));
+    }
+
+    private PreparedStatement prepareInsert(Session session) {
+        return session.prepare(insertInto(TABLE_NAME)
+            .value(NAMESPACE_AND_USER, bindMarker(NAMESPACE_AND_USER))
+            .value(MAILBOX_NAME, bindMarker(MAILBOX_NAME))
+            .value(MAILBOX_ID, bindMarker(MAILBOX_ID))
+            .ifNotExists());
+    }
+
+    private PreparedStatement prepareSelect(Session session) {
+        return session.prepare(select(FIELDS)
+            .from(TABLE_NAME)
+            .where(eq(NAMESPACE_AND_USER, bindMarker(NAMESPACE_AND_USER)))
+            .and(eq(MAILBOX_NAME, bindMarker(MAILBOX_NAME))));
+    }
+
+    private PreparedStatement prepareSelectAll(Session session) {
+        return session.prepare(select(FIELDS)
+            .from(TABLE_NAME)
+            .where(eq(NAMESPACE_AND_USER, bindMarker(NAMESPACE_AND_USER))));
+    }
+
+    public CompletableFuture<Optional<CassandraIdAndPath>> 
retrieveId(MailboxPath mailboxPath) {
+        return cassandraAsyncExecutor.executeSingleRow(
+            select.bind()
+                .setUDTValue(NAMESPACE_AND_USER, 
mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), 
mailboxPath.getUser()))
+                .setString(MAILBOX_NAME, mailboxPath.getName()))
+            .thenApply(rowOptional ->
+                rowOptional.map(row -> new CassandraIdAndPath(
+                    CassandraId.of(row.getUUID(MAILBOX_ID)),
+                    mailboxPath)));
+    }
+
+    public CompletableFuture<Stream<CassandraIdAndPath>> 
listUserMailboxes(String namespace, String user) {
+        return cassandraAsyncExecutor.execute(
+            selectAll.bind()
+                .setUDTValue(NAMESPACE_AND_USER, 
mailboxBaseTupleUtil.createMailboxBaseUDT(namespace, user)))
+            .thenApply(resultSet -> 
CassandraUtils.convertToStream(resultSet).map(this::fromRowToCassandraIdAndPath));
+    }
+
+    private CassandraIdAndPath fromRowToCassandraIdAndPath(Row row) {
+        return new CassandraIdAndPath(
+            CassandraId.of(row.getUUID(MAILBOX_ID)),
+            new 
MailboxPath(row.getUDTValue(NAMESPACE_AND_USER).getString(CassandraMailboxTable.MailboxBase.NAMESPACE),
+                
row.getUDTValue(NAMESPACE_AND_USER).getString(CassandraMailboxTable.MailboxBase.USER),
+                row.getString(MAILBOX_NAME)));
+    }
+
+    public CompletableFuture<Boolean> save(MailboxPath mailboxPath, 
CassandraId mailboxId) {
+        return cassandraAsyncExecutor.executeReturnApplied(insert.bind()
+            .setUDTValue(NAMESPACE_AND_USER, 
mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), 
mailboxPath.getUser()))
+            .setString(MAILBOX_NAME, mailboxPath.getName())
+            .setUUID(MAILBOX_ID, mailboxId.asUuid()));
+    }
+
+    public CompletableFuture<Void> delete(MailboxPath mailboxPath) {
+        return cassandraAsyncExecutor.executeVoid(delete.bind()
+            .setUDTValue(NAMESPACE_AND_USER, 
mailboxBaseTupleUtil.createMailboxBaseUDT(mailboxPath.getNamespace(), 
mailboxPath.getUser()))
+            .setString(MAILBOX_NAME, mailboxPath.getName()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/422209ea/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxPathTable.java
----------------------------------------------------------------------
diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxPathTable.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxPathTable.java
index be9eb54..efc6168 100644
--- 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxPathTable.java
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/table/CassandraMailboxPathTable.java
@@ -29,4 +29,6 @@ public interface CassandraMailboxPathTable {
 
     String MAILBOX_ID = "mailboxId";
 
+    String[] FIELDS = { NAMESPACE_AND_USER, MAILBOX_NAME, MAILBOX_ID};
+
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/422209ea/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
----------------------------------------------------------------------
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
new file mode 100644
index 0000000..b6c1c10
--- /dev/null
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMailboxPathDAOTest.java
@@ -0,0 +1,138 @@
+/****************************************************************
+ * 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.mailbox.cassandra.mail;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
+import org.apache.james.mailbox.cassandra.CassandraId;
+import 
org.apache.james.mailbox.cassandra.mail.CassandraMailboxPathDAO.CassandraIdAndPath;
+import org.apache.james.mailbox.cassandra.modules.CassandraMailboxModule;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.github.steveash.guavate.Guavate;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class CassandraMailboxPathDAOTest {
+    private static final String PRIVATE_NAMESPACE = "#private";
+    private static final String USER = "user";
+    private static final String OTHER_USER = "other";
+    private static final CassandraId INBOX_ID = CassandraId.timeBased();
+    private static final CassandraId OUTBOX_ID = CassandraId.timeBased();
+    private static final CassandraId otherMailboxId = CassandraId.timeBased();
+
+    public static final MailboxPath USER_INBOX_MAILBOXPATH = new 
MailboxPath(PRIVATE_NAMESPACE, USER, "INBOX");
+    public static final CassandraIdAndPath INBOX_ID_AND_PATH = new 
CassandraIdAndPath(INBOX_ID, USER_INBOX_MAILBOXPATH);
+    public static final MailboxPath USER_OUTBOX_MAILBOXPATH = new 
MailboxPath(PRIVATE_NAMESPACE, USER, "OUTBOX");
+    public static final MailboxPath OTHER_USER_MAILBOXPATH = new 
MailboxPath(PRIVATE_NAMESPACE, OTHER_USER, "INBOX");
+
+    private CassandraCluster cassandra;
+
+    private CassandraMailboxPathDAO testee;
+
+    @Before
+    public void setUp() throws Exception {
+        cassandra = CassandraCluster.create(new CassandraMailboxModule());
+        cassandra.ensureAllTables();
+
+        testee = new CassandraMailboxPathDAO(cassandra.getConf(), 
cassandra.getTypesProvider());
+
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        cassandra.clearAllTables();
+    }
+
+    @Test
+    public void cassandraIdAndPathShouldRespectBeanContract() {
+        
EqualsVerifier.forClass(CassandraMailboxPathDAO.CassandraIdAndPath.class).verify();
+    }
+
+    @Test
+    public void saveShouldInsertNewEntry() throws Exception {
+        assertThat(testee.save(USER_INBOX_MAILBOXPATH, 
INBOX_ID).join()).isTrue();
+
+        Optional<CassandraIdAndPath> cassandraIdAndPath = 
testee.retrieveId(USER_INBOX_MAILBOXPATH).join();
+        assertThat(cassandraIdAndPath.get())
+            .isEqualTo(INBOX_ID_AND_PATH);
+    }
+
+    @Test
+    public void saveOnSecondShouldBeFalse() throws Exception {
+        assertThat(testee.save(USER_INBOX_MAILBOXPATH, 
INBOX_ID).join()).isTrue();
+        assertThat(testee.save(USER_INBOX_MAILBOXPATH, 
INBOX_ID).join()).isFalse();
+    }
+
+    @Test
+    public void retrieveIdShouldReturnEmptyWhenEmptyData() throws Exception {
+        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).join()
+            .isPresent())
+            .isFalse();
+    }
+
+    @Test
+    public void retrieveIdShouldReturnStoredData() throws Exception {
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
+
+        Optional<CassandraIdAndPath> cassandraIdAndPath = 
testee.retrieveId(USER_INBOX_MAILBOXPATH).join();
+        assertThat(cassandraIdAndPath.get())
+            .isEqualTo(INBOX_ID_AND_PATH);
+    }
+
+    @Test
+    public void getUserMailboxesShouldReturnAllMailboxesOfUser() throws 
Exception {
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
+        testee.save(USER_OUTBOX_MAILBOXPATH, OUTBOX_ID).join();
+        testee.save(OTHER_USER_MAILBOXPATH, otherMailboxId).join();
+
+        List<CassandraIdAndPath> cassandraIds = testee
+            .listUserMailboxes(USER_INBOX_MAILBOXPATH.getNamespace(), 
USER_INBOX_MAILBOXPATH.getUser())
+            .join()
+            .collect(Guavate.toImmutableList());
+
+        assertThat(cassandraIds)
+            .hasSize(2)
+            .containsOnly(INBOX_ID_AND_PATH, new CassandraIdAndPath(OUTBOX_ID, 
USER_OUTBOX_MAILBOXPATH));
+    }
+
+    @Test
+    public void deleteShouldNotThrowWhenEmpty() throws Exception {
+        testee.delete(USER_INBOX_MAILBOXPATH).join();
+    }
+
+    @Test
+    public void deleteShouldDeleteTheExistingMailboxId() throws Exception {
+        testee.save(USER_INBOX_MAILBOXPATH, INBOX_ID).join();
+
+        testee.delete(USER_INBOX_MAILBOXPATH).join();
+
+        assertThat(testee.retrieveId(USER_INBOX_MAILBOXPATH).join()
+            .isPresent())
+            .isFalse();
+    }
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to