]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
6dc7c1cc0c70b1f37fe40563942a9110c11afdac
[tmp/jakarta-migration.git] /
1 /**
2  * This document is a part of the source code and related artifacts
3  * for CollectionSpace, an open source collections management system
4  * for museums and related institutions:
5  *
6  * http://www.collectionspace.org
7  * http://wiki.collectionspace.org
8  *
9  * Copyright © 2009 Regents of the University of California
10  *
11  * Licensed under the Educational Community License (ECL), Version 2.0.
12  * You may not use this file except in compliance with this License.
13  *
14  * You may obtain a copy of the ECL 2.0 License at
15  * https://source.collectionspace.org/collection-space/LICENSE.txt
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 package org.collectionspace.services.client.test;
24
25 import java.text.Collator;
26 import java.util.ArrayList;
27 import java.util.Comparator;
28 import java.util.List;
29 import java.util.Locale;
30 import javax.ws.rs.core.Response;
31
32 import org.collectionspace.services.MovementJAXBSchema;
33 import org.collectionspace.services.client.AbstractCommonListUtils;
34 import org.collectionspace.services.client.CollectionSpaceClient;
35 import org.collectionspace.services.client.MovementClient;
36 import org.collectionspace.services.client.PayloadInputPart;
37 import org.collectionspace.services.client.PayloadOutputPart;
38 import org.collectionspace.services.client.PoxPayloadIn;
39 import org.collectionspace.services.client.PoxPayloadOut;
40 import org.collectionspace.services.movement.MovementsCommon;
41 import org.collectionspace.services.jaxb.AbstractCommonList;
42
43 import org.jboss.resteasy.client.ClientResponse;
44
45 import org.testng.Assert;
46 import org.testng.annotations.AfterClass;
47 import org.testng.annotations.DataProvider;
48 import org.testng.annotations.Test;
49
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 /**
54  * MovementSortByTest, tests sorting of summary lists by fields
55  * of various datatypes.
56  *
57  * $LastChangedRevision: 2562 $
58  * $LastChangedDate: 2010-06-22 23:26:51 -0700 (Tue, 22 Jun 2010) $
59  */
60 public class MovementSortByTest extends BaseServiceTest<AbstractCommonList> {
61
62     private final String CLASS_NAME = MovementSortByTest.class.getName();
63     private final Logger logger = LoggerFactory.getLogger(CLASS_NAME);
64     final String SERVICE_NAME = "movements";
65
66     // Instance variables specific to this test.
67     private final String DELIMITER_SCHEMA_AND_FIELD = ":";
68     private final String KEYWORD_DESCENDING_SEARCH = "DESC";
69     private final String SERVICE_PATH_COMPONENT = "movements";
70     private final String TEST_SPECIFIC_KEYWORD = "msotebstpfscn";
71     private List<String> movementIdsCreated = new ArrayList<String>();
72     private final String SORT_FIELD_SEPARATOR = ", ";
73     private final Locale LOCALE = Locale.US;
74     private final String LOCATION_DATE_EL_NAME = "locationDate";
75     private final Comparator<String> CASE_INSENSITIVE_STRING_COMPARATOR =
76             String.CASE_INSENSITIVE_ORDER;
77     private final Collator LOCALE_SPECIFIC_COLLATOR = Collator.getInstance(LOCALE);
78
79
80
81     /* (non-Javadoc)
82      * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
83      */
84     @Override
85     protected CollectionSpaceClient getClientInstance() {
86         throw new UnsupportedOperationException(); //method not supported (or needed) in this test class
87     }
88
89     /* (non-Javadoc)
90      * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
91      */
92     @Override
93     protected AbstractCommonList getCommonList(
94             ClientResponse<AbstractCommonList> response) {
95         throw new UnsupportedOperationException(); //method not supported (or needed) in this test class
96     }
97
98     // ---------------------------------------------------------------
99     // Sort tests
100     // ---------------------------------------------------------------
101
102     // Success outcomes
103
104     /*
105      * Tests whether a list of records, sorted by a String field in
106      * ascending order, is returned in the expected order.
107      */
108     @Test(dataProvider = "testName",
109                 dependsOnMethods = {"createList"})
110     public void sortByStringFieldAscending(String testName) throws Exception {
111         String sortFieldName = qualifySortFieldName(MovementJAXBSchema.MOVEMENT_NOTE);
112         if (logger.isDebugEnabled()) {
113             logger.debug("Sorting on field name=" + sortFieldName);
114         }
115         AbstractCommonList list = readSortedList(sortFieldName);
116         List<AbstractCommonList.ListItem> items =
117                 list.getListItem();
118
119         ArrayList<String> values = new ArrayList<String>();
120         int i = 0;
121         for (AbstractCommonList.ListItem item : items) {
122             // Because movementNote is not currently a summary field
123             // (returned in summary list items), we will need to verify
124             // sort order by using the IDs provided in the summary list
125             // items to retrieve full records, amd then obtaining
126             // the value of that field from each of those records.
127             MovementsCommon movement = read(AbstractCommonListUtils.ListItemGetCSID(item));
128             values.add(i, movement.getMovementNote());
129             if (logger.isTraceEnabled()) {
130                 logger.trace("list-item[" + i + "] movementNote=" + values.get(i));
131             }
132             // Verify that the value of the specified field in the current record
133             // is equal to or greater than its value in the previous record.
134             //
135             // (Note: when used with certain text, this test case could potentially
136             // reflect inconsistencies, if any, between Java's collator and the
137             // collator used for ordering by the database.  To help avoid this,
138             // it might be useful to keep test strings fairly generic.)
139             if (i > 0 && values.get(i) != null && values.get(i - 1) != null) {
140                 if (logger.isDebugEnabled()) {
141                     logger.debug("Comparing " + values.get(i) + " with previous value " + values.get(i - 1) + "...");
142                 }
143                 // Assert.assertTrue(LOCALE_SPECIFIC_COLLATOR.compare(values.get(i), values.get(i - 1)) >= 0);
144                 // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(values.get(i), values.get(i - 1)) >= 0);
145                 Assert.assertTrue(values.get(i).compareTo(values.get(i - 1)) >= 0);
146             }
147             i++;
148         }
149
150     }
151
152     /*
153      * Tests whether a list of records, obtained by a keyword search, and
154      * sorted by a String field in ascending order, is returned in the expected order.
155      *
156      * This verifies that summary list results from keyword searches, in
157      * addition to 'read list' requests, can be returned in sorted order.
158      */
159     @Test(dataProvider = "testName",
160                 dependsOnMethods = {"createList"})
161     public void sortKeywordSearchResultsByStringFieldAscending(String testName) throws Exception {
162         String sortFieldName = qualifySortFieldName(MovementJAXBSchema.MOVEMENT_NOTE);
163         if (logger.isDebugEnabled()) {
164             logger.debug("Sorting on field name=" + sortFieldName);
165         }
166         AbstractCommonList list = keywordSearchSortedBy(TEST_SPECIFIC_KEYWORD, sortFieldName);
167         List<AbstractCommonList.ListItem> items =
168                 list.getListItem();
169
170         ArrayList<String> values = new ArrayList<String>();
171         int i = 0;
172         for (AbstractCommonList.ListItem item : items) {
173             // Because movementNote is not currently a summary field
174             // (returned in summary list items), we will need to verify
175             // sort order by using the IDs provided in the summary list
176             // items to retrieve full records, amd then obtaining
177             // the value of that field from each of those records.
178             MovementsCommon movement = read(AbstractCommonListUtils.ListItemGetCSID(item));
179             values.add(i, movement.getMovementNote());
180             if (logger.isTraceEnabled()) {
181                 logger.trace("list-item[" + i + "] movementNote=" + values.get(i));
182             }
183             // Verify that the value of the specified field in the current record
184             // is equal to or greater than its value in the previous record.
185             //
186             // (Note: when used with certain text, this test case could potentially
187             // reflect inconsistencies, if any, between Java's collator and the
188             // collator used for ordering by the database.  To help avoid this,
189             // it might be useful to keep test strings fairly generic.)
190             if (i > 0 && values.get(i) != null && values.get(i - 1) != null) {
191                 if (logger.isDebugEnabled()) {
192                     logger.debug("Comparing " + values.get(i) + " with previous value " + values.get(i - 1) + "...");
193                 }
194                 // Assert.assertTrue(LOCALE_SPECIFIC_COLLATOR.compare(values.get(i), values.get(i - 1)) >= 0);
195                 // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(values.get(i), values.get(i - 1)) >= 0);
196                 Assert.assertTrue(values.get(i).compareTo(values.get(i - 1)) >= 0);
197             }
198             i++;
199         }
200
201     }
202
203     /*
204      * Tests whether a list of records, sorted by a String field in
205      * descending order, is returned in the expected order.
206      */
207     @Test(dataProvider = "testName",
208                 dependsOnMethods = {"createList"})
209     public void sortByStringFieldDescending(String testName) throws Exception {
210         String sortFieldName =
211                 asDescendingSort(qualifySortFieldName(MovementJAXBSchema.MOVEMENT_NOTE));
212         if (logger.isDebugEnabled()) {
213             logger.debug("Sorting on field name=" + sortFieldName);
214         }
215         AbstractCommonList list = readSortedList(sortFieldName);
216         List<AbstractCommonList.ListItem> items =
217                 list.getListItem();
218
219         ArrayList<String> values = new ArrayList<String>();
220         int i = 0;
221         for (AbstractCommonList.ListItem item : items) {
222             // Because movementNote is not currently a summary field
223             // (returned in summary list items), we will need to verify
224             // sort order by using the IDs provided in the summary list
225             // items to retrieve full records, amd then obtaining
226             // the value of that field from each of those records.
227             MovementsCommon movement = read(AbstractCommonListUtils.ListItemGetCSID(item));
228             values.add(i, movement.getMovementNote());
229             if (logger.isTraceEnabled()) {
230                 logger.trace("list-item[" + i + "] movementNote=" + values.get(i));
231             }
232             // Verify that the value of the specified field in the current record
233             // is less than or equal to than its value in the previous record.
234             //
235             // (Note: when used with certain text, this test case could potentially
236             // reflect inconsistencies, if any, between Java's comparator or collator,
237             // and the collator used for ordering by the database.  To help avoid this,
238             // it might be useful to keep test strings fairly generic.)
239             if (i > 0 && values.get(i) != null && values.get(i - 1) != null) {
240                 if (logger.isDebugEnabled()) {
241                     logger.debug("Comparing " + values.get(i) + " with previous value " + values.get(i - 1) + "...");
242                 }
243                 // Assert.assertTrue(LOCALE_SPECIFIC_COLLATOR.compare(values.get(i), values.get(i - 1)) <= 0);
244                 // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(values.get(i), values.get(i - 1)) <= 0);
245                 Assert.assertTrue(values.get(i).compareTo(values.get(i - 1)) <= 0);
246             }
247             i++;
248         }
249
250     }
251
252     /*
253      * Tests whether a list of records, sorted by a dateTime field in
254      * ascending order, is returned in the expected order.
255      */
256     @Test(dataProvider = "testName",
257                 dependsOnMethods = {"createList"})
258     public void sortByDateTimeFieldAscending(String testName) throws Exception {
259         String sortFieldName = qualifySortFieldName(MovementJAXBSchema.LOCATION_DATE);
260         if (logger.isDebugEnabled()) {
261             logger.debug("Sorting on field name=" + sortFieldName);
262         }
263         AbstractCommonList list = readSortedList(sortFieldName);
264         List<AbstractCommonList.ListItem> items =
265                 list.getListItem();
266
267         ArrayList<String> values = new ArrayList<String>();
268         int i = 0;
269         for (AbstractCommonList.ListItem item : items) {
270                 String locDate = 
271                         AbstractCommonListUtils.ListItemGetElementValue(item, LOCATION_DATE_EL_NAME);
272                 values.add(i, locDate);
273             if (logger.isTraceEnabled()) {
274                 logger.trace("list-item[" + i + "] locationDate=" + values.get(i));
275             }
276             // Verify that the value of the specified field in the current record
277             // is equal to or greater than its value in the previous record.
278             if (i > 0 && values.get(i) != null && values.get(i - 1) != null) {
279                 if (logger.isDebugEnabled()) {
280                     logger.debug("Comparing " + values.get(i) + " with previous value " + values.get(i - 1) + "...");
281                 }
282                 // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(values.get(i), values.get(i - 1)) >= 0);
283                 Assert.assertTrue(values.get(i).compareTo(values.get(i - 1)) >= 0);
284             }
285             i++;
286         }
287     }
288
289     /*
290      * Tests whether a list of records, sorted by a dateTime field in
291      * descending order, is returned in the expected order.
292      */
293     @Test(dataProvider = "testName",
294                 dependsOnMethods = {"createList"})
295     public void sortByDateTimeFieldDescending(String testName) throws Exception {
296         String sortFieldName =
297                 asDescendingSort(qualifySortFieldName(MovementJAXBSchema.LOCATION_DATE));
298         if (logger.isDebugEnabled()) {
299             logger.debug("Sorting on field name=" + sortFieldName);
300         }
301         AbstractCommonList list = readSortedList(sortFieldName);
302         List<AbstractCommonList.ListItem> items =
303                 list.getListItem();
304
305         ArrayList<String> values = new ArrayList<String>();
306         int i = 0;
307         for (AbstractCommonList.ListItem item : items) {
308                 String locDate = 
309                         AbstractCommonListUtils.ListItemGetElementValue(item, LOCATION_DATE_EL_NAME);
310                 values.add(i, locDate);
311             if (logger.isTraceEnabled()) {
312                 logger.trace("list-item[" + i + "] locationDate=" + values.get(i));
313             }
314             // Verify that the value of the specified field in the current record
315             // is less than or equal to its value in the previous record.
316             if (i > 0 && values.get(i) != null && values.get(i - 1) != null) {
317                 if (logger.isDebugEnabled()) {
318                     logger.debug("Comparing " + values.get(i) + " with previous value " + values.get(i - 1) + "...");
319                 }
320                 // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(values.get(i), values.get(i - 1)) <= 0);
321                 Assert.assertTrue(values.get(i).compareTo(values.get(i - 1)) <= 0);
322             }
323             i++;
324         }
325     }
326
327     /*
328      * Tests whether a list of records, sorted by two different fields in
329      * ascending order, is returned in the expected order.
330      */
331     @Test(dataProvider = "testName",
332                 dependsOnMethods = {"createList"})
333     public void sortByTwoFieldsAscending(String testName) throws Exception {
334         String firstSortFieldName = qualifySortFieldName(MovementJAXBSchema.MOVEMENT_NOTE);
335         String secondSortFieldName = qualifySortFieldName(MovementJAXBSchema.LOCATION_DATE);
336         if (logger.isDebugEnabled()) {
337             logger.debug("Sorting on field names=" + firstSortFieldName + " and " + secondSortFieldName);
338         }
339         String sortExpression = firstSortFieldName + SORT_FIELD_SEPARATOR + secondSortFieldName;
340         AbstractCommonList list = readSortedList(sortExpression);
341         List<AbstractCommonList.ListItem> items =
342                 list.getListItem();
343
344         ArrayList<String> firstFieldValues = new ArrayList<String>();
345         ArrayList<String> secondFieldValues = new ArrayList<String>();
346         int i = 0;
347         for (AbstractCommonList.ListItem item : items) {
348             // Because movementNote is not currently a summary field
349             // (returned in summary list items), we will need to verify
350             // sort order by using the IDs provided in the summary list
351             // items to retrieve full records, amd then obtaining
352             // the value of that field from each of those records.
353             MovementsCommon movement = read(AbstractCommonListUtils.ListItemGetCSID(item));
354             firstFieldValues.add(i, movement.getMovementNote());
355             secondFieldValues.add(i, movement.getLocationDate());
356             if (logger.isDebugEnabled()) {
357                 logger.debug("list-item[" + i + "] movementNote=" + firstFieldValues.get(i));
358                 logger.debug("list-item[" + i + "] locationDate=" + secondFieldValues.get(i));
359             }
360             // Verify that the value of the specified field in the current record
361             // is less than or greater than its value in the previous record.
362             if (i > 0 && firstFieldValues.get(i) != null && firstFieldValues.get(i - 1) != null) {
363                 // Assert.assertTrue(LOCALE_SPECIFIC_COLLATOR.compare(firstFieldValues.get(i), firstFieldValues.get(i - 1)) >= 0);
364                 // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(firstFieldValues.get(i), firstFieldValues.get(i - 1)) >= 0);
365                 Assert.assertTrue(firstFieldValues.get(i).compareTo(firstFieldValues.get(i - 1)) >= 0);
366                 // If the value of the first sort field in the current record is identical to
367                 // its value in the previous record, verify that the value of the second sort
368                 // field is equal to or greater than its value in the previous record.
369                 // if (LOCALE_SPECIFIC_COLLATOR.compare(firstFieldValues.get(i), firstFieldValues.get(i - 1)) == 0) {
370                 // if (CASE_INSENSITIVE_STRING_COMPARATOR.compare(firstFieldValues.get(i), firstFieldValues.get(i - 1)) == 0) {
371                 if (firstFieldValues.get(i).compareTo(firstFieldValues.get(i - 1)) == 0) {
372                     if (i > 0 && secondFieldValues.get(i) != null && secondFieldValues.get(i - 1) != null) {
373                         // Assert.assertTrue(comparator.compare(secondFieldValues.get(i), secondFieldValues.get(i - 1)) >= 0);
374                         // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(secondFieldValues.get(i), secondFieldValues.get(i - 1)) >= 0);
375                         Assert.assertTrue(secondFieldValues.get(i).compareTo(secondFieldValues.get(i - 1)) >= 0);
376                     }
377                 }
378             }
379             i++;
380         }
381     }
382
383     /*
384      * Tests whether a list of records, sorted by one different fields in
385      * descending order and a second field in ascending order, is returned in the expected order.
386      */
387     @Test(dataProvider = "testName",
388                 dependsOnMethods = {"createList"})
389     public void sortByOneFieldAscendingOneFieldDescending(String testName) throws Exception {
390         String firstSortFieldName =
391                 asDescendingSort(qualifySortFieldName(MovementJAXBSchema.LOCATION_DATE));
392         String secondSortFieldName = qualifySortFieldName(MovementJAXBSchema.MOVEMENT_NOTE);
393         if (logger.isDebugEnabled()) {
394             logger.debug("Sorting on field names=" + firstSortFieldName + " and " + secondSortFieldName);
395         }
396         String sortExpression = firstSortFieldName + SORT_FIELD_SEPARATOR + secondSortFieldName;
397         AbstractCommonList list = readSortedList(sortExpression);
398         List<AbstractCommonList.ListItem> items =
399                 list.getListItem();
400
401         ArrayList<String> firstFieldValues = new ArrayList<String>();
402         ArrayList<String> secondFieldValues = new ArrayList<String>();
403         int i = 0;
404         for (AbstractCommonList.ListItem item : items) {
405             // Because movementNote is not currently a summary field
406             // (returned in summary list items), we will need to verify
407             // sort order by using the IDs provided in the summary list
408             // items to retrieve full records, amd then obtaining
409             // the value of that field from each of those records.
410             MovementsCommon movement = read(AbstractCommonListUtils.ListItemGetCSID(item));
411             firstFieldValues.add(i, movement.getLocationDate());
412             secondFieldValues.add(i, movement.getMovementNote());
413             if (logger.isDebugEnabled()) {
414                 logger.debug("list-item[" + i + "] locationDate=" + firstFieldValues.get(i));
415                 logger.debug("list-item[" + i + "] movementNote=" + secondFieldValues.get(i));
416             }
417             // Verify that the value of the specified field in the current record
418             // is less than or equal to than its value in the previous record.
419             if (i > 0 && firstFieldValues.get(i) != null && firstFieldValues.get(i - 1) != null) {
420                 // Assert.assertTrue(CASE_INSENSITIVE_STRING_COMPARATOR.compare(firstFieldValues.get(i), firstFieldValues.get(i - 1)) <= 0);
421                 Assert.assertTrue(firstFieldValues.get(i).compareTo(firstFieldValues.get(i - 1)) <= 0);
422                 // If the value of the first sort field in the current record is identical to
423                 // its value in the previous record, verify that the value of the second sort
424                 // field is equal to or greater than its value in the previous record,
425                 // using a locale-specific collator.
426                 // if (comparator.compare(firstFieldValues.get(i), firstFieldValues.get(i - 1)) == 0) {
427                 if (firstFieldValues.get(i).compareTo(firstFieldValues.get(i - 1)) == 0) {
428                     if (i > 0 && secondFieldValues.get(i) != null && secondFieldValues.get(i - 1) != null) {
429                         // Assert.assertTrue(LOCALE_SPECIFIC_COLLATOR.compare(secondFieldValues.get(i), secondFieldValues.get(i - 1)) >= 0);
430                         Assert.assertTrue(secondFieldValues.get(i).compareTo(secondFieldValues.get(i - 1)) >= 0);
431                     }
432                 }
433             }
434             i++;
435         }
436     }
437
438
439     /*
440      * Tests whether a request to sort by an empty field name is handled
441      * as expected: the query parameter is simply ignored, and a list
442      * of records is returned, unsorted, with a success result.
443      */
444     @Test(dataProvider = "testName")
445     public void sortWithEmptySortFieldName(String testName) throws Exception {
446         testSetup(STATUS_OK, ServiceRequestType.READ);
447
448         // Submit the request to the service and store the response.
449         MovementClient client = new MovementClient();
450         final String EMPTY_SORT_FIELD_NAME = "";
451         ClientResponse<AbstractCommonList> res =
452                 client.readListSortedBy(EMPTY_SORT_FIELD_NAME);
453         try {
454                 assertStatusCode(res, testName);
455         } finally {
456                 if (res != null) {
457                 res.releaseConnection();
458             }
459         }
460     }
461
462     // Failure outcomes
463
464     /*
465      * Tests whether a request to sort by an unqualified field name is
466      * handled as expected.  The field name provided in this test is valid,
467      * but has not been qualified by being prefixed by a schema name and delimiter.
468      */
469     @Test(dataProvider = "testName")
470     public void sortWithUnqualifiedFieldName(String testName) throws Exception {
471         testSetup(STATUS_BAD_REQUEST, ServiceRequestType.READ);
472
473         // Submit the request to the service and store the response.
474         MovementClient client = new MovementClient();
475         ClientResponse<AbstractCommonList> res =
476                 client.readListSortedBy(MovementJAXBSchema.LOCATION_DATE);
477         try {
478                 assertStatusCode(res, testName);
479         } finally {
480                 if (res != null) {
481                 res.releaseConnection();
482             }
483         }
484     }
485
486     /*
487      * Tests whether a request to sort by an invalid identifier for the
488      * sort order (ascending or descending) is handled as expected.
489      */
490     @Test(dataProvider = "testName")
491     public void sortWithInvalidSortOrderIdentifier(String testName) throws Exception {
492         testSetup(STATUS_BAD_REQUEST, ServiceRequestType.READ);
493
494         // Submit the request to the service and store the response.
495         MovementClient client = new MovementClient();
496         final String INVALID_SORT_ORDER_IDENTIFIER = "NO_DIRECTION";
497         ClientResponse<AbstractCommonList> res =
498                 client.readListSortedBy(MovementJAXBSchema.LOCATION_DATE
499                 + " " + INVALID_SORT_ORDER_IDENTIFIER);
500         try {
501                 assertStatusCode(res, testName);
502         } finally {
503                 if (res != null) {
504                 res.releaseConnection();
505             }
506         }
507     }
508
509     // ---------------------------------------------------------------
510     // Cleanup of resources created during testing
511     // ---------------------------------------------------------------
512     /**
513      * Deletes all resources created by tests, after all tests have been run.
514      *
515      * This cleanup method will always be run, even if one or more tests fail.
516      * For this reason, it attempts to remove all resources created
517      * at any point during testing, even if some of those resources
518      * may be expected to be deleted by certain tests.
519      */
520     @AfterClass(alwaysRun = true)
521     public void cleanUp() {
522         String noTest = System.getProperty("noTestCleanup");
523         if (Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
524             if (logger.isDebugEnabled()) {
525                 logger.debug("Skipping Cleanup phase ...");
526             }
527             return;
528         }
529         if (logger.isDebugEnabled()) {
530             logger.debug("Cleaning up temporary resources created for testing ...");
531         }
532         // Delete all Movement resource(s) created during this test.
533         MovementClient movementClient = new MovementClient();
534         for (String resourceId : movementIdsCreated) {
535             // Note: Any non-success responses are ignored and not reported.
536             movementClient.delete(resourceId).releaseConnection();
537         }
538     }
539
540     // ---------------------------------------------------------------
541     // Utility methods used by tests above
542     // ---------------------------------------------------------------
543
544     @Override
545     protected String getServiceName() {
546         return SERVICE_NAME;
547     }
548
549     @Override
550     public String getServicePathComponent() {
551         return SERVICE_PATH_COMPONENT;
552     }
553
554     private String getCommonSchemaName() {
555         // FIXME: While this convention - appending a suffix to the name of
556         // the service's first unique URL path component - works, it would
557         // be preferable to get the common schema name from configuration.
558         //
559         // Such configuration is provided for example, on the services side, in
560         // org.collectionspace.services.common.context.AbstractServiceContextImpl
561         return getServicePathComponent() + "_" + "common";
562     }
563
564     public String qualifySortFieldName(String fieldName) {
565         return getCommonSchemaName() + DELIMITER_SCHEMA_AND_FIELD + fieldName;
566     }
567
568     public String asDescendingSort(String qualifiedFieldName) {
569         return qualifiedFieldName + " " + KEYWORD_DESCENDING_SEARCH;
570     }
571
572     /*
573      * A data provider that provides a set of unsorted values, which are
574      * to be used in populating (seeding) values in test records.
575      *
576      * Data elements provided for each test record consist of:
577      * * An integer, reflecting expected sort order.
578      * * US English text, to populate the value of a free text (String) field.
579      * * An ISO 8601 timestamp, to populate the value of a calendar date (dateTime) field.
580      */
581     @DataProvider(name = "unsortedValues")
582     public Object[][] unsortedValues() {
583         // FIXME: ADR Add a test record-specific string so we have the option of
584         // constraining tests to only test records, in list or search results.
585         final String TEST_RECORD_SPECIFIC_STRING = CLASS_NAME + " " + TEST_SPECIFIC_KEYWORD;
586         return new Object[][]{
587                     {1, "Aardvark and plumeria. " + TEST_RECORD_SPECIFIC_STRING, "2009-01-29T00:00:05Z"},
588                     {10, "Zounds! " + TEST_RECORD_SPECIFIC_STRING, "2010-08-31T00:00:00Z"},
589                     {3, "Aardvark and plumeria. " + TEST_RECORD_SPECIFIC_STRING, "2010-08-30T00:00:00Z"},
590                     {7, "Bat fling off wall. " + TEST_RECORD_SPECIFIC_STRING, "2010-08-30T00:00:00Z"},
591                     {4, "Aardvarks and plumeria. " + TEST_RECORD_SPECIFIC_STRING, "2009-01-29T08:00:00Z"},
592                     {5, "Aardvarks and plumeria. " + TEST_RECORD_SPECIFIC_STRING, "2009-05-29T00:00:00Z"},
593                     {2, "Aardvark and plumeria. " + TEST_RECORD_SPECIFIC_STRING, "2009-05-29T00:00:00Z"},
594                     {9, "Zounds! " + TEST_RECORD_SPECIFIC_STRING, "2009-05-29T00:00:00Z"}, // Identical to next record
595                     {8, "Zounds! " + TEST_RECORD_SPECIFIC_STRING, "2009-05-29T00:00:00Z"},
596                     {6, "Bat flies off ball. " + TEST_RECORD_SPECIFIC_STRING, "2009-05-29T00:00:00Z"}
597                 };
598     }
599
600     /*
601      * Create multiple test records, initially in unsorted order,
602      * using values for various fields obtained from the data provider.
603      */
604     @Test(dataProvider = "unsortedValues")
605     public void createList(int expectedSortOrder, String movementNote,
606             String locationDate) throws Exception {
607
608         String testName = "createList";
609         if (logger.isDebugEnabled()) {
610             logger.debug(getTestBanner(testName, CLASS_NAME));
611         }
612         testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
613
614         // Iterates through the sets of values returned by the data provider,
615         // and creates a corresponding test record for each set of values.
616         create(movementNote, locationDate);
617     }
618
619     private void create(String movementNote, String locationDate) throws Exception {
620         String result = null;
621         
622         String testName = "create";
623         testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
624
625         // Submit the request to the service and store the response.
626         PoxPayloadOut multipart = createMovementInstance(createIdentifier(),
627                 movementNote, locationDate);
628         MovementClient client = new MovementClient();
629         ClientResponse<Response> res = client.create(multipart);
630         try {
631                 assertStatusCode(res, testName);
632             // Store the IDs from every resource created by tests,
633             // so they can be deleted after tests have been run.
634                 result = extractId(res);
635         } finally {
636                 if (res != null) {
637                 res.releaseConnection();
638             }
639         }
640         
641         if (result != null) {
642                 movementIdsCreated.add(result);
643         }
644     }
645
646     private MovementsCommon read(String csid) throws Exception {
647         String testName = "read";
648         testSetup(STATUS_OK, ServiceRequestType.READ);
649
650         // Submit the request to the service and store the response.
651         MovementClient client = new MovementClient();
652         ClientResponse<String> res = client.read(csid);
653         MovementsCommon movementCommon = null;
654         try {
655                 assertStatusCode(res, testName);
656                 // Extract and return the common part of the record.
657                 PoxPayloadIn input = new PoxPayloadIn(res.getEntity());
658                 PayloadInputPart payloadInputPart = input.getPart(client.getCommonPartName());
659                 if (payloadInputPart != null) {
660                         movementCommon = (MovementsCommon) payloadInputPart.getBody();
661                 }
662         } finally {
663                 if (res != null) {
664                 res.releaseConnection();
665             }
666         }
667
668         return movementCommon;
669     }
670
671     private PoxPayloadOut createMovementInstance(
672             String movementReferenceNumber,
673             String movementNote,
674             String locationDate) {
675         MovementsCommon movementCommon = new MovementsCommon();
676         movementCommon.setMovementReferenceNumber(movementReferenceNumber);
677         movementCommon.setMovementNote(movementNote);
678         movementCommon.setLocationDate(locationDate);
679
680         PoxPayloadOut multipart = new PoxPayloadOut(this.getServicePathComponent());
681         PayloadOutputPart commonPart =
682             multipart.addPart(new MovementClient().getCommonPartName(), movementCommon);
683         if (logger.isDebugEnabled()) {
684             logger.debug("to be created, movement common");
685             logger.debug(objectAsXmlString(movementCommon, MovementsCommon.class));
686         }
687
688         return multipart;
689     }
690
691     private AbstractCommonList readSortedList(String sortFieldName) throws Exception {
692         String testName = "readSortedList";
693         testSetup(STATUS_OK, ServiceRequestType.READ);
694
695         // Submit the request to the service and store the response.
696         MovementClient client = new MovementClient();
697
698         ClientResponse<AbstractCommonList> res = client.readListSortedBy(sortFieldName);
699         AbstractCommonList list = null;
700         try {
701                 assertStatusCode(res, testName);
702                 list = res.getEntity();
703         } finally {
704                 if (res != null) {
705                 res.releaseConnection();
706             }
707         }        
708
709         return list;
710
711     }
712
713     private AbstractCommonList keywordSearchSortedBy(String keywords,
714             String sortFieldName) throws Exception {
715         AbstractCommonList result = null;
716         
717         String testName = "keywordSearchSortedBy";
718         testSetup(STATUS_OK, ServiceRequestType.READ);
719
720         // Submit the request to the service and store the response.
721         MovementClient client = new MovementClient();
722
723         ClientResponse<AbstractCommonList> res =
724                 client.keywordSearchSortedBy(keywords, sortFieldName);
725         AbstractCommonList list = null;
726         try {
727                 assertStatusCode(res, testName);
728                 list = res.getEntity();
729         } finally {
730                 if (res != null) {
731                 res.releaseConnection();
732             }
733         }
734
735         return list;
736     }
737
738 }