From c07a0d8b652c832c5a07a9ec3ae923260c4a19ca Mon Sep 17 00:00:00 2001 From: Jan van Mansum Date: Tue, 12 Nov 2024 15:31:01 +0100 Subject: [PATCH] Implemented ordering of deposits, by creation.timestamp or sequence-number. --- .../nl/knaw/dans/dvingest/core/Deposit.java | 21 +++- .../knaw/dans/dvingest/core/DepositTest.java | 116 +++++++++++++++++- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/src/main/java/nl/knaw/dans/dvingest/core/Deposit.java b/src/main/java/nl/knaw/dans/dvingest/core/Deposit.java index 12fa9e1..b233ad7 100644 --- a/src/main/java/nl/knaw/dans/dvingest/core/Deposit.java +++ b/src/main/java/nl/knaw/dans/dvingest/core/Deposit.java @@ -18,8 +18,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; +import lombok.ToString; import lombok.extern.slf4j.Slf4j; import nl.knaw.dans.lib.dataverse.MetadataFieldDeserializer; import nl.knaw.dans.lib.dataverse.model.dataset.Dataset; @@ -38,6 +40,8 @@ @Getter @Slf4j +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@ToString public class Deposit implements Comparable { private static final ObjectMapper MAPPER; @@ -63,6 +67,7 @@ public Deposit(@NonNull Path location) { } } + @EqualsAndHashCode.Include public UUID getId() { return UUID.fromString(location.getFileName().toString()); } @@ -93,12 +98,16 @@ public Path getFilesDir() { return getBagDir().resolve("data"); } - public int getSeqNumber() { - return depositProperties.get("seqNumber") == null ? -1 : Integer.parseInt(depositProperties.getProperty("seqNumber")); + public int getSequenceNumber() { + return depositProperties.get("sequence-number") == null ? -1 : Integer.parseInt(depositProperties.getProperty("sequence-number")); } public OffsetDateTime getCreationTimestamp() { - return OffsetDateTime.parse(depositProperties.getProperty("creation.timestamp")); + var creationTimestamp = depositProperties.getProperty("creation-timestamp"); + if (creationTimestamp == null) { + return null; + } + return OffsetDateTime.parse(creationTimestamp); } public void moveTo(Path targetDir) throws IOException { @@ -108,14 +117,14 @@ public void moveTo(Path targetDir) throws IOException { @Override public int compareTo(@NotNull Deposit deposit) { - if (getSeqNumber() != -1 && deposit.getSeqNumber() != -1) { - return Integer.compare(getSeqNumber(), deposit.getSeqNumber()); + if (getSequenceNumber() != -1 && deposit.getSequenceNumber() != -1) { + return Integer.compare(getSequenceNumber(), deposit.getSequenceNumber()); } else if (getCreationTimestamp() != null && deposit.getCreationTimestamp() != null) { return getCreationTimestamp().compareTo(deposit.getCreationTimestamp()); } else { - throw new IllegalStateException("Deposit " + getId() + " or " + deposit.getId() + " has no sequence number"); + throw new IllegalStateException("Deposit " + getId() + " should contain either a sequence number or a creation timestamp"); } } } diff --git a/src/test/java/nl/knaw/dans/dvingest/core/DepositTest.java b/src/test/java/nl/knaw/dans/dvingest/core/DepositTest.java index e32666a..8dd9a9b 100644 --- a/src/test/java/nl/knaw/dans/dvingest/core/DepositTest.java +++ b/src/test/java/nl/knaw/dans/dvingest/core/DepositTest.java @@ -1,8 +1,25 @@ +/* + * Copyright (C) 2024 DANS - Data Archiving and Networked Services (info@dans.knaw.nl) + * + * Licensed 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 nl.knaw.dans.dvingest.core; import org.junit.jupiter.api.Test; import java.nio.file.Files; +import java.util.Properties; +import java.util.TreeSet; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -39,23 +56,110 @@ public void getId_should_return_uuid_from_dir_name() throws Exception { } @Test - public void deposits_should_be_ordered_by_seqNums() throws Exception { + public void deposits_should_be_ordered_by_sequence_number() throws Exception { // Given var id1 = UUID.randomUUID().toString(); var id2 = UUID.randomUUID().toString(); var id3 = UUID.randomUUID().toString(); - var deposit1 = testDir.resolve(id1); - Files.createDirectories(deposit1); - Files.createFile(deposit1.resolve("deposit.properties")); - + var dir1 = testDir.resolve(id1); + Files.createDirectories(dir1); + var props1 = new Properties(); + props1.setProperty("sequence-number", "1"); + props1.store(Files.newBufferedWriter(dir1.resolve("deposit.properties")), ""); + var dir2 = testDir.resolve(id2); + Files.createDirectories(dir2); + var props2 = new Properties(); + props2.setProperty("sequence-number", "2"); + props2.store(Files.newBufferedWriter(dir2.resolve("deposit.properties")), ""); + var dir3 = testDir.resolve(id3); + Files.createDirectories(dir3); + var props3 = new Properties(); + props3.setProperty("sequence-number", "3"); + props3.store(Files.newBufferedWriter(dir3.resolve("deposit.properties")), ""); + + var deposit1 = new Deposit(dir1); + var deposit2 = new Deposit(dir2); + var deposit3 = new Deposit(dir3); // When - var deposits = List.of(deposit2, deposit3, deposit1); + var deposits = new TreeSet<>(); + deposits.add(deposit2); + deposits.add(deposit1); + deposits.add(deposit3); // Then assertThat(deposits).containsExactly(deposit1, deposit2, deposit3); } + @Test + public void deposits_should_be_ordered_by_creation_timestamp() throws Exception { + // Given + var id1 = UUID.randomUUID().toString(); + var id2 = UUID.randomUUID().toString(); + var id3 = UUID.randomUUID().toString(); + + var dir1 = testDir.resolve(id1); + Files.createDirectories(dir1); + var props1 = new Properties(); + props1.setProperty("creation-timestamp", "2023-01-01T10:00:00Z"); + props1.store(Files.newBufferedWriter(dir1.resolve("deposit.properties")), ""); + + var dir2 = testDir.resolve(id2); + Files.createDirectories(dir2); + var props2 = new Properties(); + props2.setProperty("creation-timestamp", "2023-01-02T10:00:00Z"); + props2.store(Files.newBufferedWriter(dir2.resolve("deposit.properties")), ""); + + var dir3 = testDir.resolve(id3); + Files.createDirectories(dir3); + var props3 = new Properties(); + props3.setProperty("creation-timestamp", "2023-01-03T10:00:00Z"); + props3.store(Files.newBufferedWriter(dir3.resolve("deposit.properties")), ""); + + var deposit1 = new Deposit(dir1); + var deposit2 = new Deposit(dir2); + var deposit3 = new Deposit(dir3); + + // When + var deposits = new TreeSet<>(); + deposits.add(deposit2); + deposits.add(deposit1); + deposits.add(deposit3); + + // Then + assertThat(deposits).containsExactly(deposit1, deposit2, deposit3); + } + + @Test + public void ordering_should_fail_if_both_sequence_number_and_creation_timestamp_are_missing_in_one_of_the_deposits() throws Exception { + // Given + var id1 = UUID.randomUUID().toString(); + var id2 = UUID.randomUUID().toString(); + var id3 = UUID.randomUUID().toString(); + + var dir1 = testDir.resolve(id1); + Files.createDirectories(dir1); + var props1 = new Properties(); + props1.store(Files.newBufferedWriter(dir1.resolve("deposit.properties")), ""); + + var dir2 = testDir.resolve(id2); + Files.createDirectories(dir2); + var props2 = new Properties(); + props2.setProperty("sequence-number", "2"); + props2.store(Files.newBufferedWriter(dir2.resolve("deposit.properties")), ""); + + var deposit1 = new Deposit(dir1); + var deposit2 = new Deposit(dir2); + + // Then + assertThatIllegalStateException().isThrownBy(() -> { + // When + var deposits = new TreeSet<>(); + deposits.add(deposit2); + deposits.add(deposit1); + }) + .withMessage("Deposit " + deposit1.getId() + " should contain either a sequence number or a creation timestamp"); + } }