]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
b9f7bcd8048b1a8415acf0621bbf15d42c66dca6
[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 CollectionObjectClient client = new CollectionObjectClient();
60     private String knownResourceId = null;
61     private List<String> allResourceIdsCreated = new ArrayList();
62     private boolean multivalue; //toggle
63
64     /*
65      * This method is called only by the parent class, AbstractServiceTest
66      */
67     @Override
68     protected String getServicePathComponent() {
69         return client.getServicePathComponent();
70     }
71
72     // ---------------------------------------------------------------
73     // CRUD tests : CREATE tests
74     // ---------------------------------------------------------------
75     // Success outcomes
76     @Override
77     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
78     public void create(String testName) throws Exception {
79
80         // Perform setup, such as initializing the type of service request
81         // (e.g. CREATE, DELETE), its valid and expected status codes, and
82         // its associated HTTP method name (e.g. POST, DELETE).
83         setupCreate(testName);
84
85         // Submit the request to the service and store the response.
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         MultipartOutput multipart =
329                 createCollectionObjectInstance(client.getCommonPartName(), collectionObject, null);
330         ClientResponse<Response> res = client.create(multipart);
331         int statusCode = res.getStatus();
332
333         // Read the response and verify that the create attempt failed.
334         if (logger.isDebugEnabled()) {
335             logger.debug(testName + ": status = " + statusCode);
336         }
337         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
338                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
339         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
340
341         // FIXME: Consider splitting off the following into its own test method.
342         
343         // Build a payload with invalid content, by setting a value to the
344         // empty String, in a field that requires a non-empty value,
345         // as enforced by the service's validation routine(s).
346         collectionObject = new CollectionobjectsCommon();
347         collectionObject.setTitle("atitle");
348         collectionObject.setObjectName("some name");
349         collectionObject.setObjectNumber("");
350
351         // Submit the request to the service and store the response.
352         multipart =
353             createCollectionObjectInstance(client.getCommonPartName(), collectionObject, null);
354         res = client.create(multipart);
355         statusCode = res.getStatus();
356
357         // Read the response and verify that the create attempt failed.
358         if (logger.isDebugEnabled()) {
359             logger.debug(testName + ": status = " + statusCode);
360         }
361         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
362                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
363         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
364
365     }
366
367
368     // ---------------------------------------------------------------
369     // CRUD tests : READ tests
370     // ---------------------------------------------------------------
371     // Success outcomes
372     @Override
373     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
374     dependsOnMethods = {"create"})
375     public void read(String testName) throws Exception {
376
377         // Perform setup.
378         setupRead(testName);
379
380         // Submit the request to the service and store the response.
381         ClientResponse<MultipartInput> res = client.read(knownResourceId);
382         int statusCode = res.getStatus();
383
384         // Check the status code of the response: does it match
385         // the expected response(s)?
386         if (logger.isDebugEnabled()) {
387             logger.debug(testName + ": status = " + statusCode);
388         }
389         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
390                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
391         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
392
393         MultipartInput input = (MultipartInput) res.getEntity();
394
395         if (logger.isDebugEnabled()) {
396             logger.debug(testName + ": Reading Common part ...");
397         }
398         CollectionobjectsCommon collectionObject =
399                 (CollectionobjectsCommon) extractPart(input,
400                 client.getCommonPartName(), CollectionobjectsCommon.class);
401         Assert.assertNotNull(collectionObject);
402
403         if (logger.isDebugEnabled()) {
404             logger.debug(testName + ": Reading Natural History part ...");
405         }
406         CollectionobjectsNaturalhistory conh =
407                 (CollectionobjectsNaturalhistory) extractPart(input,
408                 getNHPartName(), CollectionobjectsNaturalhistory.class);
409         Assert.assertNotNull(conh);
410     }
411
412     // Failure outcomes
413     @Override
414     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
415     dependsOnMethods = {"read"})
416     public void readNonExistent(String testName) throws Exception {
417
418         // Perform setup.
419         setupReadNonExistent(testName);
420
421         // Submit the request to the service and store the response.
422         ClientResponse<MultipartInput> res = client.read(NON_EXISTENT_ID);
423         int statusCode = res.getStatus();
424
425         // Check the status code of the response: does it match
426         // the expected response(s)?
427         if (logger.isDebugEnabled()) {
428             logger.debug(testName + ": status = " + statusCode);
429         }
430         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
431                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
432         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
433     }
434
435     // ---------------------------------------------------------------
436     // CRUD tests : READ_LIST tests
437     // ---------------------------------------------------------------
438     // Success outcomes
439     @Override
440     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
441     dependsOnMethods = {"createList", "read"})
442     public void readList(String testName) throws Exception {
443
444         // Perform setup.
445         setupReadList(testName);
446
447         // Submit the request to the service and store the response.
448         ClientResponse<CollectionobjectsCommonList> res = client.readList();
449         CollectionobjectsCommonList list = res.getEntity();
450         int statusCode = res.getStatus();
451
452         // Check the status code of the response: does it match
453         // the expected response(s)?
454         if (logger.isDebugEnabled()) {
455             logger.debug(testName + ": status = " + statusCode);
456         }
457         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
458                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
459         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
460
461         // Optionally output additional data about list members for debugging.
462         boolean iterateThroughList = false;
463         if (iterateThroughList && logger.isDebugEnabled()) {
464             List<CollectionobjectsCommonList.CollectionObjectListItem> items =
465                     list.getCollectionObjectListItem();
466             int i = 0;
467
468             for (CollectionobjectsCommonList.CollectionObjectListItem item : items) {
469                 logger.debug(testName + ": list-item[" + i + "] csid="
470                         + item.getCsid());
471                 logger.debug(testName + ": list-item[" + i + "] objectNumber="
472                         + item.getObjectNumber());
473                 logger.debug(testName + ": list-item[" + i + "] URI="
474                         + item.getUri());
475                 i++;
476
477             }
478         }
479     }
480
481     // Failure outcomes
482     // None at present.
483     // ---------------------------------------------------------------
484     // CRUD tests : UPDATE tests
485     // ---------------------------------------------------------------
486     // Success outcomes
487     @Override
488     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
489     dependsOnMethods = {"read"})
490     public void update(String testName) throws Exception {
491
492         // Perform setup.
493         setupUpdate(testName);
494
495         // Read an existing resource that will be updated.
496         ClientResponse<MultipartInput> res = updateRetrieve(testName, knownResourceId);
497
498         // Extract its common part.
499         MultipartInput input = (MultipartInput) res.getEntity();
500         CollectionobjectsCommon collectionObject =
501                 (CollectionobjectsCommon) extractPart(input,
502                 client.getCommonPartName(), CollectionobjectsCommon.class);
503         Assert.assertNotNull(collectionObject);
504
505         // Change the content of one or more fields in the common part.
506         collectionObject.setObjectNumber("updated-" + collectionObject.getObjectNumber());
507         collectionObject.setObjectName("updated-" + collectionObject.getObjectName());
508         if (logger.isDebugEnabled()) {
509             logger.debug("sparse update that will be sent in update request:");
510             logger.debug(objectAsXmlString(collectionObject,
511                     CollectionobjectsCommon.class));
512         }
513
514         // Send the changed resource to be updated.
515         res = updateSend(testName, knownResourceId, collectionObject);
516         int statusCode = res.getStatus();
517         // Check the status code of the response: does it match the expected response(s)?
518         if (logger.isDebugEnabled()) {
519             logger.debug(testName + ": status = " + statusCode);
520         }
521         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
522                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
523         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
524
525         // Read the response and verify that the resource was correctly updated.
526         input = (MultipartInput) res.getEntity();
527         CollectionobjectsCommon updatedCollectionObject =
528                 (CollectionobjectsCommon) extractPart(input,
529                 client.getCommonPartName(), CollectionobjectsCommon.class);
530         Assert.assertNotNull(updatedCollectionObject);
531         Assert.assertEquals(updatedCollectionObject.getObjectName(),
532                 collectionObject.getObjectName(),
533                 "Data in updated object did not match submitted data.");
534
535     }
536
537     private ClientResponse<MultipartInput> updateRetrieve(String testName, String id) {
538         final int EXPECTED_STATUS = Response.Status.OK.getStatusCode();
539         ClientResponse<MultipartInput> res = client.read(id);
540         if (logger.isDebugEnabled()) {
541             logger.debug("read in updateRetrieve for " + testName + " status = " + res.getStatus());
542         }
543         Assert.assertEquals(res.getStatus(), EXPECTED_STATUS);
544         if (logger.isDebugEnabled()) {
545             logger.debug("got object to updateRetrieve for " + testName + " with ID: " + id);
546         }
547         return res;
548     }
549
550     private ClientResponse<MultipartInput> updateSend(String testName, String id,
551             CollectionobjectsCommon collectionObject) {
552         MultipartOutput output = new MultipartOutput();
553         OutputPart commonPart = output.addPart(collectionObject, MediaType.APPLICATION_XML_TYPE);
554         commonPart.getHeaders().add("label", client.getCommonPartName());
555         ClientResponse<MultipartInput> res = client.update(knownResourceId, output);
556         return res;
557     }
558
559     // Failure outcomes
560     // Placeholders until the three tests below can be uncommented.
561     // See Issue CSPACE-401.
562     @Override
563     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
564     dependsOnMethods = {"read"})
565     public void updateWithEmptyEntityBody(String testName) throws Exception {
566     }
567
568    /**
569     * Test how the service handles XML that is not well formed,
570     * when sent in the payload of an Update request.
571     *
572     * @param testName  The name of this test method.  This name is supplied
573     *     automatically, via reflection, by a TestNG 'data provider' in
574     *     a base class.
575     */
576     @Override
577     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
578     dependsOnMethods = {"read"})
579     public void updateWithMalformedXml(String testName) throws Exception {
580     }
581
582     @Override
583     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
584     dependsOnMethods = {"read"})
585     public void updateWithWrongXmlSchema(String testName) throws Exception {
586     }
587
588 /*
589     @Override
590     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
591     dependsOnMethods = {"create", "update", "testSubmitRequest"})
592     public void updateWithEmptyEntityBody(String testName) throws Exception {
593
594     // Perform setup.
595     setupUpdateWithEmptyEntityBody(testName);
596
597     // Submit the request to the service and store the response.
598     String method = REQUEST_TYPE.httpMethodName();
599     String url = getResourceURL(knownResourceId);
600     String mediaType = MediaType.APPLICATION_XML;
601     final String entity = "";
602     int statusCode = submitRequest(method, url, mediaType, entity);
603
604     // Check the status code of the response: does it match
605     // the expected response(s)?
606     if(logger.isDebugEnabled()){
607     logger.debug(testName + ": url=" + url +
608     " status=" + statusCode);
609     }
610     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
611     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
612     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
613     }
614
615     @Override
616     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
617     dependsOnMethods = {"create", "update", "testSubmitRequest"})
618     public void updateWithMalformedXml() throws Exception {
619
620     // Perform setup.
621     setupUpdateWithMalformedXml(testName);
622
623     // Submit the request to the service and store the response.
624     String method = REQUEST_TYPE.httpMethodName();
625     String url = getResourceURL(knownResourceId);
626     final String entity = MALFORMED_XML_DATA;
627     String mediaType = MediaType.APPLICATION_XML;
628     int statusCode = submitRequest(method, url, mediaType, entity);
629
630     // Check the status code of the response: does it match
631     // the expected response(s)?
632     if(logger.isDebugEnabled()){
633     logger.debug(testName + ": url=" + url +
634     " status=" + statusCode);
635     }
636     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
637     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
638     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
639     }
640
641     @Override
642     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTest.class,
643     dependsOnMethods = {"create", "update", "testSubmitRequest"})
644     public void updateWithWrongXmlSchema(String testName) throws Exception {
645
646     // Perform setup.
647     setupUpdateWithWrongXmlSchema(String testName);
648
649     // Submit the request to the service and store the response.
650     String method = REQUEST_TYPE.httpMethodName();
651     String url = getResourceURL(knownResourceId);
652     String mediaType = MediaType.APPLICATION_XML;
653     final String entity = WRONG_XML_SCHEMA_DATA;
654     int statusCode = submitRequest(method, url, mediaType, entity);
655
656     // Check the status code of the response: does it match
657     // the expected response(s)?
658     if(logger.isDebugEnabled()){
659     logger.debug(testName + ": url=" + url +
660     " status=" + statusCode);
661     }
662     Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
663     invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
664     Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
665     }
666 */
667
668     @Override
669     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
670     dependsOnMethods = {"update", "testSubmitRequest"})
671     public void updateNonExistent(String testName) throws Exception {
672
673         // Perform setup.
674         setupUpdateNonExistent(testName);
675
676         // Submit the request to the service and store the response.
677         //
678         // Note: The ID used in this 'create' call may be arbitrary.
679         // The only relevant ID may be the one used in updateCollectionObject(), below.
680         MultipartOutput multipart =
681                 createCollectionObjectInstance(client.getCommonPartName(),
682                 NON_EXISTENT_ID);
683         ClientResponse<MultipartInput> res =
684                 client.update(NON_EXISTENT_ID, multipart);
685         int statusCode = res.getStatus();
686
687         // Check the status code of the response: does it match
688         // the expected response(s)?
689         if (logger.isDebugEnabled()) {
690             logger.debug(testName + ": status = " + statusCode);
691         }
692         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
693                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
694         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
695     }
696
697    /**
698     * Test how the service handles, in an Update request, payloads
699     * containing null values (or, in the case of String fields,
700     * empty String values) in one or more fields in which non-empty
701     * values are required.
702     *
703     * This is a test of code and/or configuration in the service's
704     * validation routine(s).
705     *
706     * @param testName  The name of this test method.  This name is supplied
707     *     automatically, via reflection, by a TestNG 'data provider' in
708     *     a base class.
709     */
710     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
711     dependsOnMethods = {"read"})
712     public void updateWithRequiredValuesNullOrEmpty(String testName) throws Exception {
713         // Perform setup.
714         setupUpdate(testName);
715         if (logger.isDebugEnabled()) {
716             logger.debug(testName + " got object to update with ID: " + knownResourceId);
717         }
718
719         // Read an existing record for updating.
720         ClientResponse<MultipartInput> res = updateRetrieve(testName, knownResourceId);
721
722         MultipartInput input = (MultipartInput) res.getEntity();
723         CollectionobjectsCommon collectionObject =
724                 (CollectionobjectsCommon) extractPart(input,
725                 client.getCommonPartName(), CollectionobjectsCommon.class);
726         Assert.assertNotNull(collectionObject);
727
728         // Update with invalid content, by setting a value to the
729         // empty String, in a field that requires a non-empty value,
730         // as enforced by the service's validation routine(s).
731         collectionObject.setObjectNumber("");
732
733         if (logger.isDebugEnabled()) {
734             logger.debug(testName + " updated object");
735             logger.debug(objectAsXmlString(collectionObject,
736                     CollectionobjectsCommon.class));
737         }
738
739         // Submit the request to the service and store the response.
740         res = updateSend(testName, knownResourceId, collectionObject);
741         int statusCode = res.getStatus();
742
743         // Read the response and verify that the update attempt failed.
744         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
745                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
746         Assert.assertEquals(statusCode, Response.Status.BAD_REQUEST.getStatusCode());
747
748     }
749
750     // ---------------------------------------------------------------
751     // CRUD tests : DELETE tests
752     // ---------------------------------------------------------------
753     // Success outcomes
754     @Override
755     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
756     dependsOnMethods = {"create", "readList", "testSubmitRequest", "update"})
757     public void delete(String testName) throws Exception {
758
759         // Perform setup.
760         setupDelete(testName);
761
762         // Submit the request to the service and store the response.
763         ClientResponse<Response> res = client.delete(knownResourceId);
764         int statusCode = res.getStatus();
765
766         // Check the status code of the response: does it match
767         // the expected response(s)?
768         if (logger.isDebugEnabled()) {
769             logger.debug(testName + ": status = " + statusCode);
770         }
771         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
772                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
773         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
774     }
775
776     // Failure outcomes
777     @Override
778     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
779     dependsOnMethods = {"delete"})
780     public void deleteNonExistent(String testName) throws Exception {
781
782         // Perform setup.
783         setupDeleteNonExistent(testName);
784
785         // Submit the request to the service and store the response.
786         ClientResponse<Response> res = client.delete(NON_EXISTENT_ID);
787         int statusCode = res.getStatus();
788
789         // Check the status code of the response: does it match
790         // the expected response(s)?
791         if (logger.isDebugEnabled()) {
792             logger.debug(testName + ": status = " + statusCode);
793         }
794         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
795                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
796         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
797     }
798
799     // ---------------------------------------------------------------
800     // Utility tests : tests of code used in tests above
801     // ---------------------------------------------------------------
802     /**
803      * Tests the code for manually submitting data that is used by several
804      * of the methods above.
805      */
806
807     @Test(dependsOnMethods = {"create", "read"})
808     public void testSubmitRequest() throws Exception {
809         testSubmitRequest(knownResourceId);
810     }
811
812     private void testSubmitRequest(String resourceId) throws Exception {
813
814         // Expected status code: 200 OK
815         final int EXPECTED_STATUS = Response.Status.OK.getStatusCode();
816
817         // Submit the request to the service and store the response.
818         String method = ServiceRequestType.READ.httpMethodName();
819         String url = getResourceURL(resourceId);
820         int statusCode = submitRequest(method, url);
821
822         // Check the status code of the response: does it match
823         // the expected response(s)?
824         if (logger.isDebugEnabled()) {
825             logger.debug("testSubmitRequest: url=" + url
826                     + " status=" + statusCode);
827         }
828         Assert.assertEquals(statusCode, EXPECTED_STATUS);
829
830     }
831
832     // ---------------------------------------------------------------
833     // Cleanup of resources created during testing
834     // ---------------------------------------------------------------
835     /**
836      * Deletes all resources created by tests, after all tests have been run.
837      *
838      * This cleanup method will always be run, even if one or more tests fail.
839      * For this reason, it attempts to remove all resources created
840      * at any point during testing, even if some of those resources
841      * may be expected to be deleted by certain tests.
842      */
843     @AfterClass(alwaysRun = true)
844     public void cleanUp() {
845         if (logger.isDebugEnabled()) {
846             logger.debug("Cleaning up temporary resources created for testing ...");
847         }
848         for (String resourceId : allResourceIdsCreated) {
849             // Note: Any non-success responses are ignored and not reported.
850             ClientResponse<Response> res = client.delete(resourceId);
851         }
852     }
853
854     // ---------------------------------------------------------------
855     // Utility methods used by tests above
856     // ---------------------------------------------------------------
857     private MultipartOutput createCollectionObjectInstance(String commonPartName,
858             String identifier) {
859         return createCollectionObjectInstance(commonPartName,
860                 "objectNumber-" + identifier,
861                 "objectName-" + identifier);
862     }
863
864     private MultipartOutput createCollectionObjectInstance(String commonPartName,
865             String objectNumber, String objectName) {
866         CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
867         ResponsibleDepartmentList deptList = new ResponsibleDepartmentList();
868         List<String> depts = deptList.getResponsibleDepartment();
869         // @TODO Use properly formatted refNames for representative departments
870         // in this example test record. The following are mere placeholders.
871         depts.add("urn:org.collectionspace.services.department:Registrar");
872         if (multivalue) {
873             depts.add("urn:org.walkerart.department:Fine Art");
874         }
875         multivalue = !multivalue;
876         //FIXME: Title does not need to be set.
877         collectionObject.setTitle("atitle");
878         collectionObject.setResponsibleDepartments(deptList);
879         collectionObject.setObjectNumber(objectNumber);
880         collectionObject.setOtherNumber("urn:org.walkerart.id:123");
881         collectionObject.setObjectName(objectName);
882         collectionObject.setAge(""); //test for null string
883         collectionObject.setBriefDescription("Papier mache bird cow mask with horns, "
884                 + "painted red with black and yellow spots. "
885                 + "Puerto Rico. ca. 8&quot; high, 6&quot; wide, projects 10&quot; (with horns).");
886
887         CollectionobjectsNaturalhistory conh = new CollectionobjectsNaturalhistory();
888         conh.setNhString("test-string");
889         conh.setNhInt(999);
890         conh.setNhLong(9999);
891
892
893         MultipartOutput multipart = createCollectionObjectInstance(commonPartName, collectionObject, conh);
894         return multipart;
895     }
896
897     private MultipartOutput createCollectionObjectInstance(String commonPartName,
898             CollectionobjectsCommon collectionObject, CollectionobjectsNaturalhistory conh) {
899
900         MultipartOutput multipart = new MultipartOutput();
901         OutputPart commonPart = multipart.addPart(collectionObject,
902                 MediaType.APPLICATION_XML_TYPE);
903         commonPart.getHeaders().add("label", commonPartName);
904
905         if (logger.isDebugEnabled()) {
906             logger.debug("to be created, collectionobject common");
907             logger.debug(objectAsXmlString(collectionObject,
908                     CollectionobjectsCommon.class));
909         }
910
911         if (conh != null) {
912             OutputPart nhPart = multipart.addPart(conh, MediaType.APPLICATION_XML_TYPE);
913             nhPart.getHeaders().add("label", getNHPartName());
914
915             if (logger.isDebugEnabled()) {
916                 logger.debug("to be created, collectionobject nhistory");
917                 logger.debug(objectAsXmlString(conh,
918                         CollectionobjectsNaturalhistory.class));
919             }
920         }
921         return multipart;
922
923     }
924
925     /**
926      * createCollectionObjectInstanceFromXml uses JAXB unmarshaller to retrieve
927      * collectionobject from given file
928      * @param commonPartName
929      * @param commonPartFileName
930      * @return
931      * @throws Exception
932      */
933     private MultipartOutput createCollectionObjectInstanceFromXml(String testName, String commonPartName,
934             String commonPartFileName) throws Exception {
935
936         CollectionobjectsCommon collectionObject =
937                 (CollectionobjectsCommon) getObjectFromFile(CollectionobjectsCommon.class,
938                 commonPartFileName);
939         MultipartOutput multipart = new MultipartOutput();
940         OutputPart commonPart = multipart.addPart(collectionObject,
941                 MediaType.APPLICATION_XML_TYPE);
942         commonPart.getHeaders().add("label", commonPartName);
943
944         if (logger.isDebugEnabled()) {
945             logger.debug(testName + " to be created, collectionobject common");
946             logger.debug(objectAsXmlString(collectionObject,
947                     CollectionobjectsCommon.class));
948         }
949         return multipart;
950
951     }
952
953     /**
954      * createCollectionObjectInstanceFromRawXml uses stringified collectionobject
955      * retrieve from given file
956      * @param commonPartName
957      * @param commonPartFileName
958      * @return
959      * @throws Exception
960      */
961     private MultipartOutput createCollectionObjectInstanceFromRawXml(String testName, String commonPartName,
962             String commonPartFileName) throws Exception {
963
964         MultipartOutput multipart = new MultipartOutput();
965         String stringObject = getXmlDocumentAsString(commonPartFileName);
966         if (logger.isDebugEnabled()) {
967             logger.debug(testName + " to be created, collectionobject common " + "\n" + stringObject);
968         }
969         OutputPart commonPart = multipart.addPart(stringObject,
970                 MediaType.APPLICATION_XML_TYPE);
971         commonPart.getHeaders().add("label", commonPartName);
972
973         return multipart;
974
975     }
976
977     private String getNHPartName() {
978         return "collectionobjects_naturalhistory";
979     }
980
981     private String createFromXmlFile(String testName, String fileName, boolean useJaxb) throws Exception {
982         // Perform setup, such as initializing the type of service request
983         // (e.g. CREATE, DELETE), its valid and expected status codes, and
984         // its associated HTTP method name (e.g. POST, DELETE).
985         setupCreate(testName);
986
987         MultipartOutput multipart = null;
988
989         if (useJaxb) {
990             multipart = createCollectionObjectInstanceFromXml(testName,
991                     client.getCommonPartName(), fileName);
992         } else {
993             multipart = createCollectionObjectInstanceFromRawXml(testName,
994                     client.getCommonPartName(), fileName);
995         }
996         ClientResponse<Response> res = client.create(multipart);
997         int statusCode = res.getStatus();
998
999         if (logger.isDebugEnabled()) {
1000             logger.debug(testName + ": status = " + statusCode);
1001         }
1002         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
1003                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
1004         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
1005         String newId = extractId(res);
1006         allResourceIdsCreated.add(newId);
1007         return newId;
1008     }
1009 }