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