This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 151db97de33fbffb6924cfe19273de8433e1fc8b Author: Benoit Tellier <[email protected]> AuthorDate: Mon Mar 2 07:10:25 2020 +0100 JAMES-3074 UidValidity sanitizing at the IMAP level --- .../parser/AbstractSelectionCommandParser.java | 20 +--- .../imap/decode/parser/ExamineCommandParser.java | 4 +- .../imap/decode/parser/SelectCommandParser.java | 4 +- .../request/AbstractMailboxSelectionRequest.java | 125 ++++++++++++++++++++- .../james/imap/message/request/ExamineRequest.java | 3 +- .../james/imap/message/request/SelectRequest.java | 3 +- .../imap/processor/AbstractSelectionProcessor.java | 9 +- .../james/imap/processor/ExamineProcessor.java | 5 +- .../james/imap/processor/SelectProcessor.java | 5 +- .../decode/parser/SelectCommandParserTest.java | 17 ++- .../AbstractMailboxSelectionRequestTest.java | 123 ++++++++++++++++++++ 11 files changed, 276 insertions(+), 42 deletions(-) diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java index d183a29..5014107 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java @@ -32,8 +32,8 @@ import org.apache.james.imap.decode.ImapRequestLineReader; import org.apache.james.imap.decode.ImapRequestLineReader.StringMatcherCharacterValidator; import org.apache.james.imap.decode.base.AbstractImapCommandParser; import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest; +import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity; import org.apache.james.mailbox.MessageUid; -import org.apache.james.mailbox.model.UidValidity; public abstract class AbstractSelectionCommandParser extends AbstractImapCommandParser { private static final String CONDSTORE = ImapConstants.SUPPORTS_CONDSTORE.asString(); @@ -47,7 +47,7 @@ public abstract class AbstractSelectionCommandParser extends AbstractImapCommand protected ImapMessage decode(ImapRequestLineReader request, Tag tag, ImapSession session) throws DecodingException { final String mailboxName = request.mailbox(); boolean condstore = false; - UidValidity lastKnownUidValidity = null; + ClientSpecifiedUidValidity lastKnownUidValidity = ClientSpecifiedUidValidity.UNKNOWN; Long knownModSeq = null; UidRange[] uidSet = null; UidRange[] knownUidSet = null; @@ -81,7 +81,7 @@ public abstract class AbstractSelectionCommandParser extends AbstractImapCommand // Consume enclosing paren request.consumeChar('('); long uidValidityAsNumber = request.number(); - lastKnownUidValidity = sanitizeUidValidity(uidValidityAsNumber); + lastKnownUidValidity = ClientSpecifiedUidValidity.of(uidValidityAsNumber); // Consume the SP request.consumeChar(' '); @@ -131,18 +131,6 @@ public abstract class AbstractSelectionCommandParser extends AbstractImapCommand return createRequest(mailboxName, condstore, lastKnownUidValidity, knownModSeq, uidSet, knownUidSet, knownSequenceSet, tag); } - private UidValidity sanitizeUidValidity(long uidValidityAsNumber) { - if (UidValidity.isValid(uidValidityAsNumber)) { - return UidValidity.of(uidValidityAsNumber); - } else { - // The UidValidity cached by the client is invalid - // We know that the backend will regenerate it - // Hence we force the mismatch - // QRSYNC command will be ignored - return UidValidity.random(); - } - } - /** * Check if the {@link IdRange}'s are formatted like stated in the QRESYNC RFC. * @@ -220,5 +208,5 @@ public abstract class AbstractSelectionCommandParser extends AbstractImapCommand /** * Create a new {@link AbstractMailboxSelectionRequest} for the given arguments */ - protected abstract AbstractMailboxSelectionRequest createRequest(String mailboxName, boolean condstore, UidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag); + protected abstract AbstractMailboxSelectionRequest createRequest(String mailboxName, boolean condstore, ClientSpecifiedUidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag); } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java index b2bef7e..e711e9d 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java @@ -24,8 +24,8 @@ import org.apache.james.imap.api.message.IdRange; import org.apache.james.imap.api.message.UidRange; import org.apache.james.imap.api.message.response.StatusResponseFactory; import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest; +import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity; import org.apache.james.imap.message.request.ExamineRequest; -import org.apache.james.mailbox.model.UidValidity; /** * Parse EXAMINE commands @@ -37,7 +37,7 @@ public class ExamineCommandParser extends AbstractSelectionCommandParser { } @Override - protected AbstractMailboxSelectionRequest createRequest(String mailboxName, boolean condstore, UidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { + protected AbstractMailboxSelectionRequest createRequest(String mailboxName, boolean condstore, ClientSpecifiedUidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { return new ExamineRequest(mailboxName, condstore, lastKnownUidValidity, knownModSeq, uidSet, knownUidSet, knownSequenceSet, tag); } } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java index dd30d44..c9ad85a 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java @@ -24,8 +24,8 @@ import org.apache.james.imap.api.message.IdRange; import org.apache.james.imap.api.message.UidRange; import org.apache.james.imap.api.message.response.StatusResponseFactory; import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest; +import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity; import org.apache.james.imap.message.request.SelectRequest; -import org.apache.james.mailbox.model.UidValidity; /** * Parse SELECT commands @@ -36,7 +36,7 @@ public class SelectCommandParser extends AbstractSelectionCommandParser { } @Override - protected AbstractMailboxSelectionRequest createRequest(String mailboxName, boolean condstore, UidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { + protected AbstractMailboxSelectionRequest createRequest(String mailboxName, boolean condstore, ClientSpecifiedUidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { return new SelectRequest(mailboxName, condstore, lastKnownUidValidity, knownModSeq, uidSet, knownUidSet, knownSequenceSet, tag); } } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java b/protocols/imap/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java index 468e2b0..bfdb30d 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java @@ -19,6 +19,8 @@ package org.apache.james.imap.message.request; +import java.util.Objects; + import org.apache.james.imap.api.ImapCommand; import org.apache.james.imap.api.Tag; import org.apache.james.imap.api.message.IdRange; @@ -26,29 +28,144 @@ import org.apache.james.imap.api.message.UidRange; import org.apache.james.imap.api.message.request.ImapRequest; import org.apache.james.mailbox.model.UidValidity; +import com.google.common.base.Preconditions; + /** * {@link ImapRequest} which selects a Mailbox. * * This supports also the <code>CONDSTORE</code> and the <code>QRESYNC</code> extension */ public abstract class AbstractMailboxSelectionRequest extends AbstractImapRequest { + public interface ClientSpecifiedUidValidity { + ClientSpecifiedUidValidity UNKNOWN = new ClientSpecifiedUidValidity() { + @Override + public boolean isUnknown() { + return true; + } + + @Override + public boolean correspondsTo(UidValidity uidValidity) { + return false; + } + + @Override + public String toString() { + return "UidValidity{UNKNOWN}"; + } + }; + + static ClientSpecifiedUidValidity of(long value) { + if (UidValidity.isValid(value)) { + return valid(UidValidity.of(value)); + } + return invalid(value); + } + + class Invalid implements ClientSpecifiedUidValidity { + private final long invalidUidValidity; + + public Invalid(long invalidUidValidity) { + Preconditions.checkArgument(!UidValidity.isValid(invalidUidValidity), "Need to supply an invalid value"); + this.invalidUidValidity = invalidUidValidity; + } + + @Override + public boolean isUnknown() { + return false; + } + + @Override + public boolean correspondsTo(UidValidity uidValidity) { + return false; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof Invalid) { + Invalid invalid = (Invalid) o; + + return Objects.equals(this.invalidUidValidity, invalid.invalidUidValidity); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(invalidUidValidity); + } + + @Override + public String toString() { + return String.format("Invalid UidValidity{%d}", invalidUidValidity); + } + } + class Valid implements ClientSpecifiedUidValidity { + private final UidValidity uidValidity; + + public Valid(UidValidity uidValidity) { + this.uidValidity = uidValidity; + } + + @Override + public boolean isUnknown() { + return false; + } + + @Override + public boolean correspondsTo(UidValidity uidValidity) { + return this.uidValidity.equals(uidValidity); + } + + @Override + public final boolean equals(Object o) { + if (o instanceof Valid) { + Valid valid = (Valid) o; + + return Objects.equals(this.uidValidity, valid.uidValidity); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(uidValidity); + } + + @Override + public String toString() { + return String.format("UidValidity{%d}", uidValidity.asLong()); + } + } + + static ClientSpecifiedUidValidity invalid(long invalidValue) { + return new Invalid(invalidValue); + } + + static ClientSpecifiedUidValidity valid(UidValidity uidValidity) { + return new Valid(uidValidity); + } + + boolean isUnknown(); + + boolean correspondsTo(UidValidity uidValidity); + } private final String mailboxName; private final boolean condstore; - private final UidValidity lastKnownUidValidity; + private final ClientSpecifiedUidValidity lastKnownUidValidity; private final Long knownModSeq; private final UidRange[] uidSet; private final UidRange[] knownUidSet; private final IdRange[] knownSequenceSet; - public AbstractMailboxSelectionRequest(ImapCommand command, String mailboxName, boolean condstore, UidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { + public AbstractMailboxSelectionRequest(ImapCommand command, String mailboxName, boolean condstore, ClientSpecifiedUidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { super(tag, command); this.mailboxName = mailboxName; this.condstore = condstore; this.lastKnownUidValidity = lastKnownUidValidity; this.knownModSeq = knownModSeq; - if ((lastKnownUidValidity == null && knownModSeq != null) || (this.lastKnownUidValidity != null && knownModSeq == null)) { + if ((lastKnownUidValidity.isUnknown() && knownModSeq != null) || (! lastKnownUidValidity.isUnknown() && knownModSeq == null)) { throw new IllegalArgumentException(); } this.uidSet = uidSet; @@ -80,7 +197,7 @@ public abstract class AbstractMailboxSelectionRequest extends AbstractImapReques * * @return lastKnownUidValidity */ - public final UidValidity getLastKnownUidValidity() { + public final ClientSpecifiedUidValidity getLastKnownUidValidity() { return lastKnownUidValidity; } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java b/protocols/imap/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java index a3989e8..208c0d9 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java @@ -22,10 +22,9 @@ import org.apache.james.imap.api.ImapConstants; import org.apache.james.imap.api.Tag; import org.apache.james.imap.api.message.IdRange; import org.apache.james.imap.api.message.UidRange; -import org.apache.james.mailbox.model.UidValidity; public class ExamineRequest extends AbstractMailboxSelectionRequest { - public ExamineRequest(String mailboxName, boolean condstore, UidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { + public ExamineRequest(String mailboxName, boolean condstore, ClientSpecifiedUidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { super(ImapConstants.EXAMINE_COMMAND, mailboxName, condstore, lastKnownUidValidity, knownModSeq, uidSet, knownUidSet, knownSequenceSet, tag); } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/message/request/SelectRequest.java b/protocols/imap/src/main/java/org/apache/james/imap/message/request/SelectRequest.java index b8bf1a3..d7b98ad 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/message/request/SelectRequest.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/message/request/SelectRequest.java @@ -22,10 +22,9 @@ import org.apache.james.imap.api.ImapConstants; import org.apache.james.imap.api.Tag; import org.apache.james.imap.api.message.IdRange; import org.apache.james.imap.api.message.UidRange; -import org.apache.james.mailbox.model.UidValidity; public class SelectRequest extends AbstractMailboxSelectionRequest { - public SelectRequest(String mailboxName, boolean condstore, UidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { + public SelectRequest(String mailboxName, boolean condstore, ClientSpecifiedUidValidity lastKnownUidValidity, Long knownModSeq, UidRange[] uidSet, UidRange[] knownUidSet, IdRange[] knownSequenceSet, Tag tag) { super(ImapConstants.SELECT_COMMAND, mailboxName, condstore, lastKnownUidValidity, knownModSeq, uidSet, knownUidSet, knownSequenceSet, tag); } } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java index e243fdf..11edf91 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java @@ -38,6 +38,7 @@ import org.apache.james.imap.api.process.SearchResUtil; import org.apache.james.imap.api.process.SelectedMailbox; import org.apache.james.imap.main.PathConverter; import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest; +import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity; import org.apache.james.imap.message.response.ExistsResponse; import org.apache.james.imap.message.response.RecentResponse; import org.apache.james.imap.processor.base.SelectedMailboxImpl; @@ -98,7 +99,7 @@ abstract class AbstractSelectionProcessor<R extends AbstractMailboxSelectionRequ private void respond(ImapSession session, MailboxPath fullMailboxPath, AbstractMailboxSelectionRequest request, Responder responder) throws MailboxException, MessageRangeException { - UidValidity lastKnownUidValidity = request.getLastKnownUidValidity(); + ClientSpecifiedUidValidity lastKnownUidValidity = request.getLastKnownUidValidity(); Long modSeq = request.getKnownModSeq(); IdRange[] knownSequences = request.getKnownSequenceSet(); UidRange[] knownUids = request.getKnownUidSet(); @@ -112,7 +113,7 @@ abstract class AbstractSelectionProcessor<R extends AbstractMailboxSelectionRequ // Resynchronization parameter to SELECT/EXAMINE command is specified // and the client hasn't issued "ENABLE QRESYNC" in the current // connection. - if (lastKnownUidValidity != null && !EnableProcessor.getEnabledCapabilities(session).contains(ImapConstants.SUPPORTS_QRESYNC)) { + if (!lastKnownUidValidity.isUnknown() && !EnableProcessor.getEnabledCapabilities(session).contains(ImapConstants.SUPPORTS_QRESYNC)) { taggedBad(request, responder, HumanReadableText.QRESYNC_NOT_ENABLED); return; } @@ -154,8 +155,8 @@ abstract class AbstractSelectionProcessor<R extends AbstractMailboxSelectionRequ // // If the mailbox does not store the mod-sequence in a permanent way its needed to not process the QRESYNC paramters // The same is true if none are given ;) - if (metaData.isModSeqPermanent() && lastKnownUidValidity != null) { - if (lastKnownUidValidity == metaData.getUidValidity()) { + if (metaData.isModSeqPermanent() && !lastKnownUidValidity.isUnknown()) { + if (lastKnownUidValidity.correspondsTo(metaData.getUidValidity())) { final MailboxManager mailboxManager = getMailboxManager(); final MailboxSession mailboxSession = session.getMailboxSession(); diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/ExamineProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/ExamineProcessor.java index 0468251..5486524 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/ExamineProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/ExamineProcessor.java @@ -20,7 +20,6 @@ package org.apache.james.imap.processor; import java.io.Closeable; -import java.util.Optional; import org.apache.james.imap.api.message.IdRange; import org.apache.james.imap.api.message.UidRange; @@ -29,7 +28,6 @@ import org.apache.james.imap.api.process.ImapProcessor; import org.apache.james.imap.message.request.ExamineRequest; import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.events.EventBus; -import org.apache.james.mailbox.model.UidValidity; import org.apache.james.metrics.api.MetricFactory; import org.apache.james.util.MDCBuilder; @@ -49,8 +47,7 @@ public class ExamineProcessor extends AbstractSelectionProcessor<ExamineRequest> .addContext("knownModseq", request.getKnownModSeq()) .addContext("knownUids", UidRange.toString(request.getKnownUidSet())) .addContext("knownIdRange", IdRange.toString(request.getKnownSequenceSet())) - .addContext("lastKnownUidValidity", Optional.ofNullable(request.getLastKnownUidValidity()) - .map(UidValidity::asLong)) + .addContext("lastKnownUidValidity", request.getLastKnownUidValidity()) .addContext("uidSet", UidRange.toString(request.getUidSet())) .build(); } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/SelectProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/SelectProcessor.java index 12a67aa..6d9bb18 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/SelectProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/SelectProcessor.java @@ -20,7 +20,6 @@ package org.apache.james.imap.processor; import java.io.Closeable; -import java.util.Optional; import org.apache.james.imap.api.message.IdRange; import org.apache.james.imap.api.message.UidRange; @@ -29,7 +28,6 @@ import org.apache.james.imap.api.process.ImapProcessor; import org.apache.james.imap.message.request.SelectRequest; import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.events.EventBus; -import org.apache.james.mailbox.model.UidValidity; import org.apache.james.metrics.api.MetricFactory; import org.apache.james.util.MDCBuilder; @@ -49,8 +47,7 @@ public class SelectProcessor extends AbstractSelectionProcessor<SelectRequest> { .addContext("knownModseq", message.getKnownModSeq()) .addContext("knownUids", UidRange.toString(message.getKnownUidSet())) .addContext("knownIdRange", IdRange.toString(message.getKnownSequenceSet())) - .addContext("lastKnownUidValidity", Optional.ofNullable(message.getLastKnownUidValidity()) - .map(UidValidity::asLong)) + .addContext("lastKnownUidValidity", message.getLastKnownUidValidity()) .addContext("uidSet", UidRange.toString(message.getUidSet())) .build(); } diff --git a/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SelectCommandParserTest.java b/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SelectCommandParserTest.java index 683385b..6d73240 100644 --- a/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SelectCommandParserTest.java +++ b/protocols/imap/src/test/java/org/apache/james/imap/decode/parser/SelectCommandParserTest.java @@ -30,7 +30,10 @@ import org.apache.james.imap.api.Tag; import org.apache.james.imap.api.message.response.StatusResponseFactory; import org.apache.james.imap.api.process.ImapSession; import org.apache.james.imap.decode.ImapRequestStreamLineReader; +import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest; +import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity; import org.apache.james.imap.message.request.SelectRequest; +import org.apache.james.mailbox.model.UidValidity; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -48,8 +51,18 @@ class SelectCommandParserTest { SelectRequest selectRequest = (SelectRequest) testee.decode(request, new Tag("0001"), mock(ImapSession.class)); - assertThat(selectRequest.getLastKnownUidValidity().isValid()) - .isTrue(); + assertThat(selectRequest.getLastKnownUidValidity()) + .isEqualTo(ClientSpecifiedUidValidity.invalid(0)); + } + + @Test + void decodeShouldParseValidUidValidity() throws Exception { + ImapRequestStreamLineReader request = toRequest("mailbox (QRESYNC (18 42))\n"); + + SelectRequest selectRequest = (SelectRequest) testee.decode(request, new Tag("0001"), mock(ImapSession.class)); + + assertThat(selectRequest.getLastKnownUidValidity()) + .isEqualTo(ClientSpecifiedUidValidity.valid(UidValidity.of(18))); } private ImapRequestStreamLineReader toRequest(String input) { diff --git a/protocols/imap/src/test/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequestTest.java b/protocols/imap/src/test/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequestTest.java new file mode 100644 index 0000000..8e50036 --- /dev/null +++ b/protocols/imap/src/test/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequestTest.java @@ -0,0 +1,123 @@ +/**************************************************************** + * 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.message.request; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity; +import org.apache.james.mailbox.model.UidValidity; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Nested; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class AbstractMailboxSelectionRequestTest { + private static final ClientSpecifiedUidValidity INVALID = ClientSpecifiedUidValidity.invalid(0); + private static final UidValidity UID_VALIDITY = UidValidity.of(42); + private static final ClientSpecifiedUidValidity VALID = ClientSpecifiedUidValidity.valid(UID_VALIDITY); + + @Nested + class Unknown { + @Test + void isUnknownShouldReturnTrue() { + assertThat(ClientSpecifiedUidValidity.UNKNOWN.isUnknown()) + .isTrue(); + } + + @Test + void correspondsToShouldReturnFalse() { + assertThat(ClientSpecifiedUidValidity.UNKNOWN.correspondsTo(UID_VALIDITY)) + .isFalse(); + } + + @Test + void toStringShouldBeInformative() { + assertThat(ClientSpecifiedUidValidity.UNKNOWN.toString()) + .isEqualTo("UidValidity{UNKNOWN}"); + } + } + + @Nested + class Invalid { + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(ClientSpecifiedUidValidity.Invalid.class) + .verify(); + } + + @Test + void invalidShouldThrowOnValidValue() { + assertThatThrownBy(() -> ClientSpecifiedUidValidity.invalid(42)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void isUnknownShouldReturnFalse() { + assertThat(INVALID.isUnknown()) + .isFalse(); + } + + @Test + void correspondsToShouldReturnFalse() { + assertThat(INVALID.correspondsTo(UID_VALIDITY)) + .isFalse(); + } + + @Test + void toStringShouldBeInformative() { + assertThat(INVALID.toString()) + .isEqualTo("Invalid UidValidity{0}"); + } + } + + @Nested + class Valid { + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(ClientSpecifiedUidValidity.Valid.class) + .verify(); + } + + @Test + void isUnknownShouldReturnFalse() { + assertThat(VALID.isUnknown()) + .isFalse(); + } + + @Test + void correspondsToShouldReturnFalseWhenDifferent() { + assertThat(VALID.correspondsTo(UidValidity.of(40))) + .isFalse(); + } + + @Test + void correspondsToShouldReturnTrueWhenSame() { + assertThat(VALID.correspondsTo(UID_VALIDITY)) + .isTrue(); + } + + @Test + void toStringShouldBeInformative() { + assertThat(VALID.toString()) + .isEqualTo("UidValidity{42}"); + } + } +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
