Skip to content

Commit

Permalink
MAILBOX-259 Adding tests for reindexing registration listeners
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/james/project/trunk@1717083 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
chibenwa committed Nov 29, 2015
1 parent 6416574 commit 288cb62
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 14 deletions.
Expand Up @@ -19,6 +19,7 @@

package org.apache.james.mailbox.indexer;

import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
Expand Down Expand Up @@ -80,18 +81,16 @@ public void reIndex(MailboxPath path) throws MailboxException {

public void reIndex() throws MailboxException {
MailboxSession mailboxSession = mailboxManager.createSystemSession("re-indexing", LOGGER);
LOGGER.info("Starting a full reindex");
List<MailboxPath> mailboxPaths = mailboxManager.list(mailboxSession);
GlobalRegistration globalRegistration = new GlobalRegistration();
mailboxManager.addGlobalListener(globalRegistration, mailboxSession);
try {
for (MailboxPath mailboxPath : mailboxPaths) {
if (globalRegistration.pathNeedsIndexing(mailboxPath)) {
reIndex(mailboxPath, mailboxSession);
}
}
handleFullReindexingIterations(mailboxPaths, globalRegistration);
} finally {
mailboxManager.removeGlobalListener(globalRegistration, mailboxSession);
}
LOGGER.info("Full reindex finished");
}

private void reIndex(MailboxPath path, MailboxSession mailboxSession) throws MailboxException {
Expand All @@ -101,7 +100,7 @@ private void reIndex(MailboxPath path, MailboxSession mailboxSession) throws Mai
messageSearchIndex.delete(mailboxSession, mailbox, MessageRange.all());
mailboxManager.addListener(path, mailboxRegistration, mailboxSession);
try {
handleIterations(mailboxSession,
handleMailboxIndexingIterations(mailboxSession,
mailboxRegistration,
mailbox,
mailboxSessionMapperFactory.getMessageMapper(mailboxSession)
Expand All @@ -115,7 +114,20 @@ private void reIndex(MailboxPath path, MailboxSession mailboxSession) throws Mai
}
}

private void handleIterations(MailboxSession mailboxSession, MailboxRegistration mailboxRegistration, Mailbox<Id> mailbox, Iterator<Message<Id>> iterator) throws MailboxException {
private void handleFullReindexingIterations(List<MailboxPath> mailboxPaths, GlobalRegistration globalRegistration) throws MailboxException {
for (MailboxPath mailboxPath : mailboxPaths) {
Optional<MailboxPath> pathToIndex = globalRegistration.getPathToIndex(mailboxPath);
if (pathToIndex.isPresent()) {
try {
reIndex(pathToIndex.get());
} catch(Throwable e) {
LOGGER.error("Error while proceeding to full reindexing on {}", pathToIndex.get(), e);
}
}
}
}

private void handleMailboxIndexingIterations(MailboxSession mailboxSession, MailboxRegistration mailboxRegistration, Mailbox<Id> mailbox, Iterator<Message<Id>> iterator) throws MailboxException {
while (iterator.hasNext()) {
Message<Id> message = iterator.next();
ImpactingMessageEvent impactingMessageEvent = findMostRelevant(mailboxRegistration.getImpactingEvents(message.getUid()));
Expand Down
Expand Up @@ -19,6 +19,7 @@

package org.apache.james.mailbox.indexer.events;

import com.google.common.base.Objects;
import org.apache.james.mailbox.model.MailboxPath;

import javax.mail.Flags;
Expand Down Expand Up @@ -53,4 +54,18 @@ public ImpactingEventType getType() {
public Flags getFlags() {
return flags;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
FlagsMessageEvent that = (FlagsMessageEvent) o;
return Objects.equal(uid, that.uid) &&
Objects.equal(mailboxPath, that.mailboxPath) &&
Objects.equal(flags, that.flags);
}

@Override
public int hashCode() {
return Objects.hashCode(uid, mailboxPath, flags);
}
}
Expand Up @@ -19,6 +19,7 @@

package org.apache.james.mailbox.indexer.events;

import com.google.common.base.Objects;
import org.apache.james.mailbox.model.MailboxPath;

public class MessageDeletedEvent implements ImpactingMessageEvent {
Expand All @@ -45,4 +46,16 @@ public MailboxPath getMailboxPath() {
public ImpactingEventType getType() {
return ImpactingEventType.Deletion;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
MessageDeletedEvent that = (MessageDeletedEvent) o;
return Objects.equal(uid, that.uid) && Objects.equal(mailboxPath, that.mailboxPath);
}

@Override
public int hashCode() {
return Objects.hashCode(uid, mailboxPath);
}
}
Expand Up @@ -19,21 +19,28 @@

package org.apache.james.mailbox.indexer.registrations;

import com.google.common.base.Optional;
import org.apache.james.mailbox.MailboxListener;
import org.apache.james.mailbox.model.MailboxPath;

import java.util.concurrent.ConcurrentHashMap;

public class GlobalRegistration implements MailboxListener {

private final ConcurrentHashMap<MailboxPath, Boolean> impactingEvents;
private final ConcurrentHashMap<MailboxPath, Boolean> isPathDeleted;
private final ConcurrentHashMap<MailboxPath, MailboxPath> nameCorrespondence;

public GlobalRegistration() {
this.impactingEvents = new ConcurrentHashMap<MailboxPath, Boolean>();
this.isPathDeleted = new ConcurrentHashMap<MailboxPath, Boolean>();
this.nameCorrespondence = new ConcurrentHashMap<MailboxPath, MailboxPath>();
}

public boolean pathNeedsIndexing(MailboxPath mailboxPath) {
return impactingEvents.get(mailboxPath) != null;
public Optional<MailboxPath> getPathToIndex(MailboxPath mailboxPath) {
if (isPathDeleted.get(mailboxPath) != null) {
return Optional.absent();
}
return Optional.of(
Optional.fromNullable(nameCorrespondence.get(mailboxPath)).or(mailboxPath));
}

@Override
Expand All @@ -49,9 +56,9 @@ public ExecutionMode getExecutionMode() {
@Override
public void event(Event event) {
if (event instanceof MailboxDeletion) {
impactingEvents.put(event.getMailboxPath(), true);
} else if (event instanceof Expunged) {
impactingEvents.put(event.getMailboxPath(), true);
isPathDeleted.put(event.getMailboxPath(), true);
} else if (event instanceof MailboxRenamed) {
nameCorrespondence.put(event.getMailboxPath(), ((MailboxRenamed) event).getNewPath());
}
}
}
@@ -0,0 +1,79 @@
/****************************************************************
* 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.indexer.registrations;

import static org.assertj.core.api.Assertions.assertThat;

import com.google.common.base.Optional;
import org.apache.james.mailbox.MailboxListener;
import org.apache.james.mailbox.mock.MockMailboxSession;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.store.TestId;
import org.apache.james.mailbox.store.event.EventFactory;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
import org.junit.Before;
import org.junit.Test;

public class GlobalRegistrationTest {

public static final MockMailboxSession SESSION = new MockMailboxSession("test");
public static final MailboxPath INBOX = new MailboxPath("#private", "btellier@apache.org", "INBOX");
public static final MailboxPath NEW_PATH = new MailboxPath("#private", "btellier@apache.org", "INBOX.new");
public static final int UID_VALIDITY = 45;
public static final SimpleMailbox<TestId> MAILBOX = new SimpleMailbox<TestId>(INBOX, UID_VALIDITY);
public static final SimpleMailbox<TestId> NEW_MAILBOX = new SimpleMailbox<TestId>(NEW_PATH, UID_VALIDITY);

private GlobalRegistration globalRegistration;
private EventFactory<TestId> eventFactory;

@Before
public void setUp() {
eventFactory = new EventFactory<TestId>();
globalRegistration = new GlobalRegistration();
}

@Test
public void pathToIndexShouldNotBeChangedByDefault() {
assertThat(globalRegistration.getPathToIndex(INBOX).get()).isEqualTo(INBOX);
}

@Test
public void pathToIndexShouldNotBeChangedByAddedEvents() {
MailboxListener.Event event = eventFactory.mailboxAdded(SESSION, MAILBOX);
globalRegistration.event(event);
assertThat(globalRegistration.getPathToIndex(INBOX).get()).isEqualTo(INBOX);
}

@Test
public void pathToIndexShouldBeNullifiedByDeletedEvents() {
MailboxListener.Event event = eventFactory.mailboxDeleted(SESSION, MAILBOX);
globalRegistration.event(event);
assertThat(globalRegistration.getPathToIndex(INBOX)).isEqualTo(Optional.absent());
}

@Test
public void pathToIndexShouldBeModifiedByRenamedEvents() {
MailboxListener.Event event = eventFactory.mailboxRenamed(SESSION, INBOX, NEW_MAILBOX);
globalRegistration.event(event);
assertThat(globalRegistration.getPathToIndex(INBOX).get()).isEqualTo(NEW_PATH);
}


}
@@ -0,0 +1,96 @@
/****************************************************************
* 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.indexer.registrations;

import static org.assertj.core.api.Assertions.assertThat;

import com.google.common.collect.Lists;
import org.apache.james.mailbox.MailboxListener;
import org.apache.james.mailbox.indexer.events.FlagsMessageEvent;
import org.apache.james.mailbox.indexer.events.MessageDeletedEvent;
import org.apache.james.mailbox.mock.MockMailboxSession;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.MessageMetaData;
import org.apache.james.mailbox.model.UpdatedFlags;
import org.apache.james.mailbox.store.SimpleMessageMetaData;
import org.apache.james.mailbox.store.TestId;
import org.apache.james.mailbox.store.event.EventFactory;
import org.apache.james.mailbox.store.mail.model.impl.SimpleMailbox;
import org.junit.Before;
import org.junit.Test;

import javax.mail.Flags;
import java.util.Date;
import java.util.TreeMap;

public class MailboxRegistrationTest {

public static final MailboxPath INBOX = new MailboxPath("#private", "btellier@apache.org", "INBOX");
public static final Long UID = 18L;
public static final int UID_VALIDITY = 45;
public static final SimpleMailbox<TestId> MAILBOX = new SimpleMailbox<TestId>(INBOX, UID_VALIDITY);
public static final MockMailboxSession SESSION = new MockMailboxSession("test");
public static final int MOD_SEQ = 21;
public static final int SIZE = 41;
public static final Flags NEW_FLAGS = new Flags(Flags.Flag.ANSWERED);
private MailboxRegistration mailboxRegistration;
private EventFactory<TestId> eventFactory;

@Before
public void setUp() {
eventFactory = new EventFactory<TestId>();
mailboxRegistration = new MailboxRegistration(INBOX);
}

@Test
public void reportedEventsShouldBeInitiallyEmpty() {
assertThat(mailboxRegistration.getImpactingEvents(UID)).isEmpty();
}


@Test
public void AddedEventsShouldNotBeReported() {
TreeMap<Long, MessageMetaData> treeMap = new TreeMap<Long, MessageMetaData>();
treeMap.put(UID, new SimpleMessageMetaData(UID, MOD_SEQ, new Flags(), SIZE, new Date()));
MailboxListener.Event event = eventFactory.added(SESSION, treeMap, MAILBOX);
mailboxRegistration.event(event);
assertThat(mailboxRegistration.getImpactingEvents(UID)).isEmpty();
}

@Test
public void ExpungedEventsShouldBeReported() {
TreeMap<Long, MessageMetaData> treeMap = new TreeMap<Long, MessageMetaData>();
treeMap.put(UID, new SimpleMessageMetaData(UID, MOD_SEQ, new Flags(), SIZE, new Date()));
MailboxListener.Event event = eventFactory.expunged(SESSION, treeMap, MAILBOX);
mailboxRegistration.event(event);
assertThat(mailboxRegistration.getImpactingEvents(UID)).containsExactly(new MessageDeletedEvent(INBOX, UID));
}

@Test
public void FlagsEventsShouldBeReported() {
MailboxListener.Event event = eventFactory.flagsUpdated(SESSION,
Lists.newArrayList(UID),
MAILBOX,
Lists.newArrayList(new UpdatedFlags(UID, MOD_SEQ, new Flags(), NEW_FLAGS)));
mailboxRegistration.event(event);
assertThat(mailboxRegistration.getImpactingEvents(UID)).containsExactly(new FlagsMessageEvent(INBOX, UID, NEW_FLAGS));
}

}

0 comments on commit 288cb62

Please sign in to comment.