]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
b886b06c424c81f469e71960a20184b1015cc578
[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.util.List;
26 import javax.ws.rs.core.MediaType;
27 import javax.ws.rs.core.Response;
28
29 //import org.collectionspace.services.client.AbstractServiceClientImpl;
30 import org.collectionspace.services.client.CollectionObjectClient;
31 import org.collectionspace.services.client.CollectionObjectFactory;
32 import org.collectionspace.services.client.CollectionSpaceClient;
33 import org.collectionspace.services.collectionobject.BriefDescriptionList;
34 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
35 import org.collectionspace.services.collectionobject.domain.naturalhistory.CollectionobjectsNaturalhistory;
36 import org.collectionspace.services.collectionobject.CollectionobjectsCommonList;
37 import org.collectionspace.services.collectionobject.ResponsibleDepartmentList;
38 import org.collectionspace.services.collectionobject.DimensionGroup;
39 import org.collectionspace.services.collectionobject.DimensionList;
40 import org.collectionspace.services.collectionobject.ObjectNameGroup;
41 import org.collectionspace.services.collectionobject.ObjectNameList;
42 import org.collectionspace.services.collectionobject.OtherNumber;
43 import org.collectionspace.services.collectionobject.OtherNumberList;
44 import org.collectionspace.services.collectionobject.TitleGroup;
45 import org.collectionspace.services.collectionobject.TitleGroupList;
46
47 import org.collectionspace.services.jaxb.AbstractCommonList;
48
49 import org.jboss.resteasy.client.ClientResponse;
50 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
51 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
52 import org.jboss.resteasy.plugins.providers.multipart.OutputPart;
53 import org.testng.Assert;
54 import org.testng.annotations.Test;
55
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 /**
60  * CollectionObjectServiceTest, carries out tests against a
61  * deployed and running CollectionObject Service.
62  *
63  * $LastChangedRevision$
64  * $LastChangedDate$
65  */
66 public class CollectionObjectServiceTest extends AbstractServiceTestImpl {
67
68     /** The logger. */
69     private final String CLASS_NAME = CollectionObjectServiceTest.class.getName();
70     private final Logger logger = LoggerFactory.getLogger(CLASS_NAME);
71     
72     // Instance variables specific to this test.
73     /** The known resource id. */
74     private String knownResourceId = null;
75
76     private final String OBJECT_NAME_VALUE = "an object name";
77     private final String UPDATED_MEASURED_PART_VALUE = "updated measured part value";
78     private final String UTF8_TITLE = "Audiorecording album cover signed by Lech "
79             + "Wa" + '\u0142' + '\u0119' + "sa";
80
81     /* (non-Javadoc)
82      * @see org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
83      */
84     @Override
85     protected String getServicePathComponent() {
86         return new CollectionObjectClient().getServicePathComponent();
87     }
88     
89     /* (non-Javadoc)
90      * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
91      */
92     @Override
93     protected CollectionSpaceClient getClientInstance() {
94         return new CollectionObjectClient();
95     }
96     
97     /* (non-Javadoc)
98      * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
99      */
100     @Override
101         protected AbstractCommonList getAbstractCommonList(
102                         ClientResponse<AbstractCommonList> response) {
103         return response.getEntity(CollectionobjectsCommonList.class);
104     }
105  
106     // ---------------------------------------------------------------
107     // CRUD tests : CREATE tests
108     // ---------------------------------------------------------------
109     // Success outcomes
110     /* (non-Javadoc)
111      * @see org.collectionspace.services.client.test.ServiceTest#create(java.lang.String)
112      */
113     @Override
114     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
115     public void create(String testName) throws Exception {
116
117         if (logger.isDebugEnabled()) {
118             logger.debug(testBanner(testName, CLASS_NAME));
119         }
120         // Perform setup, such as initializing the type of service request
121         // (e.g. CREATE, DELETE), its valid and expected status codes, and
122         // its associated HTTP method name (e.g. POST, DELETE).
123         setupCreate();
124
125         // Submit the request to the service and store the response.
126         CollectionObjectClient client = new CollectionObjectClient();
127         String identifier = createIdentifier();
128         MultipartOutput multipart =
129                 createCollectionObjectInstance(client.getCommonPartName(), identifier);
130         ClientResponse<Response> res = client.create(multipart);
131         int statusCode = res.getStatus();
132
133         // Check the status code of the response: does it match
134         // the expected response(s)?
135         //
136         // Specifically:
137         // Does it fall within the set of valid status codes?
138         // Does it exactly match the expected status code?
139         if (logger.isDebugEnabled()) {
140             logger.debug(testName + ": status = " + statusCode);
141         }
142         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
143                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
144         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
145
146         // Store the ID returned from the first resource created
147         // for additional tests below.
148         if (knownResourceId == null) {
149             knownResourceId = extractId(res);
150             if (logger.isDebugEnabled()) {
151                 logger.debug(testName + ": knownResourceId=" + knownResourceId);
152             }
153         }
154
155         // Store the IDs from every resource created by tests,
156         // so they can be deleted after tests have been run.
157         allResourceIdsCreated.add(extractId(res));
158     }
159
160
161     /*
162      * Tests to diagnose and verify the fixed status of CSPACE-1026,
163      * "Whitespace at certain points in payload cause failure"
164      */
165     /**
166      * Creates the from xml cambridge.
167      *
168      * @param testName the test name
169      * @throws Exception the exception
170      */
171     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
172         dependsOnMethods = {"create", "testSubmitRequest"})
173     public void createFromXmlCambridge(String testName) throws Exception {
174         String newId =
175             createFromXmlFile(testName, "./test-data/testCambridge.xml", true);
176         testSubmitRequest(newId);
177     }
178
179    /*
180     * Tests to diagnose and fix CSPACE-2242.
181     *
182     * This is a bug identified in release 0.8 in which value instances of a
183     * repeatable field are not stored when the first value instance of that
184     * field is blank.
185     */
186
187     // Verify that record creation occurs successfully when the first value instance
188     // of a single, repeatable String scalar field is non-blank.
189     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
190         dependsOnMethods = {"create", "testSubmitRequest"}, groups = {"cspace2242group"})
191     public void createFromXmlNonBlankFirstValueInstance(String testName) throws Exception {
192         if (logger.isDebugEnabled()) {
193             logger.debug(testBanner(testName, CLASS_NAME));
194         }
195         String newId =
196             createFromXmlFile(testName, "./test-data/cspace-2242-first-value-instance-nonblank.xml", true);
197         CollectionobjectsCommon collectionObject = readCollectionObjectCommonPart(newId);
198         // Verify that at least one value instance of the repeatable field was successfully persisted.
199         BriefDescriptionList descriptionList = collectionObject.getBriefDescriptions();
200         List<String> descriptions = descriptionList.getBriefDescription();
201         Assert.assertTrue(descriptions.size() > 0);
202     }
203
204     // Verify that record creation occurs successfully when the first value instance
205     // of a single, repeatable String scalar field is blank.
206     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
207         dependsOnMethods = {"create", "testSubmitRequest"}, groups = {"cspace2242group"})
208     public void createFromXmlBlankFirstValueInstance(String testName) throws Exception {
209         if (logger.isDebugEnabled()) {
210             logger.debug(testBanner(testName, CLASS_NAME));
211         }
212         String newId =
213             createFromXmlFile(testName, "./test-data/cspace-2242-first-value-instance-blank.xml", true);
214         CollectionobjectsCommon collectionObject = readCollectionObjectCommonPart(newId);
215         // Verify that at least one value instance of the repeatable field was successfully persisted.
216         BriefDescriptionList descriptionList = collectionObject.getBriefDescriptions();
217         List<String> descriptions = descriptionList.getBriefDescription();
218         Assert.assertTrue(descriptions.size() > 0);
219     }
220
221     /**
222      * Creates the from xml rfw s1.
223      *
224      * @param testName the test name
225      * @throws Exception the exception
226      */
227     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
228         dependsOnMethods = {"create", "testSubmitRequest"})
229     public void createFromXmlRFWS1(String testName) throws Exception {
230         String testDataDir = System.getProperty("test-data.fileName");
231         String newId =
232             //createFromXmlFile(testName, "./target/test-classes/test-data/repfield_whitesp1.xml", false);
233                 createFromXmlFile(testName, testDataDir + "/repfield_whitesp1.xml", false);
234         testSubmitRequest(newId);
235     }
236
237     /**
238      * Creates the from xml rfw s2.
239      *
240      * @param testName the test name
241      * @throws Exception the exception
242      */
243     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
244         dependsOnMethods = {"create", "testSubmitRequest"})
245     public void createFromXmlRFWS2(String testName) throws Exception {
246         String testDataDir = System.getProperty("test-data.fileName");
247         String newId =
248             //createFromXmlFile(testName, "./target/test-classes/test-data/repfield_whitesp2.xml", false);
249                 createFromXmlFile(testName, testDataDir + "/repfield_whitesp2.xml", false);
250         testSubmitRequest(newId);
251     }
252
253     /**
254      * Creates the from xml rfw s3.
255      *
256      * @param testName the test name
257      * @throws Exception the exception
258      */
259     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
260         dependsOnMethods = {"create", "testSubmitRequest"})
261     public void createFromXmlRFWS3(String testName) throws Exception {
262         String testDataDir = System.getProperty("test-data.fileName");
263         String newId =
264             //createFromXmlFile(testName, "./target/test-classes/test-data/repfield_whitesp3.xml", false);
265                 createFromXmlFile(testName, testDataDir + "/repfield_whitesp3.xml", false);
266         testSubmitRequest(newId);
267     }
268
269     /**
270      * Creates the from xml rfw s4.
271      *
272      * @param testName the test name
273      * @throws Exception the exception
274      */
275     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
276         dependsOnMethods = {"create", "testSubmitRequest"})
277     public void createFromXmlRFWS4(String testName) throws Exception {
278         String testDataDir = System.getProperty("test-data.fileName");
279         String newId =
280             createFromXmlFile(testName, testDataDir + "/repfield_whitesp4.xml", false);
281         testSubmitRequest(newId);
282     }
283
284     /*
285      * Tests to diagnose and verify the fixed status of CSPACE-1248,
286      * "Wedged records created!" (i.e. records with child repeatable
287      * fields, which contain null values, can be successfully created
288      * but an error occurs on trying to retrieve those records).
289      */
290
291     /**
292      * Creates a CollectionObject resource with a null value repeatable field.
293      *
294      * @param testName the test name
295      * @throws Exception the exception
296      */
297     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
298         dependsOnMethods = {"create", "testSubmitRequest"})
299     public void createWithNullValueRepeatableField(String testName) throws Exception {
300         String testDataDir = System.getProperty("test-data.fileName");
301         String newId =
302             createFromXmlFile(testName, testDataDir + "/repfield_null1.xml", false);
303         if (logger.isDebugEnabled()) {
304             logger.debug("Successfully created record with null value repeatable field.");
305             logger.debug("Attempting to retrieve just-created record ...");
306         }
307         testSubmitRequest(newId);
308     }
309
310     /**
311      * Creates a CollectionObject resource, one of whose fields contains
312      * non-Latin 1 Unicode UTF-8 characters.
313      *
314      * @param testName the test name
315      * @throws Exception the exception
316      */
317  /*
318     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
319         dependsOnMethods = {"create", "testSubmitRequest"}, groups={"utf8-create"})
320     public void createWithUTF8Title(String testName) throws Exception {
321         String testDataDir = System.getProperty("test-data.fileName");
322         String newId =
323             createFromXmlFile(testName, testDataDir + "/cspace-2779-utf-8-create.xml", false);
324         if (logger.isDebugEnabled()) {
325             logger.debug("Created record with UTF-8 chars in payload.");
326             logger.debug("Attempting to retrieve just-created record ...");
327         }
328         CollectionobjectsCommon collectionObject = readCollectionObjectCommonPart(newId);
329         String title = collectionObject.getTitle(); // will need to be changed for multi-valued title
330         if (logger.isDebugEnabled()) {
331             logger.debug("Sent title: " + UTF8_TITLE);
332             logger.debug("Received title: " + title);
333         }
334         Assert.assertTrue(title.equals(UTF8_TITLE));
335     }
336  */
337
338     /* (non-Javadoc)
339      * @see org.collectionspace.services.client.test.ServiceTest#createList()
340      */
341     @Override
342     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
343     dependsOnMethods = {"create"})
344     public void createList(String testName) throws Exception {
345         this.createPaginatedList(testName, DEFAULT_LIST_SIZE);
346     }
347
348     // Failure outcomes
349     // Placeholders until the three tests below can be uncommented.
350     // See Issue CSPACE-401.
351     /* (non-Javadoc)
352      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#createWithEmptyEntityBody(java.lang.String)
353      */
354     @Override
355     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
356     public void createWithEmptyEntityBody(String testName) throws Exception {
357         //FIXME: Should this test really be empty?
358     }
359
360    /**
361     * Test how the service handles XML that is not well formed,
362     * when sent in the payload of a Create request.
363     *
364     * @param testName  The name of this test method.  This name is supplied
365     *     automatically, via reflection, by a TestNG 'data provider' in
366     *     a base class.
367     */
368     @Override
369     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
370     public void createWithMalformedXml(String testName) throws Exception {
371     }
372
373     /* (non-Javadoc)
374      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#createWithWrongXmlSchema(java.lang.String)
375      */
376     @Override
377     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
378     public void createWithWrongXmlSchema(String testName) throws Exception {
379         //FIXME: Should this test really be empty?
380     }
381
382
383 /*
384     @Override
385     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
386     dependsOnMethods = {"create", "testSubmitRequest"})
387     public void createWithEmptyEntityBody(String testName) throwsException {
388
389         if (logger.isDebugEnabled()) {
390             logger.debug(testBanner(testName, CLASS_NAME));
391         }
392         // Perform setup.
393         setupCreateWithEmptyEntityBody();
394
395         // Submit the request to the service and store the response.
396         String method = REQUEST_TYPE.httpMethodName();
397         String url = getServiceRootURL();
398         String mediaType = MediaType.APPLICATION_XML;
399         final String entity = "";
400         int statusCode = submitRequest(method, url, mediaType, entity);
401
402         // Check the status code of the response: does it match
403         // the expected response(s)?
404         if(logger.isDebugEnabled()){
405         logger.debug(testName + ": url=" + url +
406         " status=" + statusCode);
407         }
408         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
409         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
410         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
411     }
412
413     @Override
414     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
415     dependsOnMethods = {"create", "testSubmitRequest"})
416     public void createWithMalformedXml(String testName) throws Exception {
417
418         if (logger.isDebugEnabled()) {
419             logger.debug(testBanner(testName, CLASS_NAME));
420         }
421         // Perform setup.
422         setupCreateWithMalformedXml();
423
424         // Submit the request to the service and store the response.
425         String method = REQUEST_TYPE.httpMethodName();
426         String url = getServiceRootURL();
427         String mediaType = MediaType.APPLICATION_XML;
428         final String entity = MALFORMED_XML_DATA; // Constant from base class.
429         int statusCode = submitRequest(method, url, mediaType, entity);
430
431         // Check the status code of the response: does it match
432         // the expected response(s)?
433         if(logger.isDebugEnabled()){
434         logger.debug(testName + ": url=" + url +
435         " status=" + statusCode);
436         }
437         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
438         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
439         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
440     }
441
442     @Override
443     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
444     dependsOnMethods = {"create", "testSubmitRequest"})
445     public void createWithWrongXmlSchema(String testName) throws Exception {
446
447         if (logger.isDebugEnabled()) {
448             logger.debug(testBanner(testName, CLASS_NAME));
449         }
450         // Perform setup.
451         setupCreateWithWrongXmlSchema();
452
453         // Submit the request to the service and store the response.
454         String method = REQUEST_TYPE.httpMethodName();
455         String url = getServiceRootURL();
456         String mediaType = MediaType.APPLICATION_XML;
457         final String entity = WRONG_XML_SCHEMA_DATA;
458         int statusCode = submitRequest(method, url, mediaType, entity);
459
460         // Check the status code of the response: does it match
461         // the expected response(s)?
462         if(logger.isDebugEnabled()){
463         logger.debug(testName + ": url=" + url +
464         " status=" + statusCode);
465         }
466         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
467         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
468         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
469     }
470 */
471
472    /**
473     * Test how the service handles, in a Create request, payloads
474     * containing null values (or, in the case of String fields,
475     * empty String values) in one or more fields which must be
476     * present and are required to contain non-empty values.
477     *
478     * This is a test of code and/or configuration in the service's
479     * validation routine(s).
480     *
481     * @param testName  The name of this test method.  This name is supplied
482     *     automatically, via reflection, by a TestNG 'data provider' in
483     *     a base class.
484     * @throws Exception 
485     */
486     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
487     public void createWithRequiredValuesNullOrEmpty(String testName) throws Exception {
488         if (logger.isDebugEnabled()) {
489             logger.debug(testBanner(testName, CLASS_NAME));
490         }
491         setupCreate();
492
493         // Build a payload with invalid content, by omitting a
494         // field (objectNumber) which must be present, and in which
495         // a non-empty value is required, as enforced by the service's
496         // validation routine(s).
497         CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
498
499         TitleGroupList titleGroupList = new TitleGroupList();
500         List<TitleGroup> titleGroups = titleGroupList.getTitleGroup();
501         TitleGroup titleGroup = new TitleGroup();
502         titleGroup.setTitle("a title");
503         titleGroups.add(titleGroup);
504         collectionObject.setTitleGroupList(titleGroupList);
505
506         ObjectNameList objNameList = new ObjectNameList();
507         List<ObjectNameGroup> objNameGroups = objNameList.getObjectNameGroup();
508         ObjectNameGroup objectNameGroup = new ObjectNameGroup();
509         objectNameGroup.setObjectName("an object name");
510         objNameGroups.add(objectNameGroup);
511         collectionObject.setObjectNameList(objNameList);
512
513         // Submit the request to the service and store the response.
514         CollectionObjectClient client = new CollectionObjectClient();
515         MultipartOutput multipart =
516                 createCollectionObjectInstance(client.getCommonPartName(), collectionObject, null);
517         ClientResponse<Response> res = client.create(multipart);
518         int statusCode = res.getStatus();
519
520         // Read the response and verify that the create attempt failed.
521         if (logger.isDebugEnabled()) {
522             logger.debug(testName + ": status = " + statusCode);
523         }
524         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
525                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
526         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
527
528         // FIXME: Consider splitting off the following into its own test method.
529         
530         // Build a payload with invalid content, by setting a value to the
531         // empty String, in a field (objectNumber) that requires a non-empty
532         // value, as enforced by the service's validation routine(s).
533         collectionObject = new CollectionobjectsCommon();
534         collectionObject.setObjectNumber("");
535         collectionObject.setDistinguishingFeatures("Distinguishing features.");
536
537         objNameList = new ObjectNameList();
538         objNameGroups = objNameList.getObjectNameGroup();
539         objectNameGroup = new ObjectNameGroup();
540         objectNameGroup.setObjectName(OBJECT_NAME_VALUE);
541         objNameGroups.add(objectNameGroup);
542         collectionObject.setObjectNameList(objNameList);
543
544         // Submit the request to the service and store the response.
545         multipart =
546             createCollectionObjectInstance(client.getCommonPartName(), collectionObject, null);
547         res = client.create(multipart);
548         statusCode = res.getStatus();
549
550         // Read the response and verify that the create attempt failed.
551         if (logger.isDebugEnabled()) {
552             logger.debug(testName + ": status = " + statusCode);
553         }
554         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
555                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
556         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
557
558     }
559
560
561     // ---------------------------------------------------------------
562     // CRUD tests : READ tests
563     // ---------------------------------------------------------------
564     // Success outcomes
565     /* (non-Javadoc)
566      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#read(java.lang.String)
567      */
568     @Override
569     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
570     dependsOnMethods = {"create"})
571     public void read(String testName) throws Exception {
572
573         if (logger.isDebugEnabled()) {
574             logger.debug(testBanner(testName, CLASS_NAME));
575         }
576         // Perform setup.
577         setupRead();
578
579         // Submit the request to the service and store the response.
580         CollectionObjectClient client = new CollectionObjectClient();
581         ClientResponse<MultipartInput> res = client.read(knownResourceId);
582         int statusCode = res.getStatus();
583
584         // Check the status code of the response: does it match
585         // the expected response(s)?
586         if (logger.isDebugEnabled()) {
587             logger.debug(testName + ": status = " + statusCode);
588         }
589         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
590                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
591         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
592
593         MultipartInput input = (MultipartInput) res.getEntity();
594
595         if (logger.isDebugEnabled()) {
596             logger.debug(testName + ": Reading Common part ...");
597         }
598         CollectionobjectsCommon collectionObject =
599                 (CollectionobjectsCommon) extractPart(input,
600                 client.getCommonPartName(), CollectionobjectsCommon.class);
601         Assert.assertNotNull(collectionObject);
602
603         // Verify the number and contents of values in repeatable fields,
604         // as created in the instance record used for testing.
605         DimensionList dimensionList = collectionObject.getDimensions();
606         Assert.assertNotNull(dimensionList);
607         List<DimensionGroup> dimensionsGroups = dimensionList.getDimensionGroup();
608         Assert.assertNotNull(dimensionsGroups);
609         Assert.assertTrue(dimensionsGroups.size() > 0);
610         Assert.assertNotNull(dimensionsGroups.get(0));
611         Assert.assertNotNull(dimensionsGroups.get(0).getMeasuredPart());
612
613         if (logger.isDebugEnabled()) {
614             logger.debug(testName + ": Reading Natural History part ...");
615         }
616         CollectionobjectsNaturalhistory conh =
617                 (CollectionobjectsNaturalhistory) extractPart(input,
618                 getNHPartName(), CollectionobjectsNaturalhistory.class);
619         Assert.assertNotNull(conh);
620     }
621
622     // Failure outcomes
623     /* (non-Javadoc)
624      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#readNonExistent(java.lang.String)
625      */
626     @Override
627     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
628     dependsOnMethods = {"read"})
629     public void readNonExistent(String testName) throws Exception {
630
631         if (logger.isDebugEnabled()) {
632             logger.debug(testBanner(testName, CLASS_NAME));
633         }
634         // Perform setup.
635         setupReadNonExistent();
636
637         // Submit the request to the service and store the response.
638         CollectionObjectClient client = new CollectionObjectClient();
639         ClientResponse<MultipartInput> res = client.read(NON_EXISTENT_ID);
640         int statusCode = res.getStatus();
641
642         // Check the status code of the response: does it match
643         // the expected response(s)?
644         if (logger.isDebugEnabled()) {
645             logger.debug(testName + ": status = " + statusCode);
646         }
647         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
648                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
649         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
650     }
651
652     
653     // ---------------------------------------------------------------
654     // CRUD tests : READ_LIST tests
655     // ---------------------------------------------------------------
656     // Success outcomes
657     /* (non-Javadoc)
658      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#readList(java.lang.String)
659      */
660     @Override
661     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
662     dependsOnMethods = {"createList", "read"})
663     public void readList(String testName) throws Exception {
664
665         if (logger.isDebugEnabled()) {
666             logger.debug(testBanner(testName, CLASS_NAME));
667         }
668         // Perform setup.
669         setupReadList();
670
671         // Submit the request to the service and store the response.
672         CollectionObjectClient client = new CollectionObjectClient();
673         ClientResponse<CollectionobjectsCommonList> res = client.readList();
674         CollectionobjectsCommonList list = res.getEntity();
675         int statusCode = res.getStatus();
676
677         // Check the status code of the response: does it match
678         // the expected response(s)?
679         if (logger.isDebugEnabled()) {
680             logger.debug(testName + ": status = " + statusCode);
681         }
682         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
683                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
684         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
685
686         // Optionally output additional data about list members for debugging.
687         boolean iterateThroughList = false;
688         if (iterateThroughList && logger.isDebugEnabled()) {
689             List<CollectionobjectsCommonList.CollectionObjectListItem> items =
690                     list.getCollectionObjectListItem();
691             int i = 0;
692
693             for (CollectionobjectsCommonList.CollectionObjectListItem item : items) {
694                 logger.debug(testName + ": list-item[" + i + "] csid="
695                         + item.getCsid());
696                 logger.debug(testName + ": list-item[" + i + "] objectNumber="
697                         + item.getObjectNumber());
698                 logger.debug(testName + ": list-item[" + i + "] URI="
699                         + item.getUri());
700                 i++;
701
702             }
703         }
704     }
705
706     // Failure outcomes
707     // None at present.
708     // ---------------------------------------------------------------
709     // CRUD tests : UPDATE tests
710     // ---------------------------------------------------------------
711     // Success outcomes
712     /* (non-Javadoc)
713      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#update(java.lang.String)
714      */
715     @Override
716     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
717     dependsOnMethods = {"read"})
718     public void update(String testName) throws Exception {
719
720         if (logger.isDebugEnabled()) {
721             logger.debug(testBanner(testName, CLASS_NAME));
722         }
723         // Perform setup.
724         setupUpdate();
725
726         // Read an existing resource that will be updated.
727         ClientResponse<MultipartInput> res = updateRetrieve(testName, knownResourceId);
728
729         // Extract its common part.
730         CollectionObjectClient client = new CollectionObjectClient();
731         MultipartInput input = (MultipartInput) res.getEntity();
732         CollectionobjectsCommon collectionObject =
733                 (CollectionobjectsCommon) extractPart(input,
734                 client.getCommonPartName(), CollectionobjectsCommon.class);
735         Assert.assertNotNull(collectionObject);
736
737         // Change the content of one or more fields in the common part.
738
739         collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber());
740
741         // Change the object name in the first value instance in the
742         // object name repeatable group.
743         ObjectNameList objNameList = collectionObject.getObjectNameList();
744         List<ObjectNameGroup> objNameGroups = objNameList.getObjectNameGroup();
745         Assert.assertNotNull(objNameGroups);
746         Assert.assertTrue(objNameGroups.size() >= 1);
747         String objectName = objNameGroups.get(0).getObjectName();
748         Assert.assertEquals(objectName, OBJECT_NAME_VALUE);
749         String updatedObjectName = "updated-" + objectName;
750         objNameGroups.get(0).setObjectName(updatedObjectName);
751         collectionObject.setObjectNameList(objNameList);
752
753         // Replace the existing value instances in the dimensions repeatable group
754         // with entirely new value instances, also changing the number of such instances.
755         DimensionList dimensionList = collectionObject.getDimensions();
756         Assert.assertNotNull(dimensionList);
757         List<DimensionGroup> dimensionGroups = dimensionList.getDimensionGroup();
758         Assert.assertNotNull(dimensionGroups);
759         int originalDimensionGroupSize = dimensionGroups.size();
760         Assert.assertTrue(originalDimensionGroupSize >= 1);
761
762         DimensionGroup updatedDimensionGroup = new DimensionGroup();
763         updatedDimensionGroup.setMeasuredPart(UPDATED_MEASURED_PART_VALUE);
764         dimensionGroups.clear();
765         dimensionGroups.add(updatedDimensionGroup);
766         int updatedDimensionGroupSize = dimensionGroups.size();
767         Assert.assertTrue(updatedDimensionGroupSize >= 1);
768         Assert.assertTrue(updatedDimensionGroupSize != originalDimensionGroupSize);
769         collectionObject.setDimensions(dimensionList);
770
771         if (logger.isDebugEnabled()) {
772             logger.debug("sparse update that will be sent in update request:");
773             logger.debug(objectAsXmlString(collectionObject,
774                     CollectionobjectsCommon.class));
775         }
776
777         // Send the changed resource to be updated.
778         res = updateSend(testName, knownResourceId, collectionObject);
779         int statusCode = res.getStatus();
780         // Check the status code of the response: does it match the expected response(s)?
781         if (logger.isDebugEnabled()) {
782             logger.debug(testName + ": status = " + statusCode);
783         }
784         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
785                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
786         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
787
788         // Read the response and verify that the resource was correctly updated.
789         input = (MultipartInput) res.getEntity();
790         CollectionobjectsCommon updatedCollectionObject =
791                 (CollectionobjectsCommon) extractPart(input,
792                 client.getCommonPartName(), CollectionobjectsCommon.class);
793         Assert.assertNotNull(updatedCollectionObject);
794
795         objNameList = collectionObject.getObjectNameList();
796         objNameGroups = objNameList.getObjectNameGroup();
797         Assert.assertNotNull(objNameGroups);
798         Assert.assertTrue(objNameGroups.size() >= 1);
799         Assert.assertEquals(updatedObjectName,
800                 objNameGroups.get(0).getObjectName(),
801                 "Data in updated object did not match submitted data.");
802         
803         dimensionList = collectionObject.getDimensions();
804         Assert.assertNotNull(dimensionList);
805         dimensionGroups = dimensionList.getDimensionGroup();
806         Assert.assertNotNull(dimensionGroups);
807         Assert.assertTrue(dimensionGroups.size() == updatedDimensionGroupSize);
808         Assert.assertEquals(UPDATED_MEASURED_PART_VALUE,
809                 dimensionGroups.get(0).getMeasuredPart(),
810                 "Data in updated object did not match submitted data.");
811
812     }
813
814     /**
815      * Update retrieve.
816      *
817      * @param testName the test name
818      * @param id the id
819      * @return the client response
820      */
821     private ClientResponse<MultipartInput> updateRetrieve(String testName, String id) {
822         final int EXPECTED_STATUS = Response.Status.OK.getStatusCode();
823         CollectionObjectClient client = new CollectionObjectClient();
824         ClientResponse<MultipartInput> res = client.read(id);
825         if (logger.isDebugEnabled()) {
826             logger.debug("read in updateRetrieve for " + testName + " status = " + res.getStatus());
827         }
828         Assert.assertEquals(res.getStatus(), EXPECTED_STATUS);
829         if (logger.isDebugEnabled()) {
830             logger.debug("got object to updateRetrieve for " + testName + " with ID: " + id);
831         }
832         return res;
833     }
834
835     /**
836      * Update send.
837      *
838      * @param testName the test name
839      * @param id the id
840      * @param collectionObject the collection object
841      * @return the client response
842      */
843     private ClientResponse<MultipartInput> updateSend(String testName, String id,
844             CollectionobjectsCommon collectionObject) {
845         MultipartOutput output = new MultipartOutput();
846         OutputPart commonPart = output.addPart(collectionObject, MediaType.APPLICATION_XML_TYPE);
847         CollectionObjectClient client = new CollectionObjectClient();
848         commonPart.getHeaders().add("label", client.getCommonPartName());
849         ClientResponse<MultipartInput> res = client.update(knownResourceId, output);
850         return res;
851     }
852
853     // Failure outcomes
854     // Placeholders until the three tests below can be uncommented.
855     // See Issue CSPACE-401.
856     /* (non-Javadoc)
857      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#updateWithEmptyEntityBody(java.lang.String)
858      */
859     @Override
860     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
861     dependsOnMethods = {"read"})
862     public void updateWithEmptyEntityBody(String testName) throws Exception {
863         //FIXME: Should this test really be empty?
864     }
865
866    /**
867     * Test how the service handles XML that is not well formed,
868     * when sent in the payload of an Update request.
869     *
870     * @param testName  The name of this test method.  This name is supplied
871     *     automatically, via reflection, by a TestNG 'data provider' in
872     *     a base class.
873     */
874     @Override
875     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
876     dependsOnMethods = {"read"})
877     public void updateWithMalformedXml(String testName) throws Exception {
878         //FIXME: Should this test really be empty?
879     }
880
881     /* (non-Javadoc)
882      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#updateWithWrongXmlSchema(java.lang.String)
883      */
884     @Override
885     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
886     dependsOnMethods = {"read"})
887     public void updateWithWrongXmlSchema(String testName) throws Exception {
888         //FIXME: Should this test really be empty?
889     }
890
891 /*
892     @Override
893     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
894     dependsOnMethods = {"create", "update", "testSubmitRequest"})
895     public void updateWithEmptyEntityBody(String testName) throws Exception {
896
897         if (logger.isDebugEnabled()) {
898             logger.debug(testBanner(testName, CLASS_NAME));
899         }
900         // Perform setup.
901         setupUpdateWithEmptyEntityBody();
902
903         // Submit the request to the service and store the response.
904         String method = REQUEST_TYPE.httpMethodName();
905         String url = getResourceURL(knownResourceId);
906         String mediaType = MediaType.APPLICATION_XML;
907         final String entity = "";
908         int statusCode = submitRequest(method, url, mediaType, entity);
909
910         // Check the status code of the response: does it match
911         // the expected response(s)?
912         if(logger.isDebugEnabled()){
913         logger.debug(testName + ": url=" + url +
914         " status=" + statusCode);
915         }
916         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
917         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
918         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
919     }
920
921     @Override
922     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
923     dependsOnMethods = {"create", "update", "testSubmitRequest"})
924     public void updateWithMalformedXml() throws Exception {
925
926         if (logger.isDebugEnabled()) {
927             logger.debug(testBanner(testName, CLASS_NAME));
928         }
929         // Perform setup.
930         setupUpdateWithMalformedXml();
931
932         // Submit the request to the service and store the response.
933         String method = REQUEST_TYPE.httpMethodName();
934         String url = getResourceURL(knownResourceId);
935         final String entity = MALFORMED_XML_DATA;
936         String mediaType = MediaType.APPLICATION_XML;
937         int statusCode = submitRequest(method, url, mediaType, entity);
938
939         // Check the status code of the response: does it match
940         // the expected response(s)?
941         if(logger.isDebugEnabled()){
942         logger.debug(testName + ": url=" + url +
943         " status=" + statusCode);
944         }
945         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
946         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
947         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
948     }
949
950     @Override
951     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
952     dependsOnMethods = {"create", "update", "testSubmitRequest"})
953     public void updateWithWrongXmlSchema(String testName) throws Exception {
954
955         if (logger.isDebugEnabled()) {
956             logger.debug(testBanner(testName, CLASS_NAME));
957         }
958         // Perform setup.
959         setupUpdateWithWrongXmlSchema();
960
961         // Submit the request to the service and store the response.
962         String method = REQUEST_TYPE.httpMethodName();
963         String url = getResourceURL(knownResourceId);
964         String mediaType = MediaType.APPLICATION_XML;
965         final String entity = WRONG_XML_SCHEMA_DATA;
966         int statusCode = submitRequest(method, url, mediaType, entity);
967
968         // Check the status code of the response: does it match
969         // the expected response(s)?
970         if(logger.isDebugEnabled()){
971         logger.debug(testName + ": url=" + url +
972         " status=" + statusCode);
973         }
974         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
975         invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
976         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
977     }
978 */
979
980     /* (non-Javadoc)
981  * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#updateNonExistent(java.lang.String)
982  */
983 @Override
984     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
985     dependsOnMethods = {"update", "testSubmitRequest"})
986     public void updateNonExistent(String testName) throws Exception {
987
988         if (logger.isDebugEnabled()) {
989             logger.debug(testBanner(testName, CLASS_NAME));
990         }
991         // Perform setup.
992         setupUpdateNonExistent();
993
994         // Submit the request to the service and store the response.
995         //
996         // Note: The ID used in this 'create' call may be arbitrary.
997         // The only relevant ID may be the one used in updateCollectionObject(), below.
998         CollectionObjectClient client = new CollectionObjectClient();
999         MultipartOutput multipart =
1000                 createCollectionObjectInstance(client.getCommonPartName(),
1001                 NON_EXISTENT_ID);
1002         ClientResponse<MultipartInput> res =
1003                 client.update(NON_EXISTENT_ID, multipart);
1004         int statusCode = res.getStatus();
1005
1006         // Check the status code of the response: does it match
1007         // the expected response(s)?
1008         if (logger.isDebugEnabled()) {
1009             logger.debug(testName + ": status = " + statusCode);
1010         }
1011         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1012                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1013         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
1014     }
1015
1016    /**
1017     * Test how the service handles, in an Update request, payloads
1018     * containing null values (or, in the case of String fields,
1019     * empty String values) in one or more fields in which non-empty
1020     * values are required.
1021     *
1022     * This is a test of code and/or configuration in the service's
1023     * validation routine(s).
1024     *
1025     * @param testName  The name of this test method.  This name is supplied
1026     *     automatically, via reflection, by a TestNG 'data provider' in
1027     *     a base class.
1028  * @throws Exception 
1029     */
1030     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
1031     dependsOnMethods = {"read"})
1032     public void updateWithRequiredValuesNullOrEmpty(String testName) throws Exception {
1033   
1034         if (logger.isDebugEnabled()) {
1035             logger.debug(testBanner(testName, CLASS_NAME));
1036         }
1037         // Perform setup.
1038         setupUpdate();
1039         if (logger.isDebugEnabled()) {
1040             logger.debug(testName + " got object to update with ID: " + knownResourceId);
1041         }
1042
1043         // Read an existing record for updating.
1044         ClientResponse<MultipartInput> res = updateRetrieve(testName, knownResourceId);
1045
1046         CollectionObjectClient client = new CollectionObjectClient();
1047         MultipartInput input = (MultipartInput) res.getEntity();
1048         CollectionobjectsCommon collectionObject =
1049                 (CollectionobjectsCommon) extractPart(input,
1050                 client.getCommonPartName(), CollectionobjectsCommon.class);
1051         Assert.assertNotNull(collectionObject);
1052
1053         // Update with invalid content, by setting a value to the
1054         // empty String, in a field that requires a non-empty value,
1055         // as enforced by the service's validation routine(s).
1056         collectionObject.setObjectNumber("");
1057
1058         if (logger.isDebugEnabled()) {
1059             logger.debug(testName + " updated object");
1060             logger.debug(objectAsXmlString(collectionObject,
1061                     CollectionobjectsCommon.class));
1062         }
1063
1064         // Submit the request to the service and store the response.
1065         res = updateSend(testName, knownResourceId, collectionObject);
1066         int statusCode = res.getStatus();
1067
1068         // Read the response and verify that the update attempt failed.
1069         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1070                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1071         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
1072
1073     }
1074
1075     // ---------------------------------------------------------------
1076     // CRUD tests : DELETE tests
1077     // ---------------------------------------------------------------
1078     // Success outcomes
1079     /* (non-Javadoc)
1080      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#delete(java.lang.String)
1081      */
1082     @Override
1083     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
1084     dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"})
1085     public void delete(String testName) throws Exception {
1086
1087         if (logger.isDebugEnabled()) {
1088             logger.debug(testBanner(testName, CLASS_NAME));
1089         }
1090         // Perform setup.
1091         setupDelete();
1092
1093         // Submit the request to the service and store the response.
1094         CollectionObjectClient client = new CollectionObjectClient();
1095         ClientResponse<Response> res = client.delete(knownResourceId);
1096         int statusCode = res.getStatus();
1097
1098         // Check the status code of the response: does it match
1099         // the expected response(s)?
1100         if (logger.isDebugEnabled()) {
1101             logger.debug(testName + ": status = " + statusCode);
1102         }
1103         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1104                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1105         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
1106     }
1107
1108     // Failure outcomes
1109     /* (non-Javadoc)
1110      * @see org.collectionspace.services.client.test.AbstractServiceTestImpl#deleteNonExistent(java.lang.String)
1111      */
1112     @Override
1113     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
1114     dependsOnMethods = {"delete"})
1115     public void deleteNonExistent(String testName) throws Exception {
1116
1117         if (logger.isDebugEnabled()) {
1118             logger.debug(testBanner(testName, CLASS_NAME));
1119         }
1120         // Perform setup.
1121         setupDeleteNonExistent();
1122
1123         // Submit the request to the service and store the response.
1124         CollectionObjectClient client = new CollectionObjectClient();
1125         ClientResponse<Response> res = client.delete(NON_EXISTENT_ID);
1126         int statusCode = res.getStatus();
1127
1128         // Check the status code of the response: does it match
1129         // the expected response(s)?
1130         if (logger.isDebugEnabled()) {
1131             logger.debug(testName + ": status = " + statusCode);
1132         }
1133         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1134                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1135         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
1136     }
1137
1138     // ---------------------------------------------------------------
1139     // Utility tests : tests of code used in tests above
1140     // ---------------------------------------------------------------
1141     /**
1142      * Tests the code for manually submitting data that is used by several
1143      * of the methods above.
1144      * @throws Exception 
1145      */
1146
1147     @Test(dependsOnMethods = {"create", "read"})
1148     public void testSubmitRequest() throws Exception {
1149         testSubmitRequest(knownResourceId);
1150     }
1151
1152     /**
1153      * Test submit request.
1154      *
1155      * @param resourceId the resource id
1156      * @throws Exception the exception
1157      */
1158     private void testSubmitRequest(String resourceId) throws Exception {
1159
1160         // Expected status code: 200 OK
1161         final int EXPECTED_STATUS = Response.Status.OK.getStatusCode();
1162
1163         // Submit the request to the service and store the response.
1164         String method = ServiceRequestType.READ.httpMethodName();
1165         String url = getResourceURL(resourceId);
1166         int statusCode = submitRequest(method, url);
1167
1168         // Check the status code of the response: does it match
1169         // the expected response(s)?
1170         if (logger.isDebugEnabled()) {
1171             logger.debug("testSubmitRequest: url=" + url
1172                     + " status=" + statusCode);
1173         }
1174         Assert.assertEquals(statusCode, EXPECTED_STATUS);
1175
1176     }
1177
1178     // ---------------------------------------------------------------
1179     // Utility methods used by tests above
1180     // ---------------------------------------------------------------
1181     /**
1182      * Creates the collection object instance.
1183      *
1184      * @param commonPartName the common part name
1185      * @param identifier the identifier
1186      * @return the multipart output
1187      */
1188     private MultipartOutput createCollectionObjectInstance(String commonPartName,
1189             String identifier) {
1190         return createCollectionObjectInstance(commonPartName,
1191                 "objectNumber-" + identifier,
1192                 "objectName-" + identifier);
1193     }
1194
1195     /**
1196      * Creates the collection object instance.
1197      *
1198      * @param commonPartName the common part name
1199      * @param objectNumber the object number
1200      * @param objectName the object name
1201      * @return the multipart output
1202      */
1203     private MultipartOutput createCollectionObjectInstance(String commonPartName,
1204             String objectNumber, String objectName) {
1205         CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
1206
1207         //REM
1208         OtherNumber remNumber = new OtherNumber();
1209         remNumber.setNumberType("remNumber");
1210         remNumber.setNumberValue("2271966-" + System.currentTimeMillis());
1211         collectionObject.setRemNumber(remNumber);
1212         
1213         // Scalar fields
1214         collectionObject.setObjectNumber(objectNumber);
1215         collectionObject.setAge(""); //test for null string
1216         
1217         // FIXME this can be removed when the repeatable other number list
1218         // is supported by the application layers
1219         collectionObject.setOtherNumber("urn:org.walkerart.id:123");
1220
1221         // Repeatable structured groups
1222
1223         TitleGroupList titleGroupList = new TitleGroupList();
1224         List<TitleGroup> titleGroups = titleGroupList.getTitleGroup();
1225         TitleGroup titleGroup = new TitleGroup();
1226         titleGroup.setTitle("a title");
1227         titleGroups.add(titleGroup);
1228         collectionObject.setTitleGroupList(titleGroupList);
1229
1230         ObjectNameList objNameList = new ObjectNameList();
1231         List<ObjectNameGroup> objNameGroups = objNameList.getObjectNameGroup();
1232         ObjectNameGroup objectNameGroup = new ObjectNameGroup();
1233         objectNameGroup.setObjectName(OBJECT_NAME_VALUE);
1234         objNameGroups.add(objectNameGroup);
1235         collectionObject.setObjectNameList(objNameList);
1236
1237         DimensionList dimensionList = new DimensionList();
1238         List<DimensionGroup> dimensionGroups = dimensionList.getDimensionGroup();
1239         DimensionGroup dimensionGroup1 = new DimensionGroup();
1240         dimensionGroup1.setMeasuredPart("head");
1241         dimensionGroup1.setDimension("length");
1242         dimensionGroup1.setValue("30");
1243         dimensionGroup1.setMeasurementUnit("cm");
1244         DimensionGroup dimensionGroup2 = new DimensionGroup();
1245         dimensionGroup2.setMeasuredPart("leg");
1246         dimensionGroup2.setDimension("width");
1247         dimensionGroup2.setValue("2.57");
1248         dimensionGroup2.setMeasurementUnit("m");
1249         dimensionGroup2.setValueQualifier("");  // test null string
1250         dimensionGroups.add(dimensionGroup1);
1251         dimensionGroups.add(dimensionGroup2);
1252         collectionObject.setDimensions(dimensionList);
1253
1254         // Repeatable scalar fields
1255         
1256         BriefDescriptionList descriptionList = new BriefDescriptionList();
1257         List<String> descriptions = descriptionList.getBriefDescription();
1258         descriptions.add("Papier mache bird cow mask with horns, "
1259                 + "painted red with black and yellow spots. "
1260                 + "Puerto Rico. ca. 8&quot; high, 6&quot; wide, projects 10&quot; (with horns).");
1261         descriptions.add("Acrylic rabbit mask with wings, "
1262                 + "painted red with green and aquamarine spots. "
1263                 + "Puerto Rico. ca. 8&quot; high, 6&quot; wide, projects 10&quot; (with wings).");
1264         collectionObject.setBriefDescriptions(descriptionList);
1265
1266         ResponsibleDepartmentList deptList = new ResponsibleDepartmentList();
1267         List<String> depts = deptList.getResponsibleDepartment();
1268         // @TODO Use properly formatted refNames for representative departments
1269         // in this example test record. The following are mere placeholders.
1270         depts.add("urn:org.collectionspace.services.department:Registrar");
1271         depts.add("urn:org.walkerart.department:Fine Art");
1272         collectionObject.setResponsibleDepartments(deptList);
1273
1274         OtherNumberList otherNumList = new OtherNumberList();
1275         List<OtherNumber> otherNumbers = otherNumList.getOtherNumber();
1276         OtherNumber otherNumber1 = new OtherNumber();        
1277         otherNumber1.setNumberValue("101." + objectName);
1278         otherNumber1.setNumberType("integer");
1279         otherNumbers.add(otherNumber1);
1280         OtherNumber otherNumber2 = new OtherNumber();
1281         otherNumber2.setNumberValue("101.502.23.456." + objectName);
1282         otherNumber2.setNumberType("ipaddress");
1283         otherNumbers.add(otherNumber2);
1284         collectionObject.setOtherNumberList(otherNumList);
1285
1286         // Add instances of fields from an extension schema
1287
1288         CollectionobjectsNaturalhistory conh = new CollectionobjectsNaturalhistory();
1289         conh.setNhString("test-string");
1290         conh.setNhInt(999);
1291         conh.setNhLong(9999);
1292
1293         MultipartOutput multipart = createCollectionObjectInstance(commonPartName, collectionObject, conh);
1294         return multipart;
1295     }
1296
1297     /**
1298      * Creates the collection object instance.
1299      *
1300      * @param commonPartName the common part name
1301      * @param collectionObject the collection object
1302      * @param conh the conh
1303      * @return the multipart output
1304      */
1305     private MultipartOutput createCollectionObjectInstance(String commonPartName,
1306             CollectionobjectsCommon collectionObject, CollectionobjectsNaturalhistory conh) {
1307
1308         MultipartOutput multipart = CollectionObjectFactory.createCollectionObjectInstance(
1309                 commonPartName, collectionObject, getNHPartName(), conh);
1310         if (logger.isDebugEnabled()) {
1311             logger.debug("to be created, collectionobject common");
1312             logger.debug(objectAsXmlString(collectionObject,
1313                     CollectionobjectsCommon.class));
1314         }
1315
1316         if (conh != null) {
1317             if (logger.isDebugEnabled()) {
1318                 logger.debug("to be created, collectionobject nhistory");
1319                 logger.debug(objectAsXmlString(conh,
1320                         CollectionobjectsNaturalhistory.class));
1321             }
1322         }
1323         return multipart;
1324
1325     }
1326
1327     /**
1328      * createCollectionObjectInstanceFromXml uses JAXB unmarshaller to retrieve
1329      * collectionobject from given file
1330      * @param commonPartName
1331      * @param commonPartFileName
1332      * @return
1333      * @throws Exception
1334      */
1335     private MultipartOutput createCollectionObjectInstanceFromXml(String testName, String commonPartName,
1336             String commonPartFileName) throws Exception {
1337
1338         CollectionobjectsCommon collectionObject =
1339                 (CollectionobjectsCommon) getObjectFromFile(CollectionobjectsCommon.class,
1340                 commonPartFileName);
1341         MultipartOutput multipart = new MultipartOutput();
1342         OutputPart commonPart = multipart.addPart(collectionObject,
1343                 MediaType.APPLICATION_XML_TYPE);
1344         commonPart.getHeaders().add("label", commonPartName);
1345
1346         if (logger.isDebugEnabled()) {
1347             logger.debug(testName + " to be created, collectionobject common");
1348             logger.debug(objectAsXmlString(collectionObject,
1349                     CollectionobjectsCommon.class));
1350         }
1351         return multipart;
1352
1353     }
1354
1355     /**
1356      * createCollectionObjectInstanceFromRawXml uses stringified collectionobject
1357      * retrieve from given file
1358      * @param commonPartName
1359      * @param commonPartFileName
1360      * @return
1361      * @throws Exception
1362      */
1363     private MultipartOutput createCollectionObjectInstanceFromRawXml(String testName, String commonPartName,
1364             String commonPartFileName) throws Exception {
1365
1366         MultipartOutput multipart = new MultipartOutput();
1367         String stringObject = getXmlDocumentAsString(commonPartFileName);
1368         if (logger.isDebugEnabled()) {
1369             logger.debug(testName + " to be created, collectionobject common " + "\n" + stringObject);
1370         }
1371         OutputPart commonPart = multipart.addPart(stringObject,
1372                 MediaType.APPLICATION_XML_TYPE);
1373         commonPart.getHeaders().add("label", commonPartName);
1374
1375         return multipart;
1376
1377     }
1378
1379     /**
1380      * Gets the nH part name.
1381      *
1382      * @return the nH part name
1383      */
1384     private String getNHPartName() {
1385         return "collectionobjects_naturalhistory";
1386     }
1387
1388     /**
1389      * Creates the from xml file.
1390      *
1391      * @param testName the test name
1392      * @param fileName the file name
1393      * @param useJaxb the use jaxb
1394      * @return the string
1395      * @throws Exception the exception
1396      */
1397     private String createFromXmlFile(String testName, String fileName, boolean useJaxb) throws Exception {
1398   
1399         // Perform setup.
1400         setupCreate();
1401
1402         MultipartOutput multipart = null;
1403
1404         CollectionObjectClient client = new CollectionObjectClient();
1405         if (useJaxb) {
1406             multipart = createCollectionObjectInstanceFromXml(testName,
1407                     client.getCommonPartName(), fileName);
1408         } else {
1409             multipart = createCollectionObjectInstanceFromRawXml(testName,
1410                     client.getCommonPartName(), fileName);
1411         }
1412         ClientResponse<Response> res = client.create(multipart);
1413         int statusCode = res.getStatus();
1414
1415         if (logger.isDebugEnabled()) {
1416             logger.debug(testName + ": status = " + statusCode);
1417         }
1418         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1419                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1420         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
1421         String newId = extractId(res);
1422         allResourceIdsCreated.add(newId);
1423         return newId;
1424     }
1425
1426     // FIXME: This duplicates code in read(), and should be consolidated.
1427     // This is an expedient to support reading and verifying the contents
1428     // of resources that have been created from test data XML files.
1429     private CollectionobjectsCommon readCollectionObjectCommonPart(String csid)
1430         throws Exception {
1431
1432         String testName = "readCollectionObjectCommonPart";
1433
1434         setupRead();
1435
1436         // Submit the request to the service and store the response.
1437         CollectionObjectClient client = new CollectionObjectClient();
1438         ClientResponse<MultipartInput> res = client.read(csid);
1439         int statusCode = res.getStatus();
1440
1441         // Check the status code of the response: does it match
1442         // the expected response(s)?
1443         if (logger.isDebugEnabled()) {
1444             logger.debug(testName + ": status = " + statusCode);
1445         }
1446         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1447                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1448         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
1449
1450         MultipartInput input = (MultipartInput) res.getEntity();
1451
1452         if (logger.isDebugEnabled()) {
1453             logger.debug(testName + ": Reading Common part ...");
1454         }
1455         CollectionobjectsCommon collectionObject =
1456                 (CollectionobjectsCommon) extractPart(input,
1457                 client.getCommonPartName(), CollectionobjectsCommon.class);
1458         Assert.assertNotNull(collectionObject);
1459
1460         return collectionObject;
1461      }
1462 }