This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push: new a87147ca88 JAMES-4077 Renaming LuceneMemorySearchHighlighter -> LuceneSearchHighlighter & add new Lucene File system test a87147ca88 is described below commit a87147ca8815afada2404f3370a4cb1e3b2177ab Author: TungTV <vtt...@linagora.com> AuthorDate: Mon Oct 7 16:28:04 2024 +0700 JAMES-4077 Renaming LuceneMemorySearchHighlighter -> LuceneSearchHighlighter & add new Lucene File system test --- .../searchhighligt/SearchHighLighterContract.java} | 261 +++++++++------------ ...ghlighter.java => LuceneSearchHighlighter.java} | 18 +- .../search/LuceneFSSearchHighLighterTest.java | 118 ++++++++++ .../search/LuceneMemorySearchHighLighterTest.java | 115 +++++++++ 4 files changed, 350 insertions(+), 162 deletions(-) diff --git a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighLightTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/searchhighligt/SearchHighLighterContract.java similarity index 57% rename from mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighLightTest.java rename to mailbox/api/src/test/java/org/apache/james/mailbox/searchhighligt/SearchHighLighterContract.java index f4e0232bf8..e95f5f8d06 100644 --- a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighLightTest.java +++ b/mailbox/api/src/test/java/org/apache/james/mailbox/searchhighligt/SearchHighLighterContract.java @@ -16,7 +16,9 @@ * specific language governing permissions and limitations * * under the License. * ****************************************************************/ -package org.apache.james.mailbox.lucene.search; + +package org.apache.james.mailbox.searchhighligt; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.SoftAssertions.assertSoftly; @@ -26,108 +28,61 @@ import java.util.List; import java.util.Optional; import org.apache.james.core.Username; -import org.apache.james.events.EventBus; import org.apache.james.mailbox.MailboxSession; -import org.apache.james.mailbox.MessageIdManager; import org.apache.james.mailbox.MessageManager; -import org.apache.james.mailbox.inmemory.InMemoryId; -import org.apache.james.mailbox.inmemory.InMemoryMessageId; -import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources; +import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.ComposedMessageId; -import org.apache.james.mailbox.model.Mailbox; -import org.apache.james.mailbox.model.MailboxACL; import org.apache.james.mailbox.model.MailboxId; -import org.apache.james.mailbox.model.MailboxPath; -import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MultimailboxesSearchQuery; import org.apache.james.mailbox.model.SearchQuery; -import org.apache.james.mailbox.searchhighligt.SearchHighlighterConfiguration; -import org.apache.james.mailbox.searchhighligt.SearchSnippet; -import org.apache.james.mailbox.store.StoreMailboxManager; -import org.apache.james.mailbox.store.StoreMessageManager; -import org.apache.james.mailbox.store.search.MessageSearchIndex; import org.apache.james.mime4j.dom.Message; -import org.apache.james.utils.UpdatableTickingClock; -import org.apache.lucene.store.ByteBuffersDirectory; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import com.github.fge.lambdas.Throwing; - -class LuceneMemorySearchHighLightTest { - private static final Username USERNAME1 = Username.of("username1"); - protected MessageSearchIndex messageSearchIndex; - protected StoreMailboxManager storeMailboxManager; - protected MessageIdManager messageIdManager; - protected EventBus eventBus; - protected MessageId.Factory messageIdFactory; - protected UpdatableTickingClock clock; - private StoreMessageManager inboxMessageManager; - private MailboxSession session; - private LuceneMemorySearchHighlighter testee; - - private Mailbox mailbox; - - @BeforeEach - public void setUp() throws Exception { - messageIdFactory = new InMemoryMessageId.Factory(); - InMemoryIntegrationResources resources = InMemoryIntegrationResources.builder() - .preProvisionnedFakeAuthenticator() - .fakeAuthorizator() - .inVmEventBus() - .defaultAnnotationLimits() - .defaultMessageParser() - .listeningSearchIndex(Throwing.function(preInstanciationStage -> new LuceneMessageSearchIndex( - preInstanciationStage.getMapperFactory(), new InMemoryId.Factory(), new ByteBuffersDirectory(), - messageIdFactory, - preInstanciationStage.getSessionProvider()))) - .noPreDeletionHooks() - .storeQuotaManager() - .build(); - storeMailboxManager = resources.getMailboxManager(); - messageIdManager = resources.getMessageIdManager(); - messageSearchIndex = resources.getSearchIndex(); - eventBus = resources.getEventBus(); - messageIdFactory = new InMemoryMessageId.Factory(); - - clock = (UpdatableTickingClock) storeMailboxManager.getClock(); - testee = new LuceneMemorySearchHighlighter(((LuceneMessageSearchIndex) messageSearchIndex), - SearchHighlighterConfiguration.DEFAULT, - messageIdFactory, storeMailboxManager); - - session = storeMailboxManager.createSystemSession(USERNAME1); - MailboxPath inboxPath = MailboxPath.inbox(USERNAME1); - storeMailboxManager.createMailbox(inboxPath, session); - inboxMessageManager = (StoreMessageManager) storeMailboxManager.getMailbox(inboxPath, session); - mailbox = inboxMessageManager.getMailboxEntity(); +import reactor.core.publisher.Flux; + +public interface SearchHighLighterContract { + Username USERNAME1 = Username.of("username1"); + + SearchHighlighter testee(); + + MailboxSession session(Username username); + + MessageManager.AppendResult appendMessage(MessageManager.AppendCommand appendCommand, MailboxSession session); + + MailboxId randomMailboxId(Username username); + + void applyRightsCommand(MailboxId mailboxId, Username owner, Username delegated); + + default void verifyMessageWasIndexed(int indexedMessageCount) throws MailboxException { } @Test - void highlightSearchShouldReturnHighLightedSubjectWhenMatched() throws Exception { + default void highlightSearchShouldReturnHighLightedSubjectWhenMatched() throws Exception { + MailboxSession session = session(USERNAME1); + // Given m1,m2 with m1 has subject containing the searched word (Matthieu) - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Matthieu for your help") .setBody("append contentA to inbox", StandardCharsets.UTF_8)), session).getId(); - ComposedMessageId m2 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m2 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Alex for your help") .setBody("append contentB to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(2); + verifyMessageWasIndexed(2); // When searching for the word (Matthieu) in the subject MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("Matthieu"))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m2.getMailboxId())) .build(); - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session)) .collectList() .block(); @@ -140,33 +95,34 @@ class LuceneMemorySearchHighLightTest { } @Test - void highlightSearchShouldReturnHighlightedBodyWhenMatched() throws Exception { + default void highlightSearchShouldReturnHighlightedBodyWhenMatched() throws Exception { + MailboxSession session = session(USERNAME1); + // Given m1,m2 with m1 has body containing the searched word (contentA) - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Matthieu for your help") .setBody("append contentA to inbox", StandardCharsets.UTF_8)), session).getId(); - ComposedMessageId m2 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m2 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Alex for your help") .setBody("append contentB to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(2); + verifyMessageWasIndexed(2); // When searching for the word (contentA) in the body MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of( SearchQuery.bodyContains("contentA"))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId(), m2.getMailboxId())) .build(); // Then highlightSearch should return the SearchSnippet with the highlightedBody containing the word (contentA) - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session)) .collectList() .block(); assertThat(searchSnippets).hasSize(1); @@ -177,67 +133,67 @@ class LuceneMemorySearchHighLightTest { } @Test - void searchBothSubjectAndBodyHighLightShouldReturnEmptyWhenNotMatched() throws Exception { + default void searchBothSubjectAndBodyHighLightShouldReturnEmptyWhenNotMatched() throws Exception { + MailboxSession session = session(USERNAME1); // Given m1,m2 with m1,m2 has both body+subject not containing the searched word (contentC) - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Matthieu for your help") .setBody("append contentA to inbox", StandardCharsets.UTF_8)), session).getId(); - ComposedMessageId m2 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m2 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Alex for your help") .setBody("append contentB to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(2); + verifyMessageWasIndexed(2); // When searching for the word (contentC) in both subject and body MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of( SearchQuery.bodyContains("contentC"), SearchQuery.subject("contentC"))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId())) .build(); // Then highlightSearch should return an empty - assertThat(testee.highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session) + assertThat(Flux.from(testee().highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session)) .collectList() .block()).isEmpty(); } @Test - void searchBothSubjectAndBodyHighLightShouldReturnEntryWhenMatched() throws Exception { + default void searchBothSubjectAndBodyHighLightShouldReturnEntryWhenMatched() throws Exception { + MailboxSession session = session(USERNAME1); // Given m1,m2 with m1 has body + subject containing the searched word (Naruto) - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Naruto for your help") .setBody("append Naruto to inbox", StandardCharsets.UTF_8)), session).getId(); - ComposedMessageId m2 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m2 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Alex for your help") .setBody("append contentB to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(2); + verifyMessageWasIndexed(2); // When searching for the word (Naruto) in both subject and body MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of( SearchQuery.bodyContains("Naruto"), SearchQuery.subject("Naruto"))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId(), m2.getMailboxId())) .build(); // Then highlightSearch should return the SearchSnippet with the highlightedBody/highlightedSubject containing the word (Naruto) - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()),multiMailboxSearch, session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session)) .collectList() .block(); assertThat(searchSnippets).hasSize(1); @@ -248,33 +204,34 @@ class LuceneMemorySearchHighLightTest { }); } + @Test - void highlightSearchShouldReturnMultipleResultsWhenMultipleMatches() throws Exception { + default void highlightSearchShouldReturnMultipleResultsWhenMultipleMatches() throws Exception { + MailboxSession session = session(USERNAME1); // Given m1,m2 with m1,m2 has subject containing the searched word (WeeklyReport) - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Tran Van Tung WeeklyReport 04/10/2024") .setBody("The weekly report has been in attachment1", StandardCharsets.UTF_8)), session).getId(); - ComposedMessageId m2 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m2 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Tran Van Tung WeeklyReport 11/10/2024") .setBody("The weekly report has been in attachment2", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(2); + verifyMessageWasIndexed(2); // When searching for the word (WeeklyReport) in the subject MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("WeeklyReport"))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId(), m2.getMailboxId())) .build(); // Then highlightSearch should return the SearchSnippet with the highlightedSubject containing the word (WeeklyReport) - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()),multiMailboxSearch, session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session)) .collectList() .block(); assertThat(searchSnippets).hasSize(2); @@ -283,24 +240,24 @@ class LuceneMemorySearchHighLightTest { } @Test - void highlightSearchShouldReturnCorrectFormatWhenSearchTwoWords() throws Exception { - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + default void highlightSearchShouldReturnCorrectFormatWhenSearchTwoWords() throws Exception { + MailboxSession session = session(USERNAME1); + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Naruto Itachi for your help") .setBody("append Naruto Itachi to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(1); + verifyMessageWasIndexed(1); // When searching for the word (Naruto and Itachi) in the subject MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.bodyContains("Naruto Itachi"))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId())) .build(); // Then highlightSearch should return the SearchSnippet with the highlightedSubject containing the word (Naruto) (and) (Itachi) - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId()),multiMailboxSearch, session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId()), multiMailboxSearch, session)) .collectList() .block(); assertThat(searchSnippets).hasSize(1); @@ -308,71 +265,71 @@ class LuceneMemorySearchHighLightTest { } @Test - void highlightSearchShouldReturnEmptyResultsWhenKeywordNoMatch() throws Exception { + default void highlightSearchShouldReturnEmptyResultsWhenKeywordNoMatch() throws Exception { + MailboxSession session = session(USERNAME1); // Given m1 that has both subject + body not containing the searched word (Vietnam) - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Tran Van Tung WeeklyReport 04/10/2024") .setBody("The weekly report has been in attachment1", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(1); + verifyMessageWasIndexed(1); // When searching for the word (Vietnam) in the subject MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("Vietnam"))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId())) .build(); // Then highlightSearch should return an empty list - assertThat(testee.highlightSearch(List.of(m1.getMessageId()),multiMailboxSearch, session) + assertThat(Flux.from(testee().highlightSearch(List.of(m1.getMessageId()), multiMailboxSearch, session)) .collectList() .block()).isEmpty(); } @Test - void highlightSearchShouldReturnEmptyResultsWhenMailboxIdNoMatch() throws Exception { + default void highlightSearchShouldReturnEmptyResultsWhenMailboxIdNoMatch() throws Exception { + MailboxSession session = session(USERNAME1); // Given message m1 of mailbox Mailbox.inbox(username1) - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Tran Van Tung WeeklyReport 04/10/2024") .setBody("The weekly report has been in attachment1", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(1); + verifyMessageWasIndexed(1); // When searching for the word (WeeklyReport) in the subject but in another mailbox - MailboxId randomMailboxId = storeMailboxManager.createMailbox(MailboxPath.forUser(USERNAME1, "random1"), session).get(); + MailboxId randomMailboxId = randomMailboxId(USERNAME1); // Then highlightSearch should return an empty list - assertThat(testee.highlightSearch(List.of(m1.getMessageId()), + assertThat(Flux.from(testee().highlightSearch(List.of(m1.getMessageId()), MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("WeeklyReport"))) - .inMailboxes(List.of(randomMailboxId)).build(), session) + .inMailboxes(List.of(randomMailboxId)).build(), session)) .collectList() .block()).isEmpty(); } @Test - void highlightSearchShouldNotReturnEntryWhenDoesNotAccessible() throws Exception { + default void highlightSearchShouldNotReturnEntryWhenDoesNotAccessible() throws Exception { + MailboxSession session = session(USERNAME1); // Given messages of username1 - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Matthieu for your help") .setBody("append contentA to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(1); + verifyMessageWasIndexed(1); // When searching for the word (Matthieu) in the subject, but the mailbox is not accessible - MailboxSession notAccessible = storeMailboxManager.createSystemSession(Username.of("notAccessible")); - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId()),MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("Matthieu"))) - .inMailboxes(List.of(mailbox.getMailboxId())) - .build(), notAccessible) + MailboxSession notAccessible = session(Username.of("notAccessible")); + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId()), MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("Matthieu"))) + .inMailboxes(List.of(m1.getMailboxId())) + .build(), notAccessible)) .collectList() .block(); @@ -381,29 +338,27 @@ class LuceneMemorySearchHighLightTest { } @Test - void highlightSearchShouldReturnEntryWhenHasAccessible() throws Exception { + default void highlightSearchShouldReturnEntryWhenHasAccessible() throws Exception { + MailboxSession session = session(USERNAME1); // Given messages of username1 - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Matthieu for your help") .setBody("append contentA to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(1); + verifyMessageWasIndexed(1); // Set right for delegated1 to access username1 mailbox Username delegated1 = Username.of("delegated"); - MailboxSession delegated1Session = storeMailboxManager.createSystemSession(delegated1); - storeMailboxManager.applyRightsCommand(mailbox.generateAssociatedPath(), - MailboxACL.command().forUser(delegated1).rights(MailboxACL.FULL_RIGHTS).asAddition(), - session); + MailboxSession delegated1Session = session(delegated1); + applyRightsCommand(m1.getMailboxId(), USERNAME1, delegated1); // When searching for the word (Matthieu) in the subject - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId()), MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("Matthieu"))) - .inMailboxes(List.of(mailbox.getMailboxId())) - .build(), delegated1Session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId()), MultimailboxesSearchQuery.from(SearchQuery.of(SearchQuery.subject("Matthieu"))) + .inMailboxes(List.of(m1.getMailboxId())) + .build(), delegated1Session)) .collectList() .block(); @@ -413,34 +368,34 @@ class LuceneMemorySearchHighLightTest { } @Test - void highLightSearchShouldSupportConjunctionCriterionInMultiMessage() throws Exception { + default void highLightSearchShouldSupportConjunctionCriterionInMultiMessage() throws Exception { + MailboxSession session = session(USERNAME1); // Given m1,m2 - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Naruto for your help") .setBody("append Naruto to inbox", StandardCharsets.UTF_8)), session).getId(); - ComposedMessageId m2 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m2 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Alex for your help") .setBody("append contentB to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(2); + verifyMessageWasIndexed(2); // When searching for the word (Naruto) or (Alex) in the subject MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of( new SearchQuery.ConjunctionCriterion(SearchQuery.Conjunction.OR, List.of(SearchQuery.subject("Naruto"), SearchQuery.subject("Alex"))))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId(), m2.getMailboxId())) .build(); // Then highlightSearch should return the SearchSnippet with the highlightedSubject containing the word (Naruto) or (Alex) - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session)) .collectList() .block(); assertThat(searchSnippets).hasSize(2); @@ -452,34 +407,34 @@ class LuceneMemorySearchHighLightTest { } @Test - void highLightSearchShouldSupportConjunctionCriterionInSingleMessage() throws Exception { + default void highLightSearchShouldSupportConjunctionCriterionInSingleMessage() throws Exception { + MailboxSession session = session(USERNAME1); // Given m1,m2 - ComposedMessageId m1 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m1 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Naruto for your help - Sasuke for your help") .setBody("append Naruto to inbox", StandardCharsets.UTF_8)), session).getId(); - ComposedMessageId m2 = inboxMessageManager.appendMessage(MessageManager.AppendCommand.from( + ComposedMessageId m2 = appendMessage(MessageManager.AppendCommand.from( Message.Builder.of() .setTo("to@james.local") .setSubject("Hallo! Thx Alex for your help") .setBody("append contentB to inbox", StandardCharsets.UTF_8)), session).getId(); - // Verify that the messages are indexed - assertThat(messageSearchIndex.search(session, mailbox, SearchQuery.of()).toStream().count()).isEqualTo(2); + verifyMessageWasIndexed(2); // When searching for the word (Naruto) or (Sasuke) in the subject MultimailboxesSearchQuery multiMailboxSearch = MultimailboxesSearchQuery.from(SearchQuery.of( new SearchQuery.ConjunctionCriterion(SearchQuery.Conjunction.OR, List.of(SearchQuery.subject("Naruto"), SearchQuery.subject("Sasuke"))))) - .inMailboxes(List.of(mailbox.getMailboxId())) + .inMailboxes(List.of(m1.getMailboxId(), m2.getMailboxId())) .build(); // Then highlightSearch should return the SearchSnippet with the highlightedSubject containing the word (Naruto) or (Sasuke) - List<SearchSnippet> searchSnippets = testee.highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session) + List<SearchSnippet> searchSnippets = Flux.from(testee().highlightSearch(List.of(m1.getMessageId(), m2.getMessageId()), multiMailboxSearch, session)) .collectList() .block(); assertThat(searchSnippets).hasSize(1); diff --git a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighlighter.java b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneSearchHighlighter.java similarity index 91% rename from mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighlighter.java rename to mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneSearchHighlighter.java index 82997cfa2a..6a4facb1de 100644 --- a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighlighter.java +++ b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneSearchHighlighter.java @@ -61,7 +61,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; -public class LuceneMemorySearchHighlighter implements SearchHighlighter { +public class LuceneSearchHighlighter implements SearchHighlighter { private static Analyzer defaultAnalyzer() { return new StandardAnalyzer(); } @@ -73,10 +73,10 @@ public class LuceneMemorySearchHighlighter implements SearchHighlighter { private final SearchHighlighterConfiguration configuration; private final StoreMailboxManager storeMailboxManager; - public LuceneMemorySearchHighlighter(LuceneMessageSearchIndex luceneMessageSearchIndex, - SearchHighlighterConfiguration searchHighlighterConfiguration, - MessageId.Factory messageIdFactory, StoreMailboxManager storeMailboxManager, - Analyzer analyzer) { + public LuceneSearchHighlighter(LuceneMessageSearchIndex luceneMessageSearchIndex, + SearchHighlighterConfiguration searchHighlighterConfiguration, + MessageId.Factory messageIdFactory, StoreMailboxManager storeMailboxManager, + Analyzer analyzer) { this.luceneMessageSearchIndex = luceneMessageSearchIndex; this.messageIdFactory = messageIdFactory; this.analyzer = analyzer; @@ -85,10 +85,10 @@ public class LuceneMemorySearchHighlighter implements SearchHighlighter { this.formatter = new SimpleHTMLFormatter(searchHighlighterConfiguration.preTagFormatter(), searchHighlighterConfiguration.postTagFormatter()); } - public LuceneMemorySearchHighlighter(LuceneMessageSearchIndex luceneMessageSearchIndex, - SearchHighlighterConfiguration searchHighlighterConfiguration, - MessageId.Factory messageIdFactory, - StoreMailboxManager storeMailboxManager) { + public LuceneSearchHighlighter(LuceneMessageSearchIndex luceneMessageSearchIndex, + SearchHighlighterConfiguration searchHighlighterConfiguration, + MessageId.Factory messageIdFactory, + StoreMailboxManager storeMailboxManager) { this(luceneMessageSearchIndex, searchHighlighterConfiguration, messageIdFactory, diff --git a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneFSSearchHighLighterTest.java b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneFSSearchHighLighterTest.java new file mode 100644 index 0000000000..ea43b4b87a --- /dev/null +++ b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneFSSearchHighLighterTest.java @@ -0,0 +1,118 @@ +/**************************************************************** + * 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.lucene.search; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Path; + +import org.apache.james.core.Username; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageManager; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.inmemory.InMemoryId; +import org.apache.james.mailbox.inmemory.InMemoryMessageId; +import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources; +import org.apache.james.mailbox.model.Mailbox; +import org.apache.james.mailbox.model.MailboxACL; +import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MessageId; +import org.apache.james.mailbox.model.SearchQuery; +import org.apache.james.mailbox.searchhighligt.SearchHighLighterContract; +import org.apache.james.mailbox.searchhighligt.SearchHighlighter; +import org.apache.james.mailbox.searchhighligt.SearchHighlighterConfiguration; +import org.apache.james.mailbox.store.StoreMailboxManager; +import org.apache.james.mailbox.store.StoreMessageManager; +import org.apache.james.mailbox.store.search.MessageSearchIndex; +import org.apache.lucene.store.FSDirectory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; + +import com.github.fge.lambdas.Throwing; + +class LuceneFSSearchHighLighterTest implements SearchHighLighterContract { + private MessageSearchIndex messageSearchIndex; + private StoreMailboxManager storeMailboxManager; + private StoreMessageManager inboxMessageManager; + private LuceneSearchHighlighter testee; + + @BeforeEach + public void setUp(@TempDir Path tempPath) throws Exception { + final MessageId.Factory messageIdFactory = new InMemoryMessageId.Factory(); + InMemoryIntegrationResources resources = InMemoryIntegrationResources.builder() + .preProvisionnedFakeAuthenticator() + .fakeAuthorizator() + .inVmEventBus() + .defaultAnnotationLimits() + .defaultMessageParser() + .listeningSearchIndex(Throwing.function(preInstanciationStage -> new LuceneMessageSearchIndex( + preInstanciationStage.getMapperFactory(), new InMemoryId.Factory(), FSDirectory.open(tempPath), + messageIdFactory, + preInstanciationStage.getSessionProvider()))) + .noPreDeletionHooks() + .storeQuotaManager() + .build(); + storeMailboxManager = resources.getMailboxManager(); + messageSearchIndex = resources.getSearchIndex(); + testee = new LuceneSearchHighlighter(((LuceneMessageSearchIndex) messageSearchIndex), + SearchHighlighterConfiguration.DEFAULT, + messageIdFactory, storeMailboxManager); + + MailboxSession session = storeMailboxManager.createSystemSession(USERNAME1); + MailboxPath inboxPath = MailboxPath.inbox(USERNAME1); + storeMailboxManager.createMailbox(inboxPath, session); + inboxMessageManager = (StoreMessageManager) storeMailboxManager.getMailbox(inboxPath, session); + } + + @Override + public SearchHighlighter testee() { + return testee; + } + + @Override + public MailboxSession session(Username username) { + return storeMailboxManager.createSystemSession(username); + } + + @Override + public MessageManager.AppendResult appendMessage(MessageManager.AppendCommand appendCommand, MailboxSession session) { + return Throwing.supplier(() -> inboxMessageManager.appendMessage(appendCommand, session)).get(); + } + + @Override + public MailboxId randomMailboxId(Username username) { + String random = new String(new byte[8]); + return Throwing.supplier(() -> storeMailboxManager.createMailbox(MailboxPath.forUser(USERNAME1, random), session(username)).get()).get(); + } + + @Override + public void verifyMessageWasIndexed(int indexedMessageCount) throws MailboxException { + assertThat(messageSearchIndex.search(session(USERNAME1), inboxMessageManager.getMailboxEntity(), SearchQuery.of()).toStream().count()) + .isEqualTo(indexedMessageCount); + } + + @Override + public void applyRightsCommand(MailboxId mailboxId, Username owner, Username delegated) { + Mailbox mailbox = inboxMessageManager.getMailboxEntity(); + Throwing.runnable(() -> storeMailboxManager.applyRightsCommand(mailbox.generateAssociatedPath(), + MailboxACL.command().forUser(delegated).rights(MailboxACL.FULL_RIGHTS).asAddition(), + session(owner))).run(); + } +} diff --git a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighLighterTest.java b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighLighterTest.java new file mode 100644 index 0000000000..ca97c12441 --- /dev/null +++ b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMemorySearchHighLighterTest.java @@ -0,0 +1,115 @@ +/**************************************************************** + * 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.lucene.search; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.james.core.Username; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageManager; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.inmemory.InMemoryId; +import org.apache.james.mailbox.inmemory.InMemoryMessageId; +import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources; +import org.apache.james.mailbox.model.Mailbox; +import org.apache.james.mailbox.model.MailboxACL; +import org.apache.james.mailbox.model.MailboxId; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MessageId; +import org.apache.james.mailbox.model.SearchQuery; +import org.apache.james.mailbox.searchhighligt.SearchHighLighterContract; +import org.apache.james.mailbox.searchhighligt.SearchHighlighter; +import org.apache.james.mailbox.searchhighligt.SearchHighlighterConfiguration; +import org.apache.james.mailbox.store.StoreMailboxManager; +import org.apache.james.mailbox.store.StoreMessageManager; +import org.apache.james.mailbox.store.search.MessageSearchIndex; +import org.apache.lucene.store.ByteBuffersDirectory; +import org.junit.jupiter.api.BeforeEach; + +import com.github.fge.lambdas.Throwing; + +class LuceneMemorySearchHighLighterTest implements SearchHighLighterContract { + private MessageSearchIndex messageSearchIndex; + private StoreMailboxManager storeMailboxManager; + private StoreMessageManager inboxMessageManager; + private LuceneSearchHighlighter testee; + + @BeforeEach + public void setUp() throws Exception { + final MessageId.Factory messageIdFactory = new InMemoryMessageId.Factory(); + InMemoryIntegrationResources resources = InMemoryIntegrationResources.builder() + .preProvisionnedFakeAuthenticator() + .fakeAuthorizator() + .inVmEventBus() + .defaultAnnotationLimits() + .defaultMessageParser() + .listeningSearchIndex(Throwing.function(preInstanciationStage -> new LuceneMessageSearchIndex( + preInstanciationStage.getMapperFactory(), new InMemoryId.Factory(), new ByteBuffersDirectory(), + messageIdFactory, + preInstanciationStage.getSessionProvider()))) + .noPreDeletionHooks() + .storeQuotaManager() + .build(); + storeMailboxManager = resources.getMailboxManager(); + messageSearchIndex = resources.getSearchIndex(); + testee = new LuceneSearchHighlighter(((LuceneMessageSearchIndex) messageSearchIndex), + SearchHighlighterConfiguration.DEFAULT, + messageIdFactory, storeMailboxManager); + + MailboxSession session = storeMailboxManager.createSystemSession(USERNAME1); + MailboxPath inboxPath = MailboxPath.inbox(USERNAME1); + storeMailboxManager.createMailbox(inboxPath, session); + inboxMessageManager = (StoreMessageManager) storeMailboxManager.getMailbox(inboxPath, session); + } + + @Override + public SearchHighlighter testee() { + return testee; + } + + @Override + public MailboxSession session(Username username) { + return storeMailboxManager.createSystemSession(username); + } + + @Override + public MessageManager.AppendResult appendMessage(MessageManager.AppendCommand appendCommand, MailboxSession session) { + return Throwing.supplier(() -> inboxMessageManager.appendMessage(appendCommand, session)).get(); + } + + @Override + public MailboxId randomMailboxId(Username username) { + String random = new String(new byte[8]); + return Throwing.supplier(() -> storeMailboxManager.createMailbox(MailboxPath.forUser(USERNAME1, random), session(username)).get()).get(); + } + + @Override + public void verifyMessageWasIndexed(int indexedMessageCount) throws MailboxException { + assertThat(messageSearchIndex.search(session(USERNAME1), inboxMessageManager.getMailboxEntity(), SearchQuery.of()).toStream().count()) + .isEqualTo(indexedMessageCount); + } + + @Override + public void applyRightsCommand(MailboxId mailboxId, Username owner, Username delegated) { + Mailbox mailbox = inboxMessageManager.getMailboxEntity(); + Throwing.runnable(() -> storeMailboxManager.applyRightsCommand(mailbox.generateAssociatedPath(), + MailboxACL.command().forUser(delegated).rights(MailboxACL.FULL_RIGHTS).asAddition(), + session(owner))).run(); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org