james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From adup...@apache.org
Subject [james-project] branch master updated: JAMES-2704 Add Mailet to randomly assign messages to users
Date Wed, 10 Apr 2019 09:00:56 GMT
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 <gdifolco@linagora.com>
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 = "to@any.com";
+    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: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Mime
View raw message