2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright © 2009 Regents of the University of California
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
15 * https://source.collectionspace.org/collection-space/LICENSE.txt
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
24 package org.collectionspace.services.client.test;
26 import java.util.ArrayList;
27 import java.util.List;
28 import javax.ws.rs.core.MultivaluedMap;
29 import javax.ws.rs.core.Response;
30 import javax.xml.bind.JAXBContext;
31 import javax.xml.bind.Marshaller;
32 import org.jboss.resteasy.client.ClientResponse;
33 import org.testng.Assert;
34 import org.testng.annotations.Test;
36 import org.collectionspace.services.client.CollectionObjectClient;
37 import org.collectionspace.services.client.test.ServiceRequestType;
38 import org.collectionspace.services.collectionobject.CollectionObject;
39 import org.collectionspace.services.collectionobject.CollectionObjectList;
41 import java.io.IOException;
42 import java.io.UnsupportedEncodingException;
43 import java.util.Arrays;
45 import javax.ws.rs.core.MediaType;
46 import javax.ws.rs.core.Response.Status;
47 // import org.jboss.resteasy.client.ClientRequest;
48 import org.collectionspace.services.client.TestServiceClient;
49 import org.apache.commons.httpclient.Header;
50 import org.apache.commons.httpclient.HttpClient;
51 import org.apache.commons.httpclient.HttpException;
52 import org.apache.commons.httpclient.HttpMethod;
53 import org.apache.commons.httpclient.HttpStatus;
54 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
55 import org.apache.commons.httpclient.methods.GetMethod;
56 import org.apache.commons.httpclient.methods.PostMethod;
57 import org.apache.commons.httpclient.methods.PutMethod;
58 import org.apache.commons.httpclient.methods.RequestEntity;
59 import org.apache.commons.httpclient.methods.StringRequestEntity;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
65 * CollectionObjectServiceTest, carries out tests against a
66 * deployed and running CollectionObject Service.
68 * $LastChangedRevision$
71 public class CollectionObjectServiceTest {
73 // Instance variables specific to this test.
74 final Logger logger = LoggerFactory.getLogger(CollectionObjectServiceTest.class);
75 private CollectionObjectClient client = new CollectionObjectClient();
77 // Instance variables common to all entity service test classes.
78 private String knownObjectId = null;
79 private final String NON_EXISTENT_ID = createNonExistentIdentifier();
80 private HttpClient httpClient = new HttpClient();
81 private TestServiceClient serviceClient = new TestServiceClient();
83 // ---------------------------------------------------------------
84 // Service Discovery tests
85 // ---------------------------------------------------------------
90 // ---------------------------------------------------------------
91 // CRUD tests : CREATE tests
92 // ---------------------------------------------------------------
98 * Tests creation of a new resource of the specified type.
100 * The 'Location' header will contain the URL for the newly created object.
101 * This is required by the extractId() utility method, below.
103 * The newly-created resource is also used by other test(s)
104 * (e.g. update, delete) which follow, below.
107 public void create() {
109 // Expected status code: 201 Created
110 final int EXPECTED_STATUS_CODE = Response.Status.CREATED.getStatusCode();
112 // Type of service request being tested
113 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE;
115 // Submit the request to the service and store the response.
116 String identifier = this.createIdentifier();
117 CollectionObject collectionObject = createCollectionObject(identifier);
118 ClientResponse<Response> res = client.createCollectionObject(collectionObject);
119 int statusCode = res.getStatus();
121 // Check the status code of the response: does it match the expected response(s)?
122 verbose("create: status = " + statusCode);
123 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
124 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
125 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
127 // Store the ID returned from this create operation for additional tests below.
128 knownObjectId = extractId(res);
132 * Creates two or more new objects of the specified type.
134 * Repeatedly calls the create test, above, and relies on its
137 * The newly-created objects are also used by other test(s)
138 * (e.g. read multiple/list) which follow, below.
140 @Test(dependsOnMethods = {"create"})
141 public void createMultiple() {
142 for(int i = 0; i < 3; i++){
151 * Tests creation of a resource of the specified type by sending a null to the client proxy.
154 @Test(dependsOnMethods = {"create"}, expectedExceptions = IllegalArgumentException.class)
155 public void createNull() {
157 // Expected result: IllegalArgumentException
158 ClientResponse<Response> res = client.createCollectionObject(null);
162 * Tests creation of a resource of the specified type by sending malformed XML data
163 * in the entity body of the request.
166 @Test(dependsOnMethods = {"create", "testSubmitRequest"})
167 public void createWithMalformedXml() {
169 // Expected status code: 400 Bad Request
170 final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
172 // Type of service request being tested
173 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE;
175 // @TODO This test is currently commented out, because it returns a
176 // 500 Internal Server Error status code, rather than the expected status code.
178 // Submit the request to the service and store the response.
179 String url = getServiceRootURL();
180 PostMethod method = new PostMethod(url);
181 final String MALFORMED_XML_DATA =
182 "<malformed_xml>wrong schema contents</malformed_xml"; // Note: intentionally missing bracket.
183 StringRequestEntity entity = getXmlEntity(MALFORMED_XML_DATA);
184 int statusCode = submitRequest(method, entity);
186 // Check the status code of the response: does it match the expected response(s)?
187 verbose("createWithMalformedXml url=" + url + " status=" + statusCode);
188 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
189 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
190 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
195 * Tests creation of a resource of the specified type by sending data
196 * in the wrong schema (e.g. in a format that doesn't match the object's schema)
197 * in the entity body of the request.
200 @Test(dependsOnMethods = {"create", "testSubmitRequest", "createWithMalformedXml"})
201 public void createWithWrongSchema() {
203 // Expected status code: 400 Bad Request
204 final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
206 // Type of service request being tested
207 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE;
209 // @TODO This test is currently commented out, because it returns a
210 // 500 Internal Server Error status code, rather than the expected status code.
212 // Submit the request to the service and store the response.
213 String url = getServiceRootURL();
214 PostMethod method = new PostMethod(url);
215 final String WRONG_SCHEMA_DATA = "<wrong_schema>wrong schema contents</wrong_schema>";
216 StringRequestEntity entity = getXmlEntity(WRONG_SCHEMA_DATA);
217 int statusCode = submitRequest(method, entity);
219 // Check the status code of the response: does it match the expected response(s)?
220 verbose("createWithWrongSchema url=" + url + " status=" + statusCode);
221 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
222 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
223 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
228 * Tests creation of a resource of the specified type,
229 * by a user who is not authorized to perform this action.
232 @Test(dependsOnMethods = {"create"})
233 public void createWithoutAuthorization() {
235 // Expected status code: 403 Forbidden
236 final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode();
238 // @TODO Currently only a stub. This test can be implemented
239 // when the service is revised to require authorization.
244 * Tests creation of a duplicate object of the specified type,
245 * whose unique resource identifier duplicates that of an existing object.
248 @Test(dependsOnMethods = {"create"})
249 public void createDuplicate() {
251 // Expected status code: 409 Conflict
252 final int EXPECTED_STATUS_CODE = Response.Status.CONFLICT.getStatusCode();
254 // Type of service request being tested
255 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.CREATE;
257 // @TODO This test is currently commented out because our current
258 // services do not appear to permit creation of duplicate records.
259 // Please see below for more details.
261 // Note: there doesn't appear to be a way to create a duplicate
262 // resource (object) by POSTing:
264 // 1. We can't POST to a specific resource by ID; that returns a
265 // response with a 405 Method Not Allowed status code.
267 // 2. If we POST to the container in which new resources are created,
268 // it doesn't appear that we can specify the CSID that the newly-created
269 // resource (object) will receive.
271 // If the two points above are accurate, this test is thus unneeded, until
272 // and unless, in our service(s), we begin detecting duplicates via a
273 // technique that isn't dependent on CSIDs; for instance, by checking for
274 // duplicate data in other information units (fields) whose values must be unique.
276 // One possible example of the above: checking for duplicate Accession numbers
277 // in the "Object entry" information unit in CollectionObject resources.
281 // ---------------------------------------------------------------
282 // CRUD tests : READ tests
283 // ---------------------------------------------------------------
289 * Tests reading (i.e. retrieval) of a resource of the specified type.
291 @Test(dependsOnMethods = {"create"})
294 // Expected status code: 200 OK
295 final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
297 // Type of service request being tested
298 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ;
300 // Submit the request to the service and store the response.
301 ClientResponse<CollectionObject> res =
302 client.getCollectionObject(knownObjectId);
303 int statusCode = res.getStatus();
305 // Check the status code of the response: does it match the expected response(s)?
306 verbose("read: status = " + statusCode);
307 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
308 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
309 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
316 * Tests reading (i.e. retrieval) of a resource of the specified type by a user who
317 * is not authorized to perform this action.
320 @Test(dependsOnMethods = {"read"})
321 public void readWithoutAuthorization() {
323 // Expected status code: 403 Forbidden
324 final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode();
326 // Type of service request being tested
327 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ;
329 // @TODO Currently only a stub. This test can be implemented
330 // when the service is revised to require authorization.
335 * Tests reading (i.e. retrieval) of a non-existent object of the specified type,
336 * whose resource identifier does not exist at the specified URL.
338 @Test(dependsOnMethods = {"read"})
339 public void readNonExistent() {
341 // Expected status code: 404 Not Found
342 final int EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode();
344 // Type of service request being tested
345 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ;
347 // Submit the request to the service and store the response.
348 ClientResponse<CollectionObject> res =
349 client.getCollectionObject(NON_EXISTENT_ID);
350 int statusCode = res.getStatus();
352 // Check the status code of the response: does it match the expected response(s)?
353 verbose("readNonExistent: status = " + res.getStatus());
354 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
355 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
356 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
360 // ---------------------------------------------------------------
361 // CRUD tests : READ (list, or multiple) tests
362 // ---------------------------------------------------------------
368 * Tests reading (i.e. retrieval) of a list of multiple objects of the specified type.
370 * Also expected: The entity body in the response contains
371 * a representation of a list of objects of the specified type.
373 @Test(dependsOnMethods = {"createMultiple"})
374 public void readList() {
376 // Expected status code: 200 OK
377 final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
379 // Type of service request being tested
380 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE;
382 // Submit the request to the service and store the response.
383 ClientResponse<CollectionObjectList> res = client.getCollectionObjectList();
384 CollectionObjectList coList = res.getEntity();
385 int statusCode = res.getStatus();
387 // Check the status code of the response: does it match the expected response(s)?
388 verbose("readList: status = " + res.getStatus());
389 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
390 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
391 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
393 // Optionally output additional data about list members for debugging.
394 boolean iterateThroughList = false;
395 if (iterateThroughList && logger.isDebugEnabled()) {
396 List<CollectionObjectList.CollectionObjectListItem> coItemList =
397 coList.getCollectionObjectListItem();
399 for(CollectionObjectList.CollectionObjectListItem pli : coItemList){
400 verbose("readList: list-item[" + i + "] csid=" + pli.getCsid());
401 verbose("readList: list-item[" + i + "] objectNumber=" + pli.getObjectNumber());
402 verbose("readList: list-item[" + i + "] URI=" + pli.getUri());
410 * Tests reading (i.e. retrieval) of a list of multiple objects of the specified type
411 * when the contents of the list are expected to be empty.
413 * Also expected: The entity body in the response contains
414 * a representation of an empty list of objects of the specified type.
417 @Test(dependsOnMethods = {"readList"})
418 public void readEmptyList() {
420 // Expected status code: 200 OK
421 // (NOTE: *not* 204 No Content)
422 final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
424 // Type of service request being tested
425 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE;
427 // @TODO Currently only a stub. Consider how to implement this.
435 * Tests reading (i.e. retrieval) of a list of objects of the specified type
436 * when sending unrecognized query parameters with the request.
439 @Test(dependsOnMethods = {"readList"})
440 public void readListWithBadParams() {
442 // Expected status code: 400 Bad Request
443 final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
445 // Type of service request being tested
446 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE;
448 // @TODO This test is currently commented out, because it returns a
449 // 200 OK status code, rather than the expected status code.
451 // @TODO Another variant of this test should use a URL for the service
452 // root that ends in a trailing slash.
454 // Submit the request to the service and store the response.
455 String url = getServiceRootURL() + "?param=nonexistent";
456 GetMethod method = new GetMethod(url);
457 int statusCode = submitRequest(method);
459 // Check the status code of the response: does it match the expected response(s)?
460 verbose("readListWithBadParams: url=" + url + " status=" + statusCode);
461 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
462 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
463 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
468 * Tests reading (i.e. retrieval) of a list of objects of the specified type by a user who
469 * is not authorized to perform this action.
473 @Test(dependsOnMethods = {"readList"})
474 public void readListWithoutAuthorization() {
476 // Expected status code: 403 Forbidden
477 final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode();
479 // Type of service request being tested
480 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.READ_MULTIPLE;
482 // @TODO Currently only a stub. This test can be implemented
483 // when the service is revised to require authorization.
488 // ---------------------------------------------------------------
489 // CRUD tests : UPDATE tests
490 // ---------------------------------------------------------------
496 * Tests updating the content of a resource of the specified type.
498 * Also expected: The entity body in the response contains
499 * a representation of the updated object of the specified type.
501 @Test(dependsOnMethods = {"create"})
502 public void update() {
504 // Expected status code: 200 OK
505 final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
507 // Type of service request being tested
508 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.UPDATE;
510 // Retrieve an existing resource that we can update.
511 ClientResponse<CollectionObject> res =
512 client.getCollectionObject(knownObjectId);
513 verbose("read: status = " + res.getStatus());
514 Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE);
515 CollectionObject collectionObject = res.getEntity();
516 verbose("Got object to update with ID: " + knownObjectId,
517 collectionObject, CollectionObject.class);
519 // Update the content of this resource.
520 //collectionObject.setCsid("updated-" + knownObjectId);
521 collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber());
522 collectionObject.setObjectName("updated-" + collectionObject.getObjectName());
524 // Submit the request to the service and store the response.
525 res = client.updateCollectionObject(knownObjectId, collectionObject);
526 int statusCode = res.getStatus();
527 CollectionObject updatedCollectionObject = res.getEntity();
529 // Check the status code of the response: does it match the expected response(s)?
530 verbose("update: status = " + res.getStatus());
531 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
532 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
533 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
535 // Check the contents of the response: does it match what was submitted?
536 verbose("update: ", updatedCollectionObject, CollectionObject.class);
537 Assert.assertEquals(updatedCollectionObject.getObjectName(),
538 collectionObject.getObjectName(), "Data in updated object did not match submitted data.");
542 * Tests updating the content of a resource of the specified type
543 * by sending malformed XML data in the entity body of the request.
546 @Test(dependsOnMethods = {"create", "testSubmitRequest"})
547 public void updateWithMalformedXml() {
549 // Expected status code: 400 Bad Request
550 final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
552 // Type of service request being tested
553 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.UPDATE;
555 // @TODO This test is currently commented out, because it returns a
556 // 500 Internal Server Error status code, rather than the expected status code.
558 // Submit the request to the service and store the response.
559 String url = getResourceURL(knownObjectId);
560 PutMethod method = new PutMethod(url);
561 final String MALFORMED_XML_DATA =
562 "<malformed_xml>wrong schema contents</malformed_xml"; // Note: intentionally missing bracket.
563 StringRequestEntity entity = getXmlEntity(MALFORMED_XML_DATA);
564 int statusCode = submitRequest(method, entity);
566 // Check the status code of the response: does it match the expected response(s)?
567 verbose("updateWithMalformedXml: url=" + url + " status=" + statusCode);
568 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
569 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
570 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
575 * Tests updating the content of a resource of the specified type
576 * by sending data in the wrong schema (e.g. in a format that
577 * doesn't match the object's schema) in the entity body of the request.
580 @Test(dependsOnMethods = {"create", "testSubmitRequest", "createWithMalformedXml"})
581 public void updateWithWrongSchema() {
583 // Expected status code: 400 Bad Request
584 final int EXPECTED_STATUS_CODE = Response.Status.BAD_REQUEST.getStatusCode();
586 // Type of service request being tested
587 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.UPDATE;
589 // @TODO This test is currently commented out, because it returns a
590 // 500 Internal Server Error status code, rather than the expected status code.
592 // Submit the request to the service and store the response.
593 String url = getResourceURL(knownObjectId);
594 PutMethod method = new PutMethod(url);
595 final String WRONG_SCHEMA_DATA = "<wrong_schema>wrong schema contents</wrong_schema>";
596 StringRequestEntity entity = getXmlEntity(WRONG_SCHEMA_DATA);
597 int statusCode = submitRequest(method, entity);
599 // Check the status code of the response: does it match the expected response(s)?
600 verbose("updateWithWrongSchema: url=" + url + " status=" + statusCode);
601 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
602 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
603 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
608 * Tests updating the content of a resource of the specified type,
609 * by a user who is not authorized to perform this action.
612 @Test(dependsOnMethods = {"update"})
613 public void updateWithoutAuthorization() {
615 // Expected status code: 403 Forbidden
616 final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode();
618 // @TODO Currently only a stub. This test can be implemented
619 // when the service is revised to require authorization.
624 * Tests updating the content of a non-existent object of the specified type,
625 * whose resource identifier does not exist.
627 @Test(dependsOnMethods = {"update"})
628 public void updateNonExistent() {
630 // Expected status code: 404 Not Found
631 final int EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode();
633 // Type of service request being tested
634 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.UPDATE;
636 // Submit the request to the service and store the response.
637 // Note: The ID used in this 'create' call may be arbitrary.
638 // The only relevant ID may be the one used in updateCollectionObject(), below.
639 CollectionObject collectionObject = createCollectionObject(NON_EXISTENT_ID);
640 ClientResponse<CollectionObject> res =
641 client.updateCollectionObject(NON_EXISTENT_ID, collectionObject);
642 int statusCode = res.getStatus();
644 // Check the status code of the response: does it match the expected response(s)?
645 verbose("updateNonExistent: status = " + res.getStatus());
646 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
647 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
648 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
652 // ---------------------------------------------------------------
653 // CRUD tests : DELETE tests
654 // ---------------------------------------------------------------
660 * Tests deleting an object of the specified type.
662 * Expected status code: 200 OK
664 @Test(dependsOnMethods =
665 {"create", "read", "testSubmitRequest", "update"})
666 public void delete() {
668 // Expected status code: 200 OK
669 final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
671 // Type of service request being tested
672 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.DELETE;
674 // Submit the request to the service and store the response.
675 ClientResponse<Response> res = client.deleteCollectionObject(knownObjectId);
676 int statusCode = res.getStatus();
678 // Check the status code of the response: does it match the expected response(s)?
679 verbose("delete: status = " + res.getStatus());
680 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
681 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
682 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
689 * Tests deleting an object of the specified type,
690 * by a user who is not authorized to perform this action.
693 @Test(dependsOnMethods = {"delete"})
694 public void deleteWithoutAuthorization() {
696 // Expected status code: 403 Forbidden
697 final int EXPECTED_STATUS_CODE = Response.Status.FORBIDDEN.getStatusCode();
699 // Type of service request being tested
700 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.DELETE;
702 // @TODO Currently only a stub. This test can be implemented
703 // when the service is revised to require authorization.
708 * Tests deleting a non-existent object of the specified type,
709 * whose resource identifier does not exist at the specified URL.
711 @Test(dependsOnMethods = {"delete"})
712 public void deleteNonExistent() {
714 // Expected status code: 404 Not Found
715 final int EXPECTED_STATUS_CODE = Response.Status.NOT_FOUND.getStatusCode();
717 // Type of service request being tested
718 final ServiceRequestType REQUEST_TYPE = ServiceRequestType.DELETE;
720 // Submit the request to the service and store the response.
721 ClientResponse<Response> res =
722 client.deleteCollectionObject(NON_EXISTENT_ID);
723 int statusCode = res.getStatus();
725 // Check the status code of the response: does it match the expected response(s)?
726 verbose("deleteNonExistent: status = " + res.getStatus());
727 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
728 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
729 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
733 // ---------------------------------------------------------------
734 // Utility tests : tests of code used in tests above
735 // ---------------------------------------------------------------
738 * Tests the HttpClient-based code used to submit data, in various methods below.
740 @Test(dependsOnMethods = {"create", "read"})
741 public void testSubmitRequest() {
743 // Expected status code: 200 OK
744 final int EXPECTED_STATUS_CODE = Response.Status.OK.getStatusCode();
746 // Submit the request to the service and store the response.
747 String url = getResourceURL(knownObjectId);
748 GetMethod method = new GetMethod(url);
749 int statusCode = submitRequest(method);
751 // Check the status code of the response: does it match the expected response(s)?
752 verbose("testSubmitRequest: url=" + url + " status=" + statusCode);
753 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
758 // ---------------------------------------------------------------
759 // Utility methods used by tests above
760 // ---------------------------------------------------------------
762 // @TODO Add Javadoc comments to all of these methods.
764 // -----------------------------
765 // Methods specific to this test
766 // -----------------------------
768 private CollectionObject createCollectionObject(String identifier) {
769 CollectionObject collectionObject = createCollectionObject("objectNumber-" + identifier,
770 "objectName-" + identifier);
771 return collectionObject;
774 private CollectionObject createCollectionObject(String objectNumber, String objectName) {
775 CollectionObject collectionObject = new CollectionObject();
776 collectionObject.setObjectNumber(objectNumber);
777 collectionObject.setObjectName(objectName);
778 return collectionObject;
781 private String getServicePathComponent() {
782 // @TODO Determine if it is possible to obtain this value programmatically.
783 // We set this in an annotation in the CollectionObjectProxy interface, for instance.
784 final String SERVICE_PATH_COMPONENT = "collectionobjects";
785 return SERVICE_PATH_COMPONENT;
788 // -------------------------------------------------------------
789 // Methods common to all entity service test classes.
791 // These can be moved out of individual service test classes
792 // into a common class, perhaps at the top-level 'client' module.
793 // -------------------------------------------------------------
795 protected String invalidStatusCodeMessage(ServiceRequestType requestType, int statusCode) {
797 "Status code '" + statusCode + "' in response is NOT within the expected set: " +
798 requestType.validStatusCodesAsString();
801 private String getServiceRootURL() {
802 return serviceClient.getBaseURL() + getServicePathComponent();
805 private String getResourceURL(String resourceIdentifier) {
806 return getServiceRootURL() + "/" + resourceIdentifier;
809 private int submitRequest(HttpMethod method) {
812 statusCode = httpClient.executeMethod(method);
813 } catch(HttpException e) {
814 logger.error("Fatal protocol violation: ", e);
815 } catch(IOException e) {
816 logger.error("Fatal transport error: ", e);
817 } catch(Exception e) {
818 logger.error("Unknown exception: ", e);
820 // Release the connection.
821 method.releaseConnection();
826 private int submitRequest(EntityEnclosingMethod method, RequestEntity entity) {
829 method.setRequestEntity(entity);
830 statusCode = httpClient.executeMethod(method);
831 } catch(HttpException e) {
832 logger.error("Fatal protocol violation: ", e);
833 } catch(IOException e) {
834 logger.error("Fatal transport error: ", e);
835 } catch(Exception e) {
836 logger.error("Unknown exception: ", e);
838 // Release the connection.
839 method.releaseConnection();
844 private StringRequestEntity getXmlEntity(String contents) {
845 if (contents == null) {
848 StringRequestEntity entity = null;
849 final String XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
850 final String XML_CONTENT_TYPE=MediaType.APPLICATION_XML;
851 final String UTF8_CHARSET_NAME = "UTF-8";
854 new StringRequestEntity(XML_DECLARATION + contents, XML_CONTENT_TYPE, UTF8_CHARSET_NAME);
855 } catch (UnsupportedEncodingException e) {
856 logger.error("Unsupported character encoding error: ", e);
861 private String extractId(ClientResponse<Response> res) {
862 MultivaluedMap mvm = res.getMetadata();
863 String uri = (String) ((ArrayList) mvm.get("Location")).get(0);
864 verbose("extractId:uri=" + uri);
865 String[] segments = uri.split("/");
866 String id = segments[segments.length - 1];
871 private void verbose(String msg) {
872 if (logger.isDebugEnabled()) {
877 private void verbose(String msg, Object o, Class clazz) {
880 JAXBContext jc = JAXBContext.newInstance(clazz);
881 Marshaller m = jc.createMarshaller();
882 m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
884 m.marshal(o, System.out);
890 private void verboseMap(MultivaluedMap map) {
891 for(Object entry : map.entrySet()){
892 MultivaluedMap.Entry mentry = (MultivaluedMap.Entry) entry;
893 verbose(" name=" + mentry.getKey() + " value=" + mentry.getValue());
897 private String createIdentifier() {
898 long identifier = System.currentTimeMillis();
899 return Long.toString(identifier);
902 private String createNonExistentIdentifier() {
903 return Long.toString(Long.MAX_VALUE);