JAMES-1804 Index text attribute Append of: from, to, cc, bcc, subjects, body
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/c321b93c Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/c321b93c Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/c321b93c Branch: refs/heads/master Commit: c321b93cde4ec1afa344770acef46810aa8ffead Parents: 9470ccf Author: Antoine Duprat <[email protected]> Authored: Wed Jul 20 10:53:46 2016 +0200 Committer: Antoine Duprat <[email protected]> Committed: Tue Jul 26 08:57:04 2016 +0200 ---------------------------------------------------------------------- .../apache/james/mailbox/model/SearchQuery.java | 23 +++ mailbox/elasticsearch/pom.xml | 5 + .../elasticsearch/NodeMappingFactory.java | 11 ++ .../elasticsearch/json/IndexableMessage.java | 20 ++ .../json/JsonMessageConstants.java | 1 + .../elasticsearch/query/CriterionConverter.java | 3 + .../json/IndexableMessageTest.java | 185 +++++++++++++++++++ .../src/test/resources/eml/mailWithHeaders.eml | 14 ++ .../search/AbstractMessageSearchIndexTest.java | 66 +++++++ .../store/src/test/resources/eml/htmlMail.json | 3 +- mailbox/store/src/test/resources/eml/mail.json | 3 +- .../src/test/resources/eml/nonTextual.json | 3 +- .../src/test/resources/eml/pgpSignedMail.json | 3 +- .../src/test/resources/eml/recursiveMail.json | 3 +- .../store/src/test/resources/eml/spamMail.json | 3 +- 15 files changed, 340 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java index d815d9d..8a62315 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/SearchQuery.java @@ -30,6 +30,8 @@ import java.util.Set; import javax.mail.Flags; import javax.mail.Flags.Flag; +import org.apache.james.mailbox.model.SearchQuery.Sort; + /** * <p> * Models a query used to search for messages. A query is the logical @@ -428,6 +430,22 @@ public class SearchQuery implements Serializable { } /** + * Creates a filter matching messages which contains the given text either + * within the headers (From, To, Cc, Bcc & Subject) and text / html bodies. + * Implementations may choose to ignore mime parts which cannot be decoded to text. + * + * All to-compared Strings MUST BE converted to uppercase before doing so + * (this also include the search value) + * + * @param value + * search value + * @return <code>Criterion</code>, not null + */ + public static final Criterion textContains(String value) { + return new TextCriterion(value, Scope.TEXT); + } + + /** * Creates a filter matching messages which contains the given text within * the body. Implementations may choose to ignore mime parts which cannot be * decoded to text. @@ -950,6 +968,11 @@ public class SearchQuery implements Serializable { /** Only message body content */ BODY, + /** Headers: From, To, Cc, Bcc & Subjects + * plus text/plain & text/html part + */ + TEXT, + /** Full message content including headers */ FULL } http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/elasticsearch/pom.xml ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/pom.xml b/mailbox/elasticsearch/pom.xml index 59df4ee..5e43f4f 100644 --- a/mailbox/elasticsearch/pom.xml +++ b/mailbox/elasticsearch/pom.xml @@ -259,6 +259,11 @@ <type>test-jar</type> </dependency> <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/NodeMappingFactory.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/NodeMappingFactory.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/NodeMappingFactory.java index 91bf2e6..14af791 100644 --- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/NodeMappingFactory.java +++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/NodeMappingFactory.java @@ -212,6 +212,17 @@ public class NodeMappingFactory { .endObject() .endObject() .endObject() + + + .startObject(JsonMessageConstants.TEXT) + .field(TYPE, STRING) + .startObject(FIELDS) + .startObject(RAW) + .field(TYPE, STRING) + .field(ANALYZER, IndexCreationFactory.CASE_INSENSITIVE) + .endObject() + .endObject() + .endObject() .endObject() .endObject() .endObject(); http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessage.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessage.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessage.java index ec58c3c..a3d1ae4 100644 --- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessage.java +++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessage.java @@ -26,6 +26,7 @@ import java.time.ZonedDateTime; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.james.mailbox.MailboxSession.User; import org.apache.james.mailbox.elasticsearch.query.DateResolutionFormater; @@ -37,6 +38,7 @@ import org.apache.james.mime4j.MimeException; import com.fasterxml.jackson.annotation.JsonProperty; import com.github.steveash.guavate.Guavate; import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.base.Throwables; import com.google.common.collect.Multimap; @@ -52,6 +54,7 @@ public class IndexableMessage { indexableMessage.bodyText = parsingResult.locateFirstTextualBody(); indexableMessage.setFlattenedAttachments(parsingResult); indexableMessage.copyHeaderFields(parsingResult.getHeaderCollection(), getSanitizedInternalDate(message, zoneId)); + indexableMessage.generateText(); } catch (IOException | MimeException e) { throw Throwables.propagate(e); } @@ -102,6 +105,17 @@ public class IndexableMessage { zoneId); } + private void generateText() { + this.text = Stream.of(from.serialize(), + to.serialize(), + cc.serialize(), + bcc.serialize(), + subjects.serialize(), + bodyText.orElse(null)) + .filter(str -> !Strings.isNullOrEmpty(str)) + .collect(Collectors.joining(" ")); + } + private Long id; private String mailboxId; private List<String> users; @@ -128,6 +142,7 @@ public class IndexableMessage { private List<Property> properties; private List<MimePart> attachments; private Optional<String> bodyText; + private String text; @JsonProperty(JsonMessageConstants.ID) public Long getId() { @@ -263,4 +278,9 @@ public class IndexableMessage { public boolean getHasAttachment() { return attachments.size() > 0; } + + @JsonProperty(JsonMessageConstants.TEXT) + public String getText() { + return text; + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/JsonMessageConstants.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/JsonMessageConstants.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/JsonMessageConstants.java index 56361e8..25df70b 100644 --- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/JsonMessageConstants.java +++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/json/JsonMessageConstants.java @@ -43,6 +43,7 @@ public interface JsonMessageConstants { String TEXT_BODY = "textBody"; String SENT_DATE = "sentDate"; String ATTACHMENTS = "attachments"; + String TEXT = "text"; /* James properties we can easily get http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/CriterionConverter.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/CriterionConverter.java b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/CriterionConverter.java index a523c3d..a49713d 100644 --- a/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/CriterionConverter.java +++ b/mailbox/elasticsearch/src/main/java/org/apache/james/mailbox/elasticsearch/query/CriterionConverter.java @@ -128,6 +128,9 @@ public class CriterionConverter { switch (textCriterion.getType()) { case BODY: return matchQuery(JsonMessageConstants.TEXT_BODY, textCriterion.getOperator().getValue()); + case TEXT: + return boolQuery() + .should(matchQuery(JsonMessageConstants.TEXT, textCriterion.getOperator().getValue())); case FULL: return boolQuery() .should(matchQuery(JsonMessageConstants.TEXT_BODY, textCriterion.getOperator().getValue())) http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java new file mode 100644 index 0000000..2a62f2c --- /dev/null +++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java @@ -0,0 +1,185 @@ +/**************************************************************** + * 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.elasticsearch.json; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.time.ZoneId; + +import javax.mail.Flags; + +import org.apache.commons.io.IOUtils; +import org.apache.james.mailbox.mock.MockMailboxSession; +import org.apache.james.mailbox.store.TestId; +import org.apache.james.mailbox.store.extractor.DefaultTextExtractor; +import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +public class IndexableMessageTest { + + @Test + public void textShouldBeEmptyWhenNoMatchingHeaders() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream("".getBytes())); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEmpty(); + } + + @Test + public void textShouldContainsFromWhenFrom() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream("From: First user <[email protected]>\nFrom: Second user <[email protected]>".getBytes())); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEqualTo("Second user [email protected] First user [email protected]"); + } + + @Test + public void textShouldContainsToWhenTo() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream("To: First to <[email protected]>\nTo: Second to <[email protected]>".getBytes())); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEqualTo("First to [email protected] Second to [email protected]"); + } + + @Test + public void textShouldContainsCcWhenCc() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream("Cc: First cc <[email protected]>\nCc: Second cc <[email protected]>".getBytes())); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEqualTo("First cc [email protected] Second cc [email protected]"); + } + + @Test + public void textShouldContainsBccWhenBcc() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream("Bcc: First bcc <[email protected]>\nBcc: Second bcc <[email protected]>".getBytes())); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEqualTo("Second bcc [email protected] First bcc [email protected]"); + } + + @Test + public void textShouldContainsSubjectsWhenSubjects() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream("Subject: subject1\nSubject: subject2".getBytes())); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEqualTo("subject1 subject2"); + } + + @Test + public void textShouldContainsBodyWhenBody() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream("\nMy body".getBytes())); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEqualTo("My body"); + } + + @Test + public void textShouldContainsAllFieldsWhenAllSet() throws Exception { + MailboxMessage mailboxMessage = mock(MailboxMessage.class); + TestId mailboxId = TestId.of(1); + when(mailboxMessage.getMailboxId()) + .thenReturn(mailboxId); + when(mailboxMessage.getFullContent()) + .thenReturn(new ByteArrayInputStream(IOUtils.toByteArray(ClassLoader.getSystemResourceAsStream("eml/mailWithHeaders.eml")))); + when(mailboxMessage.createFlags()) + .thenReturn(new Flags()); + + IndexableMessage indexableMessage = IndexableMessage.from(mailboxMessage, ImmutableList.of(new MockMailboxSession("username").getUser()), + new DefaultTextExtractor(), ZoneId.of("Europe/Paris")); + + assertThat(indexableMessage.getText()).isEqualTo("Ad Min [email protected] " + + "a@test a@test B b@test " + + "c@test c@test " + + "dD d@test " + + "my subject " + + "Mail content\n" + + "\n" + + "-- \n" + + "Ad Min\n"); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/mailbox/elasticsearch/src/test/resources/eml/mailWithHeaders.eml ---------------------------------------------------------------------- diff --git a/mailbox/elasticsearch/src/test/resources/eml/mailWithHeaders.eml b/mailbox/elasticsearch/src/test/resources/eml/mailWithHeaders.eml new file mode 100644 index 0000000..2aff55d --- /dev/null +++ b/mailbox/elasticsearch/src/test/resources/eml/mailWithHeaders.eml @@ -0,0 +1,14 @@ +Content-Type: text/plain; Charset=UTF-8 +Date: Fri, 17 Sep 2010 17:12:26 +0200 +Subject: my subject +To: a@test, B <b@test> +Cc: c@test +Bcc: dD <d@test> +MIME-Version: 1.0 +Message-Id: <20100917151246.2A9384BA1@lenny> +From: Ad Min <[email protected]> + +Mail content + +-- +Ad Min http://git-wip-us.apache.org/repos/asf/james-project/blob/c321b93c/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 index c2a1fcb..b889778 100644 --- 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 @@ -757,4 +757,70 @@ public abstract class AbstractMessageSearchIndexTest { assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) .containsExactly(2L, 3L, 4L, 5L); } + + @Test + public void searchWithFullTextShouldReturnNoMailWhenNotMatching() throws Exception { + Assume.assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text)); + SearchQuery searchQuery = new SearchQuery(); + searchQuery.andCriteria(SearchQuery.textContains("unmatching")); + assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) + .isEmpty(); + } + + @Test + public void searchWithFullTextShouldReturnMailsWhenFromMatches() throws Exception { + Assume.assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text)); + SearchQuery searchQuery = new SearchQuery(); + searchQuery.andCriteria(SearchQuery.textContains("spam.minet.net")); + assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) + .containsExactly(1l); + } + + @Test + public void searchWithFullTextShouldReturnMailsWhenToMatches() throws Exception { + Assume.assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text)); + SearchQuery searchQuery = new SearchQuery(); + searchQuery.andCriteria(SearchQuery.textContains("listes.minet.net")); + assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) + .containsExactly(1l); + } + + @Test + public void searchWithFullTextShouldReturnMailsWhenCcMatches() throws Exception { + Assume.assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text)); + SearchQuery searchQuery = new SearchQuery(); + searchQuery.andCriteria(SearchQuery.textContains("abc.org")); + assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) + .containsExactly(3l); + } + + @Test + public void searchWithFullTextShouldReturnMailsWhenBccMatches() throws Exception { + Assume.assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text)); + SearchQuery searchQuery = new SearchQuery(); + searchQuery.andCriteria(SearchQuery.textContains("any.com")); + assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) + .containsExactly(5l); + } + + @Test + public void searchWithFullTextShouldReturnMailsWhenTextBodyMatches() throws Exception { + Assume.assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text)); + SearchQuery searchQuery = new SearchQuery(); + searchQuery.andCriteria(SearchQuery.textContains("reviewing work")); + // text/plain contains: "We are reviewing work I did for this feature." + assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) + .containsExactly(3l); + } + + @Test + public void searchWithFullTextShouldReturnMailsWhenTextBodyMatchesAndNonContinuousWords() throws Exception { + Assume.assumeTrue(storeMailboxManager.getSupportedSearchCapabilities().contains(MailboxManager.SearchCapabilities.Text)); + SearchQuery searchQuery = new SearchQuery(); + // 2: text/plain contains: "Issue Type: New Feature" + // 3: text/plain contains: "We are reviewing work I did for this feature." + searchQuery.andCriteria(SearchQuery.textContains("reviewing feature")); + assertThat(messageSearchIndex.search(session, mailbox, searchQuery)) + .containsExactly(2l, 3l); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
