This is an automated email from the ASF dual-hosted git repository.
aduprat 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 f633c2d JAMES-2704 Add Mailet to randomly assign messages to users
f633c2d is described below
commit f633c2da38aece949552a6f409f6b03a4d6d64b4
Author: Gautier DI FOLCO <[email protected]>
AuthorDate: Fri Mar 29 09:50:36 2019 +0100
JAMES-2704 Add Mailet to randomly assign messages to users
---
.../apache/james/smtp/SmtpRandomStoringTest.java | 208 +++++++++++++++++++++
.../james/transport/mailets/RandomStoring.java | 170 +++++++++++++++++
.../org/apache/james/utils/IMAPMessageReader.java | 15 ++
3 files changed, 393 insertions(+)
diff --git
a/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/SmtpRandomStoringTest.java
b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/SmtpRandomStoringTest.java
new file mode 100644
index 0000000..d313c9b
--- /dev/null
+++
b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/SmtpRandomStoringTest.java
@@ -0,0 +1,208 @@
+/****************************************************************
+ * 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.smtp;
+
+import static org.apache.james.mailets.configuration.Constants.DEFAULT_DOMAIN;
+import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP;
+import static org.apache.james.mailets.configuration.Constants.PASSWORD;
+import static org.apache.james.mailets.configuration.Constants.calmlyAwait;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import javax.mail.MessagingException;
+
+import org.apache.james.MemoryJamesServerMain;
+import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.james.mailbox.model.MailboxConstants;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailets.TemporaryJamesServer;
+import org.apache.james.mailets.configuration.CommonProcessors;
+import org.apache.james.mailets.configuration.MailetConfiguration;
+import org.apache.james.mailets.configuration.MailetContainer;
+import org.apache.james.mailets.configuration.ProcessorConfiguration;
+import org.apache.james.modules.MailboxProbeImpl;
+import org.apache.james.modules.protocols.ImapGuiceProbe;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.probe.DataProbe;
+import org.apache.james.server.core.MailImpl;
+import org.apache.james.transport.mailets.RandomStoring;
+import org.apache.james.transport.matchers.All;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.IMAPMessageReader;
+import org.apache.james.utils.SMTPMessageSender;
+import org.apache.mailet.Mail;
+
+import org.awaitility.Duration;
+import org.awaitility.core.ConditionFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+
+public class SmtpRandomStoringTest {
+ private static final String FROM = "from@" + DEFAULT_DOMAIN;
+ private static final String TO = "[email protected]";
+ private static final Long USERS_NUMBERS = 10L;
+ private static final ConditionFactory awaitAtMostTenSeconds = calmlyAwait
+ .atMost(Duration.TEN_SECONDS);
+
+ private static final ImmutableList<String> USERS = LongStream.range(0L,
USERS_NUMBERS)
+ .boxed()
+ .map(index -> "user" + index + "@" + DEFAULT_DOMAIN)
+ .collect(Guavate.toImmutableList());
+
+ private static final ImmutableList<String> MAILBOXES =
ImmutableList.of(MailboxConstants.INBOX, "arbitrary");
+ private static final MailetConfiguration RANDOM_STORING =
MailetConfiguration.builder()
+ .matcher(All.class)
+ .mailet(RandomStoring.class)
+ .build();
+
+ @Rule
+ public IMAPMessageReader imapMessageReader = new IMAPMessageReader();
+ @Rule
+ public SMTPMessageSender messageSender = new
SMTPMessageSender(DEFAULT_DOMAIN);
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ private TemporaryJamesServer jamesServer;
+ private ImapGuiceProbe imapProbe;
+
+ @Before
+ public void setUp() throws Exception {
+ createJamesServer();
+
+ createUsersAndMailboxes();
+
+ imapProbe = jamesServer.getProbe(ImapGuiceProbe.class);
+ }
+
+ private void createUsersAndMailboxes() throws Exception {
+ MailboxProbeImpl mailboxes =
jamesServer.getProbe(MailboxProbeImpl.class);
+ DataProbe dataProbe = jamesServer.getProbe(DataProbeImpl.class);
+ dataProbe.addDomain(DEFAULT_DOMAIN);
+ dataProbe.addUser(FROM, PASSWORD);
+ USERS.forEach(user -> populateUser(mailboxes, dataProbe, user));
+ }
+
+ private void populateUser(MailboxProbeImpl mailboxProbe, DataProbe
dataProbe, String user) {
+ try {
+ dataProbe.addUser(user, PASSWORD);
+ MAILBOXES.forEach(mailbox ->
mailboxProbe.createMailbox(MailboxPath.forUser(user, mailbox)));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void createJamesServer() throws Exception {
+ MailetContainer.Builder mailetContainer =
TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION
+ .putProcessor(ProcessorConfiguration.transport()
+ .addMailet(RANDOM_STORING)
+ .addMailetsFrom(CommonProcessors.deliverOnlyTransport()));
+
+ jamesServer = TemporaryJamesServer.builder()
+ .withBase(MemoryJamesServerMain.SMTP_AND_IMAP_MODULE)
+ .withMailetContainer(mailetContainer)
+ .build(temporaryFolder);
+ }
+
+ @After
+ public void tearDown() {
+ jamesServer.shutdown();
+ }
+
+ @Test
+ public void
sendingOneHundredMessagesShouldBeRandomlyAssignedToEveryMailboxesOfEveryUsers()
throws Exception {
+ int numberOfMails = 100;
+
+ SMTPMessageSender authenticatedSmtpConnection =
messageSender.connect(LOCALHOST_IP,
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+ .authenticate(FROM, PASSWORD);
+
+ IntStream.range(1, numberOfMails)
+ .forEach(Throwing.intConsumer(index ->
+ authenticatedSmtpConnection
+ .sendMessage(buildMail("Message " +
index))).sneakyThrow());
+
+ Collection<IMAPMessageReader> connections = USERS
+ .stream()
+ .map(this::createIMAPConnection)
+ .collect(Guavate.toImmutableList());
+
+ awaitAtMostTenSeconds
+ .untilAsserted(() -> checkMailboxesHaveBeenFilled(connections,
numberOfMails));
+ }
+
+ private IMAPMessageReader createIMAPConnection(String username) {
+ try {
+ return new IMAPMessageReader()
+ .connect(LOCALHOST_IP, imapProbe.getImapPort())
+ .login(username, PASSWORD);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void checkMailboxesHaveBeenFilled(Collection<IMAPMessageReader>
connections, int numberOfMails) {
+ assertThat(connections
+ .stream()
+ .flatMapToLong(this::numberOfAUserMessages)
+ .sum())
+ .isBetween(numberOfMails * 4L, numberOfMails * 8L);
+ }
+
+ private LongStream numberOfAUserMessages(IMAPMessageReader
imapMessageReader) {
+ return MAILBOXES
+ .stream()
+ .mapToLong(mailbox -> numberOfMessagesInMailbox(imapMessageReader,
mailbox));
+ }
+
+ private Long numberOfMessagesInMailbox(IMAPMessageReader
imapMessageReader, String mailbox) {
+ try {
+ long numberOfMails = imapMessageReader
+ .getMessageCount(mailbox);
+
+ assertThat(numberOfMails)
+ .isGreaterThan(0);
+
+ return numberOfMails;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Mail buildMail(String subject) throws MessagingException {
+ return MailImpl.builder()
+ .name(subject)
+ .sender(FROM)
+ .addRecipient(TO)
+ .mimeMessage(MimeMessageBuilder.mimeMessageBuilder()
+ .setSubject(subject)
+ .setText("content"))
+ .build();
+ }
+}
+
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RandomStoring.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RandomStoring.java
new file mode 100644
index 0000000..74d33e8
--- /dev/null
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RandomStoring.java
@@ -0,0 +1,170 @@
+/****************************************************************
+ * 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.transport.mailets;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.inject.Inject;
+import javax.mail.MessagingException;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.User;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.transport.mailets.delivery.MailStore;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.Mail;
+import org.apache.mailet.base.GenericMailet;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.Streams;
+
+/**
+ * Process messages and randomly assign them to 4 to 8 mailboxes.
+ */
+public class RandomStoring extends GenericMailet {
+
+ private static final int MIN_NUMBER_OF_RECIPIENTS = 4;
+ private static final int MAX_NUMBER_OF_RECIPIENTS = 8;
+ private final UsersRepository usersRepository;
+ private final MailboxManager mailboxManager;
+ private final Iterator<Integer> randomRecipientsNumbers;
+
+ @Inject
+ public RandomStoring(UsersRepository usersRepository, MailboxManager
mailboxManager) {
+ this.usersRepository = usersRepository;
+ this.mailboxManager = mailboxManager;
+ this.randomRecipientsNumbers = new
Random().ints(MIN_NUMBER_OF_RECIPIENTS, MAX_NUMBER_OF_RECIPIENTS +
1).boxed().iterator();
+ }
+
+ @Override
+ public void service(Mail mail) throws MessagingException {
+ try {
+ Collection<ReroutingInfos> reroutingInfos =
generateRandomMailboxes();
+ Collection<MailAddress> mailAddresses = reroutingInfos
+ .stream()
+ .map(ReroutingInfos::getMailAddress)
+ .collect(Guavate.toImmutableList());
+
+ mail.setRecipients(mailAddresses);
+ reroutingInfos.forEach(reroutingInfo ->
+
mail.setAttribute(Attribute.convertToAttribute(MailStore.DELIVERY_PATH_PREFIX +
reroutingInfo.getUser(), reroutingInfo.getMailbox())));
+ } catch (UsersRepositoryException e) {
+ throw new MessagingException("Unable to compute a random user
list", e);
+ }
+ }
+
+ @Override
+ public String getMailetInfo() {
+ return "Random Storing Mailet";
+ }
+
+ @Override
+ public void init() throws MessagingException {
+ }
+
+ private Collection<ReroutingInfos> generateRandomMailboxes() throws
UsersRepositoryException {
+ List<ReroutingInfos> reroutingInfos =
Streams.stream(usersRepository.list())
+ .map(User::fromUsername)
+ .flatMap(this::buildReRoutingInfos)
+ .distinct()
+ .collect(Collectors.toList());
+
+ Collections.shuffle(reroutingInfos);
+ return reroutingInfos
+ .stream()
+ .limit(randomRecipientsNumbers.next())
+ .collect(Guavate.toImmutableSet());
+ }
+
+ private Stream<ReroutingInfos> buildReRoutingInfos(User user) {
+ try {
+ MailAddress mailAddress = usersRepository.getMailAddressFor(user);
+
+ MailboxSession session =
mailboxManager.createSystemSession(user.asString());
+ return mailboxManager
+ .list(session)
+ .stream()
+ .map(mailboxPath -> new ReroutingInfos(mailAddress,
mailboxPath.getName(), user.asString()));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private class ReroutingInfos {
+ private final MailAddress mailAddress;
+ private final String mailbox;
+ private final String user;
+
+ ReroutingInfos(MailAddress mailAddress, String mailbox, String user) {
+ this.mailAddress = mailAddress;
+ this.mailbox = mailbox;
+ this.user = user;
+ }
+
+ public MailAddress getMailAddress() {
+ return mailAddress;
+ }
+
+ public String getMailbox() {
+ return mailbox;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ReroutingInfos) {
+ ReroutingInfos that = (ReroutingInfos) o;
+
+ return Objects.equals(this.mailAddress, that.mailAddress)
+ && Objects.equals(this.mailbox, that.mailbox)
+ && Objects.equals(this.user, that.user);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mailAddress, mailbox, user);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("user", mailAddress.asString())
+ .add("mailbox", mailbox)
+ .add("user", user)
+ .toString();
+ }
+ }
+}
+
diff --git
a/server/testing/src/main/java/org/apache/james/utils/IMAPMessageReader.java
b/server/testing/src/main/java/org/apache/james/utils/IMAPMessageReader.java
index 0c9826f..9dbe6ee 100644
--- a/server/testing/src/main/java/org/apache/james/utils/IMAPMessageReader.java
+++ b/server/testing/src/main/java/org/apache/james/utils/IMAPMessageReader.java
@@ -22,6 +22,9 @@ package org.apache.james.utils;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
import org.apache.commons.net.imap.IMAPClient;
import org.awaitility.core.ConditionFactory;
@@ -34,6 +37,8 @@ import com.google.common.base.Splitter;
public class IMAPMessageReader extends ExternalResource implements Closeable,
AfterEachCallback {
+ private static final Pattern EXAMINE_EXISTS = Pattern.compile("^\\* (\\d+)
EXISTS$");
+ private static final int MESSAGE_NUMBER_MATCHING_GROUP = 1;
public static final String INBOX = "INBOX";
private final IMAPClient imapClient;
@@ -222,4 +227,14 @@ public class IMAPMessageReader extends ExternalResource
implements Closeable, Af
imapClient.sendCommand("GETQUOTAROOT " + mailbox);
return imapClient.getReplyString();
}
+
+ public long getMessageCount(String mailboxName) throws IOException {
+ imapClient.examine(mailboxName);
+ return Stream.of(imapClient.getReplyStrings())
+ .map(EXAMINE_EXISTS::matcher)
+ .filter(Matcher::matches)
+ .map(m -> m.group(MESSAGE_NUMBER_MATCHING_GROUP))
+ .mapToLong(Long::valueOf)
+ .sum();
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]