You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2017/06/21 08:01:24 UTC

[1/3] james-project git commit: JAMES-2063 Add tests on SelectedMailboxImpl for concurrent events

Repository: james-project
Updated Branches:
  refs/heads/master ce408bf81 -> be37b9c0c


JAMES-2063 Add tests on SelectedMailboxImpl for concurrent events


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b74db024
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b74db024
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b74db024

Branch: refs/heads/master
Commit: b74db024409fea9edeb84c571eb02e4863391ca6
Parents: ce408bf
Author: benwa <bt...@linagora.com>
Authored: Tue Jun 20 10:49:28 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Tue Jun 20 11:47:24 2017 +0700

----------------------------------------------------------------------
 protocols/imap/pom.xml                          |   5 +
 .../processor/base/SelectedMailboxImplTest.java | 172 +++++++++++++++++++
 2 files changed, 177 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/b74db024/protocols/imap/pom.xml
----------------------------------------------------------------------
diff --git a/protocols/imap/pom.xml b/protocols/imap/pom.xml
index c2f590d..12b9826 100644
--- a/protocols/imap/pom.xml
+++ b/protocols/imap/pom.xml
@@ -75,6 +75,11 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>commons-codec</groupId>

http://git-wip-us.apache.org/repos/asf/james-project/blob/b74db024/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java
new file mode 100644
index 0000000..a9e7144
--- /dev/null
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java
@@ -0,0 +1,172 @@
+/****************************************************************
+ * 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.imap.processor.base;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.mail.Flags;
+
+import org.apache.james.imap.api.ImapSessionUtils;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.mailbox.MailboxListener;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.model.MailboxConstants;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageMetaData;
+import org.apache.james.mailbox.model.SearchQuery;
+import org.apache.james.mailbox.store.SimpleMessageMetaData;
+import org.apache.james.mailbox.store.event.EventFactory;
+import org.apache.james.mailbox.store.mail.model.DefaultMessageId;
+import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+
+public class SelectedMailboxImplTest {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SelectedMailboxImplTest.class);
+    public static final MessageUid MESSAGE_UID_5 = MessageUid.of(5);
+
+    private ExecutorService executorService;
+    private MailboxManager mailboxManager;
+    private MessageManager messageManager;
+    private MailboxPath mailboxPath;
+    private ImapSession imapSession;
+    private Mailbox mailbox;
+
+    @Before
+    public void setUp() throws Exception {
+        executorService = Executors.newFixedThreadPool(1);
+
+        mailboxPath = new MailboxPath(MailboxConstants.USER_NAMESPACE, "tellier@linagora.com", MailboxConstants.INBOX);
+        mailboxManager = mock(MailboxManager.class);
+        messageManager = mock(MessageManager.class);
+        when(mailboxManager.getMailbox(eq(mailboxPath), any(MailboxSession.class))).thenReturn(messageManager);
+        when(messageManager.getApplicableFlags(any(MailboxSession.class))).thenReturn(new Flags());
+        when(messageManager.search(any(SearchQuery.class), any(MailboxSession.class)))
+            .then(sleepThenSearchAnswer());
+
+        imapSession = mock(ImapSession.class);
+        when(imapSession.getAttribute(ImapSessionUtils.MAILBOX_SESSION_ATTRIBUTE_SESSION_KEY)).thenReturn(mock(MailboxSession.class));
+
+        mailbox = mock(Mailbox.class);
+        when(mailbox.generateAssociatedPath()).thenReturn(mailboxPath);
+    }
+
+    @After
+    public void tearDown() {
+        executorService.shutdownNow();
+    }
+
+    @Ignore
+    @Test
+    public void concurrentEventShouldNotSkipUidEmmitedDuringInitialization() throws Exception {
+        final AtomicInteger success = new AtomicInteger(0);
+        doAnswer(generateEmitEventAnswer(success))
+            .when(mailboxManager)
+            .addListener(eq(mailboxPath), any(MailboxListener.class), any(MailboxSession.class));
+
+        SelectedMailboxImpl selectedMailbox = new SelectedMailboxImpl(
+            mailboxManager,
+            imapSession,
+            mailboxPath);
+
+        assertThat(selectedMailbox.getLastUid().get()).isEqualTo(MESSAGE_UID_5);
+    }
+
+    @Ignore
+    @Test
+    public void concurrentEventShouldBeSupportedDuringInitialisation() throws Exception {
+        final AtomicInteger success = new AtomicInteger(0);
+        doAnswer(generateEmitEventAnswer(success))
+            .when(mailboxManager)
+            .addListener(eq(mailboxPath), any(MailboxListener.class), any(MailboxSession.class));
+
+        new SelectedMailboxImpl(
+            mailboxManager,
+            imapSession,
+            mailboxPath);
+
+        assertThat(success.get())
+            .as("Get the incremented value in case of successful event processing.")
+            .isEqualTo(1);
+    }
+
+    private Answer<Iterator<MessageUid>> sleepThenSearchAnswer() {
+        return new Answer<Iterator<MessageUid>>() {
+            @Override
+            public Iterator<MessageUid> answer(InvocationOnMock invocation) throws Throwable {
+                Thread.sleep(1000);
+                return ImmutableList.of(MessageUid.of(1), MessageUid.of(3)).iterator();
+            }
+        };
+    }
+
+    private Answer generateEmitEventAnswer(final AtomicInteger success) {
+        return new Answer() {
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                Object[] args = invocation.getArguments();
+                final MailboxListener mailboxListener = (MailboxListener) args[1];
+                executorService.submit(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            emitEvent(mailboxListener);
+                            success.incrementAndGet();
+                        } catch (Exception e) {
+                            LOGGER.error("Error while processing event on a concurrent thread", e);
+                        }
+                    }
+                });
+                return null;
+            }
+        };
+    }
+
+    private void emitEvent(MailboxListener mailboxListener) {
+        TreeMap<MessageUid, MessageMetaData> result = new TreeMap<MessageUid, MessageMetaData>();
+        result.put(MESSAGE_UID_5, new SimpleMessageMetaData(MESSAGE_UID_5, 12, new Flags(), 38, new Date(), new DefaultMessageId()));
+        mailboxListener.event(new EventFactory().added(mock(MailboxSession.class), result, mailbox));
+    }
+}


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


[3/3] james-project git commit: JAMES-2058 Add new page on the website to configure Spring JPA with Postgres

Posted by bt...@apache.org.
JAMES-2058 Add new page on the website to configure Spring JPA with Postgres


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/be37b9c0
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/be37b9c0
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/be37b9c0

Branch: refs/heads/master
Commit: be37b9c0c1d6eb50df4ea06761b9b8013a7b6b0d
Parents: 53d7536
Author: quynhn <qn...@linagora.com>
Authored: Thu Jun 15 17:58:37 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Jun 21 14:59:04 2017 +0700

----------------------------------------------------------------------
 src/site/site.xml                               |   1 +
 .../xdoc/server/config-spring-jpa-postgres.xml  | 109 +++++++++++++++++++
 2 files changed, 110 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/be37b9c0/src/site/site.xml
----------------------------------------------------------------------
diff --git a/src/site/site.xml b/src/site/site.xml
index b73abec..9b7fd05 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -134,6 +134,7 @@
                         <item name="Guice" href="/server/config-guice.html" />
                         <item name="ElasticSearch" href="/server/config-elasticsearch.html" />
                         <item name="Cassandra" href="/server/config-cassandra.html" />
+                        <item name="Spring JPA Postgres" href="/server/config-spring-jpa-postgres.html" />
                         <item name="Quota" href="/server/config-quota.html" />
                         <item name="Events" href="/server/config-events.html" />
                     </item>

http://git-wip-us.apache.org/repos/asf/james-project/blob/be37b9c0/src/site/xdoc/server/config-spring-jpa-postgres.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/server/config-spring-jpa-postgres.xml b/src/site/xdoc/server/config-spring-jpa-postgres.xml
new file mode 100644
index 0000000..d88824a
--- /dev/null
+++ b/src/site/xdoc/server/config-spring-jpa-postgres.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0"?>
+<!--
+  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.    
+-->
+<document>
+
+ <properties>
+  <title>Apache James Server 3 - Spring JPA With Postgres Configuration</title>
+ </properties>
+
+<body>
+
+
+    <section name="Introduction">
+      <p>Consult <a href="http://james.apache.org/server/config-system.html">System Configuration</a> to get template, some examples and hints for the configuration with JPA.</p>
+    </section>
+
+    <section name="Current Supported Relational Database">
+      <p>James supports Derby as a default database, you do not need to do any additional configuration if you are using Derby</p>
+    </section>
+
+    <section name="Spring JPA With Postgres Configuration">
+      <p>If you wish to use Postgres as a database, please follow those steps to configure it</p>
+      <subsection name="Step 1: Create database on Postgres">
+
+        <p>You need to install Postgres or run Postgres with Docker</p>
+
+        <p>Example to install it on Debian:</p>
+        <source>
+          sudo apt-get update && sudo apt-get install postgresql-9.4 postgresql-client-9.4
+        </source>
+        <p>Example to pull and launch Postgres on docker</p>
+        <source>
+          docker run --detach --name postgres library/postgres
+        </source>
+        <p>Postgres does not create database on the fly so you need to create the database manually if it does not exist. Here is the command to perform this action: </p>
+
+        <source>psql --username postgres --tuples-only --command "SELECT 1 FROM pg_database WHERE dataname = '<strong><italic>database_name</italic></strong>'" \
+          | grep -q 1 || psql --username postgres --command "CREATE DATABASE <strong><italic>database_name</italic></strong>"</source>
+
+        <dl>
+          <dt><strong>database_name</strong></dt>
+          <dd>The name of database</dd>
+        </dl>
+
+      </subsection>
+
+      <subsection name="Step 2: Point to the database in configuration file">
+        <p>Change the content of <italic>james-database.properties</italic> and point to the 'database_name' created earlier</p>
+        <source>
+          database.driverClassName=org.postgresql.Driver
+          database.url=jdbc:postgresql://<strong>ip_of_postgres</strong>/<strong>database_name</strong>
+          database.username=postgres
+          database.password=postgres
+
+          vendorAdapter.database=POSTGRESQL
+        </source>
+        <p>If you are using the James Spring docker image. You need to customise the configuration file of the docker container with those steps:</p>
+          <ul>
+            <li>Create a new james-database.properties file with above content</li>
+            <li>Then you can add the configuration file to docker container using --volume flag</li>
+              <source>
+                --volume path_to_folder_which_contain_configuration_file/james-database.properties:/root/james-server-app-3.0.0-RC2-SNAPSHOT/conf/james-database.properties
+              </source>
+          </ul>
+      </subsection>
+
+      <subsection name="Step 3: Copy driver class to the right place">
+        <p>Follow this link <a href="https://jdbc.postgresql.org/download.html">Postgres Driver</a> to download the right version of the JDBC driver.</p>
+        <p>Copy that jar file to the <strong>conf/lib/</strong> folder of Spring James</p>
+        <p>If you are using the James Spring docker image, download the jar file then make it available on the classpath of your James instance using an additional docker volume: </p>
+        <source>
+          --volume path_to_folder_which_contain_jar_file/:/root/james-server-app-3.0.0-RC2-SNAPSHOT/conf/lib/
+        </source>
+      </subsection>
+
+      <subsection name="Step 4: Restart James">
+        <p>Follow the guide on <a href="http://james.apache.org/server/install.html">Restart and Testing</a> to restart James</p>
+
+        <p>If you are using the James Spring docker image, launch James docker or just stop and start docker container again if it ran. </p>
+
+        <p>Example to launch James Spring docker image with the volume</p>
+        <source>
+          docker run --volume path_to_folder_which_contain_configuration_file/james-database.properties:/root/james-server-app-3.0.0-RC2-SNAPSHOT/conf/james-database.properties \
+          --volume path_to_folder_which_contain_jar_file/:/root/james-server-app-3.0.0-RC2-SNAPSHOT/conf/lib/ \
+          --hostname localhost --publish "25:25" --publish "110:110" --publish "143:143" --publish "465:465" --publish "587:587" --publish "993:993" \
+          --name james_run linagora/james-jpa-spring
+        </source>
+      </subsection>
+    </section>
+
+</body>
+
+</document>


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


[2/3] james-project git commit: JAMES-2063 SelectedMailboxImpl should allow concurrent events when initializing

Posted by bt...@apache.org.
JAMES-2063 SelectedMailboxImpl should allow concurrent events when initializing

Also reduce lock contention. Avoid locking while building conversion and reading from the mailbox, to avoid delaying concurrent sessions.


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/53d75365
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/53d75365
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/53d75365

Branch: refs/heads/master
Commit: 53d75365fc2de63c5c8ab7205b91f2695e8dccd5
Parents: b74db02
Author: benwa <bt...@linagora.com>
Authored: Tue Jun 20 10:55:21 2017 +0700
Committer: benwa <bt...@linagora.com>
Committed: Wed Jun 21 14:58:20 2017 +0700

----------------------------------------------------------------------
 protocols/imap/pom.xml                          |   5 +-
 .../processor/base/SelectedMailboxImpl.java     |  12 +-
 .../imap/processor/base/UidMsnConverter.java    |  17 ++-
 .../processor/base/SelectedMailboxImplTest.java |  44 +++----
 .../processor/base/UidMsnConverterTest.java     | 120 ++++++++++++++++---
 .../imap/src/test/resources/logback-test.xml    |  24 ++++
 6 files changed, 170 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/53d75365/protocols/imap/pom.xml
----------------------------------------------------------------------
diff --git a/protocols/imap/pom.xml b/protocols/imap/pom.xml
index 12b9826..78ac115 100644
--- a/protocols/imap/pom.xml
+++ b/protocols/imap/pom.xml
@@ -76,8 +76,9 @@
             <artifactId>slf4j-api</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-simple</artifactId>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.1.7</version>
             <scope>test</scope>
         </dependency>
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/53d75365/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
index d929b76..d56c6ef 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
@@ -44,6 +44,7 @@ import org.apache.james.mailbox.model.SearchQuery;
 import org.apache.james.mailbox.model.UpdatedFlags;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
 
 /**
  * Default implementation of {@link SelectedMailbox}
@@ -84,17 +85,14 @@ public class SelectedMailboxImpl implements SelectedMailbox, MailboxListener{
 
         MailboxSession mailboxSession = ImapSessionUtils.getMailboxSession(session);
 
+        uidMsnConverter = new UidMsnConverter();
+
         mailboxManager.addListener(path, this, mailboxSession);
 
         MessageManager messageManager = mailboxManager.getMailbox(path, mailboxSession);
         applicableFlags = messageManager.getApplicableFlags(mailboxSession);
-        uidMsnConverter = getUidMsnConverter(mailboxSession, messageManager);
-    }
-    
-    private UidMsnConverter getUidMsnConverter(MailboxSession mailboxSession , MessageManager messageManager) throws MailboxException {
-        return new UidMsnConverter(
-                messageManager.search(
-                        new SearchQuery(SearchQuery.all()), mailboxSession));
+        uidMsnConverter.addAll(ImmutableList.copyOf(
+            messageManager.search(new SearchQuery(SearchQuery.all()), mailboxSession)));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/53d75365/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
index 9276e27..9e09053 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/base/UidMsnConverter.java
@@ -21,7 +21,9 @@ package org.apache.james.imap.processor.base;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.TreeSet;
 
 import org.apache.james.mailbox.MessageUid;
 
@@ -35,9 +37,16 @@ public class UidMsnConverter {
 
     @VisibleForTesting final ArrayList<MessageUid> uids;
 
-    public UidMsnConverter(Iterator<MessageUid> iterator) {
-        uids = Lists.newArrayList(iterator);
-        Collections.sort(uids);
+    public UidMsnConverter() {
+        this.uids = Lists.newArrayList();
+    }
+
+    public synchronized void addAll(List<MessageUid> addedUids) {
+        TreeSet<MessageUid> tmp = new TreeSet<MessageUid>();
+        tmp.addAll(uids);
+        tmp.addAll(addedUids);
+        uids.clear();
+        uids.addAll(tmp);
     }
 
     public synchronized Optional<Integer> getMsn(MessageUid uid) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/53d75365/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java
index a9e7144..cdeef78 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/SelectedMailboxImplTest.java
@@ -52,7 +52,6 @@ import org.apache.james.mailbox.store.mail.model.DefaultMessageId;
 import org.apache.james.mailbox.store.mail.model.Mailbox;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -65,7 +64,9 @@ import com.google.common.collect.ImmutableList;
 public class SelectedMailboxImplTest {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(SelectedMailboxImplTest.class);
-    public static final MessageUid MESSAGE_UID_5 = MessageUid.of(5);
+    private static final MessageUid EMITTED_EVENT_UID = MessageUid.of(5);
+    private static final int MOD_SEQ = 12;
+    private static final int SIZE = 38;
 
     private ExecutorService executorService;
     private MailboxManager mailboxManager;
@@ -77,20 +78,23 @@ public class SelectedMailboxImplTest {
     @Before
     public void setUp() throws Exception {
         executorService = Executors.newFixedThreadPool(1);
-
         mailboxPath = new MailboxPath(MailboxConstants.USER_NAMESPACE, "tellier@linagora.com", MailboxConstants.INBOX);
         mailboxManager = mock(MailboxManager.class);
         messageManager = mock(MessageManager.class);
-        when(mailboxManager.getMailbox(eq(mailboxPath), any(MailboxSession.class))).thenReturn(messageManager);
-        when(messageManager.getApplicableFlags(any(MailboxSession.class))).thenReturn(new Flags());
+        imapSession = mock(ImapSession.class);
+        mailbox = mock(Mailbox.class);
+
+        when(mailboxManager.getMailbox(eq(mailboxPath), any(MailboxSession.class)))
+            .thenReturn(messageManager);
+        when(messageManager.getApplicableFlags(any(MailboxSession.class)))
+            .thenReturn(new Flags());
         when(messageManager.search(any(SearchQuery.class), any(MailboxSession.class)))
-            .then(sleepThenSearchAnswer());
+            .then(delayedSearchAnswer());
 
-        imapSession = mock(ImapSession.class);
         when(imapSession.getAttribute(ImapSessionUtils.MAILBOX_SESSION_ATTRIBUTE_SESSION_KEY)).thenReturn(mock(MailboxSession.class));
 
-        mailbox = mock(Mailbox.class);
-        when(mailbox.generateAssociatedPath()).thenReturn(mailboxPath);
+        when(mailbox.generateAssociatedPath())
+            .thenReturn(mailboxPath);
     }
 
     @After
@@ -98,11 +102,10 @@ public class SelectedMailboxImplTest {
         executorService.shutdownNow();
     }
 
-    @Ignore
     @Test
-    public void concurrentEventShouldNotSkipUidEmmitedDuringInitialization() throws Exception {
-        final AtomicInteger success = new AtomicInteger(0);
-        doAnswer(generateEmitEventAnswer(success))
+    public void concurrentEventShouldNotSkipAddedEventsEmittedDuringInitialisation() throws Exception {
+        final AtomicInteger successCount = new AtomicInteger(0);
+        doAnswer(generateEmitEventAnswer(successCount))
             .when(mailboxManager)
             .addListener(eq(mailboxPath), any(MailboxListener.class), any(MailboxSession.class));
 
@@ -111,14 +114,13 @@ public class SelectedMailboxImplTest {
             imapSession,
             mailboxPath);
 
-        assertThat(selectedMailbox.getLastUid().get()).isEqualTo(MESSAGE_UID_5);
+        assertThat(selectedMailbox.getLastUid().get()).isEqualTo(EMITTED_EVENT_UID);
     }
 
-    @Ignore
     @Test
-    public void concurrentEventShouldBeSupportedDuringInitialisation() throws Exception {
-        final AtomicInteger success = new AtomicInteger(0);
-        doAnswer(generateEmitEventAnswer(success))
+    public void concurrentEventShouldBeProcessedSuccessfullyDuringInitialisation() throws Exception {
+        final AtomicInteger successCount = new AtomicInteger(0);
+        doAnswer(generateEmitEventAnswer(successCount))
             .when(mailboxManager)
             .addListener(eq(mailboxPath), any(MailboxListener.class), any(MailboxSession.class));
 
@@ -127,12 +129,12 @@ public class SelectedMailboxImplTest {
             imapSession,
             mailboxPath);
 
-        assertThat(success.get())
+        assertThat(successCount.get())
             .as("Get the incremented value in case of successful event processing.")
             .isEqualTo(1);
     }
 
-    private Answer<Iterator<MessageUid>> sleepThenSearchAnswer() {
+    private Answer<Iterator<MessageUid>> delayedSearchAnswer() {
         return new Answer<Iterator<MessageUid>>() {
             @Override
             public Iterator<MessageUid> answer(InvocationOnMock invocation) throws Throwable {
@@ -166,7 +168,7 @@ public class SelectedMailboxImplTest {
 
     private void emitEvent(MailboxListener mailboxListener) {
         TreeMap<MessageUid, MessageMetaData> result = new TreeMap<MessageUid, MessageMetaData>();
-        result.put(MESSAGE_UID_5, new SimpleMessageMetaData(MESSAGE_UID_5, 12, new Flags(), 38, new Date(), new DefaultMessageId()));
+        result.put(EMITTED_EVENT_UID, new SimpleMessageMetaData(EMITTED_EVENT_UID, MOD_SEQ, new Flags(), SIZE, new Date(), new DefaultMessageId()));
         mailboxListener.event(new EventFactory().added(mock(MailboxSession.class), result, mailbox));
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/53d75365/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
index 4606e83..ae81f2b 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/base/UidMsnConverterTest.java
@@ -42,7 +42,7 @@ public class UidMsnConverterTest {
 
     @Before
     public void setUp() {
-        testee = new UidMsnConverter(ImmutableList.<MessageUid>of().iterator());
+        testee = new UidMsnConverter();
         messageUid1 = MessageUid.of(1);
         messageUid2 = MessageUid.of(2);
         messageUid3 = MessageUid.of(3);
@@ -178,7 +178,7 @@ public class UidMsnConverterTest {
     }
 
     @Test
-    public void removeShouldKeepAValidMappingWhenDeletingBeginning() {
+    public void removeShouldKeepAMonoticMSNToUIDConversionMappingWhenDeletingBeginning() {
         testee.addUid(messageUid1);
         testee.addUid(messageUid2);
         testee.addUid(messageUid3);
@@ -194,7 +194,7 @@ public class UidMsnConverterTest {
     }
 
     @Test
-    public void removeShouldKeepAValidMappingWhenDeletingEnd() {
+    public void removeShouldKeepAMonoticMSNToUIDConversionMappingWhenDeletingEnd() {
         testee.addUid(messageUid1);
         testee.addUid(messageUid2);
         testee.addUid(messageUid3);
@@ -210,7 +210,7 @@ public class UidMsnConverterTest {
     }
 
     @Test
-    public void removeShouldKeepAValidMappingWhenDeletingMiddle() {
+    public void removeShouldKeepAMonoticMSNToUIDConversionMappingWhenDeletingMiddle() {
         testee.addUid(messageUid1);
         testee.addUid(messageUid2);
         testee.addUid(messageUid3);
@@ -233,7 +233,7 @@ public class UidMsnConverterTest {
         testee.addUid(messageUid4);
 
         assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
-            .containsOnlyElementsOf(ImmutableMap.of(
+            .containsExactlyElementsOf(ImmutableMap.of(
                 1, messageUid1,
                 2, messageUid2,
                 3, messageUid3,
@@ -241,14 +241,14 @@ public class UidMsnConverterTest {
     }
 
     @Test
-    public void addUidShouldLeadToValidConversionWhenInsertInFirstPosition() {
+    public void addUidShouldLeadToMonoticMSNToUIDConversionWhenInsertInFirstPosition() {
         testee.addUid(messageUid2);
         testee.addUid(messageUid3);
         testee.addUid(messageUid4);
         testee.addUid(messageUid1);
 
         assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
-            .containsOnlyElementsOf(ImmutableMap.of(
+            .containsExactlyElementsOf(ImmutableMap.of(
                 1, messageUid1,
                 2, messageUid2,
                 3, messageUid3,
@@ -256,15 +256,99 @@ public class UidMsnConverterTest {
     }
 
     @Test
-    public void constructorWithOutOfOrderIteratorShouldLeadToValidConversion() {
-        testee = new UidMsnConverter(ImmutableList.of(messageUid2,
+    public void addAllShouldLeadToMonoticMSNToUIDConversion() {
+        testee.addAll(ImmutableList.of(
+            messageUid1,
+            messageUid2,
+            messageUid3,
+            messageUid4));
+
+        assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
+            .containsExactlyElementsOf(ImmutableMap.of(
+                1, messageUid1,
+                2, messageUid2,
+                3, messageUid3,
+                4, messageUid4).entrySet());
+    }
+
+    @Test
+    public void addAllShouldRemoveDuplicates() {
+        testee.addAll(ImmutableList.of(
+            messageUid1,
+            messageUid2,
+            messageUid2,
+            messageUid3,
+            messageUid4));
+
+        assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
+            .containsExactlyElementsOf(ImmutableMap.of(
+                1, messageUid1,
+                2, messageUid2,
+                3, messageUid3,
+                4, messageUid4).entrySet());
+    }
+
+    @Test
+    public void addAllShouldDeduplicateElements() {
+        testee.addUid(messageUid1);
+
+        testee.addAll(ImmutableList.of(
+            messageUid1,
+            messageUid2,
+            messageUid3,
+            messageUid4));
+
+        assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
+            .containsExactlyElementsOf(ImmutableMap.of(
+                1, messageUid1,
+                2, messageUid2,
+                3, messageUid3,
+                4, messageUid4).entrySet());
+    }
+
+    @Test
+    public void addAllShouldMergeWithPreviousData() {
+        testee.addUid(messageUid1);
+
+        testee.addAll(ImmutableList.of(messageUid2,
+            messageUid3,
+            messageUid4));
+
+        assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
+            .containsExactlyElementsOf(ImmutableMap.of(
+                1, messageUid1,
+                2, messageUid2,
+                3, messageUid3,
+                4, messageUid4).entrySet());
+    }
+
+    @Test
+    public void addAllShouldMergeAndDeduplicatePreviousData() {
+        testee.addUid(messageUid1);
+        testee.addUid(messageUid3);
+
+        testee.addAll(ImmutableList.of(messageUid2,
+            messageUid3,
+            messageUid4));
+
+        assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
+            .containsExactlyElementsOf(ImmutableMap.of(
+                1, messageUid1,
+                2, messageUid2,
+                3, messageUid3,
+                4, messageUid4).entrySet());
+    }
+
+    @Test
+    public void addAllWithOutOfOrderIteratorShouldLeadToMonoticMSNToUIDConversion() {
+        testee.addAll(ImmutableList.of(
+            messageUid2,
             messageUid3,
             messageUid4,
-            messageUid1)
-            .iterator());
+            messageUid1));
 
         assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
-            .containsOnlyElementsOf(ImmutableMap.of(
+            .containsExactlyElementsOf(ImmutableMap.of(
                 1, messageUid1,
                 2, messageUid2,
                 3, messageUid3,
@@ -281,7 +365,7 @@ public class UidMsnConverterTest {
     }
 
     @Test
-    public void addAndRemoveShouldLeadToValidConversionWhenMixed() throws Exception {
+    public void addAndRemoveShouldLeadToMonoticMSNToUIDConversionWhenMixed() throws Exception {
         final int initialCount = 1000;
         for (int i = 1; i <= initialCount; i++) {
             testee.addUid(MessageUid.of(i));
@@ -307,11 +391,11 @@ public class UidMsnConverterTest {
             resultBuilder.put(i, MessageUid.of(initialCount + i));
         }
         assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
-            .containsOnlyElementsOf(resultBuilder.build().entrySet());
+            .containsExactlyElementsOf(resultBuilder.build().entrySet());
     }
 
     @Test
-    public void addShouldLeadToValidConversionWhenConcurrent() throws Exception {
+    public void addShouldLeadToMonoticMSNToUIDConversionWhenConcurrent() throws Exception {
         final int operationCount = 1000;
         int threadCount = 2;
 
@@ -330,11 +414,11 @@ public class UidMsnConverterTest {
             resultBuilder.put(i, MessageUid.of(i));
         }
         assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
-            .containsOnlyElementsOf(resultBuilder.build().entrySet());
+            .containsExactlyElementsOf(resultBuilder.build().entrySet());
     }
 
     @Test
-    public void removeShouldLeadToValidConversionWhenConcurrent() throws Exception {
+    public void removeShouldLeadToMonoticMSNToUIDConversionWhenConcurrent() throws Exception {
         final int operationCount = 1000;
         int threadCount = 2;
         for (int i = 1; i <= operationCount * (threadCount + 1); i++) {
@@ -356,7 +440,7 @@ public class UidMsnConverterTest {
             resultBuilder.put(i, MessageUid.of((threadCount * operationCount) + i));
         }
         assertThat(mapTesteeInternalDataToMsnByUid().entrySet())
-            .containsOnlyElementsOf(resultBuilder.build().entrySet());
+            .containsExactlyElementsOf(resultBuilder.build().entrySet());
     }
 
     private Map<Integer, MessageUid> mapTesteeInternalDataToMsnByUid() {

http://git-wip-us.apache.org/repos/asf/james-project/blob/53d75365/protocols/imap/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/protocols/imap/src/test/resources/logback-test.xml b/protocols/imap/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..5e4c459
--- /dev/null
+++ b/protocols/imap/src/test/resources/logback-test.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+        <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+                <resetJUL>true</resetJUL>
+        </contextListener>
+
+        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+                <encoder>
+                        <pattern>%d{HH:mm:ss.SSS} %highlight([%-5level]) %logger{15} - %msg%n%rEx</pattern>
+                        <immediateFlush>false</immediateFlush>
+                </encoder>
+        </appender>
+
+        <root level="ERROR">
+                <appender-ref ref="CONSOLE" />
+        </root>
+
+
+        <logger name="org.apache.james" level="DEBUG" >
+                <appender-ref ref="CONSOLE" />
+        </logger>
+
+</configuration>


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