]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
e3e08fde638a578bf417e222e374c0c940c4401d
[tmp/jakarta-migration.git] /
1 /**
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:
5  *
6  * http://www.collectionspace.org
7  * http://wiki.collectionspace.org
8  *
9  * Copyright © 2009 Regents of the University of California
10  *
11  * Licensed under the Educational Community License (ECL), Version 2.0.
12  * You may not use this file except in compliance with this License.
13  *
14  * You may obtain a copy of the ECL 2.0 License at
15  * https://source.collectionspace.org/collection-space/LICENSE.txt
16  *
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.
22  */
23 package org.collectionspace.services.client.test;
24
25 import java.text.DateFormat;
26 import java.text.SimpleDateFormat;
27 import java.util.Calendar;
28 import java.util.Date;
29 import java.util.List;
30 import java.util.TimeZone;
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.Response;
33
34 import org.collectionspace.services.common.datetime.GregorianCalendarDateTimeUtils;
35 import org.collectionspace.services.client.CollectionSpaceClient;
36 import org.collectionspace.services.client.MovementClient;
37 import org.collectionspace.services.jaxb.AbstractCommonList;
38 import org.collectionspace.services.movement.MovementsCommon;
39 import org.collectionspace.services.movement.MovementsCommonList;
40 import org.collectionspace.services.movement.MovementMethodsList;
41
42 import org.jboss.resteasy.client.ClientResponse;
43
44 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
45 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
46 import org.jboss.resteasy.plugins.providers.multipart.OutputPart;
47 import org.testng.Assert;
48 import org.testng.annotations.Test;
49
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 /**
54  * MovementServiceTest, carries out tests against a
55  * deployed and running Movement Service.
56  *
57  * $LastChangedRevision$
58  * $LastChangedDate$
59  */
60 public class MovementServiceTest extends AbstractServiceTestImpl {
61
62    /** The logger. */
63     private final String CLASS_NAME = MovementServiceTest.class.getName();
64     private final Logger logger = LoggerFactory.getLogger(CLASS_NAME);
65
66     // Instance variables specific to this test.
67     /** The service path component. */
68     final String SERVICE_PATH_COMPONENT = "movements";
69     
70     /** The known resource id. */
71     private String knownResourceId = null;
72
73     private final static String TIMESTAMP_UTC = GregorianCalendarDateTimeUtils.timestampUTC();
74     
75     /* (non-Javadoc)
76      * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
77      */
78     @Override
79     protected CollectionSpaceClient getClientInstance() {
80         return new MovementClient();
81     }
82     
83     /* (non-Javadoc)
84      * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
85      */
86     @Override
87         protected AbstractCommonList getAbstractCommonList(
88                         ClientResponse<AbstractCommonList> response) {
89         return response.getEntity(MovementsCommonList.class);
90     }
91  
92     // ---------------------------------------------------------------
93     // CRUD tests : CREATE tests
94     // ---------------------------------------------------------------
95     // Success outcomes
96     /* (non-Javadoc)
97      * @see org.collectionspace.services.client.test.ServiceTest#create(java.lang.String)
98      */
99     @Override
100     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class)
101     public void create(String testName) throws Exception {
102
103         if (logger.isDebugEnabled()) {
104             logger.debug(testBanner(testName, CLASS_NAME));
105         }
106         // Perform setup, such as initializing the type of service request
107         // (e.g. CREATE, DELETE), its valid and expected status codes, and
108         // its associated HTTP method name (e.g. POST, DELETE).
109         setupCreate();
110
111         // Submit the request to the service and store the response.
112         MovementClient client = new MovementClient();
113         String identifier = createIdentifier();
114         MultipartOutput multipart = createMovementInstance(identifier);
115         ClientResponse<Response> res = client.create(multipart);
116
117         int statusCode = res.getStatus();
118
119         // Check the status code of the response: does it match
120         // the expected response(s)?
121         //
122         // Specifically:
123         // Does it fall within the set of valid status codes?
124         // Does it exactly match the expected status code?
125         if(logger.isDebugEnabled()){
126             logger.debug(testName + ": status = " + statusCode);
127         }
128         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
129                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
130         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
131
132         // Store the ID returned from the first resource created
133         // for additional tests below.
134         if (knownResourceId == null){
135             knownResourceId = extractId(res);
136             if (logger.isDebugEnabled()) {
137                 logger.debug(testName + ": knownResourceId=" + knownResourceId);
138             }
139         }
140         
141         // Store the IDs from every resource created by tests,
142         // so they can be deleted after tests have been run.
143         allResourceIdsCreated.add(extractId(res));
144     }
145
146     /* (non-Javadoc)
147      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#createList(java.lang.String)
148      */
149     @Override
150     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
151         dependsOnMethods = {"create"})
152     public void createList(String testName) throws Exception {
153         for(int i = 0; i < 3; i++){
154             create(testName);
155         }
156     }
157
158     // Failure outcomes
159     // Placeholders until the three tests below can be uncommented.
160     // See Issue CSPACE-401.
161     /* (non-Javadoc)
162      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#createWithEmptyEntityBody(java.lang.String)
163      */
164     @Override
165     public void createWithEmptyEntityBody(String testName) throws Exception {
166         //Should this really be empty?
167     }
168
169     /* (non-Javadoc)
170      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#createWithMalformedXml(java.lang.String)
171      */
172     @Override
173     public void createWithMalformedXml(String testName) throws Exception {
174         //Should this really be empty?
175     }
176
177     /* (non-Javadoc)
178      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#createWithWrongXmlSchema(java.lang.String)
179      */
180     @Override
181     public void createWithWrongXmlSchema(String testName) throws Exception {
182         //Should this really be empty?
183     }
184
185     /*
186     @Override
187     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
188         dependsOnMethods = {"create", "testSubmitRequest"})
189     public void createWithEmptyEntityBody(String testName) throws Exception {
190
191         if (logger.isDebugEnabled()) {
192             logger.debug(testBanner(testName, CLASS_NAME));
193         }
194         // Perform setup.
195         setupCreateWithEmptyEntityBody();
196
197         // Submit the request to the service and store the response.
198         String method = REQUEST_TYPE.httpMethodName();
199         String url = getServiceRootURL();
200         String mediaType = MediaType.APPLICATION_XML;
201         final String entity = "";
202         int statusCode = submitRequest(method, url, mediaType, entity);
203
204         // Check the status code of the response: does it match
205         // the expected response(s)?
206         if(logger.isDebugEnabled()){
207             logger.debug("createWithEmptyEntityBody url=" + url +
208                 " status=" + statusCode);
209          }
210         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
211         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
212         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
213     }
214
215     @Override
216     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
217         dependsOnMethods = {"create", "testSubmitRequest"})
218     public void createWithMalformedXml(String testName) throws Exception {
219
220         if (logger.isDebugEnabled()) {
221             logger.debug(testBanner(testName, CLASS_NAME));
222         }
223         // Perform setup.
224         setupCreateWithMalformedXml();
225
226         // Submit the request to the service and store the response.
227         String method = REQUEST_TYPE.httpMethodName();
228         String url = getServiceRootURL();
229         String mediaType = MediaType.APPLICATION_XML;
230         final String entity = MALFORMED_XML_DATA; // Constant from base class.
231         int statusCode = submitRequest(method, url, mediaType, entity);
232
233         // Check the status code of the response: does it match
234         // the expected response(s)?
235         if(logger.isDebugEnabled()){
236             logger.debug(testName + ": url=" + url +
237                 " status=" + statusCode);
238          }
239         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
240         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
241         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
242     }
243
244     @Override
245     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
246         dependsOnMethods = {"create", "testSubmitRequest"})
247     public void createWithWrongXmlSchema(String testName) throws Exception {
248
249         if (logger.isDebugEnabled()) {
250             logger.debug(testBanner(testName, CLASS_NAME));
251         }
252         // Perform setup.
253         setupCreateWithWrongXmlSchema();
254
255         // Submit the request to the service and store the response.
256         String method = REQUEST_TYPE.httpMethodName();
257         String url = getServiceRootURL();
258         String mediaType = MediaType.APPLICATION_XML;
259         final String entity = WRONG_XML_SCHEMA_DATA;
260         int statusCode = submitRequest(method, url, mediaType, entity);
261
262         // Check the status code of the response: does it match
263         // the expected response(s)?
264         if(logger.isDebugEnabled()){
265             logger.debug(testName + ": url=" + url +
266                 " status=" + statusCode);
267          }
268         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
269         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
270         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
271     }
272      */
273
274     // ---------------------------------------------------------------
275     // CRUD tests : READ tests
276     // ---------------------------------------------------------------
277     // Success outcomes
278     /* (non-Javadoc)
279      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#read(java.lang.String)
280      */
281     @Override
282     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
283         dependsOnMethods = {"create"})
284     public void read(String testName) throws Exception {
285
286         if (logger.isDebugEnabled()) {
287             logger.debug(testBanner(testName, CLASS_NAME));
288         }
289         // Perform setup.
290         setupRead();
291
292         // Submit the request to the service and store the response.
293         MovementClient client = new MovementClient();
294         ClientResponse<MultipartInput> res = client.read(knownResourceId);
295         int statusCode = res.getStatus();
296
297         // Check the status code of the response: does it match
298         // the expected response(s)?
299         if(logger.isDebugEnabled()){
300             logger.debug(testName + ": status = " + statusCode);
301         }
302         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
303                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
304         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
305
306         MultipartInput input = (MultipartInput) res.getEntity();
307         MovementsCommon movement = (MovementsCommon) extractPart(input,
308                 client.getCommonPartName(), MovementsCommon.class);
309         Assert.assertNotNull(movement);
310
311         // Check the values of one or more date/time fields
312         if (logger.isDebugEnabled()) {
313             logger.debug("locationDate=" + movement.getLocationDate());
314             logger.debug("TIMESTAMP_UTC=" + TIMESTAMP_UTC);
315         }
316         Assert.assertTrue(movement.getLocationDate().equals(TIMESTAMP_UTC));
317         Assert.assertTrue(movement.getPlannedRemovalDate().equals(TIMESTAMP_UTC));
318         Assert.assertTrue(movement.getRemovalDate().equals(TIMESTAMP_UTC));
319     }
320
321     // Failure outcomes
322     /* (non-Javadoc)
323      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#readNonExistent(java.lang.String)
324      */
325     @Override
326     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
327         dependsOnMethods = {"read"})
328     public void readNonExistent(String testName) throws Exception {
329
330         if (logger.isDebugEnabled()) {
331             logger.debug(testBanner(testName, CLASS_NAME));
332         }
333         // Perform setup.
334         setupReadNonExistent();
335
336         // Submit the request to the service and store the response.
337         MovementClient client = new MovementClient();
338         ClientResponse<MultipartInput> res = client.read(NON_EXISTENT_ID);
339         int statusCode = res.getStatus();
340
341         // Check the status code of the response: does it match
342         // the expected response(s)?
343         if(logger.isDebugEnabled()){
344             logger.debug(testName + ": status = " + statusCode);
345         }
346         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
347                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
348         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
349     }
350
351     // ---------------------------------------------------------------
352     // CRUD tests : READ_LIST tests
353     // ---------------------------------------------------------------
354     // Success outcomes
355     /* (non-Javadoc)
356      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#readList(java.lang.String)
357      */
358     @Override
359     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
360         dependsOnMethods = {"createList", "read"})
361     public void readList(String testName) throws Exception {
362
363         if (logger.isDebugEnabled()) {
364             logger.debug(testBanner(testName, CLASS_NAME));
365         }
366         // Perform setup.
367         setupReadList();
368
369         // Submit the request to the service and store the response.
370         MovementClient client = new MovementClient();
371         ClientResponse<MovementsCommonList> res = client.readList();
372         MovementsCommonList list = res.getEntity();
373         int statusCode = res.getStatus();
374
375         // Check the status code of the response: does it match
376         // the expected response(s)?
377         if(logger.isDebugEnabled()){
378             logger.debug(testName + ": status = " + statusCode);
379         }
380         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
381                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
382         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
383
384         // Optionally output additional data about list members for debugging.
385         boolean iterateThroughList = true;
386         if(iterateThroughList && logger.isDebugEnabled()){
387             List<MovementsCommonList.MovementListItem> items =
388                     list.getMovementListItem();
389             int i = 0;
390             for(MovementsCommonList.MovementListItem item : items){
391                 logger.debug(testName + ": list-item[" + i + "] csid=" +
392                         item.getCsid());
393                 logger.debug(testName + ": list-item[" + i + "] movementReferenceNumber=" +
394                         item.getMovementReferenceNumber());
395                 logger.debug(testName + ": list-item[" + i + "] locationDate=" +
396                         item.getLocationDate());
397                 logger.debug(testName + ": list-item[" + i + "] URI=" +
398                         item.getUri());
399                 i++;
400             }
401         }
402
403     }
404
405     // Failure outcomes
406     // None at present.
407     // ---------------------------------------------------------------
408     // CRUD tests : UPDATE tests
409     // ---------------------------------------------------------------
410     // Success outcomes
411     /* (non-Javadoc)
412      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#update(java.lang.String)
413      */
414     @Override
415     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
416         dependsOnMethods = {"read"})
417     public void update(String testName) throws Exception {
418
419         if (logger.isDebugEnabled()) {
420             logger.debug(testBanner(testName, CLASS_NAME));
421         }
422         // Perform setup.
423         setupUpdate();
424
425         // Retrieve the contents of a resource to update.
426         MovementClient client = new MovementClient();
427         ClientResponse<MultipartInput> res =
428                 client.read(knownResourceId);
429         if(logger.isDebugEnabled()){
430             logger.debug(testName + ": read status = " + res.getStatus());
431         }
432         Assert.assertEquals(res.getStatus(), EXPECTED_STATUS_CODE);
433
434         if(logger.isDebugEnabled()){
435             logger.debug("got object to update with ID: " + knownResourceId);
436         }
437         MultipartInput input = (MultipartInput) res.getEntity();
438         MovementsCommon movement = (MovementsCommon) extractPart(input,
439                 client.getCommonPartName(), MovementsCommon.class);
440         Assert.assertNotNull(movement);
441
442         // Update the content of this resource.
443         movement.setMovementReferenceNumber("updated-" + movement.getMovementReferenceNumber());
444         movement.setMovementNote("updated movement note-" + movement.getMovementNote());
445         if(logger.isDebugEnabled()){
446             logger.debug("to be updated object");
447             logger.debug(objectAsXmlString(movement, MovementsCommon.class));
448         }
449         // Submit the request to the service and store the response.
450         MultipartOutput output = new MultipartOutput();
451         OutputPart commonPart = output.addPart(movement, MediaType.APPLICATION_XML_TYPE);
452         commonPart.getHeaders().add("label", client.getCommonPartName());
453
454         res = client.update(knownResourceId, output);
455         int statusCode = res.getStatus();
456         // Check the status code of the response: does it match the expected response(s)?
457         if(logger.isDebugEnabled()){
458             logger.debug(testName + ": status = " + statusCode);
459         }
460         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
461                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
462         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
463
464
465         input = (MultipartInput) res.getEntity();
466         MovementsCommon updatedMovement =
467                 (MovementsCommon) extractPart(input,
468                         client.getCommonPartName(), MovementsCommon.class);
469         Assert.assertNotNull(updatedMovement);
470
471         Assert.assertEquals(updatedMovement.getMovementNote(),
472                 movement.getMovementNote(),
473                 "Data in updated object did not match submitted data.");
474
475     }
476
477     // Failure outcomes
478     // Placeholders until the three tests below can be uncommented.
479     // See Issue CSPACE-401.
480     /* (non-Javadoc)
481      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#updateWithEmptyEntityBody(java.lang.String)
482      */
483     @Override
484     public void updateWithEmptyEntityBody(String testName) throws Exception{
485         //Should this really be empty?
486     }
487     
488     /* (non-Javadoc)
489      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#updateWithMalformedXml(java.lang.String)
490      */
491     @Override
492     public void updateWithMalformedXml(String testName) throws Exception {
493         //Should this really be empty?
494     }
495     
496     /* (non-Javadoc)
497      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#updateWithWrongXmlSchema(java.lang.String)
498      */
499     @Override
500     public void updateWithWrongXmlSchema(String testName) throws Exception {
501         //Should this really be empty?
502     }
503
504     /*
505     @Override
506     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
507         dependsOnMethods = {"create", "update", "testSubmitRequest"})
508     public void updateWithEmptyEntityBody(String testName) throws Exception {
509
510         if (logger.isDebugEnabled()) {
511             logger.debug(testBanner(testName, CLASS_NAME));
512         }
513         // Perform setup.
514         setupUpdateWithEmptyEntityBody();
515
516         // Submit the request to the service and store the response.
517         String method = REQUEST_TYPE.httpMethodName();
518         String url = getResourceURL(knownResourceId);
519         String mediaType = MediaType.APPLICATION_XML;
520         final String entity = "";
521         int statusCode = submitRequest(method, url, mediaType, entity);
522
523         // Check the status code of the response: does it match
524         // the expected response(s)?
525         if(logger.isDebugEnabled()){
526             logger.debug(testName + ": url=" + url +
527                 " status=" + statusCode);
528          }
529         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
530         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
531         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
532     }
533
534     @Override
535     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
536         dependsOnMethods = {"create", "update", "testSubmitRequest"})
537     public void updateWithMalformedXml(String testName) throws Exception {
538
539         if (logger.isDebugEnabled()) {
540             logger.debug(testBanner(testName, CLASS_NAME));
541         }
542         // Perform setup.
543         setupUpdateWithMalformedXml();
544
545         // Submit the request to the service and store the response.
546         String method = REQUEST_TYPE.httpMethodName();
547         String url = getResourceURL(knownResourceId);
548         String mediaType = MediaType.APPLICATION_XML;
549         final String entity = MALFORMED_XML_DATA;
550         int statusCode = submitRequest(method, url, mediaType, entity);
551
552         // Check the status code of the response: does it match
553         // the expected response(s)?
554         if(logger.isDebugEnabled()){
555             logger.debug(testName + ": url=" + url +
556              " status=" + statusCode);
557          }
558         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
559         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
560         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
561     }
562
563     @Override
564     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
565         dependsOnMethods = {"create", "update", "testSubmitRequest"})
566     public void updateWithWrongXmlSchema(String testName) throws Exception {
567
568         if (logger.isDebugEnabled()) {
569             logger.debug(testBanner(testName, CLASS_NAME));
570         }
571         // Perform setup.
572         setupUpdateWithWrongXmlSchema();
573
574         // Submit the request to the service and store the response.
575         String method = REQUEST_TYPE.httpMethodName();
576         String url = getResourceURL(knownResourceId);
577         String mediaType = MediaType.APPLICATION_XML;
578         final String entity = WRONG_XML_SCHEMA_DATA;
579         int statusCode = submitRequest(method, url, mediaType, entity);
580
581         // Check the status code of the response: does it match
582         // the expected response(s)?
583         if(logger.isDebugEnabled()){
584             logger.debug(testName + ": url=" + url +
585             " status=" + statusCode);
586          }
587         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
588         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
589         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
590     }
591      */
592
593     /* (non-Javadoc)
594      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#updateNonExistent(java.lang.String)
595      */
596     @Override
597     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
598         dependsOnMethods = {"update", "testSubmitRequest"})
599     public void updateNonExistent(String testName) throws Exception {
600
601         if (logger.isDebugEnabled()) {
602             logger.debug(testBanner(testName, CLASS_NAME));
603         }
604         // Perform setup.
605         setupUpdateNonExistent();
606
607         // Submit the request to the service and store the response.
608         // Note: The ID used in this 'create' call may be arbitrary.
609         // The only relevant ID may be the one used in update(), below.
610         MovementClient client = new MovementClient();
611         MultipartOutput multipart = createMovementInstance(NON_EXISTENT_ID);
612         ClientResponse<MultipartInput> res =
613                 client.update(NON_EXISTENT_ID, multipart);
614         int statusCode = res.getStatus();
615
616         // Check the status code of the response: does it match
617         // the expected response(s)?
618         if(logger.isDebugEnabled()){
619             logger.debug(testName + ": status = " + statusCode);
620         }
621         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
622                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
623         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
624     }
625
626     // ---------------------------------------------------------------
627     // CRUD tests : DELETE tests
628     // ---------------------------------------------------------------
629     // Success outcomes
630     /* (non-Javadoc)
631      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#delete(java.lang.String)
632      */
633     @Override
634     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
635         dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"})
636     public void delete(String testName) throws Exception {
637
638         if (logger.isDebugEnabled()) {
639             logger.debug(testBanner(testName, CLASS_NAME));
640         }
641         // Perform setup.
642         setupDelete();
643
644         // Submit the request to the service and store the response.
645         MovementClient client = new MovementClient();
646         ClientResponse<Response> res = client.delete(knownResourceId);
647         int statusCode = res.getStatus();
648
649         // Check the status code of the response: does it match
650         // the expected response(s)?
651         if(logger.isDebugEnabled()){
652             logger.debug(testName + ": status = " + statusCode);
653         }
654         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
655                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
656         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
657     }
658
659     // Failure outcomes
660     /* (non-Javadoc)
661      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#deleteNonExistent(java.lang.String)
662      */
663     @Override
664     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
665         dependsOnMethods = {"delete"})
666     public void deleteNonExistent(String testName) throws Exception {
667
668         if (logger.isDebugEnabled()) {
669             logger.debug(testBanner(testName, CLASS_NAME));
670         }
671         // Perform setup.
672         setupDeleteNonExistent();
673
674         // Submit the request to the service and store the response.
675         MovementClient client = new MovementClient();
676         ClientResponse<Response> res = client.delete(NON_EXISTENT_ID);
677         int statusCode = res.getStatus();
678
679         // Check the status code of the response: does it match
680         // the expected response(s)?
681         if(logger.isDebugEnabled()){
682             logger.debug(testName + ": status = " + statusCode);
683         }
684         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
685                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
686         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
687     }
688
689     // ---------------------------------------------------------------
690     // Utility tests : tests of code used in tests above
691     // ---------------------------------------------------------------
692     /**
693      * Tests the code for manually submitting data that is used by several
694      * of the methods above.
695      */
696     @Test(dependsOnMethods = {"create", "read"})
697     public void testSubmitRequest() {
698
699         // Expected status code: 200 OK
700         final int EXPECTED_STATUS = Response.Status.OK.getStatusCode();
701
702         // Submit the request to the service and store the response.
703         String method = ServiceRequestType.READ.httpMethodName();
704         String url = getResourceURL(knownResourceId);
705         int statusCode = submitRequest(method, url);
706
707         // Check the status code of the response: does it match
708         // the expected response(s)?
709         if(logger.isDebugEnabled()){
710             logger.debug("testSubmitRequest: url=" + url +
711                 " status=" + statusCode);
712         }
713         Assert.assertEquals(statusCode, EXPECTED_STATUS);
714
715     }
716
717     // ---------------------------------------------------------------
718     // Utility methods used by tests above
719     // ---------------------------------------------------------------
720     /* (non-Javadoc)
721      * @see org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
722      */
723     @Override
724     public String getServicePathComponent() {
725         return SERVICE_PATH_COMPONENT;
726     }
727
728     /**
729      * Creates the movement instance.
730      *
731      * @param identifier the identifier
732      * @return the multipart output
733      */
734     private MultipartOutput createMovementInstance(String identifier) {
735         return createInstance("movementReferenceNumber-" + identifier);
736     }
737
738     /**
739      * Creates an instance of a Movement record for testing.
740      *
741      * @param movementReferenceNumber A movement reference number.
742      * @return Multipart output suitable for use as a payload
743      *     in a create or update request.
744      */
745     private MultipartOutput createInstance(String movementReferenceNumber) {
746         MovementsCommon movement = new MovementsCommon();
747         // FIXME: Values of currentLocation, normalLocation,
748         // and movementContact should be refNames.
749         movement.setCurrentLocation("currentLocation value");
750         movement.setCurrentLocationFitness("currentLocationFitness value");
751         movement.setCurrentLocationNote("currentLocationNote value");
752         movement.setLocationDate(TIMESTAMP_UTC);
753         movement.setNormalLocation("normalLocation value");
754         movement.setMovementContact("movementContact value");
755         MovementMethodsList movementMethodsList = new MovementMethodsList();
756         List<String> methods = movementMethodsList.getMovementMethod();
757         // @TODO Use properly formatted refNames for representative movement
758         // methods in this example record. The values below are placeholders.
759         String identifier = createIdentifier();
760         methods.add("First Movement Method-" + identifier);
761         methods.add("Second Movement Method-" + identifier);
762         movement.setMovementMethods(movementMethodsList);
763         movement.setMovementNote("movementNote value");
764         movement.setMovementReferenceNumber(movementReferenceNumber);
765         movement.setPlannedRemovalDate(TIMESTAMP_UTC);
766         movement.setRemovalDate(TIMESTAMP_UTC);
767         movement.setReasonForMove("reasonForMove value");
768         MultipartOutput multipart = new MultipartOutput();
769         OutputPart commonPart =
770             multipart.addPart(movement, MediaType.APPLICATION_XML_TYPE);
771         commonPart.getHeaders().add("label", new MovementClient().getCommonPartName());
772
773         if(logger.isDebugEnabled()){
774             logger.debug("to be created, movement common");
775             logger.debug(objectAsXmlString(movement, MovementsCommon.class));
776         }
777
778         return multipart;
779     }
780
781     // FIXME Should be moved to a common class, as these are general utilities.
782     // FIXME Should be refactored to become a convenience variant of a
783     // general method to return a current datestamp or timestamp in any
784     // provided time zone.
785
786    /**
787     * Returns an ISO 8601 formatted timestamp of the
788     * current time instance in the UTC time zone.
789     */
790     public String datestampUTC() {
791         final String ISO_8601_DATE_FORMAT_PATTERN = "yyyy-MM-dd";
792         final DateFormat ISO_8601_DATE_FORMAT =
793             new SimpleDateFormat(ISO_8601_DATE_FORMAT_PATTERN);
794
795         final String UTC_TIMEZONE_IDENTIFIER = "UTC";
796         final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone(UTC_TIMEZONE_IDENTIFIER);
797
798         Date timestamp = new Date();
799         return formatDate(timestamp, UTC_TIMEZONE, ISO_8601_DATE_FORMAT);
800     }
801
802    /**
803     * Returns an ISO 8601 formatted timestamp of the
804     * current time instance in the UTC time zone.
805     */
806     public String timestampUTC() {
807         final String ISO_8601_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
808         final DateFormat ISO_8601_FORMAT =
809             new SimpleDateFormat(ISO_8601_FORMAT_PATTERN);
810
811         final String UTC_TIMEZONE_IDENTIFIER = "UTC";
812         final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone(UTC_TIMEZONE_IDENTIFIER);
813
814         Date timestamp = new Date();
815         return formatDate(timestamp, UTC_TIMEZONE, ISO_8601_FORMAT);
816     }
817
818    /**
819     * Formats a provided date using a provided date formatter,
820     * in the default system time zone.
821     *
822     * @param date  A date to format.
823     * @param df    A date formatter to apply.
824     * @return      A formatted date string.
825     */
826     public String formatDate(Date date, DateFormat df) {
827         return formatDate(date, TimeZone.getDefault(), df);
828     }
829
830     // FIXME Add error handling.
831
832    /**
833     * Formats a provided date using a provided date formatter,
834     * in a provided time zone.
835     *
836     * @param date  A date to format.
837     * @param tz    The time zone qualifier for the date to format.
838     * @param df    A date formatter to apply.
839     *
840     * @return      A formatted date string.
841     */
842     public String formatDate(Date date, TimeZone tz, DateFormat df) {
843         df.setTimeZone(tz);
844         return df.format(date);
845     }
846
847 }