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