Skip to content

Commit

Permalink
[devscout] actually consume the iterators in ManageableMailQueueContract
Browse files Browse the repository at this point in the history
The previous implementation using `Iterators.consumingIterator`
doesn't actually consume anything. It only wraps the iterator it receives in an interator that removes the items from the underlying iterator when next is called.

We implemented a very simple : consumeIterator method to actually consume and therefore trigger the potential concurrency issues the tests were trying to protect against.

Doing so raised a failing test in ActiveMQMailQueueBlobTest.
  • Loading branch information
jeantil committed Sep 25, 2024
1 parent 314b6a7 commit f2a56fc
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.activemq.broker.BrokerService;
import org.apache.commons.io.FileUtils;
import org.apache.james.filesystem.api.FileSystem;
import org.apache.james.junit.categories.Unstable;
import org.apache.james.metrics.api.GaugeRegistry;
import org.apache.james.metrics.api.MetricFactory;
import org.apache.james.queue.api.DelayedManageableMailQueueContract;
Expand Down Expand Up @@ -157,6 +158,17 @@ public void delayedEmailsShouldBeDeletedWhenMixedWithOtherEmails() {

}

@Tag(Unstable.TAG)
@Test
@Override
public void browseShouldNotFailWhenConcurrentClearWhenIterating() throws Exception {
// This test used to pass because the assertion did not actually check anything
// it used Iterators.consumingIterator which only wraps the underlying iterator without
// actually consuming it. When replaced with an actual consumption this implementation started
// failing.
DelayedManageableMailQueueContract.super.browseShouldNotFailWhenConcurrentClearWhenIterating();
}

@Test
void computeNextDeliveryTimestampShouldReturnLongMaxWhenOverflow() {
long deliveryTimestamp = mailQueue.computeNextDeliveryTimestamp(ChronoUnit.FOREVER.getDuration());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static org.assertj.core.api.SoftAssertions.assertSoftly;

import java.time.Duration;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -41,10 +42,12 @@

import org.apache.james.core.MailAddress;
import org.apache.james.core.builder.MimeMessageBuilder;
import org.apache.james.junit.categories.Unstable;
import org.apache.mailet.Attribute;
import org.apache.mailet.Mail;
import org.apache.mailet.base.MailAddressFixture;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -53,7 +56,6 @@

import com.github.fge.lambdas.Throwing;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -217,7 +219,7 @@ default void browseShouldNotFailWhenConcurrentDequeue() throws Exception {

Flux.from(getManageableMailQueue().deQueue());

assertThatCode(() -> Iterators.consumingIterator(items)).doesNotThrowAnyException();
assertThatCode(() -> consumeIterator(items)).doesNotThrowAnyException();
}

@Test
Expand Down Expand Up @@ -266,7 +268,7 @@ default void browseShouldNotFailWhenConcurrentDequeueWhenIterating() throws Exce

Flux.from(getManageableMailQueue().deQueue());

assertThatCode(() -> Iterators.consumingIterator(items)).doesNotThrowAnyException();
assertThatCode(() -> consumeIterator(items)).doesNotThrowAnyException();
}

@Test
Expand Down Expand Up @@ -307,7 +309,7 @@ default void browseShouldNotFailWhenConcurrentEnqueue() throws Exception {
.name("name4")
.build());

assertThatCode(() -> Iterators.consumingIterator(items)).doesNotThrowAnyException();
assertThatCode(() -> consumeIterator(items)).doesNotThrowAnyException();
}

@Test
Expand Down Expand Up @@ -352,7 +354,7 @@ default void browseShouldNotFailWhenConcurrentEnqueueWhenIterating() throws Exce
.name("name2")
.build());

assertThatCode(() -> Iterators.consumingIterator(items)).doesNotThrowAnyException();
assertThatCode(() -> consumeIterator(items)).doesNotThrowAnyException();
}

@Test
Expand Down Expand Up @@ -392,7 +394,7 @@ default void browseShouldNotFailWhenConcurrentClearWhenIterating() throws Except

getManageableMailQueue().clear();

assertThatCode(() -> Iterators.consumingIterator(items)).doesNotThrowAnyException();
assertThatCode(() -> consumeIterator(items)).doesNotThrowAnyException();
}

@Test
Expand Down Expand Up @@ -432,7 +434,7 @@ default void browseShouldNotFailWhenConcurrentFlushWhenIterating() throws Except

getManageableMailQueue().flush();

assertThatCode(() -> Iterators.consumingIterator(items)).doesNotThrowAnyException();
assertThatCode(() -> consumeIterator(items)).doesNotThrowAnyException();
}

@Test
Expand Down Expand Up @@ -474,7 +476,7 @@ default void browseShouldNotFailWhenConcurrentRemoveWhenIterating() throws Excep

awaitRemove();

assertThatCode(() -> Iterators.consumingIterator(items)).doesNotThrowAnyException();
assertThatCode(() -> consumeIterator(items)).doesNotThrowAnyException();
}

@Test
Expand Down Expand Up @@ -738,4 +740,13 @@ default void removeShouldNotDeleteFutureEmailsFromBrowse() throws MessagingExcep
.containsExactly("name2");
}

default <T> int consumeIterator(Iterator<T> iterator) {
var i = 0;
while (iterator.hasNext()) {
iterator.next();
i++;
}
return i;
}

}

0 comments on commit f2a56fc

Please sign in to comment.