/** * PODD is an OWL ontology database used for scientific project management * * Copyright (C) 2009-2013 The University Of Queensland * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. */ package com.github.podd.resources.test; import java.io.ByteArrayInputStream; import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.util.Collection; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import org.openrdf.model.Model; import org.openrdf.rio.RDFFormat; import org.openrdf.rio.Rio; import org.restlet.data.MediaType; import org.restlet.data.Method; import org.restlet.data.Status; import org.restlet.representation.Representation; import org.restlet.resource.ClientResource; import org.restlet.resource.ResourceException; import com.github.podd.api.test.TestConstants; import com.github.podd.utils.InferredOWLOntologyID; import com.github.podd.utils.OntologyUtils; import com.github.podd.utils.PODD; import com.github.podd.utils.PoddWebConstants; /** * * @author kutila */ public class EditArtifactResourceImplTest extends AbstractResourceImplTest { @Ignore @Test public void testEditArtifactBasicJson() throws Exception { Assert.fail("TODO: implement"); } @Test public void testEditArtifactBasicRdf() throws Exception { // prepare: add an artifact final InferredOWLOntologyID artifactID = this.loadTestArtifact(TestConstants.TEST_ARTIFACT_20130206, MediaType.APPLICATION_RDF_TURTLE); final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactID .getOntologyIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, artifactID .getVersionIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(false)); // "force" query parameter is false by default final Representation input = this.buildRepresentationFromResource(TestConstants.TEST_ARTIFACT_FRAGMENT_NEW_FILE_REF_OBJECT, MediaType.APPLICATION_RDF_XML); final Representation results = this.doTestAuthenticatedRequest(editArtifactClientResource, Method.POST, input, MediaType.APPLICATION_RDF_XML, Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN); final String body = this.getText(results); // verify: Inferred Ontology ID is received in RDF format Assert.assertTrue("Response not in RDF format", body.contains("<rdf:RDF")); Assert.assertTrue("Artifact version has not been updated properly", body.contains("artifact:1:version:2")); Assert.assertTrue("Version IRI not in response", body.contains("versionIRI")); Assert.assertTrue("Inferred version not in response", body.contains("inferredVersion")); // verify: publication46 has been added to the artifact final String artifactBody = this.getArtifactAsString(artifactID.getOntologyIRI().toString(), MediaType.APPLICATION_RDF_XML); Assert.assertTrue("New file ref not added to artifact", artifactBody.contains("Rice tree scan 003454-98")); Assert.assertTrue("New file ref not added to artifact", artifactBody.contains("object-rice-scan-34343-a")); } finally { this.releaseClient(editArtifactClientResource); } } @Test public void testEditArtifactBasicTurtle() throws Exception { // prepare: add an artifact final InferredOWLOntologyID artifactID = this.loadTestArtifact(TestConstants.TEST_ARTIFACT_20130206, MediaType.APPLICATION_RDF_TURTLE); final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactID .getOntologyIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, artifactID .getVersionIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(false)); // "force" query parameter is false by default // edit Representation contains statements in Turtle format final Representation input = this.buildRepresentationFromResource(TestConstants.TEST_ARTIFACT_FRAGMENT_NEW_PUBLICATION_OBJECT, MediaType.APPLICATION_RDF_TURTLE); final Representation results = this.doTestAuthenticatedRequest(editArtifactClientResource, Method.POST, input, MediaType.APPLICATION_RDF_TURTLE, Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN); final String updatedArtifactDetails = this.getText(results); // verify: Inferred Ontology ID is NOT in RDF format Assert.assertFalse("Response should not be in RDF format", updatedArtifactDetails.contains("<rdf:RDF")); Assert.assertTrue("Artifact version has not been updated properly", updatedArtifactDetails.contains("artifact:1:version:2")); Assert.assertTrue("Version IRI not in response", updatedArtifactDetails.contains("versionIRI")); Assert.assertTrue("Inferred version not in response", updatedArtifactDetails.contains("inferredVersion")); // verify: publication46 has been added to the artifact final String artifactBody = this.getArtifactAsString(artifactID.getOntologyIRI().toString(), MediaType.APPLICATION_RDF_TURTLE); Assert.assertTrue("New publication not added to artifact", artifactBody.contains("publication46")); // Assert.assertTrue("New publication not added to artifact", // artifactBody.contains("http://dx.doi.org/10.1109/eScience.2013.44")); } finally { this.releaseClient(editArtifactClientResource); } } @Test public void testEditArtifactTurtleWithDanglingObjects() throws Exception { // prepare: add an artifact final InferredOWLOntologyID artifactID = this.loadTestArtifact(TestConstants.TEST_ARTIFACT_20130206, MediaType.APPLICATION_RDF_TURTLE); final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactID .getOntologyIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, artifactID .getVersionIRI().toString()); editArtifactClientResource .addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(true)); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_FORCE, Boolean.toString(true)); // edit Representation contains statements in Turtle format final Representation input = this.buildRepresentationFromResource( TestConstants.TEST_ARTIFACT_FRAGMENT_MODIFY_DEMO_INVESTIGATION, MediaType.APPLICATION_RDF_TURTLE); final Representation results = this.doTestAuthenticatedRequest(editArtifactClientResource, Method.POST, input, MediaType.APPLICATION_RDF_TURTLE, Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN); final String updatedArtifactDetails = this.getText(results); // verify: Inferred Ontology ID is NOT in RDF format Assert.assertFalse("Response should not be in RDF format", updatedArtifactDetails.contains("<rdf:RDF")); Assert.assertTrue("Artifact version has not been updated properly", updatedArtifactDetails.contains("artifact:1:version:2")); Assert.assertTrue("Version IRI not in response", updatedArtifactDetails.contains("versionIRI")); Assert.assertTrue("Inferred version not in response", updatedArtifactDetails.contains("inferredVersion")); // verify: objects left dangling after edit have been removed from // the artifact final String artifactBody = this.getArtifactAsString(artifactID.getOntologyIRI().toString(), MediaType.APPLICATION_RDF_TURTLE); final String[] danglingObjects = { "http://purl.org/podd/basic-2-20130206/artifact:1#SqueekeeMaterial", "http://purl.org/podd/basic-2-20130206/artifact:1#Demo_genotype_3", "http://purl.org/podd/basic-2-20130206/artifact:1#Sequence_A", }; for(final String deletedObject : danglingObjects) { Assert.assertFalse("Dangling object still exists", artifactBody.contains(deletedObject)); } } finally { this.releaseClient(editArtifactClientResource); } } @Test public void testEditArtifactTurtleWithMultipleNewObjects() throws Exception { // prepare: add an artifact final InferredOWLOntologyID artifactID = this.loadTestArtifact(TestConstants.TEST_ARTIFACT_20130206, MediaType.APPLICATION_RDF_TURTLE); final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactID .getOntologyIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, artifactID .getVersionIRI().toString()); editArtifactClientResource .addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(true)); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_FORCE, Boolean.toString(true)); // prepare: add (temporary) object URIs that are being added final String[] newObjects = { "urn:temp:uuid:object-rice-scan-34343-a", "urn:temp:uuid:publication35", "urn:temp:uuid:publication46" }; for(final String objectUri : newObjects) { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_OBJECT_IDENTIFIER, objectUri); } // edit Representation contains statements in Turtle format final Representation input = this.buildRepresentationFromResource(TestConstants.TEST_ARTIFACT_FRAGMENT_MULTIPLE_OBJECTS_TTL, MediaType.APPLICATION_RDF_TURTLE); final Representation results = this.doTestAuthenticatedRequest(editArtifactClientResource, Method.POST, input, MediaType.APPLICATION_RDF_TURTLE, Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN); final String updatedArtifactDetails = this.getText(results); // verify: Inferred Ontology ID is NOT in RDF format Assert.assertFalse("Response should not be in RDF format", updatedArtifactDetails.contains("<rdf:RDF")); Assert.assertTrue("Artifact version has not been updated properly", updatedArtifactDetails.contains("artifact:1:version:2")); Assert.assertTrue("Version IRI not in response", updatedArtifactDetails.contains("versionIRI")); Assert.assertTrue("Inferred version not in response", updatedArtifactDetails.contains("inferredVersion")); // verify: response contains the ontology ID final Model model = Rio.parse(new StringReader(updatedArtifactDetails), "", RDFFormat.TURTLE); final Collection<InferredOWLOntologyID> updatedOntologyID = OntologyUtils.modelToOntologyIDs(model); Assert.assertEquals("Response did not contain an ontology ID", 1, updatedOntologyID.size()); // verify: response contains object URIs and their PURLs for(final String objectUri : newObjects) { final String purl = model.filter(PODD.VF.createURI(objectUri), PODD.PODD_REPLACED_TEMP_URI_WITH, null) .objectString(); Assert.assertNotNull("Object URI's PURL not in response", purl); Assert.assertTrue("PURL does not start as expected", purl.startsWith("http://example.org/purl/")); } final String artifactBody = this.getArtifactAsString(artifactID.getOntologyIRI().toString(), MediaType.APPLICATION_RDF_TURTLE); // verify: publication46 has been added to the artifact Assert.assertTrue("New publication not added to artifact", artifactBody.contains("publication46")); // Assert.assertTrue("New publication not added to artifact", // artifactBody.contains("http://dx.doi.org/10.1109/eScience.2013.44")); // verify: publication46 has been added to the artifact Assert.assertTrue("New publication not added to artifact", artifactBody.contains("publication35")); } finally { this.releaseClient(editArtifactClientResource); } } @Test public void testErrorEditArtifactRdfWithIncorrectArtifactID() throws Exception { // prepare: add an artifact final InferredOWLOntologyID artifactID = this.loadTestArtifact(TestConstants.TEST_ARTIFACT_20130206, MediaType.APPLICATION_RDF_TURTLE); // prepare: set an INVALID artifact IRI final String incorrectArtifactID = artifactID.getOntologyIRI().toString() + "_wrong"; final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, incorrectArtifactID); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, artifactID .getVersionIRI().toString()); editArtifactClientResource .addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(true)); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_FORCE, Boolean.toString(false)); // create edit Representation final Representation input = this.buildRepresentationFromResource(TestConstants.TEST_ARTIFACT_FRAGMENT_NEW_FILE_REF_OBJECT, MediaType.APPLICATION_RDF_XML); this.doTestAuthenticatedRequest(editArtifactClientResource, Method.POST, input, MediaType.APPLICATION_RDF_XML, Status.CLIENT_ERROR_NOT_FOUND, AbstractResourceImplTest.WITH_ADMIN); Assert.fail("Should have failed due to incorrect artifact IRI"); } catch(final ResourceException e) { Assert.assertEquals(Status.CLIENT_ERROR_NOT_FOUND, e.getStatus()); // TODO: verify the cause and details (as in // UploadArtifactResourceImplTest) final String body = this.getText(editArtifactClientResource.getResponseEntity()); final ByteArrayInputStream inputStream = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); final Model model = Rio.parse(inputStream, "", RDFFormat.RDFXML); final String sourceOfError = model.filter(null, PODD.ERR_SOURCE, null).objectString(); Assert.assertEquals("Err#source is not the incorrect artifact ID", incorrectArtifactID, sourceOfError); } finally { this.releaseClient(editArtifactClientResource); } } @Test public void testErrorEditArtifactRdfWithIncorrectVersionIRI() throws Exception { // prepare: add an artifact final InferredOWLOntologyID artifactID = this.loadTestArtifact(TestConstants.TEST_ARTIFACT_20130206, MediaType.APPLICATION_RDF_TURTLE); // prepare: set an INVALID version IRI final String incorrectVersionIri = artifactID.getVersionIRI().toString() + ":nosuchversion"; final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactID .getOntologyIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, incorrectVersionIri); editArtifactClientResource .addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(true)); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_FORCE, Boolean.toString(false)); // create edit Representation final Representation input = this.buildRepresentationFromResource(TestConstants.TEST_ARTIFACT_FRAGMENT_NEW_FILE_REF_OBJECT, MediaType.APPLICATION_RDF_XML); this.doTestAuthenticatedRequest(editArtifactClientResource, Method.POST, input, MediaType.APPLICATION_RDF_XML, Status.CLIENT_ERROR_CONFLICT, AbstractResourceImplTest.WITH_ADMIN); Assert.fail("Should have failed due to incorrect version IRI"); } catch(final ResourceException e) { Assert.assertEquals(Status.CLIENT_ERROR_CONFLICT, e.getStatus()); // verify the source of error final String body = this.getText(editArtifactClientResource.getResponseEntity()); final ByteArrayInputStream inputStream = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); final Model model = Rio.parse(inputStream, "", RDFFormat.RDFXML); final String sourceOfError = model.filter(null, PODD.ERR_SOURCE, null).objectString(); Assert.assertEquals("Err#source is not the incorrect Version IRI", incorrectVersionIri, sourceOfError); } finally { this.releaseClient(editArtifactClientResource); } } @Test public void testErrorEditArtifactRdfWithoutArtifactID() throws Exception { final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); // there is no need to authenticate, have a test artifact or send RDF to // modify as the // artifact is checked for first try { editArtifactClientResource.post(null, MediaType.TEXT_PLAIN); } catch(final ResourceException e) { Assert.assertEquals(Status.CLIENT_ERROR_BAD_REQUEST, e.getStatus()); } finally { this.releaseClient(editArtifactClientResource); } } @Test public void testErrorEditArtifactRdfWithoutAuthentication() throws Exception { // prepare: add an artifact final String artifactUri = "urn:purl:dummy:artifact:uri:artifact:1"; final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); // invoke without authentication try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactUri); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, artifactUri); final Representation input = this.buildRepresentationFromResource(TestConstants.TEST_ARTIFACT_FRAGMENT_NEW_FILE_REF_OBJECT, MediaType.APPLICATION_RDF_XML); editArtifactClientResource.post(input, MediaType.APPLICATION_RDF_XML); } catch(final ResourceException e) { Assert.assertEquals(Status.CLIENT_ERROR_UNAUTHORIZED, e.getStatus()); } finally { this.releaseClient(editArtifactClientResource); } } /** * NOTE: The expected 500 error causes a stacktrace to be printed on the server */ @Test public void testErrorEditArtifactTurtleWithReportDanglingObjects() throws Exception { // prepare: add an artifact final InferredOWLOntologyID artifactID = this.loadTestArtifact(TestConstants.TEST_ARTIFACT_20130206, MediaType.APPLICATION_RDF_TURTLE); final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactID .getOntologyIRI().toString()); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, artifactID .getVersionIRI().toString()); editArtifactClientResource .addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_REPLACE, Boolean.toString(true)); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_EDIT_WITH_FORCE, Boolean.toString(false)); // edit Representation contains statements in Turtle format final Representation input = this.buildRepresentationFromResource( TestConstants.TEST_ARTIFACT_FRAGMENT_MODIFY_DEMO_INVESTIGATION, MediaType.APPLICATION_RDF_TURTLE); this.doTestAuthenticatedRequest(editArtifactClientResource, Method.POST, input, MediaType.APPLICATION_RDF_TURTLE, Status.SERVER_ERROR_INTERNAL, AbstractResourceImplTest.WITH_ADMIN); Assert.fail("Should have failed when dangling objects were identified"); } catch(final ResourceException e) { Assert.assertEquals(Status.SERVER_ERROR_INTERNAL, e.getStatus()); // the cause is not available to the client for verification } finally { this.releaseClient(editArtifactClientResource); } } /** * Test viewing the edit HTML page for an internal PODD object. */ @Test public void testGetEditArtifactHtmlForInternalObject() throws Exception { // prepare: add an artifact final String artifactUri = this.loadTestArtifact("/test/artifacts/basic-2.rdf"); final String objectUri = "urn:hardcoded:purl:artifact:1#publication45"; final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactUri); editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_OBJECT_IDENTIFIER, objectUri); final Representation results = this.doTestAuthenticatedRequest(editArtifactClientResource, Method.GET, null, MediaType.TEXT_HTML, Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN); final String body = this.getText(results); // verify: // System.out.println(body); this.assertFreemarker(body); } finally { this.releaseClient(editArtifactClientResource); } } /** * Test viewing the edit HTML page for a PODD top object (i.e. a Project). */ @Test public void testGetEditArtifactHtmlForTopObject() throws Exception { // prepare: add an artifact final String artifactUri = this.loadTestArtifact("/test/artifacts/basic-2.rdf"); final ClientResource editArtifactClientResource = new ClientResource(this.getUrl(PoddWebConstants.PATH_ARTIFACT_EDIT)); try { editArtifactClientResource.addQueryParameter(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, artifactUri); // not requesting a specific object results in the Project being // shown. final Representation results = this.doTestAuthenticatedRequest(editArtifactClientResource, Method.GET, null, MediaType.TEXT_HTML, Status.SUCCESS_OK, AbstractResourceImplTest.WITH_ADMIN); final String body = this.getText(results); // verify: // System.out.println(body); this.assertFreemarker(body); } finally { this.releaseClient(editArtifactClientResource); } } }