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