]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
77ecb474650db8bd9716570ee9cb24f2cc38d32e
[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.ArrayList;
26 import java.util.List;
27 import javax.ws.rs.core.MediaType;
28 import javax.ws.rs.core.Response;
29
30 import org.collectionspace.services.client.CollectionObjectClient;
31 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
32 import org.collectionspace.services.collectionobject.domain.naturalhistory.CollectionobjectsNaturalhistory;
33 import org.collectionspace.services.collectionobject.CollectionobjectsCommonList;
34 import org.collectionspace.services.collectionobject.ResponsibleDepartmentList;
35 import org.jboss.resteasy.client.ClientResponse;
36
37 import org.jboss.resteasy.plugins.providers.multipart.MultipartInput;
38 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
39 import org.jboss.resteasy.plugins.providers.multipart.OutputPart;
40 import org.testng.Assert;
41 import org.testng.annotations.AfterClass;
42 import org.testng.annotations.Test;
43
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * CollectionObjectServiceTest, carries out tests against a
49  * deployed and running CollectionObject Service.
50  *
51  * $LastChangedRevision$
52  * $LastChangedDate$
53  */
54 public class CollectionObjectServiceTest extends AbstractServiceTestImpl {
55
56     private final Logger logger =
57             LoggerFactory.getLogger(CollectionObjectServiceTest.class);
58     // Instance variables specific to this test.
59     private String knownResourceId = null;
60     private List<String> allResourceIdsCreated = new ArrayList();
61     private boolean multivalue; //toggle
62
63     /*
64      * This method is called only by the parent class, AbstractServiceTest
65      */
66     @Override
67     protected String getServicePathComponent() {
68         return new CollectionObjectClient().getServicePathComponent();
69     }
70
71     // ---------------------------------------------------------------
72     // CRUD tests : CREATE tests
73     // ---------------------------------------------------------------
74     // Success outcomes
75     @Override
76     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
77     public void create(String testName) throws Exception {
78
79         // Perform setup, such as initializing the type of service request
80         // (e.g. CREATE, DELETE), its valid and expected status codes, and
81         // its associated HTTP method name (e.g. POST, DELETE).
82         setupCreate(testName);
83
84         // Submit the request to the service and store the response.
85         CollectionObjectClient client = new CollectionObjectClient();
86         String identifier = createIdentifier();
87         MultipartOutput multipart =
88                 createCollectionObjectInstance(client.getCommonPartName(), identifier);
89         ClientResponse<Response> res = client.create(multipart);
90         int statusCode = res.getStatus();
91
92         // Check the status code of the response: does it match
93         // the expected response(s)?
94         //
95         // Specifically:
96         // Does it fall within the set of valid status codes?
97         // Does it exactly match the expected status code?
98         if (logger.isDebugEnabled()) {
99             logger.debug(testName + ": status = " + statusCode);
100         }
101         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
102                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
103         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
104
105         // Store the ID returned from the first resource created
106         // for additional tests below.
107         if (knownResourceId == null) {
108             knownResourceId = extractId(res);
109             if (logger.isDebugEnabled()) {
110                 logger.debug(testName + ": knownResourceId=" + knownResourceId);
111             }
112         }
113
114         // Store the IDs from every resource created by tests,
115         // so they can be deleted after tests have been run.
116         allResourceIdsCreated.add(extractId(res));
117     }
118
119
120     /*
121      * Tests to diagnose and verify the fixed status of CSPACE-1026,
122      * "Whitespace at certain points in payload cause failure"
123      */
124     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
125         dependsOnMethods = {"create", "testSubmitRequest"})
126     public void createFromXmlCambridge(String testName) throws Exception {
127         String newId =
128             createFromXmlFile(testName, "./test-data/testCambridge.xml", true);
129         testSubmitRequest(newId);
130     }
131
132     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
133         dependsOnMethods = {"create", "testSubmitRequest"})
134     public void createFromXmlRFWS1(String testName) throws Exception {
135         String newId =
136             createFromXmlFile(testName, "./target/test-classes/test-data/repfield_whitesp1.xml", false);
137         testSubmitRequest(newId);
138     }
139
140     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
141         dependsOnMethods = {"create", "testSubmitRequest"})
142     public void createFromXmlRFWS2(String testName) throws Exception {
143         String newId =
144             createFromXmlFile(testName, "./target/test-classes/test-data/repfield_whitesp2.xml", false);
145         testSubmitRequest(newId);
146     }
147
148     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
149         dependsOnMethods = {"create", "testSubmitRequest"})
150     public void createFromXmlRFWS3(String testName) throws Exception {
151         String newId =
152             createFromXmlFile(testName, "./target/test-classes/test-data/repfield_whitesp3.xml", false);
153         testSubmitRequest(newId);
154     }
155
156     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
157         dependsOnMethods = {"create", "testSubmitRequest"})
158     public void createFromXmlRFWS4(String testName) throws Exception {
159         String newId =
160             createFromXmlFile(testName, "./target/test-classes/test-data/repfield_whitesp4.xml", false);
161         testSubmitRequest(newId);
162     }
163
164     /*
165      * Tests to diagnose and verify the fixed status of CSPACE-1248,
166      * "Wedged records created!" (i.e. records with child repeatable
167      * fields, which contain null values, can be successfully created
168      * but an error occurs on trying to retrieve those records).
169      */
170     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
171         dependsOnMethods = {"create", "testSubmitRequest"})
172     public void createWithNullValueRepeatableField(String testName) throws Exception {
173         String newId =
174             createFromXmlFile(testName, "./target/test-classes/test-data/repfield_null1.xml", false);
175         if (logger.isDebugEnabled()) {
176             logger.debug("Successfully created record with null value repeatable field.");
177             logger.debug("Attempting to retrieve just-created record ...");
178         }
179         testSubmitRequest(newId);
180     }
181
182     /* (non-Javadoc)
183      * @see org.collectionspace.services.client.test.ServiceTest#createList()
184      */
185     @Override
186     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
187     dependsOnMethods = {"create"})
188     public void createList(String testName) throws Exception {
189         for (int i = 0; i < 3; i++) {
190             create(testName);
191         }
192     }
193
194     // Failure outcomes
195     // Placeholders until the three tests below can be uncommented.
196     // See Issue CSPACE-401.
197     @Override
198     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
199     public void createWithEmptyEntityBody(String testName) throws Exception {
200     }
201
202    /**
203     * Test how the service handles XML that is not well formed,
204     * when sent in the payload of a Create request.
205     *
206     * @param testName  The name of this test method.  This name is supplied
207     *     automatically, via reflection, by a TestNG 'data provider' in
208     *     a base class.
209     */
210     @Override
211     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
212     public void createWithMalformedXml(String testName) throws Exception {
213         setupCreate(testName);
214     }
215
216     @Override
217     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
218     public void createWithWrongXmlSchema(String testName) throws Exception {
219     }
220
221
222 /*
223     @Override
224     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
225     dependsOnMethods = {"create", "testSubmitRequest"})
226     public void createWithEmptyEntityBody(String testName) throwsException {
227
228     // Perform setup.
229     setupCreateWithEmptyEntityBody(testName);
230
231     // Submit the request to the service and store the response.
232     String method = REQUEST_TYPE.httpMethodName();
233     String url = getServiceRootURL();
234     String mediaType = MediaType.APPLICATION_XML;
235     final String entity = "";
236     int statusCode = submitRequest(method, url, mediaType, entity);
237
238     // Check the status code of the response: does it match
239     // the expected response(s)?
240     if(logger.isDebugEnabled()){
241     logger.debug(testName + ": url=" + url +
242     " status=" + statusCode);
243     }
244     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
245     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
246     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
247     }
248
249     @Override
250     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
251     dependsOnMethods = {"create", "testSubmitRequest"})
252     public void createWithMalformedXml(String testName) throws Exception {
253
254     // Perform setup.
255     setupCreateWithMalformedXml(testName);
256
257     // Submit the request to the service and store the response.
258     String method = REQUEST_TYPE.httpMethodName();
259     String url = getServiceRootURL();
260     String mediaType = MediaType.APPLICATION_XML;
261     final String entity = MALFORMED_XML_DATA; // Constant from base class.
262     int statusCode = submitRequest(method, url, mediaType, entity);
263
264     // Check the status code of the response: does it match
265     // the expected response(s)?
266     if(logger.isDebugEnabled()){
267     logger.debug(testName + ": url=" + url +
268     " status=" + statusCode);
269     }
270     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
271     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
272     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
273     }
274
275     @Override
276     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
277     dependsOnMethods = {"create", "testSubmitRequest"})
278     public void createWithWrongXmlSchema(String testName) throws Exception {
279
280     // Perform setup.
281     setupCreateWithWrongXmlSchema(testName);
282
283     // Submit the request to the service and store the response.
284     String method = REQUEST_TYPE.httpMethodName();
285     String url = getServiceRootURL();
286     String mediaType = MediaType.APPLICATION_XML;
287     final String entity = WRONG_XML_SCHEMA_DATA;
288     int statusCode = submitRequest(method, url, mediaType, entity);
289
290     // Check the status code of the response: does it match
291     // the expected response(s)?
292     if(logger.isDebugEnabled()){
293     logger.debug(testName + ": url=" + url +
294     " status=" + statusCode);
295     }
296     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
297     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
298     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
299     }
300 */
301
302    /**
303     * Test how the service handles, in a Create request, payloads
304     * containing null values (or, in the case of String fields,
305     * empty String values) in one or more fields which must be
306     * present and are required to contain non-empty values.
307     *
308     * This is a test of code and/or configuration in the service's
309     * validation routine(s).
310     *
311     * @param testName  The name of this test method.  This name is supplied
312     *     automatically, via reflection, by a TestNG 'data provider' in
313     *     a base class.
314     */
315     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
316     public void createWithRequiredValuesNullOrEmpty(String testName) throws Exception {
317         setupCreate(testName);
318
319         // Build a payload with invalid content, by omitting a
320         // field (objectNumber) which must be present, and in which
321         // a non-empty value is required, as enforced by the service's
322         // validation routine(s).
323         CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
324         collectionObject.setTitle("atitle");
325         collectionObject.setObjectName("some name");
326
327         // Submit the request to the service and store the response.
328         CollectionObjectClient client = new CollectionObjectClient();
329         MultipartOutput multipart =
330                 createCollectionObjectInstance(client.getCommonPartName(), collectionObject, null);
331         ClientResponse<Response> res = client.create(multipart);
332         int statusCode = res.getStatus();
333
334         // Read the response and verify that the create attempt failed.
335         if (logger.isDebugEnabled()) {
336             logger.debug(testName + ": status = " + statusCode);
337         }
338         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
339                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
340         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
341
342         // FIXME: Consider splitting off the following into its own test method.
343         
344         // Build a payload with invalid content, by setting a value to the
345         // empty String, in a field that requires a non-empty value,
346         // as enforced by the service's validation routine(s).
347         collectionObject = new CollectionobjectsCommon();
348         collectionObject.setTitle("atitle");
349         collectionObject.setObjectName("some name");
350         collectionObject.setObjectNumber("");
351
352         // Submit the request to the service and store the response.
353         multipart =
354             createCollectionObjectInstance(client.getCommonPartName(), collectionObject, null);
355         res = client.create(multipart);
356         statusCode = res.getStatus();
357
358         // Read the response and verify that the create attempt failed.
359         if (logger.isDebugEnabled()) {
360             logger.debug(testName + ": status = " + statusCode);
361         }
362         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
363                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
364         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
365
366     }
367
368
369     // ---------------------------------------------------------------
370     // CRUD tests : READ tests
371     // ---------------------------------------------------------------
372     // Success outcomes
373     @Override
374     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
375     dependsOnMethods = {"create"})
376     public void read(String testName) throws Exception {
377
378         // Perform setup.
379         setupRead(testName);
380
381         // Submit the request to the service and store the response.
382         CollectionObjectClient client = new CollectionObjectClient();
383         ClientResponse<MultipartInput> res = client.read(knownResourceId);
384         int statusCode = res.getStatus();
385
386         // Check the status code of the response: does it match
387         // the expected response(s)?
388         if (logger.isDebugEnabled()) {
389             logger.debug(testName + ": status = " + statusCode);
390         }
391         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
392                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
393         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
394
395         MultipartInput input = (MultipartInput) res.getEntity();
396
397         if (logger.isDebugEnabled()) {
398             logger.debug(testName + ": Reading Common part ...");
399         }
400         CollectionobjectsCommon collectionObject =
401                 (CollectionobjectsCommon) extractPart(input,
402                 client.getCommonPartName(), CollectionobjectsCommon.class);
403         Assert.assertNotNull(collectionObject);
404
405         if (logger.isDebugEnabled()) {
406             logger.debug(testName + ": Reading Natural History part ...");
407         }
408         CollectionobjectsNaturalhistory conh =
409                 (CollectionobjectsNaturalhistory) extractPart(input,
410                 getNHPartName(), CollectionobjectsNaturalhistory.class);
411         Assert.assertNotNull(conh);
412     }
413
414     // Failure outcomes
415     @Override
416     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
417     dependsOnMethods = {"read"})
418     public void readNonExistent(String testName) throws Exception {
419
420         // Perform setup.
421         setupReadNonExistent(testName);
422
423         // Submit the request to the service and store the response.
424         CollectionObjectClient client = new CollectionObjectClient();
425         ClientResponse<MultipartInput> res = client.read(NON_EXISTENT_ID);
426         int statusCode = res.getStatus();
427
428         // Check the status code of the response: does it match
429         // the expected response(s)?
430         if (logger.isDebugEnabled()) {
431             logger.debug(testName + ": status = " + statusCode);
432         }
433         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
434                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
435         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
436     }
437
438     // ---------------------------------------------------------------
439     // CRUD tests : READ_LIST tests
440     // ---------------------------------------------------------------
441     // Success outcomes
442     @Override
443     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
444     dependsOnMethods = {"createList", "read"})
445     public void readList(String testName) throws Exception {
446
447         // Perform setup.
448         setupReadList(testName);
449
450         // Submit the request to the service and store the response.
451         CollectionObjectClient client = new CollectionObjectClient();
452         ClientResponse<CollectionobjectsCommonList> res = client.readList();
453         CollectionobjectsCommonList list = res.getEntity();
454         int statusCode = res.getStatus();
455
456         // Check the status code of the response: does it match
457         // the expected response(s)?
458         if (logger.isDebugEnabled()) {
459             logger.debug(testName + ": status = " + statusCode);
460         }
461         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
462                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
463         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
464
465         // Optionally output additional data about list members for debugging.
466         boolean iterateThroughList = false;
467         if (iterateThroughList && logger.isDebugEnabled()) {
468             List<CollectionobjectsCommonList.CollectionObjectListItem> items =
469                     list.getCollectionObjectListItem();
470             int i = 0;
471
472             for (CollectionobjectsCommonList.CollectionObjectListItem item : items) {
473                 logger.debug(testName + ": list-item[" + i + "] csid="
474                         + item.getCsid());
475                 logger.debug(testName + ": list-item[" + i + "] objectNumber="
476                         + item.getObjectNumber());
477                 logger.debug(testName + ": list-item[" + i + "] URI="
478                         + item.getUri());
479                 i++;
480
481             }
482         }
483     }
484
485     // Failure outcomes
486     // None at present.
487     // ---------------------------------------------------------------
488     // CRUD tests : UPDATE tests
489     // ---------------------------------------------------------------
490     // Success outcomes
491     @Override
492     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
493     dependsOnMethods = {"read"})
494     public void update(String testName) throws Exception {
495
496         // Perform setup.
497         setupUpdate(testName);
498
499         // Read an existing resource that will be updated.
500         ClientResponse<MultipartInput> res = updateRetrieve(testName, knownResourceId);
501
502         // Extract its common part.
503         CollectionObjectClient client = new CollectionObjectClient();
504         MultipartInput input = (MultipartInput) res.getEntity();
505         CollectionobjectsCommon collectionObject =
506                 (CollectionobjectsCommon) extractPart(input,
507                 client.getCommonPartName(), CollectionobjectsCommon.class);
508         Assert.assertNotNull(collectionObject);
509
510         // Change the content of one or more fields in the common part.
511         collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber());
512         collectionObject.setObjectName("updated-" + collectionObject.getObjectName());
513         if (logger.isDebugEnabled()) {
514             logger.debug("sparse update that will be sent in update request:");
515             logger.debug(objectAsXmlString(collectionObject,
516                     CollectionobjectsCommon.class));
517         }
518
519         // Send the changed resource to be updated.
520         res = updateSend(testName, knownResourceId, collectionObject);
521         int statusCode = res.getStatus();
522         // Check the status code of the response: does it match the expected response(s)?
523         if (logger.isDebugEnabled()) {
524             logger.debug(testName + ": status = " + statusCode);
525         }
526         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
527                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
528         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
529
530         // Read the response and verify that the resource was correctly updated.
531         input = (MultipartInput) res.getEntity();
532         CollectionobjectsCommon updatedCollectionObject =
533                 (CollectionobjectsCommon) extractPart(input,
534                 client.getCommonPartName(), CollectionobjectsCommon.class);
535         Assert.assertNotNull(updatedCollectionObject);
536         Assert.assertEquals(updatedCollectionObject.getObjectName(),
537                 collectionObject.getObjectName(),
538                 "Data in updated object did not match submitted data.");
539
540     }
541
542     private ClientResponse<MultipartInput> updateRetrieve(String testName, String id) {
543         final int EXPECTED_STATUS = Response.Status.OK.getStatusCode();
544         CollectionObjectClient client = new CollectionObjectClient();
545         ClientResponse<MultipartInput> res = client.read(id);
546         if (logger.isDebugEnabled()) {
547             logger.debug("read in updateRetrieve for " + testName + " status = " + res.getStatus());
548         }
549         Assert.assertEquals(res.getStatus(), EXPECTED_STATUS);
550         if (logger.isDebugEnabled()) {
551             logger.debug("got object to updateRetrieve for " + testName + " with ID: " + id);
552         }
553         return res;
554     }
555
556     private ClientResponse<MultipartInput> updateSend(String testName, String id,
557             CollectionobjectsCommon collectionObject) {
558         MultipartOutput output = new MultipartOutput();
559         OutputPart commonPart = output.addPart(collectionObject, MediaType.APPLICATION_XML_TYPE);
560         CollectionObjectClient client = new CollectionObjectClient();
561         commonPart.getHeaders().add("label", client.getCommonPartName());
562         ClientResponse<MultipartInput> res = client.update(knownResourceId, output);
563         return res;
564     }
565
566     // Failure outcomes
567     // Placeholders until the three tests below can be uncommented.
568     // See Issue CSPACE-401.
569     @Override
570     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
571     dependsOnMethods = {"read"})
572     public void updateWithEmptyEntityBody(String testName) throws Exception {
573     }
574
575    /**
576     * Test how the service handles XML that is not well formed,
577     * when sent in the payload of an Update request.
578     *
579     * @param testName  The name of this test method.  This name is supplied
580     *     automatically, via reflection, by a TestNG 'data provider' in
581     *     a base class.
582     */
583     @Override
584     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
585     dependsOnMethods = {"read"})
586     public void updateWithMalformedXml(String testName) throws Exception {
587     }
588
589     @Override
590     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
591     dependsOnMethods = {"read"})
592     public void updateWithWrongXmlSchema(String testName) throws Exception {
593     }
594
595 /*
596     @Override
597     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
598     dependsOnMethods = {"create", "update", "testSubmitRequest"})
599     public void updateWithEmptyEntityBody(String testName) throws Exception {
600
601     // Perform setup.
602     setupUpdateWithEmptyEntityBody(testName);
603
604     // Submit the request to the service and store the response.
605     String method = REQUEST_TYPE.httpMethodName();
606     String url = getResourceURL(knownResourceId);
607     String mediaType = MediaType.APPLICATION_XML;
608     final String entity = "";
609     int statusCode = submitRequest(method, url, mediaType, entity);
610
611     // Check the status code of the response: does it match
612     // the expected response(s)?
613     if(logger.isDebugEnabled()){
614     logger.debug(testName + ": url=" + url +
615     " status=" + statusCode);
616     }
617     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
618     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
619     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
620     }
621
622     @Override
623     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
624     dependsOnMethods = {"create", "update", "testSubmitRequest"})
625     public void updateWithMalformedXml() throws Exception {
626
627     // Perform setup.
628     setupUpdateWithMalformedXml(testName);
629
630     // Submit the request to the service and store the response.
631     String method = REQUEST_TYPE.httpMethodName();
632     String url = getResourceURL(knownResourceId);
633     final String entity = MALFORMED_XML_DATA;
634     String mediaType = MediaType.APPLICATION_XML;
635     int statusCode = submitRequest(method, url, mediaType, entity);
636
637     // Check the status code of the response: does it match
638     // the expected response(s)?
639     if(logger.isDebugEnabled()){
640     logger.debug(testName + ": url=" + url +
641     " status=" + statusCode);
642     }
643     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
644     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
645     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
646     }
647
648     @Override
649     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
650     dependsOnMethods = {"create", "update", "testSubmitRequest"})
651     public void updateWithWrongXmlSchema(String testName) throws Exception {
652
653     // Perform setup.
654     setupUpdateWithWrongXmlSchema(String testName);
655
656     // Submit the request to the service and store the response.
657     String method = REQUEST_TYPE.httpMethodName();
658     String url = getResourceURL(knownResourceId);
659     String mediaType = MediaType.APPLICATION_XML;
660     final String entity = WRONG_XML_SCHEMA_DATA;
661     int statusCode = submitRequest(method, url, mediaType, entity);
662
663     // Check the status code of the response: does it match
664     // the expected response(s)?
665     if(logger.isDebugEnabled()){
666     logger.debug(testName + ": url=" + url +
667     " status=" + statusCode);
668     }
669     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
670     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
671     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
672     }
673 */
674
675     @Override
676     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
677     dependsOnMethods = {"update", "testSubmitRequest"})
678     public void updateNonExistent(String testName) throws Exception {
679
680         // Perform setup.
681         setupUpdateNonExistent(testName);
682
683         // Submit the request to the service and store the response.
684         //
685         // Note: The ID used in this 'create' call may be arbitrary.
686         // The only relevant ID may be the one used in updateCollectionObject(), below.
687         CollectionObjectClient client = new CollectionObjectClient();
688         MultipartOutput multipart =
689                 createCollectionObjectInstance(client.getCommonPartName(),
690                 NON_EXISTENT_ID);
691         ClientResponse<MultipartInput> res =
692                 client.update(NON_EXISTENT_ID, multipart);
693         int statusCode = res.getStatus();
694
695         // Check the status code of the response: does it match
696         // the expected response(s)?
697         if (logger.isDebugEnabled()) {
698             logger.debug(testName + ": status = " + statusCode);
699         }
700         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
701                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
702         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
703     }
704
705    /**
706     * Test how the service handles, in an Update request, payloads
707     * containing null values (or, in the case of String fields,
708     * empty String values) in one or more fields in which non-empty
709     * values are required.
710     *
711     * This is a test of code and/or configuration in the service's
712     * validation routine(s).
713     *
714     * @param testName  The name of this test method.  This name is supplied
715     *     automatically, via reflection, by a TestNG 'data provider' in
716     *     a base class.
717     */
718     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
719     dependsOnMethods = {"read"})
720     public void updateWithRequiredValuesNullOrEmpty(String testName) throws Exception {
721         // Perform setup.
722         setupUpdate(testName);
723         if (logger.isDebugEnabled()) {
724             logger.debug(testName + " got object to update with ID: " + knownResourceId);
725         }
726
727         // Read an existing record for updating.
728         ClientResponse<MultipartInput> res = updateRetrieve(testName, knownResourceId);
729
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         // Update with invalid content, by setting a value to the
738         // empty String, in a field that requires a non-empty value,
739         // as enforced by the service's validation routine(s).
740         collectionObject.setObjectNumber("");
741
742         if (logger.isDebugEnabled()) {
743             logger.debug(testName + " updated object");
744             logger.debug(objectAsXmlString(collectionObject,
745                     CollectionobjectsCommon.class));
746         }
747
748         // Submit the request to the service and store the response.
749         res = updateSend(testName, knownResourceId, collectionObject);
750         int statusCode = res.getStatus();
751
752         // Read the response and verify that the update attempt failed.
753         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
754                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
755         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
756
757     }
758
759     // ---------------------------------------------------------------
760     // CRUD tests : DELETE tests
761     // ---------------------------------------------------------------
762     // Success outcomes
763     @Override
764     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
765     dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"})
766     public void delete(String testName) throws Exception {
767
768         // Perform setup.
769         setupDelete(testName);
770
771         // Submit the request to the service and store the response.
772         CollectionObjectClient client = new CollectionObjectClient();
773         ClientResponse<Response> res = client.delete(knownResourceId);
774         int statusCode = res.getStatus();
775
776         // Check the status code of the response: does it match
777         // the expected response(s)?
778         if (logger.isDebugEnabled()) {
779             logger.debug(testName + ": status = " + statusCode);
780         }
781         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
782                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
783         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
784     }
785
786     // Failure outcomes
787     @Override
788     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
789     dependsOnMethods = {"delete"})
790     public void deleteNonExistent(String testName) throws Exception {
791
792         // Perform setup.
793         setupDeleteNonExistent(testName);
794
795         // Submit the request to the service and store the response.
796         CollectionObjectClient client = new CollectionObjectClient();
797         ClientResponse<Response> res = client.delete(NON_EXISTENT_ID);
798         int statusCode = res.getStatus();
799
800         // Check the status code of the response: does it match
801         // the expected response(s)?
802         if (logger.isDebugEnabled()) {
803             logger.debug(testName + ": status = " + statusCode);
804         }
805         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
806                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
807         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
808     }
809
810     // ---------------------------------------------------------------
811     // Utility tests : tests of code used in tests above
812     // ---------------------------------------------------------------
813     /**
814      * Tests the code for manually submitting data that is used by several
815      * of the methods above.
816      */
817
818     @Test(dependsOnMethods = {"create", "read"})
819     public void testSubmitRequest() throws Exception {
820         testSubmitRequest(knownResourceId);
821     }
822
823     private void testSubmitRequest(String resourceId) throws Exception {
824
825         // Expected status code: 200 OK
826         final int EXPECTED_STATUS = Response.Status.OK.getStatusCode();
827
828         // Submit the request to the service and store the response.
829         String method = ServiceRequestType.READ.httpMethodName();
830         String url = getResourceURL(resourceId);
831         int statusCode = submitRequest(method, url);
832
833         // Check the status code of the response: does it match
834         // the expected response(s)?
835         if (logger.isDebugEnabled()) {
836             logger.debug("testSubmitRequest: url=" + url
837                     + " status=" + statusCode);
838         }
839         Assert.assertEquals(statusCode, EXPECTED_STATUS);
840
841     }
842
843     // ---------------------------------------------------------------
844     // Cleanup of resources created during testing
845     // ---------------------------------------------------------------
846     /**
847      * Deletes all resources created by tests, after all tests have been run.
848      *
849      * This cleanup method will always be run, even if one or more tests fail.
850      * For this reason, it attempts to remove all resources created
851      * at any point during testing, even if some of those resources
852      * may be expected to be deleted by certain tests.
853      */
854     @AfterClass(alwaysRun = true)
855     public void cleanUp() {
856         if (logger.isDebugEnabled()) {
857             logger.debug("Cleaning up temporary resources created for testing ...");
858         }
859        CollectionObjectClient client = new CollectionObjectClient();
860        for (String resourceId : allResourceIdsCreated) {
861             // Note: Any non-success responses are ignored and not reported.
862             ClientResponse<Response> res = client.delete(resourceId);
863         }
864     }
865
866     // ---------------------------------------------------------------
867     // Utility methods used by tests above
868     // ---------------------------------------------------------------
869     private MultipartOutput createCollectionObjectInstance(String commonPartName,
870             String identifier) {
871         return createCollectionObjectInstance(commonPartName,
872                 "objectNumber-" + identifier,
873                 "objectName-" + identifier);
874     }
875
876     private MultipartOutput createCollectionObjectInstance(String commonPartName,
877             String objectNumber, String objectName) {
878         CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
879         ResponsibleDepartmentList deptList = new ResponsibleDepartmentList();
880         List<String> depts = deptList.getResponsibleDepartment();
881         // @TODO Use properly formatted refNames for representative departments
882         // in this example test record. The following are mere placeholders.
883         depts.add("urn:org.collectionspace.services.department:Registrar");
884         if (multivalue) {
885             depts.add("urn:org.walkerart.department:Fine Art");
886         }
887         multivalue = !multivalue;
888         //FIXME: Title does not need to be set.
889         collectionObject.setTitle("atitle");
890         collectionObject.setResponsibleDepartments(deptList);
891         collectionObject.setObjectNumber(objectNumber);
892         collectionObject.setOtherNumber("urn:org.walkerart.id:123");
893         collectionObject.setObjectName(objectName);
894         collectionObject.setAge(""); //test for null string
895         collectionObject.setBriefDescription("Papier mache bird cow mask with horns, "
896                 + "painted red with black and yellow spots. "
897                 + "Puerto Rico. ca. 8&quot; high, 6&quot; wide, projects 10&quot; (with horns).");
898
899         CollectionobjectsNaturalhistory conh = new CollectionobjectsNaturalhistory();
900         conh.setNhString("test-string");
901         conh.setNhInt(999);
902         conh.setNhLong(9999);
903
904
905         MultipartOutput multipart = createCollectionObjectInstance(commonPartName, collectionObject, conh);
906         return multipart;
907     }
908
909     private MultipartOutput createCollectionObjectInstance(String commonPartName,
910             CollectionobjectsCommon collectionObject, CollectionobjectsNaturalhistory conh) {
911
912         MultipartOutput multipart = new MultipartOutput();
913         OutputPart commonPart = multipart.addPart(collectionObject,
914                 MediaType.APPLICATION_XML_TYPE);
915         commonPart.getHeaders().add("label", commonPartName);
916
917         if (logger.isDebugEnabled()) {
918             logger.debug("to be created, collectionobject common");
919             logger.debug(objectAsXmlString(collectionObject,
920                     CollectionobjectsCommon.class));
921         }
922
923         if (conh != null) {
924             OutputPart nhPart = multipart.addPart(conh, MediaType.APPLICATION_XML_TYPE);
925             nhPart.getHeaders().add("label", getNHPartName());
926
927             if (logger.isDebugEnabled()) {
928                 logger.debug("to be created, collectionobject nhistory");
929                 logger.debug(objectAsXmlString(conh,
930                         CollectionobjectsNaturalhistory.class));
931             }
932         }
933         return multipart;
934
935     }
936
937     /**
938      * createCollectionObjectInstanceFromXml uses JAXB unmarshaller to retrieve
939      * collectionobject from given file
940      * @param commonPartName
941      * @param commonPartFileName
942      * @return
943      * @throws Exception
944      */
945     private MultipartOutput createCollectionObjectInstanceFromXml(String testName, String commonPartName,
946             String commonPartFileName) throws Exception {
947
948         CollectionobjectsCommon collectionObject =
949                 (CollectionobjectsCommon) getObjectFromFile(CollectionobjectsCommon.class,
950                 commonPartFileName);
951         MultipartOutput multipart = new MultipartOutput();
952         OutputPart commonPart = multipart.addPart(collectionObject,
953                 MediaType.APPLICATION_XML_TYPE);
954         commonPart.getHeaders().add("label", commonPartName);
955
956         if (logger.isDebugEnabled()) {
957             logger.debug(testName + " to be created, collectionobject common");
958             logger.debug(objectAsXmlString(collectionObject,
959                     CollectionobjectsCommon.class));
960         }
961         return multipart;
962
963     }
964
965     /**
966      * createCollectionObjectInstanceFromRawXml uses stringified collectionobject
967      * retrieve from given file
968      * @param commonPartName
969      * @param commonPartFileName
970      * @return
971      * @throws Exception
972      */
973     private MultipartOutput createCollectionObjectInstanceFromRawXml(String testName, String commonPartName,
974             String commonPartFileName) throws Exception {
975
976         MultipartOutput multipart = new MultipartOutput();
977         String stringObject = getXmlDocumentAsString(commonPartFileName);
978         if (logger.isDebugEnabled()) {
979             logger.debug(testName + " to be created, collectionobject common " + "\n" + stringObject);
980         }
981         OutputPart commonPart = multipart.addPart(stringObject,
982                 MediaType.APPLICATION_XML_TYPE);
983         commonPart.getHeaders().add("label", commonPartName);
984
985         return multipart;
986
987     }
988
989     private String getNHPartName() {
990         return "collectionobjects_naturalhistory";
991     }
992
993     private String createFromXmlFile(String testName, String fileName, boolean useJaxb) throws Exception {
994         // Perform setup, such as initializing the type of service request
995         // (e.g. CREATE, DELETE), its valid and expected status codes, and
996         // its associated HTTP method name (e.g. POST, DELETE).
997         setupCreate(testName);
998
999         MultipartOutput multipart = null;
1000
1001         CollectionObjectClient client = new CollectionObjectClient();
1002         if (useJaxb) {
1003             multipart = createCollectionObjectInstanceFromXml(testName,
1004                     client.getCommonPartName(), fileName);
1005         } else {
1006             multipart = createCollectionObjectInstanceFromRawXml(testName,
1007                     client.getCommonPartName(), fileName);
1008         }
1009         ClientResponse<Response> res = client.create(multipart);
1010         int statusCode = res.getStatus();
1011
1012         if (logger.isDebugEnabled()) {
1013             logger.debug(testName + ": status = " + statusCode);
1014         }
1015         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1016                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1017         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
1018         String newId = extractId(res);
1019         allResourceIdsCreated.add(newId);
1020         return newId;
1021     }
1022 }