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 ro...@apache.org on 2016/07/19 13:39:01 UTC

[04/10] james-project git commit: JAMES-1799 Extract ListeningMessageSearchIndex tests from ES implementation

http://git-wip-us.apache.org/repos/asf/james-project/blob/d5b3a42c/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
----------------------------------------------------------------------
diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
new file mode 100644
index 0000000..d52cbfe
--- /dev/null
+++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
@@ -0,0 +1,655 @@
+/****************************************************************
+ * 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.store.search;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Date;
+
+import javax.mail.Flags;
+
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.store.StoreMailboxManager;
+import org.apache.james.mailbox.store.StoreMessageManager;
+import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public abstract class AbstractMessageSearchIndexTest {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMessageSearchIndexTest.class);
+
+    protected MessageSearchIndex messageSearchIndex;
+    protected StoreMailboxManager storeMailboxManager;
+    private Mailbox mailbox;
+    private MailboxSession session;
+
+    @Before
+    public void setUp() throws Exception {
+        initializeMailboxManager();
+
+        session = storeMailboxManager.createSystemSession("benwa", LOGGER);
+
+        storeMailboxManager.createMailbox(new MailboxPath("#private", "benwa", "INBOX"), session);
+        StoreMessageManager messageManager = (StoreMessageManager) storeMailboxManager.getMailbox(new MailboxPath("#private", "benwa", "INBOX"), session);
+        mailbox = messageManager.getMailboxEntity();
+
+        // sentDate: Wed, 3 Jun 2015 09:05:46 +0000
+        // Internal date : 2014/01/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/spamMail.eml"),
+            new Date(1388617200000L),
+            session,
+            true,
+            new Flags(Flags.Flag.DELETED));
+        // sentDate: Thu, 4 Jun 2015 09:23:37 +0000
+        // Internal date : 2014/02/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/mail1.eml"),
+            new Date(1391295600000L),
+            session,
+            true,
+            new Flags(Flags.Flag.ANSWERED));
+        // sentDate: Thu, 4 Jun 2015 09:27:37 +0000
+        // Internal date : 2014/03/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/mail2.eml"),
+            new Date(1393714800000L),
+            session,
+            true,
+            new Flags(Flags.Flag.DRAFT));
+        // sentDate: Tue, 2 Jun 2015 08:16:19 +0000
+        // Internal date : 2014/05/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/mail3.eml"),
+            new Date(1398981600000L),
+            session,
+            true,
+            new Flags(Flags.Flag.RECENT));
+        // sentDate: Fri, 15 May 2015 06:35:59 +0000
+        // Internal date : 2014/04/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/mail4.eml"),
+            new Date(1396389600000L),
+            session,
+            true,
+            new Flags(Flags.Flag.FLAGGED));
+        // sentDate: Wed, 03 Jun 2015 19:14:32 +0000
+        // Internal date : 2014/06/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/pgpSignedMail.eml"),
+            new Date(1401660000000L),
+            session,
+            true,
+            new Flags(Flags.Flag.SEEN));
+        // sentDate: Thu, 04 Jun 2015 07:36:08 +0000
+        // Internal date : 2014/07/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/htmlMail.eml"),
+            new Date(1404252000000L),
+            session,
+            false,
+            new Flags());
+        // sentDate: Thu, 4 Jun 2015 06:08:41 +0200
+        // Internal date : 2014/08/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/mail.eml"),
+            new Date(1406930400000L),
+            session,
+            true,
+            new Flags("Hello"));
+        // sentDate: Tue, 2 Jun 2015 12:00:55 +0200
+        // Internal date : 2014/09/02 00:00:00.000
+        messageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/frnog.eml"),
+            new Date(1409608800000L),
+            session,
+            true,
+            new Flags("Hello you"));
+
+        await();
+    }
+
+    protected abstract void await();
+    protected abstract void initializeMailboxManager() throws Exception;
+
+    @Test
+    public void emptySearchQueryShouldReturnAllUids() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void allShouldReturnAllUids() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.all());
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void bodyContainsShouldReturnUidOfMessageContainingTheGivenText() throws MailboxException {
+        /*
+        Only mail4.eml contains word MAILET-94
+         */
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.bodyContains("MAILET-94"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(5L);
+    }
+
+    @Test
+    public void bodyContainsShouldReturnUidOfMessageContainingTheApproximativeText() throws MailboxException {
+        /*
+        mail1.eml contains words created AND summary
+        mail.eml contains created and thus matches the query with a low score
+         */
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.bodyContains("created summary"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(2L, 8L);
+    }
+
+    @Test
+    public void flagIsSetShouldReturnUidOfMessageMarkedAsDeletedWhenUsedWithFlagDeleted() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet(Flags.Flag.DELETED));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L);
+    }
+
+    @Test
+    public void flagIsSetShouldReturnUidOfMessageMarkedAsAnsweredWhenUsedWithFlagAnswered() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet(Flags.Flag.ANSWERED));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(2L);
+    }
+
+    @Test
+    public void flagIsSetShouldReturnUidOfMessageMarkedAsDraftWhenUsedWithFlagDraft() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet(Flags.Flag.DRAFT));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(3L);
+    }
+
+    @Test
+    public void flagIsSetShouldReturnUidOfMessageMarkedAsRecentWhenUsedWithFlagRecent() throws MailboxException {
+        // Only message 7 is not marked as RECENT
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet(Flags.Flag.RECENT));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 5L, 6L, 8L, 9L);
+    }
+
+    @Test
+    public void flagIsSetShouldReturnUidOfMessageMarkedAsFlaggedWhenUsedWithFlagFlagged() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet(Flags.Flag.FLAGGED));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(5L);
+    }
+
+    @Test
+    public void flagIsSetShouldReturnUidOfMessageMarkedAsSeenWhenUsedWithFlagSeen() throws MailboxException {
+        // Only message 6 is marked as read.
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet(Flags.Flag.SEEN));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(6L);
+    }
+
+    @Test
+    public void flagIsSetShouldReturnUidsOfMessageContainingAGivenUserFlag() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet("Hello"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(8L);
+    }
+
+    @Test
+    public void userFlagsShouldBeMatchedExactly() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsSet("Hello bonjour"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .isEmpty();
+    }
+
+    @Test
+    public void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsDeletedWhenUsedWithFlagDeleted() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsUnSet(Flags.Flag.DELETED));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsAnsweredWhenUsedWithFlagAnswered() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsUnSet(Flags.Flag.ANSWERED));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 3L, 4L, 5L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsDraftWhenUsedWithFlagDraft() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsUnSet(Flags.Flag.DRAFT));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 4L, 5L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsRecentWhenUsedWithFlagRecent() throws MailboxException {
+        // Only message 7 is not marked as RECENT
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsUnSet(Flags.Flag.RECENT));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(7L);
+    }
+
+    @Test
+    public void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsFlaggedWhenUsedWithFlagFlagged() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsUnSet(Flags.Flag.FLAGGED));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void flagIsUnSetShouldReturnUidOfMessageNotMarkedAsSeendWhenUsedWithFlagSeen() throws MailboxException {
+        // Only message 6 is marked as read.
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsUnSet(Flags.Flag.SEEN));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 5L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void flagIsUnSetShouldReturnUidsOfMessageNotContainingAGivenUserFlag() throws MailboxException {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.flagIsUnSet("Hello"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 5L, 6L, 7L,  9L);
+    }
+
+    @Test
+    public void internalDateAfterShouldReturnMessagesAfterAGivenDate() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        // Date : 2014/07/02 00:00:00.000 ( Paris time zone )
+        searchQuery.andCriteria(SearchQuery.internalDateAfter(new Date(1404252000000L), SearchQuery.DateResolution.Day));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(7L, 8L, 9L);
+    }
+
+    @Test
+    public void internalDateBeforeShouldReturnMessagesBeforeAGivenDate() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        // Date : 2014/02/02 00:00:00.000 ( Paris time zone )
+        searchQuery.andCriteria(SearchQuery.internalDateBefore(new Date(1391295600000L), SearchQuery.DateResolution.Day));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L);
+    }
+
+    @Test
+    public void internalDateOnShouldReturnMessagesOfTheGivenDate() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        // Date : 2014/03/02 00:00:00.000 ( Paris time zone )
+        searchQuery.andCriteria(SearchQuery.internalDateOn(new Date(1393714800000L), SearchQuery.DateResolution.Day));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(3L);
+    }
+
+    @Test
+    public void modSeqEqualsShouldReturnUidsOfMessageHavingAGivenModSeq() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.modSeqEquals(2L));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(2L);
+    }
+
+    @Test
+    public void modSeqGreaterThanShouldReturnUidsOfMessageHavingAGreaterModSeq() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.modSeqGreaterThan(7L));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(7L, 8L, 9L);
+    }
+
+    @Test
+    public void modSeqLessThanShouldReturnUidsOfMessageHavingAGreaterModSeq() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.modSeqLessThan(3L));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L);
+    }
+
+    @Test
+    public void sizeGreaterThanShouldReturnUidsOfMessageExceedingTheSpecifiedSize() throws Exception {
+        // Only message 7 is over 10 KB
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.sizeGreaterThan(10000L));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(7L);
+    }
+
+    @Test
+    public void sizeLessThanShouldReturnUidsOfMessageNotExceedingTheSpecifiedSize() throws Exception {
+        // Only message 2 3 4 5 9 are under 5 KB
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.sizeLessThan(5000L));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(2L, 3L, 4L, 5L, 9L);
+    }
+
+    @Test
+    public void headerContainsShouldReturnUidsOfMessageHavingThisHeaderWithTheSpecifiedValue() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.headerContains("Precedence", "list"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 6L, 8L, 9L);
+    }
+
+    @Test
+    public void headerExistsShouldReturnUidsOfMessageHavingThisHeader() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.headerExists("Precedence"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 5L, 6L, 8L, 9L);
+    }
+
+    @Test
+    public void addressShouldReturnUidHavingRightExpeditorWhenFromIsSpecified() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.address(SearchQuery.AddressType.From, "murari.ksr@gmail.com"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(8L);
+    }
+
+    @Test
+    public void addressShouldReturnUidHavingRightRecipientWhenToIsSpecified() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.address(SearchQuery.AddressType.To, "root@listes.minet.net"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L);
+    }
+
+    @Test
+    public void addressShouldReturnUidHavingRightRecipientWhenCcIsSpecified() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.address(SearchQuery.AddressType.Cc, "any@any.com"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(5L);
+    }
+
+    @Test
+    public void addressShouldReturnUidHavingRightRecipientWhenBccIsSpecified() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.address(SearchQuery.AddressType.Bcc, "no@no.com"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(9L);
+    }
+
+    @Test
+    public void uidShouldreturnExistingUidsOnTheGivenRanges() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 4L), new SearchQuery.NumericRange(6L, 7L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(2L, 3L, 4L, 6L, 7L);
+    }
+
+    @Test
+    public void uidShouldreturnEveryThing() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void youShouldBeAbleToSpecifySeveralCriterionOnASingleQuery() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.headerExists("Precedence"));
+        searchQuery.andCriteria(SearchQuery.modSeqGreaterThan(6L));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(6L, 8L, 9L);
+    }
+
+    @Test
+    public void andShouldReturnResultsMatchingBothRequests() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(
+            SearchQuery.and(
+                SearchQuery.headerExists("Precedence"),
+                SearchQuery.modSeqGreaterThan(6L)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(6L, 8L, 9L);
+    }
+
+    @Test
+    public void orShouldReturnResultsMatchinganyRequests() throws Exception {
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 4L)};
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(
+            SearchQuery.or(
+                SearchQuery.uid(numericRanges),
+                SearchQuery.modSeqGreaterThan(6L)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(2L, 3L, 4L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void notShouldReturnResultsThatDoNotMatchAQuery() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(
+            SearchQuery.not(SearchQuery.headerExists("Precedence")));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(7L);
+    }
+
+    @Test
+    public void sortShouldOrderMessages() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.all());
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.Arrival)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(1L, 2L, 3L, 5L, 4L, 6L, 7L, 8L, 9L);
+    }
+
+    @Test
+    public void revertSortingShouldReturnElementsInAReversedOrder() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.all());
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.Arrival, true)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(9L, 8L, 7L, 6L, 4L, 5L, 3L, 2L, 1L);
+    }
+
+    @Test
+    public void headerDateAfterShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        // Date : 2015/06/04 11:00:00.000 ( Paris time zone )
+        searchQuery.andCriteria(SearchQuery.headerDateAfter("sentDate", new Date(1433408400000L), SearchQuery.DateResolution.Second));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.Arrival, true)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(3L, 2L);
+    }
+
+    @Test
+    public void headerDateBeforeShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        // Date : 2015/06/01 00:00:00.000 ( Paris time zone )
+        searchQuery.andCriteria(SearchQuery.headerDateBefore("sentDate", new Date(1433109600000L), SearchQuery.DateResolution.Day));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.Arrival, true)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(5L);
+    }
+
+    @Test
+    public void headerDateOnShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        // Date : 2015/06/02 08:00:00.000 ( Paris time zone )
+        searchQuery.andCriteria(SearchQuery.headerDateOn("sentDate", new Date(1433224800000L), SearchQuery.DateResolution.Day));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.Arrival, true)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(4L, 9L);
+    }
+
+    @Test
+    public void mailsContainsShouldIncludeMailHavingAttachmentsMatchingTheRequest() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        searchQuery.andCriteria(SearchQuery.mailContains("root mailing list"));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsOnly(1L, 6L);
+    }
+
+    @Test
+    public void sortOnCcShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.MailboxCc)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(3L, 5L, 4L, 2L);
+        // 2 : No cc
+        // 3 : Cc : abc@abc.org
+        // 4 : zzz@bcd.org
+        // 5 : any@any.com
+    }
+
+    @Test
+    public void sortOnFromShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.MailboxFrom)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(3L, 2L, 4L, 5L);
+        // 2 : jira2@apache.org
+        // 3 : jira1@apache.org
+        // 4 : jira@apache.org
+        // 5 : mailet-api@james.apache.org
+    }
+
+    @Test
+    public void sortOnToShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.MailboxTo)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(5L, 2L, 3L, 4L);
+        // 2 : server-dev@james.apache.org
+        // 3 : server-dev@james.apache.org
+        // 4 : server-dev@james.apache.org
+        // 5 : mailet-api@james.apache.org
+    }
+
+    @Test
+    public void sortOnSubjectShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.BaseSubject)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(4L, 3L, 2L, 5L);
+        // 2 : [jira] [Created] (MAILBOX-234) Convert Message into JSON
+        // 3 : [jira] [Closed] (MAILBOX-217) We should index attachment in elastic search
+        // 4 : [jira] [Closed] (MAILBOX-11) MailboxQuery ignore namespace
+        // 5 : [jira] [Resolved] (MAILET-94) James Mailet should use latest version of other James subprojects
+    }
+
+    @Test
+    public void sortOnSizeShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.Size)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(2L, 3L, 5L, 4L);
+        // 2 : 3210 o
+        // 3 : 3647 o
+        // 4 : 4360 o
+        // 5 : 3653 o
+    }
+
+    @Test
+    public void sortOnDisplayFromShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.DisplayFrom)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(4L, 3L, 5L, 2L);
+        // 2 : Tellier Benoit (JIRA)
+        // 3 : efij
+        // 4 : abcd
+        // 5 : Eric Charles (JIRA)
+    }
+
+    @Test
+    public void sortOnDisplayToShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.DisplayTo)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(3L, 2L, 4L, 5L);
+        // 2 : abc
+        // 3 : aaa
+        // 4 : server
+        // 5 : zzz
+    }
+
+    @Test
+    public void sortOnSentDateShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.SentDate)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(5L, 4L, 2L, 3L);
+        // 2 : 4 Jun 2015 09:23:37
+        // 3 : 4 Jun 2015 09:27:37
+        // 4 : 2 Jun 2015 08:16:19
+        // 5 : 15 May 2015 06:35:59
+    }
+
+    @Test
+    public void sortOnIdShouldWork() throws Exception {
+        SearchQuery searchQuery = new SearchQuery();
+        SearchQuery.NumericRange[] numericRanges = {new SearchQuery.NumericRange(2L, 5L)};
+        searchQuery.andCriteria(SearchQuery.uid(numericRanges));
+        searchQuery.setSorts(Lists.newArrayList(new SearchQuery.Sort(SearchQuery.Sort.SortClause.Uid)));
+        assertThat(messageSearchIndex.search(session, mailbox, searchQuery))
+            .containsExactly(2L, 3L, 4L, 5L);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/d5b3a42c/mailbox/store/src/test/resources/eml/frnog.eml
----------------------------------------------------------------------
diff --git a/mailbox/store/src/test/resources/eml/frnog.eml b/mailbox/store/src/test/resources/eml/frnog.eml
new file mode 100644
index 0000000..505fbde
--- /dev/null
+++ b/mailbox/store/src/test/resources/eml/frnog.eml
@@ -0,0 +1,94 @@
+Return-Path: <fr...@frnog.org>
+Received: from mx2.minet.net (mx2.minet.net [192.168.102.26])
+	 by imap (Cyrus v2.4.16-Debian-2.4.16-4+deb7u1) with LMTPA;
+	 Tue, 02 Jun 2015 12:01:42 +0200
+X-Sieve: CMU Sieve 2.4
+Received: from localhost (spam.minet.net [192.168.102.97])
+	by mx2.minet.net (Postfix) with ESMTP id E92F2A25320
+	for <be...@minet.net>; Tue,  2 Jun 2015 12:01:46 +0200 (CEST)
+X-Virus-Scanned: by amavisd-new using ClamAV at minet.net
+X-Spam-Flag: NO
+X-Spam-Score: -1.499
+X-Spam-Level:
+X-Spam-Status: No, score=-1.499 required=1 tests=[BAYES_00=-1.5,
+	UNPARSEABLE_RELAY=0.001] autolearn=ham
+Received: from mx2.minet.net ([IPv6:::ffff:192.168.102.26])
+	by localhost (spam.minet.net [::ffff:192.168.102.97]) (amavisd-new, port 10024)
+	with ESMTP id bRNLR9Tbk4Jg for <be...@minet.net>;
+	Tue,  2 Jun 2015 10:01:46 +0000 (UTC)
+Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=217.24.82.4; helo=cabale.usenet-fr.net; envelope-from=frnog-owner@frnog.org; receiver=benwa@minet.net
+Received: from cabale.usenet-fr.net (cabale.usenet-fr.net [217.24.82.4])
+	by mx2.minet.net (Postfix) with ESMTP id 089E7A2531A
+	for <be...@minet.net>; Tue,  2 Jun 2015 12:01:45 +0200 (CEST)
+Received: by cabale.usenet-fr.net (Postfix, from userid 90)
+	id A267298A5DC6; Tue,  2 Jun 2015 12:01:44 +0200 (CEST)
+X-Original-To: frnog@frnog.org
+Delivered-To: frnog@frnog.org
+Received: from mta.mail.waycom.net (mta.mail.waycom.net [194.177.32.18])
+	by cabale.usenet-fr.net (Postfix) with ESMTP id AE2E798A58FC
+	for <fr...@frnog.org>; Tue,  2 Jun 2015 12:01:01 +0200 (CEST)
+Received: from [127.0.0.1] (localhost [127.0.0.1])
+	by mta.mail.waycom.net (Postfix) with ESMTP id D30D6567E1
+	for <fr...@frnog.org>; Tue,  2 Jun 2015 12:00:56 +0200 (CEST)
+Received: from [127.0.0.1] (localhost [127.0.0.1])
+ wcm-hv1-exch1.wcmnoc.local (2002:c3d6:f04a::c3d6:f04a) with Microsoft SMTP
+ Server (TLS) id 15.0.847.32; Tue, 2 Jun 2015 12:00:56 +0200
+Message-ID: <55...@waycom.net>
+Date: Tue, 2 Jun 2015 12:00:55 +0200
+From: Guillaume Genty <gg...@waycom.net>
+Organization: Waycom
+MIME-Version: 1.0
+To: <fr...@frnog.org>
+Cc: no@no.com
+Bcc: no@no.com
+Content-Type: text/plain; charset="utf-8"; format=flowed
+Content-Transfer-Encoding: 8bit
+X-ClientProxiedBy: WCM-HV1-EXCH1.wcmnoc.local (2002:c3d6:f04a::c3d6:f04a) To
+ wcm-hv1-exch1.wcmnoc.local (2002:c3d6:f04a::c3d6:f04a)
+X-C2ProcessedOrg: 9180093e-3f32-48c9-b36b-0805cbe4c266
+Subject: [FRnOG] [BIZ] Collecte de liens C2E/CELAN en DOM
+X-Loop: frnog@frnog.org
+X-Sequence: 5349
+Errors-to: frnog-owner@frnog.org
+Precedence: list
+Precedence: bulk
+Sender: frnog-request@frnog.org
+X-mailing-list: frnog@frnog.org
+List-Id: <frnog.frnog.org>
+List-Archive: <http://sympa.frnog.org/wss/arc/frnog>
+List-Help: <mailto:sympa@frnog.org?subject=help>
+List-Owner: <ma...@frnog.org>
+List-Post: <ma...@frnog.org>
+List-Subscribe: <mailto:sympa@frnog.org?subject=subscribe%20frnog>
+List-Unsubscribe: <mailto:sympa@frnog.org?subject=unsubscribe%20frnog>
+
+Bonjour le FRnOG,
+
+
+Je cherche un partenaire dans les DOM avec de la collecte C2E et/ou
+CELAN capable de revendre des liens et de remonter le trafic (en niveau
+2, L2TP ou PPP sur L2TP) en métropole, idéalement �  TH2.
+
+Nous aurions besoin des DOM suivants:
+- Guadeloupe
+- Martinique
+- Guyane
+- La Réunion
+(Toutes les plaques DOM sauf îles du nord)
+
+Merci d'avance !
+
+
+Cordialement,
+
+--
+Guillaume Genty | WAYCOM
+Directeur Technique Adjoint
+24-28 Avenue du Général de Gaulle | F-92150 Suresnes, FRANCE
+T. : +33 (0)1 41 44 83 00 | F. : +33 (0)1 41 44 00 22
+ggenty@waycom.net | www.waycom.net
+
+
+---------------------------
+Liste de diffusion du FRnOG
+http://www.frnog.org/


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