package edu.harvard.iq.dataverse.api; import com.jayway.restassured.RestAssured; import com.jayway.restassured.path.json.JsonPath; import com.jayway.restassured.response.Response; import edu.harvard.iq.dataverse.GlobalId; import edu.harvard.iq.dataverse.api.datadeposit.SwordConfigurationImpl; import java.util.List; import java.util.logging.Logger; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.CREATED; import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static javax.ws.rs.core.Response.Status.UNAUTHORIZED; import static javax.ws.rs.core.Response.Status.METHOD_NOT_ALLOWED; import static javax.ws.rs.core.Response.Status.NOT_FOUND; import static javax.ws.rs.core.Response.Status.NO_CONTENT; import static javax.ws.rs.core.Response.Status.OK; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.endsWith; import org.junit.AfterClass; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.BeforeClass; import org.junit.Test; /** * In all these tests you should never see something like "[long string exposing * internal user details] ...is missing permissions [AddDataset] on Object" * which is an indication that we have failed to put a permission check in place * and failed to write a human-readable response. * * @todo Add tests for "Member" role after "createAssignment" in Datasets.java * is real. "grantRoleOnDataset" in UtilIT.java is not used despite being in * https://github.com/IQSS/dataverse/pull/3111 */ public class SwordIT { private static final Logger logger = Logger.getLogger(SwordIT.class.getCanonicalName()); private static String superuser; private static final String rootDataverseAlias = "root"; private static String apiTokenSuperuser; @BeforeClass public static void setUpClass() { RestAssured.baseURI = UtilIT.getRestAssuredBaseUri(); boolean testAgainstDev1 = false; if (testAgainstDev1) { RestAssured.baseURI = "https://dev1.dataverse.org"; } Response createUser = UtilIT.createRandomUser(); superuser = UtilIT.getUsernameFromResponse(createUser); apiTokenSuperuser = UtilIT.getApiTokenFromResponse(createUser); String apitoken = UtilIT.getApiTokenFromResponse(createUser); UtilIT.makeSuperUser(superuser).then().assertThat().statusCode(OK.getStatusCode()); Response checkRootDataverse = UtilIT.listDatasetsViaSword(rootDataverseAlias, apitoken); checkRootDataverse.prettyPrint(); checkRootDataverse.then().assertThat() .statusCode(OK.getStatusCode()); boolean rootDataverseHasBeenReleased = checkRootDataverse.getBody().xmlPath().getBoolean("feed.dataverseHasBeenReleased"); if (!rootDataverseHasBeenReleased) { logger.info("Many of these SWORD tests require that the root dataverse has been published. Publish the root dataverse and then re-run these tests."); System.exit(666); } } @Test public void testServiceDocument() { Response createUser = UtilIT.createRandomUser(); String username = UtilIT.getUsernameFromResponse(createUser); String apitoken = UtilIT.getApiTokenFromResponse(createUser); Response serviceDocumentResponse = UtilIT.getServiceDocument(apitoken); serviceDocumentResponse.prettyPrint(); SwordConfigurationImpl swordConfiguration = new SwordConfigurationImpl(); serviceDocumentResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("service.version", equalTo(swordConfiguration.generatorVersion())); String collection = serviceDocumentResponse.getBody().xmlPath().get("service.workspace.collection").toString(); System.out.println("collection: " + collection); /** * We assume that you have configured your installation to allow the * ":authenticated-users" groups to create datasets in the root * dataverse via the "fullContributor" role or similar. */ assertTrue(serviceDocumentResponse.body().asString().contains("swordv2/collection/dataverse/root")); Response deleteUser1Response = UtilIT.deleteUser(username); deleteUser1Response.prettyPrint(); boolean issue2825Resolved = false; if (issue2825Resolved) { /** * We can't delete this user because in some cases the user has * released the root dataverse: * https://github.com/IQSS/dataverse/issues/2825 */ assertEquals(200, deleteUser1Response.getStatusCode()); } UtilIT.deleteUser(username); } @Test public void testServiceDocumentWithInvalidApiToken() { Response serviceDocumentResponse = UtilIT.getServiceDocument("invalidApiToken"); // serviceDocumentResponse.prettyPrint(); serviceDocumentResponse.then().assertThat() .statusCode(FORBIDDEN.getStatusCode()); } @Test public void testCreateDataverseCreateDatasetUploadFileDownloadFileEditTitle() { Response createUser = UtilIT.createRandomUser(); String username = UtilIT.getUsernameFromResponse(createUser); String apiToken = UtilIT.getApiTokenFromResponse(createUser); Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); createDataverseResponse.prettyPrint(); String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); assertEquals(CREATED.getStatusCode(), createDataverseResponse.getStatusCode()); String initialDatasetTitle = "My Working Title"; Response randomUnprivUser = UtilIT.createRandomUser(); String apiTokenNoPrivs = UtilIT.getApiTokenFromResponse(randomUnprivUser); String usernameNoPrivs = UtilIT.getUsernameFromResponse(randomUnprivUser); Response createDatasetShouldFail = UtilIT.createDatasetViaSwordApi(dataverseAlias, initialDatasetTitle, apiTokenNoPrivs); createDatasetShouldFail.prettyPrint(); createDatasetShouldFail.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("user " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to create a dataset in this dataverse.")); /** * "Clients MUST NOT require a Collection Feed Document for deposit * operation." -- 6.2 Listing Collections * http://swordapp.github.io/SWORDv2-Profile/SWORDProfile.html#protocoloperations_listingcollections */ Response createDatasetResponse = UtilIT.createDatasetViaSwordApi(dataverseAlias, initialDatasetTitle, apiToken); createDatasetResponse.prettyPrint(); assertEquals(CREATED.getStatusCode(), createDatasetResponse.getStatusCode()); String persistentId = UtilIT.getDatasetPersistentIdFromResponse(createDatasetResponse); logger.info("persistent id: " + persistentId); Response atomEntryUnAuth = UtilIT.getSwordAtomEntry(persistentId, apiTokenNoPrivs); atomEntryUnAuth.prettyPrint(); atomEntryUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("User " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to retrieve entry for " + persistentId)); Response atomEntry = UtilIT.getSwordAtomEntry(persistentId, apiToken); atomEntry.prettyPrint(); atomEntry.then().assertThat() .statusCode(OK.getStatusCode()) .body("entry.treatment", equalTo("no treatment information available")); Response listDatasetsUnAuth = UtilIT.listDatasetsViaSword(dataverseAlias, apiTokenNoPrivs); listDatasetsUnAuth.prettyPrint(); listDatasetsUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("user " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to list datasets in dataverse " + dataverseAlias)); Response listDatasetsResponse = UtilIT.listDatasetsViaSword(dataverseAlias, apiToken); listDatasetsResponse.prettyPrint(); listDatasetsResponse.then().assertThat() .statusCode(OK.getStatusCode()) .body("feed.dataverseHasBeenReleased", equalTo("false")) .body("feed.entry[0].title", equalTo(initialDatasetTitle)); Response uploadFileUnAuth = UtilIT.uploadRandomFile(persistentId, apiTokenNoPrivs); uploadFileUnAuth.prettyPrint(); uploadFileUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("user " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to modify dataset with global ID " + persistentId)); Response uploadFile1 = UtilIT.uploadRandomFile(persistentId, apiToken); uploadFile1.prettyPrint(); assertEquals(CREATED.getStatusCode(), uploadFile1.getStatusCode()); Response swordStatementUnAuth = UtilIT.getSwordStatement(persistentId, apiTokenNoPrivs); swordStatementUnAuth.prettyPrint(); swordStatementUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .body("error.summary", equalTo("user " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to view dataset with global ID " + persistentId)) .statusCode(BAD_REQUEST.getStatusCode()); Response swordStatement = UtilIT.getSwordStatement(persistentId, apiToken); swordStatement.prettyPrint(); String title = UtilIT.getTitleFromSwordStatementResponse(swordStatement); assertEquals(initialDatasetTitle, title); Integer fileId = UtilIT.getFileIdFromSwordStatementResponse(swordStatement); assertNotNull(fileId); assertEquals(Integer.class, fileId.getClass()); logger.info("Id of uploaded file: " + fileId); String filename = UtilIT.getFilenameFromSwordStatementResponse(swordStatement); assertNotNull(filename); assertEquals(String.class, filename.getClass()); logger.info("Filename of uploaded file: " + filename); assertEquals("trees.png", filename); Response attemptToDownloadUnpublishedFileWithoutApiToken = UtilIT.downloadFile(fileId); attemptToDownloadUnpublishedFileWithoutApiToken.then().assertThat() .body("html.head.title", equalTo("403 Not Authorized - Root Dataverse")) .statusCode(FORBIDDEN.getStatusCode()); Response attemptToDownloadUnpublishedFileUnauthApiToken = UtilIT.downloadFile(fileId, apiTokenNoPrivs); attemptToDownloadUnpublishedFileUnauthApiToken.prettyPrint(); attemptToDownloadUnpublishedFileUnauthApiToken.then().assertThat() .body("html.head.title", equalTo("403 Not Authorized - Root Dataverse")) .statusCode(FORBIDDEN.getStatusCode()); Response downloadUnpublishedFileWithValidApiToken = UtilIT.downloadFile(fileId, apiToken); assertEquals(OK.getStatusCode(), downloadUnpublishedFileWithValidApiToken.getStatusCode()); logger.info("downloaded " + downloadUnpublishedFileWithValidApiToken.getContentType() + " (" + downloadUnpublishedFileWithValidApiToken.asByteArray().length + " bytes)"); Response deleteFileUnAuth = UtilIT.deleteFile(fileId, apiTokenNoPrivs); deleteFileUnAuth.prettyPrint(); deleteFileUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("User " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to modify " + dataverseAlias)); Response deleteFile = UtilIT.deleteFile(fileId, apiToken); deleteFile.prettyPrint(); deleteFile.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); Response downloadDeletedFileWithValidApiToken = UtilIT.downloadFile(fileId, apiToken); assertEquals(NOT_FOUND.getStatusCode(), downloadDeletedFileWithValidApiToken.getStatusCode()); String newTitle = "My Awesome Dataset"; Response updatedMetadataUnAuth = UtilIT.updateDatasetTitleViaSword(persistentId, newTitle, apiTokenNoPrivs); updatedMetadataUnAuth.prettyPrint(); updatedMetadataUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) /** * @todo This error doesn't make a ton of sense. Something like * "not authorized to modify dataset metadata" would be better. */ .body("error.summary", equalTo("User " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to modify dataverse " + dataverseAlias)); Response updatedMetadataResponse = UtilIT.updateDatasetTitleViaSword(persistentId, newTitle, apiToken); updatedMetadataResponse.prettyPrint(); swordStatement = UtilIT.getSwordStatement(persistentId, apiToken); title = UtilIT.getTitleFromSwordStatementResponse(swordStatement); assertEquals(newTitle, title); logger.info("Title updated from \"" + initialDatasetTitle + "\" to \"" + newTitle + "\"."); Response deleteDatasetUnAuth = UtilIT.deleteLatestDatasetVersionViaSwordApi(persistentId, apiTokenNoPrivs); deleteDatasetUnAuth.prettyPrint(); deleteDatasetUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("User " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to modify " + dataverseAlias)); Response deleteDatasetResponse = UtilIT.deleteLatestDatasetVersionViaSwordApi(persistentId, apiToken); deleteDatasetResponse.prettyPrint(); deleteDatasetResponse.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); Response deleteDataverse = UtilIT.deleteDataverse(dataverseAlias, apiToken); deleteDataverse.prettyPrint(); deleteDataverse.then().assertThat() .statusCode(OK.getStatusCode()); UtilIT.deleteUser(username); UtilIT.deleteUser(usernameNoPrivs); } /** * This test requires the root dataverse to have been published already. We * assume the default, out-of-the-box configuration that the answer to the * question "What should be the default role for someone adding datasets to * this dataverse?" is "Contributor" rather than "Curator". We are * permitting both dataverse and datasets to be created in the root * dataverse (:authenticated-users gets fullContributor at root). */ @Test public void testCreateAndDeleteDatasetInRoot() { Response createUser = UtilIT.createRandomUser(); String username = UtilIT.getUsernameFromResponse(createUser); String apiTokenContributor = UtilIT.getApiTokenFromResponse(createUser); String datasetTitle = "Dataset In Root"; Response randomUnprivUser = UtilIT.createRandomUser(); String apiTokenNoPrivs = UtilIT.getApiTokenFromResponse(randomUnprivUser); String usernameNoPrivs = UtilIT.getUsernameFromResponse(randomUnprivUser); String persistentId = null; Integer datasetId = null; String protocol; String authority; String identifier = null; Response createDataset = UtilIT.createDatasetViaSwordApi(rootDataverseAlias, datasetTitle, apiTokenContributor); createDataset.prettyPrint(); createDataset.then().assertThat() .statusCode(CREATED.getStatusCode()) .body("entry.treatment", equalTo("no treatment information available")); persistentId = UtilIT.getDatasetPersistentIdFromResponse(createDataset); GlobalId globalId = new GlobalId(persistentId); protocol = globalId.getProtocol(); authority = globalId.getAuthority(); identifier = globalId.getIdentifier(); Response listDatasetsAtRoot = UtilIT.listDatasetsViaSword(rootDataverseAlias, apiTokenContributor); listDatasetsAtRoot.prettyPrint(); listDatasetsAtRoot.then().assertThat().statusCode(OK.getStatusCode()); assertTrue(listDatasetsAtRoot.body().asString().contains(identifier)); Response listDatasetsAtRootNoPrivs = UtilIT.listDatasetsViaSword(rootDataverseAlias, apiTokenNoPrivs); listDatasetsAtRootNoPrivs.prettyPrint(); listDatasetsAtRootNoPrivs.then().assertThat() .statusCode(OK.getStatusCode()) /** * Because the root dataverse allows anyone to create datasets * in it, we allow anyone to see via SWORD if the dataverse has * been published... */ .body("feed.dataverseHasBeenReleased", equalTo("true")); /** * ... but not just anyone should be able to see your dataset, only * those with edit access. */ assertFalse(listDatasetsAtRootNoPrivs.body().asString().contains(identifier)); Response atomEntry = UtilIT.getSwordAtomEntry(persistentId, apiTokenContributor); atomEntry.prettyPrint(); atomEntry.then().assertThat() .statusCode(OK.getStatusCode()) .body("entry.id", endsWith(persistentId)); Response uploadFile = UtilIT.uploadRandomFile(persistentId, apiTokenContributor); uploadFile.prettyPrint(); uploadFile.then().assertThat().statusCode(CREATED.getStatusCode()); Response statementContainingFile = UtilIT.getSwordStatement(persistentId, apiTokenContributor); statementContainingFile.prettyPrint(); statementContainingFile.then().assertThat() .statusCode(OK.getStatusCode()) .body("feed.id", endsWith(persistentId)) .body("feed.title", equalTo(datasetTitle)) .body("feed.author.name", equalTo("Lastname, Firstname")) .body("feed.entry[0].summary", equalTo("Resource Part")) .body("feed.entry[0].id", endsWith("trees.png")); String firstAndOnlyFileIdAsString = statementContainingFile.getBody().xmlPath().get("feed.entry[0].id").toString().split("/")[10]; Response deleteFile = UtilIT.deleteFile(Integer.parseInt(firstAndOnlyFileIdAsString), apiTokenContributor); deleteFile.prettyPrint(); deleteFile.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); Response statementWithNoFiles = UtilIT.getSwordStatement(persistentId, apiTokenContributor); statementWithNoFiles.prettyPrint(); statementWithNoFiles.then().assertThat() .statusCode(OK.getStatusCode()) .body("feed.title", equalTo(datasetTitle)); try { String attemptToGetFileId = statementWithNoFiles.getBody().xmlPath().get("feed.entry[0].id").toString().split("/")[10]; System.out.println("attemptToGetFileId: " + attemptToGetFileId); assertNull(attemptToGetFileId); } catch (Exception ex) { System.out.println("We expect an exception here because we can no longer find the file because deleted it: " + ex); assertTrue(ex.getClass().getName().equals(ArrayIndexOutOfBoundsException.class.getName())); } String newTitle = "A New Hope"; Response updateTitle = UtilIT.updateDatasetTitleViaSword(persistentId, newTitle, apiTokenContributor); updateTitle.prettyPrint(); updateTitle.then().assertThat() .statusCode(OK.getStatusCode()) .body("entry.treatment", equalTo("no treatment information available")); Response statementWithUpdatedTitle = UtilIT.getSwordStatement(persistentId, apiTokenContributor); statementWithUpdatedTitle.prettyPrint(); statementWithUpdatedTitle.then().assertThat() .statusCode(OK.getStatusCode()) .body("feed.title", equalTo(newTitle)); Response nativeGetToGetId = UtilIT.nativeGetUsingPersistentId(persistentId, apiTokenContributor); nativeGetToGetId.then().assertThat() .statusCode(OK.getStatusCode()); datasetId = JsonPath.from(nativeGetToGetId.body().asString()).getInt("data.id"); Response listDatasetsAtRootAsSuperuser = UtilIT.listDatasetsViaSword(rootDataverseAlias, apiTokenSuperuser); listDatasetsAtRootAsSuperuser.prettyPrint(); listDatasetsAtRootAsSuperuser.then().assertThat().statusCode(OK.getStatusCode()); assertTrue(listDatasetsAtRootAsSuperuser.body().asString().contains(identifier)); Response rootDataverseContents = UtilIT.showDataverseContents(rootDataverseAlias, apiTokenContributor); rootDataverseContents.prettyPrint(); logger.info("We expect to find \"" + identifier + "\" from the persistent ID to be present."); assertTrue(rootDataverseContents.body().asString().contains(identifier)); Response publishShouldFailForContributorViaSword = UtilIT.publishDatasetViaSword(persistentId, apiTokenContributor); publishShouldFailForContributorViaSword.prettyPrint(); publishShouldFailForContributorViaSword.then().assertThat() .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("User " + username + " " + username + " is not authorized to modify dataverse " + rootDataverseAlias)); Response publishShouldFailForContributorViaNative = UtilIT.publishDatasetViaNativeApi(datasetId, "major", apiTokenContributor); publishShouldFailForContributorViaNative.prettyPrint(); publishShouldFailForContributorViaNative.then().assertThat() .statusCode(UNAUTHORIZED.getStatusCode()) .body("message", equalTo("User @" + username + " is not permitted to perform requested action.")); Response deleteDatasetResponse = UtilIT.deleteLatestDatasetVersionViaSwordApi(persistentId, apiTokenContributor); deleteDatasetResponse.prettyPrint(); deleteDatasetResponse.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); UtilIT.deleteUser(username); UtilIT.deleteUser(usernameNoPrivs); // UtilIT.listDatasetsViaSword(rootDataverseAlias, apiTokenSuperuser).prettyPrint(); } /** * This test requires the root dataverse to have been published already. */ @Test public void testCreateDatasetPublishDestroy() { Response createUser = UtilIT.createRandomUser(); String username = UtilIT.getUsernameFromResponse(createUser); String apiToken = UtilIT.getApiTokenFromResponse(createUser); Response createDataverse = UtilIT.createRandomDataverse(apiToken); createDataverse.prettyPrint(); createDataverse.then().assertThat() .statusCode(CREATED.getStatusCode()); String dataverseAlias = UtilIT.getAliasFromResponse(createDataverse); String datasetTitle = "Publish or Perist"; Response createDataset = UtilIT.createDatasetViaSwordApi(dataverseAlias, datasetTitle, apiToken); createDataset.prettyPrint(); createDataset.then().assertThat() .statusCode(CREATED.getStatusCode()); String persistentId = UtilIT.getDatasetPersistentIdFromResponse(createDataset); Response attemptToPublishDatasetInUnpublishedDataverse = UtilIT.publishDatasetViaSword(persistentId, apiToken); attemptToPublishDatasetInUnpublishedDataverse.prettyPrint(); attemptToPublishDatasetInUnpublishedDataverse.then().assertThat() .statusCode(BAD_REQUEST.getStatusCode()); Response randomUnprivUser = UtilIT.createRandomUser(); String apiTokenNoPrivs = UtilIT.getApiTokenFromResponse(randomUnprivUser); String usernameNoPrivs = UtilIT.getUsernameFromResponse(randomUnprivUser); Response publishDataverseUnAuth = UtilIT.publishDataverseViaSword(dataverseAlias, apiTokenNoPrivs); publishDataverseUnAuth.prettyPrint(); publishDataverseUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("User " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to modify dataverse " + dataverseAlias)); Response publishDataverse = UtilIT.publishDataverseViaSword(dataverseAlias, apiToken); publishDataverse.prettyPrint(); publishDataverse.then().assertThat() .statusCode(OK.getStatusCode()); Response publishDatsetUnAuth = UtilIT.publishDatasetViaSword(persistentId, apiTokenNoPrivs); System.out.println("BEGIN"); publishDatsetUnAuth.prettyPrint(); System.out.println("END"); publishDatsetUnAuth.then().assertThat() /** * @todo It would be nice if this could be UNAUTHORIZED or * FORBIDDEN rather than BAD_REQUEST. */ .statusCode(BAD_REQUEST.getStatusCode()) .body("error.summary", equalTo("User " + usernameNoPrivs + " " + usernameNoPrivs + " is not authorized to modify dataverse " + dataverseAlias)); Response publishDataset = UtilIT.publishDatasetViaSword(persistentId, apiToken); publishDataset.prettyPrint(); publishDataset.then().assertThat() .statusCode(OK.getStatusCode()); Response attemptToDeletePublishedDataset = UtilIT.deleteLatestDatasetVersionViaSwordApi(persistentId, apiToken); attemptToDeletePublishedDataset.prettyPrint(); attemptToDeletePublishedDataset.then().assertThat() .statusCode(METHOD_NOT_ALLOWED.getStatusCode()); String newTitle = "A New Hope"; Response updateTitle = UtilIT.updateDatasetTitleViaSword(persistentId, newTitle, apiToken); updateTitle.prettyPrint(); updateTitle.then().assertThat() .statusCode(OK.getStatusCode()) .body("entry.treatment", equalTo("no treatment information available")); Response deletePostPublicationDraft = UtilIT.deleteLatestDatasetVersionViaSwordApi(persistentId, apiToken); deletePostPublicationDraft.prettyPrint(); deletePostPublicationDraft.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); /** * @todo This can probably be removed now that * https://github.com/IQSS/dataverse/issues/1837 has been fixed. */ Response reindexDatasetToFindDatabaseId = UtilIT.reindexDataset(persistentId); reindexDatasetToFindDatabaseId.prettyPrint(); reindexDatasetToFindDatabaseId.then().assertThat() .statusCode(OK.getStatusCode()); Integer datasetId = JsonPath.from(reindexDatasetToFindDatabaseId.asString()).getInt("data.id"); /** * @todo The "destroy" endpoint should accept a persistentId: * https://github.com/IQSS/dataverse/issues/1837 */ Response makeSuperuserRespone = UtilIT.makeSuperUser(username); makeSuperuserRespone.then().assertThat() .statusCode(OK.getStatusCode()); Response destroyDataset = UtilIT.destroyDataset(datasetId, apiToken); destroyDataset.prettyPrint(); destroyDataset.then().assertThat() .statusCode(OK.getStatusCode()); Response atomEntryDestroyed = UtilIT.getSwordAtomEntry(persistentId, apiToken); atomEntryDestroyed.prettyPrint(); atomEntryDestroyed.then().statusCode(400); Response deleteDataverseResponse = UtilIT.deleteDataverse(dataverseAlias, apiToken); deleteDataverseResponse.prettyPrint(); assertEquals(200, deleteDataverseResponse.getStatusCode()); UtilIT.deleteUser(username); UtilIT.deleteUser(usernameNoPrivs); } /** * This test requires the root dataverse to have been published already. * * Test the following issues: * * - https://github.com/IQSS/dataverse/issues/1784 * * - https://github.com/IQSS/dataverse/issues/2222 * * - https://github.com/IQSS/dataverse/issues/2464 */ @Test public void testDeleteFiles() { Response createUser = UtilIT.createRandomUser(); String username = UtilIT.getUsernameFromResponse(createUser); String apiToken = UtilIT.getApiTokenFromResponse(createUser); Response createDataverse = UtilIT.createRandomDataverse(apiToken); createDataverse.prettyPrint(); String dataverseAlias = UtilIT.getAliasFromResponse(createDataverse); Response createDataset = UtilIT.createRandomDatasetViaSwordApi(dataverseAlias, apiToken); createDataset.prettyPrint(); String datasetPersistentId = UtilIT.getDatasetPersistentIdFromResponse(createDataset); Response uploadZip = UtilIT.uploadFile(datasetPersistentId, "3files.zip", apiToken); uploadZip.prettyPrint(); assertEquals(CREATED.getStatusCode(), uploadZip.getStatusCode()); Response statement1 = UtilIT.getSwordStatement(datasetPersistentId, apiToken); statement1.prettyPrint(); String index0a = statement1.getBody().xmlPath().get("feed.entry[0].id").toString().split("/")[10]; String index1a = statement1.getBody().xmlPath().get("feed.entry[1].id").toString().split("/")[10]; String index2a = statement1.getBody().xmlPath().get("feed.entry[2].id").toString().split("/")[10]; List<String> fileList = statement1.getBody().xmlPath().getList("feed.entry.id"); logger.info("Dataset contains file ids: " + index0a + " " + index1a + " " + index2a + " (" + fileList.size() + ") files"); Response deleteIndex0a = UtilIT.deleteFile(Integer.parseInt(index0a), apiToken); // deleteIndex0a.prettyPrint(); deleteIndex0a.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); logger.info("Deleted file id " + index0a + " from draft of unpublished dataset."); Response statement2 = UtilIT.getSwordStatement(datasetPersistentId, apiToken); statement2.prettyPrint(); String index0b = statement2.getBody().xmlPath().get("feed.entry[0].id").toString().split("/")[10]; String index1b = statement2.getBody().xmlPath().get("feed.entry[1].id").toString().split("/")[10]; try { String index2b = statement2.getBody().xmlPath().get("feed.entry[2].id").toString().split("/")[10]; } catch (ArrayIndexOutOfBoundsException ex) { // expected since file has been deleted } logger.info("Dataset contains file ids: " + index0b + " " + index1b); List<String> twoFilesLeftInV2Draft = statement2.getBody().xmlPath().getList("feed.entry.id"); logger.info("Number of files remaining in this draft:" + twoFilesLeftInV2Draft.size()); assertEquals(2, twoFilesLeftInV2Draft.size()); Response publishDataverse = UtilIT.publishDataverseViaSword(dataverseAlias, apiToken); // publishDataverse.prettyPrint(); publishDataverse.then().assertThat() .statusCode(OK.getStatusCode()); logger.info("dataset has not yet been published:"); Response atomEntryUnpublished = UtilIT.getSwordAtomEntry(datasetPersistentId, apiToken); atomEntryUnpublished.prettyPrint(); Response publishDataset = UtilIT.publishDatasetViaSword(datasetPersistentId, apiToken); // publishDataset.prettyPrint(); publishDataset.then().assertThat() .statusCode(OK.getStatusCode()); logger.info("dataset has been published:"); Response atomEntryPublishedV1 = UtilIT.getSwordAtomEntry(datasetPersistentId, apiToken); atomEntryPublishedV1.prettyPrint(); Response deleteIndex0b = UtilIT.deleteFile(Integer.parseInt(index0b), apiToken); // deleteIndex0b.prettyPrint(); deleteIndex0b.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); logger.info("Deleted file id " + index0b + " from published dataset (should create draft)."); Response statement3 = UtilIT.getSwordStatement(datasetPersistentId, apiToken); statement3.prettyPrint(); logger.info("draft created from published dataset because a file was deleted:"); Response atomEntryDraftV2 = UtilIT.getSwordAtomEntry(datasetPersistentId, apiToken); atomEntryDraftV2.prettyPrint(); String citation = atomEntryDraftV2.body().xmlPath().getString("entry.bibliographicCitation"); logger.info("citation (should contain 'DRAFT'): " + citation); boolean draftStringFoundInCitation = citation.matches(".*DRAFT.*"); assertEquals(true, draftStringFoundInCitation); List<String> oneFileLeftInV2Draft = statement3.getBody().xmlPath().getList("feed.entry.id"); logger.info("Number of files remaining in this post version 1 draft:" + oneFileLeftInV2Draft.size()); assertEquals(1, oneFileLeftInV2Draft.size()); Response deleteIndex1b = UtilIT.deleteFile(Integer.parseInt(index1b), apiToken); deleteIndex1b.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); logger.info("Deleted file id " + index1b + " from draft version of a published dataset."); Response statement4 = UtilIT.getSwordStatement(datasetPersistentId, apiToken); statement4.prettyPrint(); List<String> fileListEmpty = statement4.getBody().xmlPath().getList("feed.entry.id"); logger.info("Number of files remaining:" + fileListEmpty.size()); assertEquals(0, fileListEmpty.size()); Response deleteDatasetDraft = UtilIT.deleteLatestDatasetVersionViaSwordApi(datasetPersistentId, apiToken); deleteDatasetDraft.prettyPrint(); Response statement5 = UtilIT.getSwordStatement(datasetPersistentId, apiToken); statement5.prettyPrint(); List<String> twoFilesinV1published = statement5.getBody().xmlPath().getList("feed.entry.id"); logger.info("Number of files in V1 (draft has been deleted)" + twoFilesinV1published.size()); assertEquals(2, twoFilesinV1published.size()); /** * @todo The "destroy" endpoint should accept a persistentId: * https://github.com/IQSS/dataverse/issues/1837 */ Response reindexDatasetToFindDatabaseId = UtilIT.reindexDataset(datasetPersistentId); reindexDatasetToFindDatabaseId.prettyPrint(); reindexDatasetToFindDatabaseId.then().assertThat() .statusCode(OK.getStatusCode()); Integer datasetId3 = JsonPath.from(reindexDatasetToFindDatabaseId.asString()).getInt("data.id"); Response makeSuperuserRespone = UtilIT.makeSuperUser(username); makeSuperuserRespone.then().assertThat() .statusCode(OK.getStatusCode()); Response destroyDataset = UtilIT.destroyDataset(datasetId3, apiToken); destroyDataset.prettyPrint(); destroyDataset.then().assertThat() .statusCode(OK.getStatusCode()); logger.info("Dataset has been destroyed: " + datasetPersistentId + " id " + datasetId3 + " but let's double check we can't access it..."); Response atomEntryDestroyed = UtilIT.getSwordAtomEntry(datasetPersistentId, apiToken); atomEntryDestroyed.prettyPrint(); atomEntryDestroyed.then().statusCode(400); Response createDataset4 = UtilIT.createRandomDatasetViaSwordApi(dataverseAlias, apiToken); createDataset4.prettyPrint(); String datasetPersistentId4 = UtilIT.getDatasetPersistentIdFromResponse(createDataset4); Response uploadZipToDataset4 = UtilIT.uploadFile(datasetPersistentId4, "3files.zip", apiToken); uploadZipToDataset4.prettyPrint(); assertEquals(CREATED.getStatusCode(), uploadZipToDataset4.getStatusCode()); Response publishDataset4 = UtilIT.publishDatasetViaSword(datasetPersistentId4, apiToken); // publishDataset4.prettyPrint(); publishDataset4.then().assertThat() .statusCode(OK.getStatusCode()); Response statement4a = UtilIT.getSwordStatement(datasetPersistentId4, apiToken); statement4a.prettyPrint(); List<String> threePublishedFiles = statement4a.getBody().xmlPath().getList("feed.entry.id"); logger.info("Number of files in lastest version (v1 published) of " + datasetPersistentId4 + threePublishedFiles.size()); assertEquals(3, threePublishedFiles.size()); String dataset4FileIndex0 = statement4a.getBody().xmlPath().get("feed.entry[0].id").toString().split("/")[10]; String dataset4FileIndex1 = statement4a.getBody().xmlPath().get("feed.entry[1].id").toString().split("/")[10]; String dataset4FileIndex2 = statement4a.getBody().xmlPath().get("feed.entry[2].id").toString().split("/")[10]; /** * @todo Fix https://github.com/IQSS/dataverse/issues/2464 so that *any* * file can be deleted via SWORD and not just the first file (zero * index). Attempting to delete dataset4FileIndex1 or dataset4FileIndex2 * will exercise the bug. Attempting to delete dataset4FileIndex0 will * not. */ String fileToDeleteFromDataset4 = dataset4FileIndex1; Response deleteFileFromDataset4 = UtilIT.deleteFile(Integer.parseInt(fileToDeleteFromDataset4), apiToken); deleteFileFromDataset4.then().assertThat() .statusCode(NO_CONTENT.getStatusCode()); logger.info("Deleted file id " + fileToDeleteFromDataset4 + " from " + datasetPersistentId4 + " which should move it from published to draft."); Response statement4b = UtilIT.getSwordStatement(datasetPersistentId4, apiToken); statement4b.prettyPrint(); boolean issue2464fixed = false; if (issue2464fixed) { List<String> datasetMovedToDraftWithTwoFilesLeft = statement4b.getBody().xmlPath().getList("feed.entry.id"); logger.info("Number of files left in " + datasetPersistentId4 + ": " + datasetMovedToDraftWithTwoFilesLeft.size()); assertEquals(2, datasetMovedToDraftWithTwoFilesLeft.size()); } else { List<String> issue2464NotFixedYetSoAllThreeFilesRemain = statement4b.getBody().xmlPath().getList("feed.entry.id"); logger.info("Number of files left in " + datasetPersistentId4 + ": " + issue2464NotFixedYetSoAllThreeFilesRemain.size()); } /** * @todo The "destroy" endpoint should accept a persistentId: * https://github.com/IQSS/dataverse/issues/1837 */ Response reindexDataset4ToFindDatabaseId = UtilIT.reindexDataset(datasetPersistentId4); reindexDataset4ToFindDatabaseId.prettyPrint(); reindexDataset4ToFindDatabaseId.then().assertThat() .statusCode(OK.getStatusCode()); Integer datasetId4 = JsonPath.from(reindexDataset4ToFindDatabaseId.asString()).getInt("data.id"); Response destroyDataset4 = UtilIT.destroyDataset(datasetId4, apiToken); destroyDataset4.prettyPrint(); destroyDataset4.then().assertThat() .statusCode(OK.getStatusCode()); Response deleteDataverse3Response = UtilIT.deleteDataverse(dataverseAlias, apiToken); deleteDataverse3Response.prettyPrint(); assertEquals(200, deleteDataverse3Response.getStatusCode()); UtilIT.deleteUser(username); } @AfterClass public static void tearDownClass() { UtilIT.deleteUser(superuser); } }