Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/main/java/edu/harvard/iq/dataverse/api/Datasets.java
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,12 @@ public Response updateDraftVersion(@Context ContainerRequestContext crc, String
return error( Response.Status.BAD_REQUEST, "You may not add files via this api.");
}

boolean updateDraft = ds.getLatestVersion().isDraft();
DatasetVersion latestVersion = ds.getLatestVersion();
if (isDatasetVersionNoOp(incomingVersion, latestVersion)) {
return ok(json(latestVersion, true));
}

boolean updateDraft = latestVersion.isDraft();

DatasetVersion managedVersion;
if (updateDraft) {
Expand Down Expand Up @@ -882,6 +887,12 @@ public Response updateDraftVersion(@Context ContainerRequestContext crc, String
}
}

// Helper extracted to make no-op detection testable.
static boolean isDatasetVersionNoOp(DatasetVersion incomingVersion, DatasetVersion latestVersion) {
DatasetVersionDifference diff = new DatasetVersionDifference(incomingVersion, latestVersion);
return diff.getDetailDataByBlock().isEmpty() && diff.getChangedTermsAccess().isEmpty();
}

@GET
@AuthRequired
@Path("{id}/versions/{versionId}/metadata")
Expand Down
60 changes: 60 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/DatasetsIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -7540,6 +7540,66 @@ public void testGetDatasetWithTermsOfUseAndGuestbook() throws IOException, JsonP
.body("data.guestbookId", equalTo(guestbook.getId().intValue()));
}

@Test
public void testUpdateDatasetMetadataNoOp() {
String apiToken = getSuperuserToken();
String collectionAlias = UtilIT.createRandomCollectionGetAlias(apiToken);
UtilIT.publishDataverseViaNativeApi(collectionAlias, apiToken)
.then().assertThat().statusCode(OK.getStatusCode());

String updateJsonFile = "doc/sphinx-guides/source/_static/api/dataset-update-metadata.json";

// 1. Create a dataset and update it with known metadata from a file
Response createDataset = UtilIT.createRandomDatasetViaNativeApi(collectionAlias, apiToken);
createDataset.then().assertThat().statusCode(CREATED.getStatusCode());
Integer datasetId = UtilIT.getDatasetIdFromResponse(createDataset);
String datasetPid = UtilIT.getDatasetPersistentIdFromResponse(createDataset);

UtilIT.updateDatasetMetadataViaNative(datasetPid, updateJsonFile, apiToken)
.then().assertThat().statusCode(OK.getStatusCode());
UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiToken)
.then().assertThat().statusCode(OK.getStatusCode());
UtilIT.getDatasetVersion(datasetPid, DS_VERSION_DRAFT, apiToken)
.then().assertThat().statusCode(NOT_FOUND.getStatusCode());

// 2. Call API with identical metadata (Published case)
UtilIT.updateDatasetMetadataViaNative(datasetPid, updateJsonFile, apiToken)
.then().assertThat().statusCode(OK.getStatusCode());

// 3. Verify no draft was created
UtilIT.getDatasetVersion(datasetPid, DS_VERSION_DRAFT, apiToken)
.then().assertThat().statusCode(NOT_FOUND.getStatusCode());

// 4. Test the scenario where a draft ALREADY exists
String currentMetadata = UtilIT.getDatasetJson(updateJsonFile);
String draftJson = currentMetadata.replace("\"newTitle\"", "\"Updated Title\"");

given()
.header(API_TOKEN_HTTP_HEADER, apiToken)
.body(draftJson)
.contentType("application/json")
.put("/api/datasets/:persistentId/versions/" + DS_VERSION_DRAFT + "?persistentId=" + datasetPid)
.then().assertThat().statusCode(OK.getStatusCode());

Response draftResponse = UtilIT.getDatasetVersion(datasetPid, DS_VERSION_DRAFT, apiToken);
draftResponse.then().assertThat().statusCode(OK.getStatusCode());
String lastUpdateTimeBefore = draftResponse.jsonPath().getString("data.lastUpdateTime");

// 5. Call API with identical metadata to the current draft
given()
.header(API_TOKEN_HTTP_HEADER, apiToken)
.body(draftJson)
.contentType("application/json")
.put("/api/datasets/:persistentId/versions/" + DS_VERSION_DRAFT + "?persistentId=" + datasetPid)
.then().assertThat().statusCode(OK.getStatusCode());

// 6. Verify it was a no-op (lastUpdateTime should NOT have changed)
Response draftResponseAfter = UtilIT.getDatasetVersion(datasetPid, DS_VERSION_DRAFT, apiToken);
String lastUpdateTimeAfter = draftResponseAfter.jsonPath().getString("data.lastUpdateTime");

assertEquals(lastUpdateTimeBefore, lastUpdateTimeAfter, "Last update time should not change for no-op metadata update on draft");
}

private String getSuperuserToken() {
Response createResponse = UtilIT.createRandomUser();
String adminApiToken = UtilIT.getApiTokenFromResponse(createResponse);
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/edu/harvard/iq/dataverse/api/DatasetsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,44 @@
import edu.harvard.iq.dataverse.Dataset;
import edu.harvard.iq.dataverse.GlobalId;
import edu.harvard.iq.dataverse.pidproviders.doi.AbstractDOIProvider;
import edu.harvard.iq.dataverse.*;
import org.junit.jupiter.api.Test;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;

public class DatasetsTest {

@Test
public void testIsDatasetVersionNoOp() {
DatasetVersion incoming = emptyVersion();
DatasetVersion latest = emptyVersion();
assertTrue(Datasets.isDatasetVersionNoOp(incoming, latest));

DatasetField field = new DatasetField();
DatasetFieldType type = new DatasetFieldType();
type.setName("title");
type.setChildDatasetFieldTypes(List.of());
field.setDatasetFieldType(type);
field.setDatasetFieldValues(List.of(new DatasetFieldValue(field, "Changed title")));
incoming.setDatasetFields(List.of(field));

assertFalse(Datasets.isDatasetVersionNoOp(incoming, latest));
}

private static DatasetVersion emptyVersion() {
DatasetVersion v = new DatasetVersion();
v.setTermsOfUseAndAccess(new TermsOfUseAndAccess());
return v;
}

/**
* Test cleanup filter
*/
Expand Down