]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
ffd0ee3c9c4755fab61dffd57757a24f14413536
[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     final String DELIMITER_SCHEMA_AND_FIELD = ":";
65     final String KEYWORD_DESCENDING_SEARCH = "DESC";
66     // Instance variables specific to this test.
67     final String SERVICE_PATH_COMPONENT = "movements";
68     private List<String> movementIdsCreated = new ArrayList<String>();
69
70     /* (non-Javadoc)
71      * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
72      */
73     @Override
74     protected CollectionSpaceClient getClientInstance() {
75         throw new UnsupportedOperationException(); //method not supported (or needed) in this test class
76     }
77
78     /* (non-Javadoc)
79      * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
80      */
81     @Override
82     protected AbstractCommonList getAbstractCommonList(
83             ClientResponse<AbstractCommonList> response) {
84         throw new UnsupportedOperationException(); //method not supported (or needed) in this test class
85     }
86
87     // ---------------------------------------------------------------
88     // Sort tests
89     // ---------------------------------------------------------------
90
91     // Success outcomes
92
93     /*
94      * Tests whether a list of records, sorted by a String field in
95      * ascending order, is returned in the expected order.
96      */
97     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
98     dependsOnMethods = {"createList"})
99     public void sortByStringFieldAscending(String testName) throws Exception {
100
101         if (logger.isDebugEnabled()) {
102             logger.debug(testBanner(testName, CLASS_NAME));
103         }
104
105         String sortFieldName = qualifySortFieldName(MovementJAXBSchema.MOVEMENT_NOTE);
106         if (logger.isDebugEnabled()) {
107             logger.debug("Sorting on field name=" + sortFieldName);
108         }
109         MovementsCommonList list = readSortedList(sortFieldName);
110         List<MovementsCommonList.MovementListItem> items =
111                 list.getMovementListItem();
112
113         String[] values = new String[100];
114         Collator usEnglishCollator = Collator.getInstance(Locale.US);
115         int i = 0;
116         for (MovementsCommonList.MovementListItem item : items) {
117             // Because movementNote is not currently a summary field
118             // (returned in summary list items), we will need to verify
119             // sort order by retrieving full records, using the
120             // IDs provided in the summary list items. amd then retriving
121             // the value of that field from each of those records.
122             MovementsCommon movement = read(item.getCsid());
123             values[i] = movement.getMovementNote();
124             if (logger.isDebugEnabled()) {
125                 logger.debug("list-item[" + i + "] movementNote=" + values[i]);
126             }
127             // Verify that the value of the specified field in the current record
128             // is equal to or greater than its value in the previous record,
129             // using a locale-specific collator.
130             //
131             // (Note: when used with certain text, this test case could potentially
132             // reflect inconsistencies, if any, between Java's collator and the
133             // collator used for ordering by the database.  To help avoid this,
134             // it might be useful to keep test strings fairly generic.)
135             if (i > 0) {
136                 Assert.assertTrue(usEnglishCollator.compare(values[i], values[i - 1]) >= 0);
137             }
138             i++;
139         }
140
141     }
142
143     /*
144      * Tests whether a list of records, sorted by a String field in
145      * descending order, is returned in the expected order.
146      */
147     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
148     dependsOnMethods = {"createList"})
149     public void sortByStringFieldDescending(String testName) throws Exception {
150
151         if (logger.isDebugEnabled()) {
152             logger.debug(testBanner(testName, CLASS_NAME));
153         }
154
155         String sortFieldName =
156                 asDescendingSort(qualifySortFieldName(MovementJAXBSchema.MOVEMENT_NOTE));
157         if (logger.isDebugEnabled()) {
158             logger.debug("Sorting on field name=" + sortFieldName);
159         }
160         MovementsCommonList list = readSortedList(sortFieldName);
161         List<MovementsCommonList.MovementListItem> items =
162                 list.getMovementListItem();
163
164         String[] values = new String[100];
165         Collator usEnglishCollator = Collator.getInstance(Locale.US);
166         int i = 0;
167         for (MovementsCommonList.MovementListItem item : items) {
168             // Because movementNote is not currently a summary field
169             // (returned in summary list items), we will need to verify
170             // sort order by retrieving full records, using the
171             // IDs provided in the summary list items. amd then retriving
172             // the value of that field from each of those records.
173             MovementsCommon movement = read(item.getCsid());
174             values[i] = movement.getMovementNote();
175             if (logger.isDebugEnabled()) {
176                 logger.debug("list-item[" + i + "] movementNote=" + values[i]);
177             }
178             // Verify that the value of the specified field in the current record
179             // is less than or equal to than its value in the previous record,
180             // using a locale-specific collator.
181             //
182             // (Note: when used with certain text, this test case could potentially
183             // reflect inconsistencies, if any, between Java's collator and the
184             // collator used for ordering by the database.  To help avoid this,
185             // it might be useful to keep test strings fairly generic.)
186             if (i > 0) {
187                 Assert.assertTrue(usEnglishCollator.compare(values[i], values[i - 1]) <= 0);
188             }
189             i++;
190         }
191
192     }
193
194     /*
195      * Tests whether a list of records, sorted by a dateTime field in
196      * ascending order, is returned in the expected order.
197      */
198     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
199     dependsOnMethods = {"createList"})
200     public void sortByDateTimeFieldAscending(String testName) throws Exception {
201
202         if (logger.isDebugEnabled()) {
203             logger.debug(testBanner(testName, CLASS_NAME));
204         }
205
206         String sortFieldName = qualifySortFieldName(MovementJAXBSchema.LOCATION_DATE);
207         if (logger.isDebugEnabled()) {
208             logger.debug("Sorting on field name=" + sortFieldName);
209         }
210         MovementsCommonList list = readSortedList(sortFieldName);
211         List<MovementsCommonList.MovementListItem> items =
212                 list.getMovementListItem();
213
214         String[] values = new String[100];
215         Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
216         int i = 0;
217         for (MovementsCommonList.MovementListItem item : items) {
218             values[i] = item.getLocationDate();
219             if (logger.isDebugEnabled()) {
220                 logger.debug("list-item[" + i + "] locationDate=" + values[i]);
221             }
222             // Verify that the value of the specified field in the current record
223             // is equal to or greater than its value in the previous record.
224             if (i > 0) {
225                 Assert.assertTrue(comparator.compare(values[i], values[i - 1]) >= 0);
226             }
227             i++;
228         }
229     }
230
231     /*
232      * Tests whether a list of records, sorted by a dateTime field in
233      * descending order, is returned in the expected order.
234      */
235     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
236     dependsOnMethods = {"createList"})
237     public void sortByDateTimeFieldDescending(String testName) throws Exception {
238
239         if (logger.isDebugEnabled()) {
240             logger.debug(testBanner(testName, CLASS_NAME));
241         }
242
243         String sortFieldName =
244                 asDescendingSort(qualifySortFieldName(MovementJAXBSchema.LOCATION_DATE));
245         if (logger.isDebugEnabled()) {
246             logger.debug("Sorting on field name=" + sortFieldName);
247         }
248         MovementsCommonList list = readSortedList(sortFieldName);
249         List<MovementsCommonList.MovementListItem> items =
250                 list.getMovementListItem();
251
252         String[] values = new String[100];
253         Comparator<String> comparator = String.CASE_INSENSITIVE_ORDER;
254         int i = 0;
255         for (MovementsCommonList.MovementListItem item : items) {
256             values[i] = item.getLocationDate();
257             if (logger.isDebugEnabled()) {
258                 logger.debug("list-item[" + i + "] locationDate=" + values[i]);
259             }
260             // Verify that the value of the specified field in the current record
261             // is less than or equal to its value in the previous record.
262             if (i > 0) {
263                 Assert.assertTrue(comparator.compare(values[i], values[i - 1]) <= 1);
264             }
265             i++;
266         }
267     }
268
269     /*
270      * Tests whether a request to sort by an empty field name is handled
271      * as expected: the query parameter is simply ignored, and a list
272      * of records is returned, unsorted, with a success result.
273      */
274     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
275     public void sortWithEmptySortFieldName(String testName) throws Exception {
276
277         if (logger.isDebugEnabled()) {
278             logger.debug(testBanner(testName, CLASS_NAME));
279         }
280         testSetup(STATUS_OK, ServiceRequestType.READ);
281
282         // Submit the request to the service and store the response.
283         MovementClient client = new MovementClient();
284         final String EMPTY_SORT_FIELD_NAME = "";
285         ClientResponse<MovementsCommonList> res =
286                 client.readListSortedBy(EMPTY_SORT_FIELD_NAME);
287         int statusCode = res.getStatus();
288
289         // Check the status code of the response: does it match
290         // the expected response(s)?
291         if (logger.isDebugEnabled()) {
292             logger.debug(testName + ": status = " + statusCode);
293         }
294         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
295                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
296         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
297
298     }
299
300     // Failure outcomes
301
302     /*
303      * Tests whether a request to sort by an unqualified field name is
304      * handled as expected.  The field name provided in this test is valid,
305      * but has not been qualified by being prefixed by a schema name and delimiter.
306      */
307     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
308     public void sortWithUnqualifiedFieldName(String testName) throws Exception {
309
310         if (logger.isDebugEnabled()) {
311             logger.debug(testBanner(testName, CLASS_NAME));
312         }
313         // FIXME: Ultimately, this should return a BAD_REQUEST status.
314         testSetup(STATUS_INTERNAL_SERVER_ERROR, ServiceRequestType.READ);
315
316         // Submit the request to the service and store the response.
317         MovementClient client = new MovementClient();
318         ClientResponse<MovementsCommonList> res =
319                 client.readListSortedBy(MovementJAXBSchema.LOCATION_DATE);
320         int statusCode = res.getStatus();
321
322         // Check the status code of the response: does it match
323         // the expected response(s)?
324         if (logger.isDebugEnabled()) {
325             logger.debug(testName + ": status = " + statusCode);
326         }
327         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
328                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
329         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
330
331     }
332
333     /*
334      * Tests whether a request to sort by a malformed field name is
335      * handled as expected.
336      */
337 /*
338     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class)
339     public void sortWithMalformedFieldName(String testName) throws Exception {
340
341     // FIXME: Implement this stub method.
342
343     // FIXME: Consider splitting this test into various tests, with
344     // different malformed field name formats that might confuse parsers
345     // and/or validation code.
346
347     // FIXME: Consider fixing DocumentFilter.setSortOrder() to return
348     // an error response to this test case, then revise this test case
349     // to expect that response.
350
351     }
352 */
353
354     // ---------------------------------------------------------------
355     // Cleanup of resources created during testing
356     // ---------------------------------------------------------------
357     /**
358      * Deletes all resources created by tests, after all tests have been run.
359      *
360      * This cleanup method will always be run, even if one or more tests fail.
361      * For this reason, it attempts to remove all resources created
362      * at any point during testing, even if some of those resources
363      * may be expected to be deleted by certain tests.
364      */
365     @AfterClass(alwaysRun = true)
366     public void cleanUp() {
367         String noTest = System.getProperty("noTestCleanup");
368         if (Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
369             if (logger.isDebugEnabled()) {
370                 logger.debug("Skipping Cleanup phase ...");
371             }
372             return;
373         }
374         if (logger.isDebugEnabled()) {
375             logger.debug("Cleaning up temporary resources created for testing ...");
376         }
377         // Delete all Movement resource(s) created during this test.
378         MovementClient movementClient = new MovementClient();
379         for (String resourceId : movementIdsCreated) {
380             // Note: Any non-success responses are ignored and not reported.
381             movementClient.delete(resourceId);
382         }
383     }
384
385     // ---------------------------------------------------------------
386     // Utility methods used by tests above
387     // ---------------------------------------------------------------
388
389     @Override
390     public String getServicePathComponent() {
391         return SERVICE_PATH_COMPONENT;
392     }
393
394     private String getCommonSchemaName() {
395         // FIXME: While this convention - appending a suffix to the name of
396         // the service's first unique URL path component - works, it would
397         // be preferable to get the common schema name from configuration.
398         return getServicePathComponent() + "_" + "common";
399     }
400
401     public String qualifySortFieldName(String fieldName) {
402         return getCommonSchemaName() + DELIMITER_SCHEMA_AND_FIELD + fieldName;
403     }
404
405     public String asDescendingSort(String qualifiedFieldName) {
406         return qualifiedFieldName + " " + KEYWORD_DESCENDING_SEARCH;
407     }
408
409     /*
410      * A data provider that provides a set of unsorted values, which are
411      * to be used in populating (seeding) values in test records.
412      *
413      * Data elements provided for each test record consist of:
414      * * An integer, reflecting expected sort order.
415      * * US English text, to populate the value of a free text (String) field.
416      * * An ISO 8601 timestamp, to populate the value of a calendar date (dateTime) field.
417      */
418     @DataProvider(name = "unsortedValues")
419     public Object[][] unsortedValues() {
420         // Add a test record-specific string so we have the option of
421         // constraining tests to only test records, in list or search results.
422         final String TEST_RECORD_SPECIFIC_STRING = CLASS_NAME + " " + "jlmbsoq";
423         return new Object[][]{
424                     {1, "Aardvark and plumeria. " + TEST_RECORD_SPECIFIC_STRING, "2009-01-29T00:00:05Z"},
425                     {4, "Bat fling off wall. " + TEST_RECORD_SPECIFIC_STRING, "2010-08-30T00:00:00Z"},
426                     {2, "Aardvarks and plumeria. " + TEST_RECORD_SPECIFIC_STRING, "2009-01-29T08:00:00Z"},
427                     {5, "Zounds! " + TEST_RECORD_SPECIFIC_STRING, "2010-08-31T00:00:00Z"},
428                     {3, "Bat flies off ball. " + TEST_RECORD_SPECIFIC_STRING, "2009-05-29T00:00:00Z"}
429                 };
430     }
431
432     @Test(dataProvider = "unsortedValues")
433     public void createList(int expectedSortOrder, String movementNote,
434             String locationDate) throws Exception {
435
436         String testName = "createList";
437         if (logger.isDebugEnabled()) {
438             logger.debug(testBanner(testName, CLASS_NAME));
439         }
440         testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
441
442         // Create each unsorted record provided by the data provider.
443         create(movementNote, locationDate);
444     }
445
446     private void create(String movementNote, String locationDate) throws Exception {
447
448         String testName = "create";
449         testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
450
451         // Submit the request to the service and store the response.
452         MovementClient client = new MovementClient();
453         MultipartOutput multipart = createMovementInstance(createIdentifier(),
454                 movementNote, locationDate);
455         ClientResponse<Response> res = client.create(multipart);
456         int statusCode = res.getStatus();
457
458         // Check the status code of the response: does it match
459         // the expected response(s)?
460         //
461         // Specifically:
462         // Does it fall within the set of valid status codes?
463         // Does it exactly match the expected status code?
464         if (logger.isDebugEnabled()) {
465             logger.debug(testName + ": status = " + statusCode);
466         }
467         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
468                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
469         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
470
471         // Store the IDs from every resource created by tests,
472         // so they can be deleted after tests have been run.
473         movementIdsCreated.add(extractId(res));
474     }
475
476     private MovementsCommon read(String csid) throws Exception {
477
478         String testName = "read";
479         testSetup(STATUS_OK, ServiceRequestType.READ);
480
481         // Submit the request to the service and store the response.
482         MovementClient client = new MovementClient();
483         ClientResponse<MultipartInput> res = client.read(csid);
484         int statusCode = res.getStatus();
485
486         // Check the status code of the response: does it match
487         // the expected response(s)?
488         if (logger.isDebugEnabled()) {
489             logger.debug(testName + ": status = " + statusCode);
490         }
491         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
492                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
493         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
494
495         // Extract and return the common part of the record.
496         MultipartInput input = (MultipartInput) res.getEntity();
497         MovementsCommon movement = (MovementsCommon) extractPart(input,
498                 client.getCommonPartName(), MovementsCommon.class);
499
500         return movement;
501     }
502
503     private MultipartOutput createMovementInstance(
504             String movementReferenceNumber,
505             String movementNote,
506             String locationDate) {
507         MovementsCommon movement = new MovementsCommon();
508         movement.setMovementReferenceNumber(movementReferenceNumber);
509         movement.setMovementNote(movementNote);
510         movement.setLocationDate(locationDate);
511         MultipartOutput multipart = new MultipartOutput();
512         OutputPart commonPart =
513                 multipart.addPart(movement, MediaType.APPLICATION_XML_TYPE);
514         commonPart.getHeaders().add("label", new MovementClient().getCommonPartName());
515
516         if (logger.isDebugEnabled()) {
517             logger.debug("to be created, movement common");
518             logger.debug(objectAsXmlString(movement, MovementsCommon.class));
519         }
520
521         return multipart;
522     }
523
524     private MovementsCommonList readSortedList(String sortFieldName) throws Exception {
525
526         String testName = "readSortedList";
527         testSetup(STATUS_OK, ServiceRequestType.READ);
528
529         // Submit the request to the service and store the response.
530         MovementClient client = new MovementClient();
531
532         ClientResponse<MovementsCommonList> res =
533                 client.readListSortedBy(sortFieldName);
534         MovementsCommonList list = res.getEntity();
535         int statusCode = res.getStatus();
536
537         // Check the status code of the response: does it match
538         // the expected response(s)?
539         if (logger.isDebugEnabled()) {
540             logger.debug(testName + ": status = " + statusCode);
541         }
542         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
543                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
544         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
545
546         return list;
547
548     }
549
550 }