From: Aron Roberts Date: Wed, 26 Aug 2009 23:24:17 +0000 (+0000) Subject: CSPACE-360,CSPACE-384: Simple, hierarchical client test framework now working. Need... X-Git-Url: https://git.aero2k.de/?a=commitdiff_plain;h=1bc355ddf51cd1760209b22b1906a35d31ee70c6;p=tmp%2Fjakarta-migration.git CSPACE-360,CSPACE-384: Simple, hierarchical client test framework now working. Need to move to client module from collectionobject/client. --- diff --git a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/AbstractServiceTest.java b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/AbstractServiceTest.java new file mode 100644 index 000000000..815a467e2 --- /dev/null +++ b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/AbstractServiceTest.java @@ -0,0 +1,402 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright © 2009 Regents of the University of California + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * + * https://source.collectionspace.org/collection-space/LICENSE.txt + * + * 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 org.collectionspace.services.client.test; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.EntityEnclosingMethod; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.PutMethod; +import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.commons.httpclient.methods.StringRequestEntity; + +import org.collectionspace.services.client.TestServiceClient; +import org.collectionspace.services.client.test.ServiceRequestType; + +import org.jboss.resteasy.client.ClientResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * AbstractServiceTest, abstract base class for the client tests to be performed + * to test an entity or relation service. + * + * For Javadoc descriptions of this class's methods, see the ServiceTest interface. + */ +public abstract class AbstractServiceTest implements ServiceTest { + + final Logger logger = LoggerFactory.getLogger(AbstractServiceTest.class); + + private final TestServiceClient serviceClient = new TestServiceClient(); + protected HttpClient httpClient = new HttpClient(); + + // The status code expected to be returned by a test method (where relevant). + int EXPECTED_STATUS_CODE = 0; + + // The generic type of service request being tested (e.g. CREATE, UPDATE, DELETE). + // + // This makes it possible to check behavior specific to that type of request, + // such as the set of valid status codes that may be returned. + ServiceRequestType REQUEST_TYPE = ServiceRequestType.NON_EXISTENT; + + + // --------------------------------------------------------------- + // CRUD tests : CREATE tests + // --------------------------------------------------------------- + + // Success outcomes + + @Override + public abstract void create(); + + protected void setupCreate() { + clearSetup(); + // Expected status code: 201 Created + EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); + // Type of service request being tested + REQUEST_TYPE = ServiceRequestType.CREATE; + } + + @Override + public abstract void createMultiple(); + + // No setup required for createMultiple() + + // Failure outcomes + + @Override + public void createNull() { + } + + // No setup required for createNull() + + @Override + public abstract void createWithMalformedXml(); + + protected void setupCreateWithMalformedXml() { + clearSetup(); + // Expected status code: 400 Bad Request + EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.CREATE; + } + + @Override + public abstract void createWithWrongXmlSchema(); + + protected void setupCreateWithWrongXmlSchema() { + clearSetup(); + // Expected status code: 400 Bad Request + EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.CREATE; + } + + + // --------------------------------------------------------------- + // CRUD tests : READ tests + // --------------------------------------------------------------- + + // Success outcomes + + @Override + public abstract void read(); + + protected void setupRead() { + clearSetup(); + // Expected status code: 200 OK + EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.READ; + } + + // Failure outcomes + + @Override + public abstract void readNonExistent(); + + protected void setupReadNonExistent() { + clearSetup(); + // Expected status code: 404 Not Found + EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.READ; + } + + + // --------------------------------------------------------------- + // CRUD tests : READ (list, or multiple) tests + // --------------------------------------------------------------- + + // Success outcomes + + @Override + public abstract void readList(); + + protected void setupReadList() { + clearSetup(); + // Expected status code: 200 OK + EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE; + } + + // Failure outcomes + + // None tested at present. + + + // --------------------------------------------------------------- + // CRUD tests : UPDATE tests + // --------------------------------------------------------------- + + // Success outcomes + // ---------------- + + @Override + public abstract void update(); + + protected void setupUpdate() { + clearSetup(); + // Expected status code: 200 OK + EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.UPDATE; + } + + // Failure outcomes + + @Override + public abstract void updateWithMalformedXml(); + + protected void setupUpdateWithMalformedXml() { + clearSetup(); + // Expected status code: 400 Bad Request + EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.UPDATE; + } + + @Override + public abstract void updateWithWrongXmlSchema(); + + protected void setupUpdateWithWrongXmlSchema() { + clearSetup(); + // Expected status code: 400 Bad Request + EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.UPDATE; + } + + @Override + public abstract void updateNonExistent(); + + protected void setupUpdateNonExistent() { + clearSetup(); + // Expected status code: 404 Not Found + EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.UPDATE; + } + + + // --------------------------------------------------------------- + // CRUD tests : DELETE tests + // --------------------------------------------------------------- + + // Success outcomes + + @Override + public abstract void delete(); + + protected void setupDelete() { + clearSetup(); + // Expected status code: 200 OK + EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.DELETE; + } + + // Failure outcomes + + @Override + public abstract void deleteNonExistent(); + + protected void setupDeleteNonExistent() { + clearSetup(); + // Expected status code: 404 Not Found + EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); + REQUEST_TYPE = ServiceRequestType.DELETE; + } + + + // --------------------------------------------------------------- + // Abstract utility methods + // + // Must be implemented by classes that extend + // this abstract base class. + // --------------------------------------------------------------- + + /** + * Returns the URL path component of the service. + * + * This component will follow directly after the + * base path, if any. + */ + protected abstract String getServicePathComponent(); + + + // --------------------------------------------------------------- + // Utility methods + // --------------------------------------------------------------- + + /** + * Reinitializes setup values to guard against unintended reuse + * of those values. + */ + protected void clearSetup() { + EXPECTED_STATUS_CODE = 0; + REQUEST_TYPE = ServiceRequestType.NON_EXISTENT; + } + + // @TODO Add Javadoc comments to all methods requiring them, below. + + protected String invalidStatusCodeMessage(ServiceRequestType requestType, int statusCode) { + return + "Status code '" + statusCode + "' in response is NOT within the expected set: " + + requestType.validStatusCodesAsString(); + } + + protected String getServiceRootURL() { + return serviceClient.getBaseURL() + getServicePathComponent(); + } + + protected String getResourceURL(String resourceIdentifier) { + return getServiceRootURL() + "/" + resourceIdentifier; + } + + protected int submitRequest(HttpMethod method) { + int statusCode = 0; + try { + statusCode = httpClient.executeMethod(method); + } catch(HttpException e) { + logger.error("Fatal protocol violation: ", e); + } catch(IOException e) { + logger.error("Fatal transport error: ", e); + } catch(Exception e) { + logger.error("Unknown exception: ", e); + } finally { + // Release the connection. + method.releaseConnection(); + } + return statusCode; + } + + protected int submitRequest(EntityEnclosingMethod method, RequestEntity entity) { + int statusCode = 0; + try { + method.setRequestEntity(entity); + statusCode = httpClient.executeMethod(method); + } catch(HttpException e) { + logger.error("Fatal protocol violation: ", e); + } catch(IOException e) { + logger.error("Fatal transport error: ", e); + } catch(Exception e) { + logger.error("Unknown exception: ", e); + } finally { + // Release the connection. + method.releaseConnection(); + } + return statusCode; + } + + protected StringRequestEntity getXmlEntity(String contents) { + if (contents == null) { + contents = ""; + } + StringRequestEntity entity = null; + final String XML_DECLARATION = ""; + final String XML_CONTENT_TYPE=MediaType.APPLICATION_XML; + final String UTF8_CHARSET_NAME = "UTF-8"; + try { + entity = + new StringRequestEntity(XML_DECLARATION + contents, XML_CONTENT_TYPE, UTF8_CHARSET_NAME); + } catch (UnsupportedEncodingException e) { + logger.error("Unsupported character encoding error: ", e); + } + return entity; + } + + protected String extractId(ClientResponse res) { + MultivaluedMap mvm = res.getMetadata(); + String uri = (String) ((ArrayList) mvm.get("Location")).get(0); + verbose("extractId:uri=" + uri); + String[] segments = uri.split("/"); + String id = segments[segments.length - 1]; + verbose("id=" + id); + return id; + } + + protected void verbose(String msg) { + if (logger.isDebugEnabled()) { + logger.debug(msg); + } + } + + protected void verbose(String msg, Object o, Class clazz) { + try{ + verbose(msg); + JAXBContext jc = JAXBContext.newInstance(clazz); + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, + Boolean.TRUE); + m.marshal(o, System.out); + }catch(Exception e){ + e.printStackTrace(); + } + } + + protected void verboseMap(MultivaluedMap map) { + for(Object entry : map.entrySet()){ + MultivaluedMap.Entry mentry = (MultivaluedMap.Entry) entry; + verbose(" name=" + mentry.getKey() + " value=" + mentry.getValue()); + } + } + + protected String createIdentifier() { + long identifier = System.currentTimeMillis(); + return Long.toString(identifier); + } + + protected String createNonExistentIdentifier() { + return Long.toString(Long.MAX_VALUE); + } + +} + + diff --git a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java index 3e5f82381..d592c3fcf 100644 --- a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java +++ b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/CollectionObjectServiceTest.java @@ -23,12 +23,8 @@ package org.collectionspace.services.client.test; -import java.util.ArrayList; import java.util.List; -import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; import org.jboss.resteasy.client.ClientResponse; import org.testng.Assert; import org.testng.annotations.Test; @@ -38,29 +34,17 @@ import org.collectionspace.services.client.test.ServiceRequestType; import org.collectionspace.services.collectionobject.CollectionObject; import org.collectionspace.services.collectionobject.CollectionObjectList; -import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Set; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.Status; // import org.jboss.resteasy.client.ClientRequest; -import org.collectionspace.services.client.TestServiceClient; -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.EntityEnclosingMethod; + import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * CollectionObjectServiceTest, carries out tests against a * deployed and running CollectionObject Service. @@ -68,839 +52,408 @@ import org.slf4j.LoggerFactory; * $LastChangedRevision$ * $LastChangedDate$ */ -public class CollectionObjectServiceTest { +public class CollectionObjectServiceTest extends AbstractServiceTest { - // Instance variables specific to this test. - final Logger logger = LoggerFactory.getLogger(CollectionObjectServiceTest.class); - private CollectionObjectClient client = new CollectionObjectClient(); + // Instance variables specific to this test. + private CollectionObjectClient client = new CollectionObjectClient(); - // Instance variables common to all entity service test classes. - private String knownObjectId = null; - private final String NON_EXISTENT_ID = createNonExistentIdentifier(); - private HttpClient httpClient = new HttpClient(); - private TestServiceClient serviceClient = new TestServiceClient(); + // Instance variables common to all entity service test classes. + private final String NON_EXISTENT_ID = createNonExistentIdentifier(); + private String knownObjectId = null; - // --------------------------------------------------------------- - // Service Discovery tests - // --------------------------------------------------------------- - - // TBA - - - // --------------------------------------------------------------- - // CRUD tests : CREATE tests - // --------------------------------------------------------------- - - // Success outcomes - // ---------------- - - /** - * Tests creation of a new resource of the specified type. - * - * The 'Location' header will contain the URL for the newly created object. - * This is required by the extractId() utility method, below. - * - * The newly-created resource is also used by other test(s) - * (e.g. update, delete) which follow, below. - */ - @Test - public void create() { - - // Expected status code: 201 Created - final int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; - - // Submit the request to the service and store the response. - String identifier = this.createIdentifier(); - CollectionObject collectionObject = createCollectionObject(identifier); - ClientResponse res = client.createCollectionObject(collectionObject); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("create: status = " + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - - // Store the ID returned from this create operation for additional tests below. - knownObjectId = extractId(res); - } - - /** - * Creates two or more new objects of the specified type. - * - * Repeatedly calls the create test, above, and relies on its - * test assertions. - * - * The newly-created objects are also used by other test(s) - * (e.g. read multiple/list) which follow, below. - */ - @Test(dependsOnMethods = {"create"}) - public void createMultiple() { - for(int i = 0; i < 3; i++){ - this.create(); - } - } - - // Failure outcomes - // ---------------- - - /** - * Tests creation of a resource of the specified type by sending a null to the client proxy. - * - */ - @Test(dependsOnMethods = {"create"}, expectedExceptions = IllegalArgumentException.class) - public void createNull() { - - // Expected result: IllegalArgumentException - ClientResponse res = client.createCollectionObject(null); - } - - /** - * Tests creation of a resource of the specified type by sending malformed XML data - * in the entity body of the request. - */ -/* - @Test(dependsOnMethods = {"create", "testSubmitRequest"}) - public void createWithMalformedXml() { - - // Expected status code: 400 Bad Request - final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE; - - // @TODO This test is currently commented out, because it returns a - // 500 Internal Server Error status code, rather than the expected status code. - - // Submit the request to the service and store the response. - String url = getServiceRootURL(); - PostMethod method = new PostMethod(url); - final String MALFORMED_XML_DATA = - "wrong schema contents res = - client.getCollectionObject(knownObjectId); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("read: status = " + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } - - // Failure outcomes - // ---------------- - - /** - * Tests reading (i.e. retrieval) of a resource of the specified type by a user who - * is not authorized to perform this action. - */ -/* - @Test(dependsOnMethods = {"read"}) - public void readWithoutAuthorization() { - - // Expected status code: 403 Forbidden - final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ; + // --------------------------------------------------------------- + // CRUD tests : CREATE tests + // --------------------------------------------------------------- + + // Success outcomes - // @TODO Currently only a stub. This test can be implemented - // when the service is revised to require authorization. - } -*/ - - /** - * Tests reading (i.e. retrieval) of a non-existent object of the specified type, - * whose resource identifier does not exist at the specified URL. - */ - @Test(dependsOnMethods = {"read"}) - public void readNonExistent() { - - // Expected status code: 404 Not Found - final int EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ; - - // Submit the request to the service and store the response. - ClientResponse res = - client.getCollectionObject(NON_EXISTENT_ID); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("readNonExistent: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } - - - // --------------------------------------------------------------- - // CRUD tests : READ (list, or multiple) tests - // --------------------------------------------------------------- - - // Success outcomes - // ---------------- - - /** - * Tests reading (i.e. retrieval) of a list of multiple objects of the specified type. - * - * Also expected: The entity body in the response contains - * a representation of a list of objects of the specified type. - */ - @Test(dependsOnMethods = {"createMultiple"}) - public void readList() { - - // Expected status code: 200 OK - final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE; - - // Submit the request to the service and store the response. - ClientResponse res = client.getCollectionObjectList(); - CollectionObjectList coList = res.getEntity(); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("readList: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - - // Optionally output additional data about list members for debugging. - boolean iterateThroughList = false; - if (iterateThroughList && logger.isDebugEnabled()) { - List coItemList = - coList.getCollectionObjectListItem(); - int i = 0; - for(CollectionObjectList.CollectionObjectListItem pli : coItemList){ - verbose("readList: list-item[" + i + "] csid=" + pli.getCsid()); - verbose("readList: list-item[" + i + "] objectNumber=" + pli.getObjectNumber()); - verbose("readList: list-item[" + i + "] URI=" + pli.getUri()); - i++; - } + @Override + @Test + public void create() { + + // Perform setup, such as initializing the type of service request + // and its valid and expected status codes. + super.setupCreate(); + + // Submit the request to the service and store the response. + String identifier = createIdentifier(); + CollectionObject collectionObject = createCollectionObject(identifier); + ClientResponse res = client.createCollectionObject(collectionObject); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match the expected response(s)? + // + // Does it fall within the set of valid status codes? + // Does it match the expected status code? + verbose("create: status = " + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + // Store the ID returned from this create operation for additional tests below. + knownObjectId = extractId(res); + } + + @Override + @Test(dependsOnMethods = {"create"}) + public void createMultiple() { + for(int i = 0; i < 3; i++){ + create (); + } + } + + // Failure outcomes + + @Override + @Test(dependsOnMethods = {"create"}, expectedExceptions = IllegalArgumentException.class) + public void createNull() { + ClientResponse res = client.createCollectionObject(null); } - } - - /** - * Tests reading (i.e. retrieval) of a list of multiple objects of the specified type - * when the contents of the list are expected to be empty. - * - * Also expected: The entity body in the response contains - * a representation of an empty list of objects of the specified type. - */ -/* - @Test(dependsOnMethods = {"readList"}) - public void readEmptyList() { - - // Expected status code: 200 OK - // (NOTE: *not* 204 No Content) - final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE; - - // @TODO Currently only a stub. Consider how to implement this. - } -*/ - - // Failure outcomes - // ---------------- - - /** - * Tests reading (i.e. retrieval) of a list of objects of the specified type - * when sending unrecognized query parameters with the request. - */ -/* - @Test(dependsOnMethods = {"readList"}) - public void readListWithBadParams() { - - // Expected status code: 400 Bad Request - final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE; - - // @TODO This test is currently commented out, because it returns a - // 200 OK status code, rather than the expected status code. - - // @TODO Another variant of this test should use a URL for the service - // root that ends in a trailing slash. - - // Submit the request to the service and store the response. - String url = getServiceRootURL() + "?param=nonexistent"; - GetMethod method = new GetMethod(url); - int statusCode = submitRequest(method); + @Override + @Test(dependsOnMethods = {"create", "testSubmitRequest"}) + public void createWithMalformedXml() { - // Check the status code of the response: does it match the expected response(s)? - verbose("readListWithBadParams: url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } -*/ - - /** - * Tests reading (i.e. retrieval) of a list of objects of the specified type by a user who - * is not authorized to perform this action. - * - */ -/* - @Test(dependsOnMethods = {"readList"}) - public void readListWithoutAuthorization() { - - // Expected status code: 403 Forbidden - final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE; - - // @TODO Currently only a stub. This test can be implemented - // when the service is revised to require authorization. - } -*/ - + // Perform setup. + super.setupCreateWithMalformedXml(); + + // Submit the request to the service and store the response. + String url = getServiceRootURL(); + PostMethod method = new PostMethod(url); + final String MALFORMED_XML_DATA = + "wrong schema contents res = - client.getCollectionObject(knownObjectId); - verbose("read: status = " + res.getStatus()); - Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); - CollectionObject collectionObject = res.getEntity(); - verbose("Got object to update with ID: " + knownObjectId, - collectionObject, CollectionObject.class); - - // Update the content of this resource. - //collectionObject.setCsid("updated-" + knownObjectId); - collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber()); - collectionObject.setObjectName("updated-" + collectionObject.getObjectName()); - - // Submit the request to the service and store the response. - res = client.updateCollectionObject(knownObjectId, collectionObject); - int statusCode = res.getStatus(); - CollectionObject updatedCollectionObject = res.getEntity(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("update: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + @Override + @Test(dependsOnMethods = {"create", "testSubmitRequest"}) //, "createWithMalformedXml"}) + public void createWithWrongXmlSchema() { - // Check the contents of the response: does it match what was submitted? - verbose("update: ", updatedCollectionObject, CollectionObject.class); - Assert.assertEquals(updatedCollectionObject.getObjectName(), - collectionObject.getObjectName(), "Data in updated object did not match submitted data."); - } - - /** - * Tests updating the content of a resource of the specified type - * by sending malformed XML data in the entity body of the request. - */ -/* - @Test(dependsOnMethods = {"create", "testSubmitRequest"}) - public void updateWithMalformedXml() { - - // Expected status code: 400 Bad Request - final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.UPDATE; - - // @TODO This test is currently commented out, because it returns a - // 500 Internal Server Error status code, rather than the expected status code. - - // Submit the request to the service and store the response. - String url = getResourceURL(knownObjectId); - PutMethod method = new PutMethod(url); - final String MALFORMED_XML_DATA = - "wrong schema contents res = + client.getCollectionObject(knownObjectId); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match the expected response(s)? + verbose("read: status = " + statusCode); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + + @Override + @Test(dependsOnMethods = {"read"}) + public void readNonExistent() { + + // Perform setup. + super.setupReadNonExistent(); + + // Submit the request to the service and store the response. + ClientResponse res = + client.getCollectionObject(NON_EXISTENT_ID); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match the expected response(s)? + verbose("readNonExistent: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } + + + // --------------------------------------------------------------- + // CRUD tests : READ (list, or multiple) tests + // --------------------------------------------------------------- + + // Success outcomes + + @Override + @Test(dependsOnMethods = {"createMultiple"}) + public void readList() { - // Check the status code of the response: does it match the expected response(s)? - verbose("updateWithWrongSchema: url=" + url + " status=" + statusCode); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } -*/ - - /** - * Tests updating the content of a resource of the specified type, - * by a user who is not authorized to perform this action. - */ -/* - @Test(dependsOnMethods = {"update"}) - public void updateWithoutAuthorization() { - - // Expected status code: 403 Forbidden - final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode(); - - // @TODO Currently only a stub. This test can be implemented - // when the service is revised to require authorization. - } -*/ - - /** - * Tests updating the content of a non-existent object of the specified type, - * whose resource identifier does not exist. - */ - @Test(dependsOnMethods = {"update"}) - public void updateNonExistent() { - - // Expected status code: 404 Not Found - final int EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.UPDATE; - - // Submit the request to the service and store the response. - // Note: The ID used in this 'create' call may be arbitrary. - // The only relevant ID may be the one used in updateCollectionObject(), below. - CollectionObject collectionObject = createCollectionObject(NON_EXISTENT_ID); - ClientResponse res = - client.updateCollectionObject(NON_EXISTENT_ID, collectionObject); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("updateNonExistent: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } - - - // --------------------------------------------------------------- - // CRUD tests : DELETE tests - // --------------------------------------------------------------- - - // Success outcomes - // ---------------- - - /** - * Tests deleting an object of the specified type. - * - * Expected status code: 200 OK - */ - @Test(dependsOnMethods = - {"create", "read", "testSubmitRequest", "update"}) - public void delete() { - - // Expected status code: 200 OK - final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.DELETE; - - // Submit the request to the service and store the response. - ClientResponse res = client.deleteCollectionObject(knownObjectId); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("delete: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } - - // Failure outcomes - // ---------------- - - /** - * Tests deleting an object of the specified type, - * by a user who is not authorized to perform this action. - */ -/* - @Test(dependsOnMethods = {"delete"}) - public void deleteWithoutAuthorization() { - - // Expected status code: 403 Forbidden - final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.DELETE; - - // @TODO Currently only a stub. This test can be implemented - // when the service is revised to require authorization. - } -*/ - - /** - * Tests deleting a non-existent object of the specified type, - * whose resource identifier does not exist at the specified URL. - */ - @Test(dependsOnMethods = {"delete"}) - public void deleteNonExistent() { - - // Expected status code: 404 Not Found - final int EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); - - // Type of service request being tested - final ServiceRequestType REQUEST_TYPE = ServiceRequestType.DELETE; - - // Submit the request to the service and store the response. - ClientResponse res = - client.deleteCollectionObject(NON_EXISTENT_ID); - int statusCode = res.getStatus(); - - // Check the status code of the response: does it match the expected response(s)? - verbose("deleteNonExistent: status = " + res.getStatus()); - Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), - invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); - } - - - // --------------------------------------------------------------- - // Utility tests : tests of code used in tests above - // --------------------------------------------------------------- - - /** - * Tests the HttpClient-based code used to submit data, in various methods below. - */ - @Test(dependsOnMethods = {"create", "read"}) - public void testSubmitRequest() { - - // Expected status code: 200 OK - final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); - - // Submit the request to the service and store the response. - String url = getResourceURL(knownObjectId); - GetMethod method = new GetMethod(url); - int statusCode = submitRequest(method); + // Perform setup. + super.setupReadList(); + + // Submit the request to the service and store the response. + ClientResponse res = client.getCollectionObjectList(); + CollectionObjectList coList = res.getEntity(); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match the expected response(s)? + verbose("readList: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + // Optionally output additional data about list members for debugging. + boolean iterateThroughList = false; + if (iterateThroughList && logger.isDebugEnabled()) { + List coItemList = + coList.getCollectionObjectListItem(); + int i = 0; + for(CollectionObjectList.CollectionObjectListItem pli : coItemList){ + verbose("readList: list-item[" + i + "] csid=" + pli.getCsid()); + verbose("readList: list-item[" + i + "] objectNumber=" + pli.getObjectNumber()); + verbose("readList: list-item[" + i + "] URI=" + pli.getUri()); + i++; + } + } + + } + + // Failure outcomes - // Check the status code of the response: does it match the expected response(s)? - verbose("testSubmitRequest: url=" + url + " status=" + statusCode); - Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + // None at present. - } - - // --------------------------------------------------------------- - // Utility methods used by tests above - // --------------------------------------------------------------- - - // @TODO Add Javadoc comments to all of these methods. - - // ----------------------------- - // Methods specific to this test - // ----------------------------- - - private CollectionObject createCollectionObject(String identifier) { - CollectionObject collectionObject = createCollectionObject("objectNumber-" + identifier, - "objectName-" + identifier); - return collectionObject; - } - - private CollectionObject createCollectionObject(String objectNumber, String objectName) { - CollectionObject collectionObject = new CollectionObject(); - collectionObject.setObjectNumber(objectNumber); - collectionObject.setObjectName(objectName); - return collectionObject; - } - - private String getServicePathComponent() { - // @TODO Determine if it is possible to obtain this value programmatically. - // We set this in an annotation in the CollectionObjectProxy interface, for instance. - final String SERVICE_PATH_COMPONENT = "collectionobjects"; - return SERVICE_PATH_COMPONENT; - } - - // ------------------------------------------------------------- - // Methods common to all entity service test classes. - // - // These can be moved out of individual service test classes - // into a common class, perhaps at the top-level 'client' module. - // ------------------------------------------------------------- - - protected String invalidStatusCodeMessage(ServiceRequestType requestType, int statusCode) { - return - "Status code '" + statusCode + "' in response is NOT within the expected set: " + - requestType.validStatusCodesAsString(); - } - - private String getServiceRootURL() { - return serviceClient.getBaseURL() + getServicePathComponent(); - } - - private String getResourceURL(String resourceIdentifier) { - return getServiceRootURL() + "/" + resourceIdentifier; - } - - private int submitRequest(HttpMethod method) { - int statusCode = 0; - try { - statusCode = httpClient.executeMethod(method); - } catch(HttpException e) { - logger.error("Fatal protocol violation: ", e); - } catch(IOException e) { - logger.error("Fatal transport error: ", e); - } catch(Exception e) { - logger.error("Unknown exception: ", e); - } finally { - // Release the connection. - method.releaseConnection(); + // --------------------------------------------------------------- + // CRUD tests : UPDATE tests + // --------------------------------------------------------------- + + // Success outcomes + + @Override + @Test(dependsOnMethods = {"create"}) + public void update() { + + // Perform setup. + super.setupUpdate(); + + // Retrieve an existing resource that we can update. + ClientResponse res = + client.getCollectionObject(knownObjectId); + verbose("read: status = " + res.getStatus()); + Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE); + CollectionObject collectionObject = res.getEntity(); + verbose("Got object to update with ID: " + knownObjectId, + collectionObject, CollectionObject.class); + + // Update the content of this resource. + //collectionObject.setCsid("updated-" + knownObjectId); + collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber()); + collectionObject.setObjectName("updated-" + collectionObject.getObjectName()); + + // Submit the request to the service and store the response. + res = client.updateCollectionObject(knownObjectId, collectionObject); + int statusCode = res.getStatus(); + CollectionObject updatedCollectionObject = res.getEntity(); + + // Check the status code of the response: does it match the expected response(s)? + verbose("update: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + + // Check the contents of the response: does it match what was submitted? + verbose("update: ", updatedCollectionObject, CollectionObject.class); + Assert.assertEquals(updatedCollectionObject.getObjectName(), + collectionObject.getObjectName(), "Data in updated object did not match submitted data."); } - return statusCode; - } - - private int submitRequest(EntityEnclosingMethod method, RequestEntity entity) { - int statusCode = 0; - try { - method.setRequestEntity(entity); - statusCode = httpClient.executeMethod(method); - } catch(HttpException e) { - logger.error("Fatal protocol violation: ", e); - } catch(IOException e) { - logger.error("Fatal transport error: ", e); - } catch(Exception e) { - logger.error("Unknown exception: ", e); - } finally { - // Release the connection. - method.releaseConnection(); + + @Override + @Test(dependsOnMethods = {"create", "testSubmitRequest"}) + public void updateWithMalformedXml() { + + // Perform setup. + super.setupUpdateWithMalformedXml(); + + // Submit the request to the service and store the response. + String url = getResourceURL(knownObjectId); + PutMethod method = new PutMethod(url); + final String MALFORMED_XML_DATA = + "wrong schema contents"; - final String XML_CONTENT_TYPE=MediaType.APPLICATION_XML; - final String UTF8_CHARSET_NAME = "UTF-8"; - try { - entity = - new StringRequestEntity(XML_DECLARATION + contents, XML_CONTENT_TYPE, UTF8_CHARSET_NAME); - } catch (UnsupportedEncodingException e) { - logger.error("Unsupported character encoding error: ", e); + + @Test(dependsOnMethods = {"update"}) + public void updateNonExistent() { + + // Perform setup. + super.setupUpdateNonExistent(); + + // Submit the request to the service and store the response. + // Note: The ID used in this 'create' call may be arbitrary. + // The only relevant ID may be the one used in updateCollectionObject(), below. + CollectionObject collectionObject = createCollectionObject(NON_EXISTENT_ID); + ClientResponse res = + client.updateCollectionObject(NON_EXISTENT_ID, collectionObject); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match the expected response(s)? + verbose("updateNonExistent: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - return entity; - } - - private String extractId(ClientResponse res) { - MultivaluedMap mvm = res.getMetadata(); - String uri = (String) ((ArrayList) mvm.get("Location")).get(0); - verbose("extractId:uri=" + uri); - String[] segments = uri.split("/"); - String id = segments[segments.length - 1]; - verbose("id=" + id); - return id; - } - - private void verbose(String msg) { - if (logger.isDebugEnabled()) { - logger.debug(msg); + + + // --------------------------------------------------------------- + // CRUD tests : DELETE tests + // --------------------------------------------------------------- + + // Success outcomes + + @Test(dependsOnMethods = + {"create", "read", "testSubmitRequest", "update"}) + public void delete() { + + // Perform setup. + super.setupDelete(); + + // Submit the request to the service and store the response. + ClientResponse res = client.deleteCollectionObject(knownObjectId); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match the expected response(s)? + verbose("delete: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - } - - private void verbose(String msg, Object o, Class clazz) { - try{ - verbose(msg); - JAXBContext jc = JAXBContext.newInstance(clazz); - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, - Boolean.TRUE); - m.marshal(o, System.out); - }catch(Exception e){ - e.printStackTrace(); + + // Failure outcomes + + @Test(dependsOnMethods = {"delete"}) + public void deleteNonExistent() { + + // Perform setup. + super.setupDeleteNonExistent(); + + // Expected status code: 404 Not Found + final int EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode(); + + // Type of service request being tested + final ServiceRequestType REQUEST_TYPE = ServiceRequestType.DELETE; + + // Submit the request to the service and store the response. + ClientResponse res = + client.deleteCollectionObject(NON_EXISTENT_ID); + int statusCode = res.getStatus(); + + // Check the status code of the response: does it match the expected response(s)? + verbose("deleteNonExistent: status = " + res.getStatus()); + Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode), + invalidStatusCodeMessage(REQUEST_TYPE, statusCode)); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); } - } - private void verboseMap(MultivaluedMap map) { - for(Object entry : map.entrySet()){ - MultivaluedMap.Entry mentry = (MultivaluedMap.Entry) entry; - verbose(" name=" + mentry.getKey() + " value=" + mentry.getValue()); + + // --------------------------------------------------------------- + // Utility tests : tests of code used in tests above + // --------------------------------------------------------------- + + /** + * Tests the HttpClient-based code used to submit data, in various methods below. + */ + @Test(dependsOnMethods = {"create", "read"}) + public void testSubmitRequest() { + + // Expected status code: 200 OK + final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode(); + + // Submit the request to the service and store the response. + String url = getResourceURL(knownObjectId); + GetMethod method = new GetMethod(url); + int statusCode = submitRequest(method); + + // Check the status code of the response: does it match the expected response(s)? + verbose("testSubmitRequest: url=" + url + " status=" + statusCode); + Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE); + } - } + - private String createIdentifier() { - long identifier = System.currentTimeMillis(); - return Long.toString(identifier); - } + // --------------------------------------------------------------- + // Utility methods used by tests above + // --------------------------------------------------------------- + + private CollectionObject createCollectionObject(String identifier) { + CollectionObject collectionObject = createCollectionObject("objectNumber-" + identifier, + "objectName-" + identifier); + return collectionObject; + } - private String createNonExistentIdentifier() { - return Long.toString(Long.MAX_VALUE); - } - + private CollectionObject createCollectionObject(String objectNumber, String objectName) { + CollectionObject collectionObject = new CollectionObject(); + collectionObject.setObjectNumber(objectNumber); + collectionObject.setObjectName(objectName); + return collectionObject; + } + + @Override + public String getServicePathComponent() { + // @TODO Determine if it is possible to obtain this value programmatically. + // We set this in an annotation in the CollectionObjectProxy interface, for instance. + // We also set service-specific constants in each service module. + final String SERVICE_PATH_COMPONENT = "collectionobjects"; + return SERVICE_PATH_COMPONENT; + } + } diff --git a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/ServiceRequestType.java b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/ServiceRequestType.java index c5142354d..65ec7734a 100644 --- a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/ServiceRequestType.java +++ b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/ServiceRequestType.java @@ -32,157 +32,178 @@ import org.slf4j.LoggerFactory; /** * ServiceRequestType, identifies types of service requests * and the valid HTTP status codes that can be returned from - * each type of request. Used by client tests of services. + * each type of request. + * + * Used by client tests of services. * * $LastChangedRevision: 566 $ * $LastChangedDate$ */ public enum ServiceRequestType { - - // Define each of the service request types and their valid HTTP status codes. - - CREATE { - @Override - public int[] validStatusCodes() { - final int[] STATUS_CODES = { - Response.Status.CREATED.getStatusCode(), - Response.Status.BAD_REQUEST.getStatusCode(), - Response.Status.FORBIDDEN.getStatusCode(), - Response.Status.CONFLICT.getStatusCode(), - Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() - }; - Arrays.sort(STATUS_CODES); - return STATUS_CODES; - } - @Override - public boolean isValidStatusCode(int statusCode) { - if (Arrays.binarySearch(CREATE.validStatusCodes(), statusCode) >= 0) { - return true; - } else { - return false; - } - } - @Override - public String validStatusCodesAsString() { - return Arrays.toString(CREATE.validStatusCodes()); - } - }, - - - READ { - @Override - public int[] validStatusCodes() { - final int[] STATUS_CODES = { - Response.Status.OK.getStatusCode(), - Response.Status.FORBIDDEN.getStatusCode(), - Response.Status.NOT_FOUND.getStatusCode(), - Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() - }; - Arrays.sort(STATUS_CODES); - return STATUS_CODES; - } - @Override - public boolean isValidStatusCode(int statusCode) { - if (Arrays.binarySearch(READ.validStatusCodes(), statusCode) >= 0) { - return true; - } else { - return false; - } - } - @Override - public String validStatusCodesAsString() { - return Arrays.toString(READ.validStatusCodes()); - } - }, - - - READ_MULTIPLE { - @Override - public int[] validStatusCodes() { - final int[] STATUS_CODES = { - Response.Status.OK.getStatusCode(), - Response.Status.BAD_REQUEST.getStatusCode(), - Response.Status.FORBIDDEN.getStatusCode(), - Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() - }; - Arrays.sort(STATUS_CODES); - return STATUS_CODES; - } - @Override - public boolean isValidStatusCode(int statusCode) { - if (Arrays.binarySearch(READ_MULTIPLE.validStatusCodes(), statusCode) >= 0) { - return true; - } else { - return false; - } - } - @Override - public String validStatusCodesAsString() { - return Arrays.toString(READ_MULTIPLE.validStatusCodes()); - } - }, - - - UPDATE { - @Override - public int[] validStatusCodes() { - final int[] STATUS_CODES = { - Response.Status.OK.getStatusCode(), - Response.Status.BAD_REQUEST.getStatusCode(), - Response.Status.FORBIDDEN.getStatusCode(), - Response.Status.NOT_FOUND.getStatusCode(), - Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() - }; - Arrays.sort(STATUS_CODES); - return STATUS_CODES; - } - @Override - public boolean isValidStatusCode(int statusCode) { - if (Arrays.binarySearch(UPDATE.validStatusCodes(), statusCode) >= 0) { - return true; - } else { - return false; - } - } - @Override - public String validStatusCodesAsString() { - return Arrays.toString(UPDATE.validStatusCodes()); - } - }, - - - DELETE { - @Override - public int[] validStatusCodes() { - final int[] STATUS_CODES = { - Response.Status.OK.getStatusCode(), - Response.Status.FORBIDDEN.getStatusCode(), - Response.Status.NOT_FOUND.getStatusCode(), - Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() - }; - Arrays.sort(STATUS_CODES); - return STATUS_CODES; - } - @Override - public boolean isValidStatusCode(int statusCode) { - if (Arrays.binarySearch(DELETE.validStatusCodes(), statusCode) >= 0) { - return true; - } else { - return false; - } - } - @Override - public String validStatusCodesAsString() { - return Arrays.toString(DELETE.validStatusCodes()); - } - }; - - // Template methods to be implemented by each ServiceRequestType. - - public abstract int[] validStatusCodes(); - - public abstract boolean isValidStatusCode(int i); - - public abstract String validStatusCodesAsString(); + + // Define each of the service request types and their valid HTTP status codes. + + CREATE { + @Override + public int[] validStatusCodes() { + final int[] STATUS_CODES = { + Response.Status.CREATED.getStatusCode(), + Response.Status.BAD_REQUEST.getStatusCode(), + Response.Status.FORBIDDEN.getStatusCode(), + Response.Status.CONFLICT.getStatusCode(), + Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() + }; + Arrays.sort(STATUS_CODES); + return STATUS_CODES; + } + @Override + public boolean isValidStatusCode(int statusCode) { + if (Arrays.binarySearch(CREATE.validStatusCodes(), statusCode) >= 0) { + return true; + } else { + return false; + } + } + @Override + public String validStatusCodesAsString() { + return Arrays.toString(CREATE.validStatusCodes()); + } + }, // Note that commas are required at the end of each enum block, except the last. + + + READ { + @Override + public int[] validStatusCodes() { + final int[] STATUS_CODES = { + Response.Status.OK.getStatusCode(), + Response.Status.FORBIDDEN.getStatusCode(), + Response.Status.NOT_FOUND.getStatusCode(), + Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() + }; + Arrays.sort(STATUS_CODES); + return STATUS_CODES; + } + @Override + public boolean isValidStatusCode(int statusCode) { + if (Arrays.binarySearch(READ.validStatusCodes(), statusCode) >= 0) { + return true; + } else { + return false; + } + } + @Override + public String validStatusCodesAsString() { + return Arrays.toString(READ.validStatusCodes()); + } + }, + + + READ_MULTIPLE { + @Override + public int[] validStatusCodes() { + final int[] STATUS_CODES = { + Response.Status.OK.getStatusCode(), + Response.Status.BAD_REQUEST.getStatusCode(), + Response.Status.FORBIDDEN.getStatusCode(), + Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() + }; + Arrays.sort(STATUS_CODES); + return STATUS_CODES; + } + @Override + public boolean isValidStatusCode(int statusCode) { + if (Arrays.binarySearch(READ_MULTIPLE.validStatusCodes(), statusCode) >= 0) { + return true; + } else { + return false; + } + } + @Override + public String validStatusCodesAsString() { + return Arrays.toString(READ_MULTIPLE.validStatusCodes()); + } + }, + + + UPDATE { + @Override + public int[] validStatusCodes() { + final int[] STATUS_CODES = { + Response.Status.OK.getStatusCode(), + Response.Status.BAD_REQUEST.getStatusCode(), + Response.Status.FORBIDDEN.getStatusCode(), + Response.Status.NOT_FOUND.getStatusCode(), + Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() + }; + Arrays.sort(STATUS_CODES); + return STATUS_CODES; + } + @Override + public boolean isValidStatusCode(int statusCode) { + if (Arrays.binarySearch(UPDATE.validStatusCodes(), statusCode) >= 0) { + return true; + } else { + return false; + } + } + @Override + public String validStatusCodesAsString() { + return Arrays.toString(UPDATE.validStatusCodes()); + } + }, + + + DELETE { + @Override + public int[] validStatusCodes() { + final int[] STATUS_CODES = { + Response.Status.OK.getStatusCode(), + Response.Status.FORBIDDEN.getStatusCode(), + Response.Status.NOT_FOUND.getStatusCode(), + Response.Status.INTERNAL_SERVER_ERROR.getStatusCode() + }; + Arrays.sort(STATUS_CODES); + return STATUS_CODES; + } + @Override + public boolean isValidStatusCode(int statusCode) { + if (Arrays.binarySearch(DELETE.validStatusCodes(), statusCode) >= 0) { + return true; + } else { + return false; + } + } + @Override + public String validStatusCodesAsString() { + return Arrays.toString(DELETE.validStatusCodes()); + } + }, + + + // Used by guard code. + NON_EXISTENT { + @Override + public int[] validStatusCodes() { + final int[] STATUS_CODES = { 0 }; + Arrays.sort(STATUS_CODES); + return STATUS_CODES; + } + @Override + public boolean isValidStatusCode(int statusCode) { + return false; + } + @Override + public String validStatusCodesAsString() { + return Arrays.toString(NON_EXISTENT.validStatusCodes()); + } + }; + + // Template methods to be implemented by each ServiceRequestType. + + public abstract int[] validStatusCodes(); + + public abstract boolean isValidStatusCode(int statusCode); + + public abstract String validStatusCodesAsString(); } diff --git a/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/ServiceTest.java b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/ServiceTest.java new file mode 100644 index 000000000..7c5bb5790 --- /dev/null +++ b/services/collectionobject/client/src/test/java/org/collectionspace/services/client/test/ServiceTest.java @@ -0,0 +1,177 @@ +/** + * This document is a part of the source code and related artifacts + * for CollectionSpace, an open source collections management system + * for museums and related institutions: + * + * http://www.collectionspace.org + * http://wiki.collectionspace.org + * + * Copyright © 2009 Regents of the University of California + * + * Licensed under the Educational Community License (ECL), Version 2.0. + * You may not use this file except in compliance with this License. + * + * You may obtain a copy of the ECL 2.0 License at + * + * https://source.collectionspace.org/collection-space/LICENSE.txt + * + * 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 org.collectionspace.services.client.test; + +/** + * ServiceTest, interface specifying the client tests to be performed + * to test an entity or relation service. + */ +public interface ServiceTest { + + // --------------------------------------------------------------- + // CRUD tests : CREATE tests + // --------------------------------------------------------------- + + // Success outcomes + + /** + * Tests creation of a new resource. + * + * Relied upon by 'read', 'update' and 'delete' tests, below. + */ + public void create(); + + /** + * Tests creation of two or more new resources by repeatedly + * calling create(), and relies on the latter's test assertion(s). + * + * Relied upon by 'read multiple' tests, below. + */ + public void createMultiple(); + + // Failure outcomes + + /** + * Tests creation of a null resource via the + * Java Client Library. + */ + public void createNull(); + + /** + * Tests creation of a resource by submitting + * a representation with malformed XML data. + */ + public void createWithMalformedXml(); + + /** + * Tests creation of a resource by submitting + * a representation in the wrong XML schema + * (e.g. not matching the object's schema). + */ + public void createWithWrongXmlSchema(); + + // @TODO If feasible, implement a negative (failure) + // test for creation of duplicate resources. + + + // --------------------------------------------------------------- + // CRUD tests : READ tests + // --------------------------------------------------------------- + + // Success outcomes + + /** + * Tests reading (i.e. retrieval) of a resource. + */ + public void read(); + + // Failure outcomes + + /** + * Tests reading (i.e. retrieval) of a non-existent + * resource, whose resource identifier does not exist + * at the specified URL. + */ + public void readNonExistent(); + + + // --------------------------------------------------------------- + // CRUD tests : READ (list, or multiple) tests + // --------------------------------------------------------------- + + // Success outcomes + + /** + * Tests reading (i.e. retrieval) of a list of + * multiple resources. + */ + public void readList(); + + // If feasible, implement a test for reading + // an empty list returned by the service. + + // Failure outcomes + + // If feasible, implement a negative (failure) test + // with unrecognized query parameters, other than + // filtering or chunking parameters, etc., recognized + // by the service. + + // --------------------------------------------------------------- + // CRUD tests : UPDATE tests + // --------------------------------------------------------------- + + // Success outcomes + // ---------------- + + /** + * Tests updating the content of a resource. + */ + public void update(); + + // Failure outcomes + + /** + * Tests updating the content of a resource + * by submitting a representation with malformed + * XML data. + */ + public void updateWithMalformedXml(); + + /** + * Tests updating the content of a resource + * by submitting a representation in the wrong + * XML schema (e.g. not matching the object's schema). + */ + public void updateWithWrongXmlSchema(); + + /** + * Tests updating the content of a non-existent + * resource, whose resource identifier does not exist. + */ + public void updateNonExistent(); + + + // --------------------------------------------------------------- + // CRUD tests : DELETE tests + // --------------------------------------------------------------- + + // Success outcomes + + /** + * Tests deleting a resource. + */ + public void delete(); + + // Failure outcomes + + /** + * Tests deleting a non-existent resource, whose resource + * identifier does not exist at the specified URL. + */ + public void deleteNonExistent(); + +} + +