JAMES-2346 Do not depend on system timezone for InternalDate serialization
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/041031b3 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/041031b3 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/041031b3 Branch: refs/heads/master Commit: 041031b3bf789e3eea5bbb37726b222f8e43ed29 Parents: 49c2a84 Author: benwa <[email protected]> Authored: Fri Jun 22 12:23:45 2018 +0700 Committer: Raphael Ouazana <[email protected]> Committed: Wed Jun 27 16:41:40 2018 +0200 ---------------------------------------------------------------------- .../mailbox/backup/InternalDateExtraField.java | 18 +- .../org/apache/james/mailbox/backup/Zipper.java | 4 +- .../backup/InternalDateExtraFieldTest.java | 254 ++++++++++++------- 3 files changed, 165 insertions(+), 111 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/041031b3/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/InternalDateExtraField.java ---------------------------------------------------------------------- diff --git a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/InternalDateExtraField.java b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/InternalDateExtraField.java index f471869..1ad65f5 100644 --- a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/InternalDateExtraField.java +++ b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/InternalDateExtraField.java @@ -19,15 +19,12 @@ package org.apache.james.mailbox.backup; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Optional; import org.apache.commons.compress.archivers.zip.ZipShort; -public class InternalDateExtraField extends StringExtraField { +public class InternalDateExtraField extends LongExtraField { public static final ZipShort ID = new ZipShort(0x6F61); // "ao" in little-endian @@ -37,24 +34,23 @@ public class InternalDateExtraField extends StringExtraField { public InternalDateExtraField(Optional<Date> date) { super(date - .map(Date::toInstant) - .map(instant -> ZonedDateTime.ofInstant(instant, ZoneId.systemDefault())) - .map(DateTimeFormatter.ISO_OFFSET_DATE_TIME::format)); + .map(Date::getTime)); } public InternalDateExtraField(Date date) { this(Optional.of(date)); } + public InternalDateExtraField(long timestamp) { + this(Optional.of(new Date(timestamp))); + } + @Override public ZipShort getHeaderId() { return ID; } public Optional<Date> getDateValue() { - return getValue() - .map(time -> ZonedDateTime.parse(time, DateTimeFormatter.ISO_OFFSET_DATE_TIME)) - .map(ZonedDateTime::toInstant) - .map(Date::from); + return getValue().map(Date::new); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/041031b3/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java ---------------------------------------------------------------------- diff --git a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java index 3a1314c..d434331 100644 --- a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java +++ b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java @@ -60,8 +60,8 @@ public class Zipper implements Backup { private void storeMessages(Stream<MailboxMessage> messages, ZipArchiveOutputStream archiveOutputStream) { messages.forEach(Throwing.<MailboxMessage>consumer(message -> { - storeInArchive(message, archiveOutputStream); - }).sneakyThrow()); + storeInArchive(message, archiveOutputStream); + }).sneakyThrow()); } private void storeInArchive(Mailbox mailbox, ZipArchiveOutputStream archiveOutputStream) throws IOException { http://git-wip-us.apache.org/repos/asf/james-project/blob/041031b3/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/InternalDateExtraFieldTest.java ---------------------------------------------------------------------- diff --git a/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/InternalDateExtraFieldTest.java b/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/InternalDateExtraFieldTest.java index de3f967..18c81bc 100644 --- a/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/InternalDateExtraFieldTest.java +++ b/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/InternalDateExtraFieldTest.java @@ -19,19 +19,17 @@ package org.apache.james.mailbox.backup; -import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.Date; +import java.util.zip.ZipException; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.org.bouncycastle.util.Arrays; import com.google.common.base.Charsets; @@ -39,18 +37,18 @@ import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; public class InternalDateExtraFieldTest { + private static final byte[] ZERO_AS_BYTE_ARRAY = {0, 0, 0, 0, 0, 0, 0, 0}; + private static final byte[] _123456789ABCDEF0_AS_LE_BYTE_ARRAY = new byte[] {(byte) 0xF0, (byte) 0xDE, (byte) 0xBC, (byte) 0x9A, 0x78, 0x56, 0x34, 0x12}; + private static final byte[] FEDCBA9876543210_AS_LE_BYTE_ARRAY = new byte[] {0x10, 0x32, 0x54, 0x76, (byte) 0x98, (byte) 0xBA, (byte) 0xDC, (byte) 0xFE}; + private static final byte[] UNUSED = new byte[] {(byte) 0xDE, (byte) 0xAD}; - public static final String DATE_STRING_1 = "2018-02-15T22:54:02+07:00"; - private static final ZonedDateTime DATE_1 = ZonedDateTime.parse(DATE_STRING_1, DateTimeFormatter.ISO_OFFSET_DATE_TIME); - private static final byte[] DATE_STRING_1_BYTE_ARRAY = DATE_STRING_1.getBytes(StandardCharsets.UTF_8); - - private static final String DEFAULT_MAILBOX_ID = "123456789ABCDEF0"; - private static final byte[] DEFAULT_MAILBOX_ID_BYTE_ARRAY = new byte[] {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30}; - private static final byte [] EMPTY_BYTE_ARRAY = {}; + private static final long DEFAULT_DATE_TIMESTAMP = 1529559708381L; + private static final byte[] DEFAULT_DATE_LE_BYTE_ARRAY = {(byte) 0xdd, (byte) 0xf2, (byte) 0xdc, 0x20, 0x64, 0x01, 0x00, 0x00 }; + private static final Date DEFAULT_DATE = new Date(DEFAULT_DATE_TIMESTAMP); @Test public void shouldMatchBeanContract() { - EqualsVerifier.forClass(MailboxIdExtraField.class) + EqualsVerifier.forClass(InternalDateExtraField.class) .suppress(Warning.NONFINAL_FIELDS) .verify(); } @@ -60,31 +58,23 @@ public class InternalDateExtraFieldTest { @Test void getHeaderIdShouldReturnSpecificStringInLittleEndian() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + InternalDateExtraField testee = new InternalDateExtraField(); + ByteBuffer byteBuffer = ByteBuffer.wrap(testee.getHeaderId().getBytes()) .order(ByteOrder.LITTLE_ENDIAN); - assertThat(Charsets.US_ASCII.decode(byteBuffer).toString()) - .isEqualTo("am"); + .isEqualTo("ao"); } } @Nested class GetLocalFileDataLength { - - @Test - void getLocalFileDataLengthShouldThrowWhenNoValue() { - MailboxIdExtraField testee = new MailboxIdExtraField(); - assertThatThrownBy(() -> testee.getLocalFileDataLength().getValue()) - .isInstanceOf(RuntimeException.class); - } - @Test void getLocalFileDataLengthShouldReturnIntegerSize() { - MailboxIdExtraField testee = new MailboxIdExtraField(DEFAULT_MAILBOX_ID); + InternalDateExtraField testee = new InternalDateExtraField(); assertThat(testee.getLocalFileDataLength().getValue()) - .isEqualTo(16); + .isEqualTo(Long.BYTES); } } @@ -92,84 +82,82 @@ public class InternalDateExtraFieldTest { class GetCentralDirectoryLength { @Test - void getCentralDirectoryLengthShouldThrowWhenNoValue() { - MailboxIdExtraField testee = new MailboxIdExtraField(); - assertThatThrownBy(() -> testee.getCentralDirectoryLength().getValue()) - .isInstanceOf(RuntimeException.class); - } - - @Test void getCentralDirectoryLengthShouldReturnIntegerSize() { - MailboxIdExtraField testee = new MailboxIdExtraField(DEFAULT_MAILBOX_ID); + InternalDateExtraField testee = new InternalDateExtraField(); assertThat(testee.getCentralDirectoryLength().getValue()) - .isEqualTo(16); + .isEqualTo(Long.BYTES); } - } - @Nested - class GetLocalFileDataData { @Test - void getLocalFileDataDataShouldThrowWhenNoValue() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void getCentralDirectoryDataShouldThrowWhenNoValue() { + InternalDateExtraField testee = new InternalDateExtraField(); - assertThatThrownBy(() -> testee.getLocalFileDataData()) + assertThatThrownBy(() -> testee.getCentralDirectoryData()) .isInstanceOf(RuntimeException.class); } @Test - void getLocalFileDataDataShouldReturnEmptyArrayWhenValueIsEmpty() { - byte[] actual = new MailboxIdExtraField(EMPTY).getLocalFileDataData(); - assertThat(actual).isEqualTo(EMPTY_BYTE_ARRAY); + void getCentralDirectoryDataShouldReturnZeroWhenZero() { + byte[] actual = new InternalDateExtraField(0).getCentralDirectoryData(); + assertThat(actual).isEqualTo(ZERO_AS_BYTE_ARRAY); + } + + @Test + void getCentralDirectoryDataShouldReturnValueInLittleIndianWhen123456789ABCDEF0() { + byte[] actual = new InternalDateExtraField(0x123456789ABCDEF0L).getCentralDirectoryData(); + assertThat(actual).isEqualTo(_123456789ABCDEF0_AS_LE_BYTE_ARRAY); } @Test - void getLocalFileDataDataShouldReturnValueInByteArray() { - byte[] actual = new MailboxIdExtraField(DEFAULT_MAILBOX_ID).getLocalFileDataData(); - assertThat(actual).isEqualTo(DEFAULT_MAILBOX_ID_BYTE_ARRAY); + void getCentralDirectoryDataShouldReturnValueInLittleIndianWhenFEDCBA9876543210() { + byte[] actual = new InternalDateExtraField(0xFEDCBA9876543210L).getCentralDirectoryData(); + assertThat(actual).isEqualTo(FEDCBA9876543210_AS_LE_BYTE_ARRAY); } @Test - void getLocalFileDataShouldReturnDateByteArrayWhenPassDate() { - byte[] actual = new InternalDateExtraField(Date.from(DATE_1.toInstant())) - .getLocalFileDataData(); + void getCentralDirectoryDataShouldReturnDefaultDateWhenPassDefaultDateInByteArray() { + byte[] actual = new InternalDateExtraField(DEFAULT_DATE).getCentralDirectoryData(); - assertThat(actual) - .isEqualTo(DATE_STRING_1_BYTE_ARRAY); + assertThat(actual).isEqualTo(DEFAULT_DATE_LE_BYTE_ARRAY); } } @Nested - class GetCentralDirectoryData { + class GetLocalFileDataData { @Test - void getCentralDirectoryDataShouldThrowWhenNoValue() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void getLocalFileDataDataShouldThrowWhenNoValue() { + InternalDateExtraField testee = new InternalDateExtraField(); - assertThatThrownBy(() -> testee.getCentralDirectoryData()) + assertThatThrownBy(() -> testee.getLocalFileDataData()) .isInstanceOf(RuntimeException.class); } @Test - void getCentralDirectoryDataShouldReturnEmptyArrayWhenValueIsEmpty() { - byte[] actual = new MailboxIdExtraField(EMPTY).getCentralDirectoryData(); - assertThat(actual).isEqualTo(EMPTY_BYTE_ARRAY); + void getLocalFileDataDataShouldReturnZeroWhenZero() { + byte[] actual = new InternalDateExtraField(0).getLocalFileDataData(); + assertThat(actual).isEqualTo(ZERO_AS_BYTE_ARRAY); } @Test - void getCentralDirectoryDataShouldReturnValueInByteArray() { - byte[] actual = new MailboxIdExtraField(DEFAULT_MAILBOX_ID).getCentralDirectoryData(); - assertThat(actual).isEqualTo(DEFAULT_MAILBOX_ID_BYTE_ARRAY); + void getLocalFileDataDataShouldReturnValueInLittleIndianWhen123456789ABCDEF0() { + byte[] actual = new InternalDateExtraField(0x123456789ABCDEF0L).getLocalFileDataData(); + assertThat(actual).isEqualTo(_123456789ABCDEF0_AS_LE_BYTE_ARRAY); } @Test - void getCentralDirectoryDataShouldReturnDateByteArrayWhenPassDate() { - byte[] actual = new InternalDateExtraField(Date.from(DATE_1.toInstant())) - .getCentralDirectoryData(); + void getLocalFileDataDataShouldReturnValueInLittleIndianWhenFEDCBA9876543210() { + byte[] actual = new InternalDateExtraField(0xFEDCBA9876543210L).getLocalFileDataData(); + assertThat(actual).isEqualTo(FEDCBA9876543210_AS_LE_BYTE_ARRAY); + } + + @Test + void getLocalFileDataDataShouldReturnDefaultDateWhenPassDefaultDateInByteArray() { + byte[] actual = new InternalDateExtraField(DEFAULT_DATE).getLocalFileDataData(); - assertThat(actual) - .isEqualTo(DATE_STRING_1_BYTE_ARRAY); + assertThat(actual).isEqualTo(DEFAULT_DATE_LE_BYTE_ARRAY); } } @@ -177,43 +165,78 @@ public class InternalDateExtraFieldTest { class ParseFromLocalFileData { @Test - void parseFromLocalFileDataShouldParseWhenZero() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void parseFromLocalFileDataShouldThrownWhenLengthIsSmallerThan8() { + InternalDateExtraField testee = new InternalDateExtraField(); + + byte[] input = new byte[] {0, 0, 0, 0, 0, 0, 0}; + assertThatThrownBy(() -> testee.parseFromLocalFileData(input, 0, 7)) + .isInstanceOf(ZipException.class); + } - testee.parseFromLocalFileData(EMPTY_BYTE_ARRAY, 0, 0); + @Test + void parseFromLocalFileDataShouldThrownWhenLengthIsBiggerThan8() { + InternalDateExtraField testee = new InternalDateExtraField(); - assertThat(testee.getValue()) - .contains(EMPTY); + byte[] input = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0}; + assertThatThrownBy(() -> testee.parseFromLocalFileData(input, 0, 9)) + .isInstanceOf(ZipException.class); } @Test - void parseFromLocalFileDataShouldParseByteArray() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void parseFromLocalFileDataShouldParseWhenZero() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); - testee.parseFromLocalFileData(DEFAULT_MAILBOX_ID_BYTE_ARRAY, 0, 16); + testee.parseFromLocalFileData(ZERO_AS_BYTE_ARRAY, 0, 8); + assertThat(testee.getValue()) + .contains(0L); + } + + @Test + void parseFromLocalFileDataShouldParseWhen123456789ABCDEF0InLittleEndian() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + testee.parseFromLocalFileData(_123456789ABCDEF0_AS_LE_BYTE_ARRAY, 0, 8); assertThat(testee.getValue()) - .contains(DEFAULT_MAILBOX_ID); + .contains(0x123456789ABCDEF0L); } @Test - void parseFromLocalFileDataShouldHandleOffset() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void parseFromLocalFileDataShouldParseWhenFEDCBA9876543210InLittleEndian() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); - testee.parseFromLocalFileData(DEFAULT_MAILBOX_ID_BYTE_ARRAY, 2, 14); + byte[] input = FEDCBA9876543210_AS_LE_BYTE_ARRAY; + testee.parseFromLocalFileData(input, 0, 8); + assertThat(testee.getValue()) + .contains(0xFEDCBA9876543210L); + } + + @Test + void parseFromLocalFileDataShouldHandleOffset() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + byte[] input = Arrays.concatenate(UNUSED, _123456789ABCDEF0_AS_LE_BYTE_ARRAY); + testee.parseFromLocalFileData(input, 2, 8); assertThat(testee.getValue()) - .contains("3456789ABCDEF0"); + .contains(0x123456789ABCDEF0L); } @Test - void parseFromLocalFileDataShouldReturnDateWhenPassDateByteArray() { + void parseFromLocalFileDataShouldReturnZeroDayWhenZero() throws Exception { InternalDateExtraField testee = new InternalDateExtraField(); - testee.parseFromLocalFileData(DATE_STRING_1_BYTE_ARRAY, 0, 25); + testee.parseFromLocalFileData(ZERO_AS_BYTE_ARRAY, 0, 8); assertThat(testee.getDateValue()) - .contains(Date.from(DATE_1.toInstant())); + .contains(new Date(0L)); + } + + @Test + void parseFromLocalFileDataShouldReturnDefaultDateWhenPassDefaultUTCDateByteArray() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + testee.parseFromLocalFileData(DEFAULT_DATE_LE_BYTE_ARRAY, 0, 8); + + assertThat(testee.getDateValue()) + .contains(DEFAULT_DATE); } } @@ -221,43 +244,78 @@ public class InternalDateExtraFieldTest { class ParseFromCentralDirectoryData { @Test - void parseFromCentralDirectoryDataShouldParseWhenZero() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void parseFromCentralDirectoryDataShouldThrownWhenLengthIsSmallerThan8() { + InternalDateExtraField testee = new InternalDateExtraField(); + byte[] input = new byte[7]; - testee.parseFromCentralDirectoryData(EMPTY_BYTE_ARRAY, 0, 0); + assertThatThrownBy(() -> testee.parseFromCentralDirectoryData(input, 0, 7)) + .isInstanceOf(ZipException.class); + } - assertThat(testee.getValue()) - .contains(EMPTY); + @Test + void parseFromCentralDirectoryDataShouldThrownWhenLengthIsBiggerThan8() { + InternalDateExtraField testee = new InternalDateExtraField(); + byte[] input = new byte[9]; + + assertThatThrownBy(() -> testee.parseFromCentralDirectoryData(input, 0, 9)) + .isInstanceOf(ZipException.class); } @Test - void parseFromCentralDirectoryDataShouldParseByteArray() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void parseFromCentralDirectoryDataShouldParseWhenZero() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + + testee.parseFromCentralDirectoryData(ZERO_AS_BYTE_ARRAY, 0, 8); + assertThat(testee.getValue()) + .contains(0L); + } - testee.parseFromCentralDirectoryData(DEFAULT_MAILBOX_ID_BYTE_ARRAY, 0, 16); + @Test + void parseFromCentralDirectoryDataShouldParseWhen123456789ABCDEF0InLittleEndian() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + testee.parseFromCentralDirectoryData(_123456789ABCDEF0_AS_LE_BYTE_ARRAY, 0, 8); assertThat(testee.getValue()) - .contains(DEFAULT_MAILBOX_ID); + .contains(0x123456789ABCDEF0L); } @Test - void parseFromCentralDirectoryDataShouldHandleOffset() { - MailboxIdExtraField testee = new MailboxIdExtraField(); + void parseFromCentralDirectoryDataShouldParseWhenFEDCBA9876543210InLittleEndian() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + byte[] input = FEDCBA9876543210_AS_LE_BYTE_ARRAY; + + testee.parseFromCentralDirectoryData(input, 0, 8); + assertThat(testee.getValue()) + .contains(0xFEDCBA9876543210L); + } - testee.parseFromCentralDirectoryData(DEFAULT_MAILBOX_ID_BYTE_ARRAY, 2, 14); + @Test + void parseFromCentralDirectoryDataShouldHandleOffset() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + byte[] input = Arrays.concatenate(UNUSED, _123456789ABCDEF0_AS_LE_BYTE_ARRAY); + testee.parseFromCentralDirectoryData(input, 2, 8); assertThat(testee.getValue()) - .contains("3456789ABCDEF0"); + .contains(0x123456789ABCDEF0L); } @Test - void parseFromCentralDirectoryDataShouldReturnDateWhenPassDateByteArray() { + void parseFromCentralDirectoryDataShouldReturnZeroDayWhenZero() throws Exception { InternalDateExtraField testee = new InternalDateExtraField(); - testee.parseFromCentralDirectoryData(DATE_STRING_1_BYTE_ARRAY, 0, 25); + testee.parseFromCentralDirectoryData(ZERO_AS_BYTE_ARRAY, 0, 8); + + assertThat(testee.getDateValue()) + .contains(new Date(0L)); + } + + @Test + void parseFromCentralDirectoryDataShouldReturnDefaultDateWhenPassDefaultUTCDateByteArray() throws Exception { + InternalDateExtraField testee = new InternalDateExtraField(); + testee.parseFromCentralDirectoryData(DEFAULT_DATE_LE_BYTE_ARRAY, 0, 8); assertThat(testee.getDateValue()) - .contains(Date.from(DATE_1.toInstant())); + .contains(DEFAULT_DATE); } } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
