]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
eec82ec743a02b324a0b3202bc1dad10e1abf98b
[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.util.Arrays;
26 import java.util.ArrayList;
27 import java.util.List;
28 import javax.ws.rs.core.MediaType;
29 import javax.ws.rs.core.Response;
30 import org.collectionspace.services.client.CollectionObjectClient;
31 import org.collectionspace.services.client.CollectionSpaceClient;
32 import org.collectionspace.services.collectionobject.BriefDescriptionList;
33 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
34 import org.collectionspace.services.collectionobject.CollectionobjectsCommonList;
35 import org.collectionspace.services.jaxb.AbstractCommonList;
36 import org.jboss.resteasy.client.ClientResponse;
37 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
38 import org.jboss.resteasy.plugins.providers.multipart.OutputPart;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.testng.Assert;
42 import org.testng.annotations.AfterClass;
43 import org.testng.annotations.BeforeClass;
44 import org.testng.annotations.Test;
45
46 /**
47  * CollectionObjectAuthRefsTest, carries out tests against a
48  * deployed and running CollectionObject Service.
49  *
50  * $LastChangedRevision: 1327 $
51  * $LastChangedDate: 2010-02-12 10:35:11 -0800 (Fri, 12 Feb 2010) $
52  */
53 public class CollectionObjectSearchTest extends BaseServiceTest {
54
55    /** The logger. */
56     private final String CLASS_NAME = CollectionObjectSearchTest.class.getName();
57     private final Logger logger = LoggerFactory.getLogger(CLASS_NAME);
58
59     final static String IDENTIFIER = getSystemTimeIdentifier();
60     final static String KEYWORD = "Tsolyani" + IDENTIFIER;
61     final static List<String> TWO_KEYWORDS =
62             Arrays.asList(new String[]{"Cheggarra" + IDENTIFIER, "Ahoggya" + IDENTIFIER});
63     final static List<String> TWO_MORE_KEYWORDS =
64             Arrays.asList(new String[]{"Karihaya" + IDENTIFIER, "Hlikku" + IDENTIFIER});
65     final static String NOISE_WORD = "Mihalli + IDENTIFIER";
66     final static String NON_EXISTENT_KEYWORD = "jlmbsoqjlmbsoq";
67     final static String KEYWORD_SEPARATOR = " ";
68     final long numNoiseWordResources = 10;
69     final double pctNonNoiseWordResources = 0.5;
70
71     /* Use this to keep track of resources to delete */
72     private List<String> allResourceIdsCreated = new ArrayList<String>();
73
74     /* (non-Javadoc)
75      * @see org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
76      */
77     @Override
78     protected String getServicePathComponent() {
79         return new CollectionObjectClient().getServicePathComponent();
80     }
81
82     /* (non-Javadoc)
83      * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
84      */
85     @Override
86     protected CollectionSpaceClient getClientInstance() {
87         return new CollectionObjectClient();
88     }
89
90     /* (non-Javadoc)
91      * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
92      */
93     @Override
94     protected AbstractCommonList getAbstractCommonList(ClientResponse<AbstractCommonList> response) {
95         return response.getEntity(CollectionobjectsCommonList.class);
96     }
97
98     /**
99      * Creates one or more resources containing a "noise" keyword,
100      * which should NOT be retrieved by keyword searches.
101      *
102      * This also helps ensure that searches will not fail, due
103      * to a database-specific constraint or otherwise, if the
104      * number of records retrieved by a particular keyword represent
105      * too high a proportion of the total records retrieved.
106      */
107     @BeforeClass(alwaysRun=true)
108     public void setup() {
109         if (logger.isDebugEnabled()) {
110             logger.debug("Creating " + numNoiseWordResources +
111                 " 'noise word' resources ...");
112         }
113         createCollectionObjects(numNoiseWordResources, NOISE_WORD);
114     }
115
116
117     // ---------------------------------------------------------------
118     // Search tests
119     // ---------------------------------------------------------------
120
121     // Success outcomes
122
123     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
124         groups = {"oneKeyword"})
125     public void searchWithOneKeyword(String testName) throws Exception {
126
127         if (logger.isDebugEnabled()) {
128             logger.debug(testBanner(testName, CLASS_NAME));
129         }
130
131         // Create one or more keyword retrievable resources, each containing
132         // a specified keyword.
133         long numKeywordRetrievableResources =
134                 (long) (numNoiseWordResources * pctNonNoiseWordResources);
135         if (logger.isDebugEnabled()) {
136             logger.debug("Creating " + numKeywordRetrievableResources +
137                 " keyword-retrievable resources ...");
138         }
139         createCollectionObjects(numKeywordRetrievableResources, KEYWORD);
140         
141         // Set the expected status code and group of valid status codes
142         testSetup(STATUS_OK, ServiceRequestType.SEARCH);
143
144         // Send the search request and receive a response
145         ClientResponse<CollectionobjectsCommonList> res = doSearch(KEYWORD);
146         int statusCode = res.getStatus();
147
148         // Check the status code of the response: does it match
149         // the expected response(s)?
150         if (logger.isDebugEnabled()) {
151             logger.debug(testName + ": status = " + statusCode);
152         }
153         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
154                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
155         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
156
157         // Verify that the number of resources matched by the search
158         // is identical to the expected result
159         long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
160         long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED);
161         Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
162     }
163
164     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class)
165     public void searchWithTwoKeywordsInSameField(String testName) throws Exception {
166
167         if (logger.isDebugEnabled()) {
168             logger.debug(testBanner(testName, CLASS_NAME));
169         }
170
171         // Create one or more keyword retrievable resources, each containing
172         // two specified keywords.
173         long numKeywordRetrievableResources =
174                 (long) (numNoiseWordResources * pctNonNoiseWordResources);
175         if (logger.isDebugEnabled()) {
176             logger.debug("Creating " + numKeywordRetrievableResources +
177                 " keyword-retrievable resources ...");
178         }
179         boolean keywordsInSameField = true;
180         createCollectionObjects(numKeywordRetrievableResources, TWO_KEYWORDS, keywordsInSameField);
181
182         // Set the expected status code and group of valid status codes
183         testSetup(STATUS_OK, ServiceRequestType.SEARCH);
184
185         // Search using both terms
186
187         // Send the search request and receive a response
188         ClientResponse<CollectionobjectsCommonList> res = doSearch(TWO_KEYWORDS);
189         int statusCode = res.getStatus();
190
191         // Check the status code of the response: does it match
192         // the expected response(s)?
193         if (logger.isDebugEnabled()) {
194             logger.debug(testName + ": status = " + statusCode);
195         }
196         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
197                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
198         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
199
200         // Verify that the number of resources matched by the search
201         // is identical to the expected result
202         long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
203         long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED);
204         Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
205
206         // Search using a single term
207
208         // Send the search request and receive a response
209         res = doSearch(TWO_KEYWORDS.get(0));
210         statusCode = res.getStatus();
211
212         // Check the status code of the response: does it match
213         // the expected response(s)?
214         if (logger.isDebugEnabled()) {
215             logger.debug(testName + ": status = " + statusCode);
216         }
217         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
218                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
219         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
220
221         // Verify that the number of resources matched by the search
222         // is identical to the expected result
223         NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
224         numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED);
225         Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
226
227     }
228
229     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class)
230     public void searchWithTwoKeywordsAcrossTwoFields(String testName) throws Exception {
231
232         if (logger.isDebugEnabled()) {
233             logger.debug(testBanner(testName, CLASS_NAME));
234         }
235
236         // Create one or more keyword retrievable resources, each containing
237         // two specified keywords.
238         long numKeywordRetrievableResources = 5;
239         if (logger.isDebugEnabled()) {
240             logger.debug("Creating " + numKeywordRetrievableResources +
241                 " keyword-retrievable resources ...");
242         }
243         boolean keywordsInSameField = false;
244         createCollectionObjects(numKeywordRetrievableResources, TWO_MORE_KEYWORDS, keywordsInSameField);
245
246         // Set the expected status code and group of valid status codes
247         testSetup(STATUS_OK, ServiceRequestType.SEARCH);
248
249         // Search using both terms
250
251         // Send the search request and receive a response
252         ClientResponse<CollectionobjectsCommonList> res = doSearch(TWO_MORE_KEYWORDS);
253         int statusCode = res.getStatus();
254
255         // Check the status code of the response: does it match
256         // the expected response(s)?
257         if (logger.isDebugEnabled()) {
258             logger.debug(testName + ": status = " + statusCode);
259         }
260         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
261                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
262         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
263
264         // Verify that the number of resources matched by the search
265         // is identical to the expected result
266         long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
267         long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED);
268         Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
269
270         // Search using a single term
271
272         // Send the search request and receive a response
273         res = doSearch(TWO_MORE_KEYWORDS.get(0));
274         statusCode = res.getStatus();
275
276         // Check the status code of the response: does it match
277         // the expected response(s)?
278         if (logger.isDebugEnabled()) {
279             logger.debug(testName + ": status = " + statusCode);
280         }
281         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
282                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
283         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
284
285         // Verify that the number of resources matched by the search
286         // is identical to the expected result
287         NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
288         numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED);
289         Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
290
291     }
292
293 //    @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class)
294 //    public void searchWithOneKeywordInRepeatableScalarField(String testName) throws Exception {
295 //    }
296
297     // Failure outcomes
298
299     // FIXME: Rename to searchWithNonExistentKeyword
300     @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class)
301     public void keywordSearchNonExistentKeyword(String testName) throws Exception {
302
303         if (logger.isDebugEnabled()) {
304             logger.debug(testBanner(testName, CLASS_NAME));
305         }
306
307         // Set the expected status code and group of valid status codes
308         testSetup(STATUS_OK, ServiceRequestType.SEARCH);
309
310         // Send the search request and receive a response
311         ClientResponse<CollectionobjectsCommonList> res = doSearch(NON_EXISTENT_KEYWORD);
312         int statusCode = res.getStatus();
313
314         // Check the status code of the response: does it match
315         // the expected response(s)?
316         if (logger.isDebugEnabled()) {
317             logger.debug(testName + ": status = " + statusCode);
318         }
319         Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
320                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
321         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
322
323         // Verify that the number of resources matched by the search
324         // is identical to the expected result
325         long NUM_MATCHES_EXPECTED = 0;
326         long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED);
327         Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
328
329     }
330
331     // ---------------------------------------------------------------
332     // Cleanup of resources created during testing
333     // ---------------------------------------------------------------
334
335     /**
336      * Deletes all resources created by setup and tests, after all tests have been run.
337      *
338      * This cleanup method will always be run, even if one or more tests fail.
339      * For this reason, it attempts to remove all resources created
340      * at any point during testing, even if some of those resources
341      * may be expected to be deleted by certain tests.
342      */
343     @AfterClass(alwaysRun=true)
344     public void cleanUp() {
345         String noTest = System.getProperty("noTestCleanup");
346         if(Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
347             if (logger.isDebugEnabled()) {
348                 logger.debug("Skipping Cleanup phase ...");
349             }
350             return;
351         }
352         if (logger.isDebugEnabled()) {
353             logger.debug("Cleaning up temporary resources created for testing ...");
354         }
355         CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
356         for (String resourceId : allResourceIdsCreated) {
357             // Note: Any non-success responses are ignored and not reported.
358             collectionObjectClient.delete(resourceId).releaseConnection();
359         }
360     }
361
362     // ---------------------------------------------------------------
363     // Utility methods used by tests above
364     // ---------------------------------------------------------------
365     
366     private void createCollectionObjects(long numToCreate, String keyword) {
367         List keywords = new ArrayList<String>();
368         keywords.add(keyword);
369         boolean keywordsInSameField = true;
370         createCollectionObjects(numToCreate, keywords, keywordsInSameField);
371     }
372     
373     private void createCollectionObjects(long numToCreate, List<String> keywords,
374             boolean keywordsInSameField) {
375         testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
376         CollectionObjectClient client = new CollectionObjectClient();
377         for (long i = 0; i < numToCreate; i++) {
378             MultipartOutput multipart =
379                     createCollectionObjectInstance(i, keywords, keywordsInSameField);
380             ClientResponse<Response> res = client.create(multipart);
381             try {
382                 int statusCode = res.getStatus();
383                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
384                 String id = extractId(res);
385                 allResourceIdsCreated.add(id);
386                 if (logger.isDebugEnabled()) {
387                     logger.debug("Created new resource [" + i + "] with ID " + id);
388                 }
389             } finally {
390                 res.releaseConnection();
391             }
392         }
393     }
394     
395     private MultipartOutput createCollectionObjectInstance(long i, List<String> keywords,
396             boolean keywordsInSameField) {
397         CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
398         collectionObject.setObjectNumber(createIdentifier());
399         if (keywordsInSameField) {
400             collectionObject.setTitle(listToString(keywords, KEYWORD_SEPARATOR));
401         } else {
402             if (keywords.size() == 1) {
403                 collectionObject.setTitle(keywords.get(0));
404             } else if (keywords.size() == 2) {
405                 collectionObject.setTitle(keywords.get(0));
406                 collectionObject.setDistinguishingFeatures(keywords.get(1));
407             } else {
408                 Assert.fail("List of keywords must have exactly one or two members.");
409             }
410         }
411         MultipartOutput multipart = new MultipartOutput();
412         OutputPart commonPart = multipart.addPart(collectionObject,
413                 MediaType.APPLICATION_XML_TYPE);
414         commonPart.getHeaders().add("label", new CollectionObjectClient().getCommonPartName());
415         return multipart;
416     }
417
418     private static String listToString(List<String> list, String separator) {
419         StringBuffer sb = new StringBuffer();
420         if (list.size() > 0) {
421             sb.append(list.get(0));
422             for (int i=1; i < list.size(); i++) {
423                 sb.append(separator);
424                 sb.append(list.get(i));
425             }
426         }
427         return sb.toString();
428     }
429
430     private ClientResponse<CollectionobjectsCommonList> doSearch(List<String> keywords) {
431         String searchParamValue = listToString(keywords, KEYWORD_SEPARATOR);
432         return doSearch(searchParamValue);
433     }
434
435     private ClientResponse<CollectionobjectsCommonList> doSearch(String keyword) {
436        String searchParamValue = keyword;
437         if (logger.isDebugEnabled()) {
438             logger.debug("Searching on keyword(s): " + searchParamValue + " ...");
439         }
440         CollectionObjectClient client = new CollectionObjectClient();
441         ClientResponse<CollectionobjectsCommonList> res =
442             client.keywordSearch(searchParamValue);
443         return res;
444     }
445
446     private long getNumMatched(ClientResponse<CollectionobjectsCommonList> res,
447             long numExpectedMatches) {
448         CollectionobjectsCommonList list = (CollectionobjectsCommonList)
449             res.getEntity(CollectionobjectsCommonList.class);
450         long numMatched = list.getTotalItems();
451
452         if (logger.isDebugEnabled()) {
453             logger.debug("Keyword search matched " + numMatched +
454                 " resources, expected to match " + numExpectedMatches);
455         }
456
457         // Optionally output additional data about list members for debugging.
458         boolean iterateThroughList = false;
459         if (iterateThroughList && logger.isDebugEnabled()) {
460             itemizeListItems(list);
461         }
462         return numMatched;
463     }
464
465     private void itemizeListItems(CollectionobjectsCommonList list) {
466         List<CollectionobjectsCommonList.CollectionObjectListItem> items =
467             list.getCollectionObjectListItem();
468         int i = 0;
469         for (CollectionobjectsCommonList.CollectionObjectListItem item : items) {
470             logger.debug("list-item[" + i + "] title="
471                     + item.getTitle());
472             logger.debug("list-item[" + i + "] URI="
473                     + item.getUri());
474             i++;
475         }
476     }
477
478     public static String getSystemTimeIdentifier() {
479       return Long.toString(System.currentTimeMillis());
480     }
481
482 }