]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
94d44e92184ccea579aaaf9fde9fda41fd227960
[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
31 import org.collectionspace.services.CollectionObjectJAXBSchema;
32 import org.collectionspace.services.client.AbstractCommonListUtils;
33 import org.collectionspace.services.client.CollectionObjectClient;
34 import org.collectionspace.services.client.CollectionSpaceClient;
35 import org.collectionspace.services.client.PayloadOutputPart;
36 import org.collectionspace.services.client.PoxPayloadOut;
37 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
38 import org.collectionspace.services.jaxb.AbstractCommonList;
39
40 import org.jboss.resteasy.client.ClientResponse;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.testng.Assert;
44 import org.testng.annotations.AfterClass;
45 import org.testng.annotations.BeforeClass;
46 import org.testng.annotations.Test;
47
48 /**
49  * CollectionObjectSearchTest, carries out tests of keyword search functionality
50  * against a deployed and running CollectionObject Service.
51  * 
52  * $LastChangedRevision: 1327 $ $LastChangedDate: 2010-02-12 10:35:11 -0800
53  * (Fri, 12 Feb 2010) $
54  */
55 public class CollectionObjectSearchTest extends BaseServiceTest<AbstractCommonList> {
56
57         /** The logger. */
58         private final String CLASS_NAME = CollectionObjectSearchTest.class
59                         .getName();
60         private final Logger logger = LoggerFactory.getLogger(CLASS_NAME);
61         final static String IDENTIFIER = getSystemTimeIdentifier();
62         final static String KEYWORD_SEPARATOR = " ";
63         final long numNoiseWordResources = 10;
64         final double pctNonNoiseWordResources = 0.5;
65         // Use this to keep track of resources to delete
66         private List<String> allResourceIdsCreated = new ArrayList<String>();
67
68         // Constants for data used in search testing
69
70         // Test keywords unlikely to be encountered in actual collections data,
71         // consisting of the names of mythical creatures in a 1970s role-playing
72         // game, which result in very few 'hits' in Google searches.
73         final static String KEYWORD = "Tsolyani" + IDENTIFIER;
74         final static List<String> TWO_KEYWORDS = Arrays.asList(new String[] {
75                         "Cheggarra" + IDENTIFIER, "Ahoggya" + IDENTIFIER });
76         final static List<String> TWO_MORE_KEYWORDS = Arrays.asList(new String[] {
77                         "Karihaya" + IDENTIFIER, "Hlikku" + IDENTIFIER });
78         final static String NOISE_WORD = "Mihalli + IDENTIFIER";
79         // Test Unicode UTF-8 term for keyword searching: a random sequence,
80         // unlikely to be encountered in actual collections data, of two USASCII
81         // characters followed by four non-USASCII range Unicode UTF-8 characters:
82         //
83         // Δ : Greek capital letter Delta (U+0394)
84         // Ж : Cyrillic capital letter Zhe with breve (U+04C1)
85         // Ŵ : Latin capital letter W with circumflex (U+0174)
86         // Ω : Greek capital letter Omega (U+03A9)
87         final String UTF8_KEYWORD = "to" + '\u0394' + '\u04C1' + '\u0174'
88                         + '\u03A9';
89         // Non-existent term unlikely to be encountered in actual collections
90         // data, consisting of two back-to-back sets of the first letters of
91         // each of the words in a short pangram for the English alphabet.
92         final static String NON_EXISTENT_KEYWORD = "jlmbsoqjlmbsoq";
93
94         @Override
95         protected String getServiceName() {
96                 throw new UnsupportedOperationException(); // FIXME: REM - See
97                                                                                                         // http://issues.collectionspace.org/browse/CSPACE-3498
98         }
99
100         @Override
101         protected String getServicePathComponent() {
102                 // TODO Auto-generated method stub
103                 throw new UnsupportedOperationException(); // FIXME: REM - See
104                                                                                                         // http://issues.collectionspace.org/browse/CSPACE-3498
105         }
106
107         // /* (non-Javadoc)
108         // * @see
109         // org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
110         // */
111         // @Override
112         // protected String getServicePathComponent() {
113         // return new CollectionObjectClient().getServicePathComponent(); //FIXME:
114         // REM = Remove all refs to this method.
115         // }
116
117         /*
118          * (non-Javadoc)
119          * 
120          * @see
121          * org.collectionspace.services.client.test.BaseServiceTest#getClientInstance
122          * ()
123          */
124         @Override
125         protected CollectionSpaceClient getClientInstance() {
126                 return new CollectionObjectClient();
127         }
128         
129         /**
130          * Creates one or more resources containing a "noise" keyword, which should
131          * NOT be retrieved by keyword searches.
132          * 
133          * This also helps ensure that searches will not fail, due to a
134          * database-specific constraint or otherwise, if the number of records
135          * containing a particular keyword represent too high a proportion of the
136          * total number of records.
137          */
138         @BeforeClass(alwaysRun = true)
139         public void setup() {
140                 if (logger.isDebugEnabled()) {
141                         logger.debug("Creating " + numNoiseWordResources
142                                         + " 'noise word' resources ...");
143                 }
144                 createCollectionObjects(numNoiseWordResources, NOISE_WORD);
145         }
146
147         // ---------------------------------------------------------------
148         // Search tests
149         // ---------------------------------------------------------------
150         // Success outcomes
151
152         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, groups = { "advancedSearch" })
153         public void advancedSearch(String testName) throws Exception {
154                 // Create one or more keyword retrievable resources, each containing
155                 // a specified keyword.
156                 String theKeyword = KEYWORD + "COW";
157                 long numKeywordRetrievableResources = 1;
158                 createCollectionObjects(numKeywordRetrievableResources, theKeyword);
159
160                 // Set the expected status code and group of valid status codes
161                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
162
163                 // Send the search request and receive a response
164                 String propertyName = CollectionObjectClient.SERVICE_COMMON_PART_NAME + ":" +
165                         CollectionObjectJAXBSchema.DISTINGUISHING_FEATURES;
166                 String propertyValue = theKeyword;
167                 ClientResponse<AbstractCommonList> res = doAdvancedSearch(propertyName, propertyValue, "=");
168                 int statusCode = res.getStatus();
169
170                 // Check the status code of the response: does it match
171                 // the expected response(s)?
172                 if (logger.isDebugEnabled()) {
173                         logger.debug(testName + ": status = " + statusCode);
174                 }
175                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
176                                 invalidStatusCodeMessage(testRequestType, statusCode));
177                 Assert.assertEquals(statusCode, testExpectedStatusCode);
178
179                 // Verify that the number of resources matched by the search
180                 // is identical to the expected result
181                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
182                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
183                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
184         }
185
186         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, groups = { "oneKeyword" })
187         public void searchWithOneKeyword(String testName) throws Exception {
188                 // Create one or more keyword retrievable resources, each containing
189                 // a specified keyword.
190                 long numKeywordRetrievableResources = (long) (numNoiseWordResources * pctNonNoiseWordResources);
191                 if (logger.isDebugEnabled()) {
192                         logger.debug("Creating " + numKeywordRetrievableResources
193                                         + " keyword-retrievable resources ...");
194                 }
195                 createCollectionObjects(numKeywordRetrievableResources, KEYWORD);
196
197                 // Set the expected status code and group of valid status codes
198                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
199
200                 // Send the search request and receive a response
201                 ClientResponse<AbstractCommonList> res = doSearch(KEYWORD);
202                 int statusCode = res.getStatus();
203
204                 // Check the status code of the response: does it match
205                 // the expected response(s)?
206                 if (logger.isDebugEnabled()) {
207                         logger.debug(testName + ": status = " + statusCode);
208                 }
209                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
210                                 invalidStatusCodeMessage(testRequestType, statusCode));
211                 Assert.assertEquals(statusCode, testExpectedStatusCode);
212
213                 // Verify that the number of resources matched by the search
214                 // is identical to the expected result
215                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
216                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
217                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
218         }
219
220         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
221         public void searchWithTwoKeywordsInSameField(String testName)
222                         throws Exception {
223                 // Create one or more keyword retrievable resources, each containing
224                 // two specified keywords.
225                 long numKeywordRetrievableResources = (long) (numNoiseWordResources * pctNonNoiseWordResources);
226                 if (logger.isDebugEnabled()) {
227                         logger.debug("Creating " + numKeywordRetrievableResources
228                                         + " keyword-retrievable resources ...");
229                 }
230                 boolean keywordsInSameField = true;
231                 createCollectionObjects(numKeywordRetrievableResources, TWO_KEYWORDS,
232                                 keywordsInSameField);
233
234                 // Set the expected status code and group of valid status codes
235                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
236
237                 // Search using both terms
238
239                 // Send the search request and receive a response
240                 ClientResponse<AbstractCommonList> res = doSearch(TWO_KEYWORDS);
241                 int statusCode = res.getStatus();
242
243                 // Check the status code of the response: does it match
244                 // the expected response(s)?
245                 if (logger.isDebugEnabled()) {
246                         logger.debug(testName + ": status = " + statusCode);
247                 }
248                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
249                                 invalidStatusCodeMessage(testRequestType, statusCode));
250                 Assert.assertEquals(statusCode, testExpectedStatusCode);
251
252                 // Verify that the number of resources matched by the search
253                 // is identical to the expected result
254                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
255                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
256                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
257
258                 // Search using a single term
259
260                 // Send the search request and receive a response
261                 res = doSearch(TWO_KEYWORDS.get(0));
262                 statusCode = res.getStatus();
263
264                 // Check the status code of the response: does it match
265                 // the expected response(s)?
266                 if (logger.isDebugEnabled()) {
267                         logger.debug(testName + ": status = " + statusCode);
268                 }
269                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
270                                 invalidStatusCodeMessage(testRequestType, statusCode));
271                 Assert.assertEquals(statusCode, testExpectedStatusCode);
272
273                 // Verify that the number of resources matched by the search
274                 // is identical to the expected result
275                 NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
276                 numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
277                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
278
279         }
280
281         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
282         public void searchWithTwoKeywordsAcrossTwoFields(String testName)
283                         throws Exception {
284                 // Create one or more keyword retrievable resources, each containing
285                 // two specified keywords.
286                 long numKeywordRetrievableResources = 5;
287                 if (logger.isDebugEnabled()) {
288                         logger.debug("Creating " + numKeywordRetrievableResources
289                                         + " keyword-retrievable resources ...");
290                 }
291                 boolean keywordsInSameField = false;
292                 createCollectionObjects(numKeywordRetrievableResources,
293                                 TWO_MORE_KEYWORDS, keywordsInSameField);
294
295                 // Set the expected status code and group of valid status codes
296                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
297
298                 // Search using both terms
299
300                 // Send the search request and receive a response
301                 ClientResponse<AbstractCommonList> res = doSearch(TWO_MORE_KEYWORDS);
302                 int statusCode = res.getStatus();
303
304                 // Check the status code of the response: does it match
305                 // the expected response(s)?
306                 if (logger.isDebugEnabled()) {
307                         logger.debug(testName + ": status = " + statusCode);
308                 }
309                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
310                                 invalidStatusCodeMessage(testRequestType, statusCode));
311                 Assert.assertEquals(statusCode, testExpectedStatusCode);
312
313                 // Verify that the number of resources matched by the search
314                 // is identical to the expected result
315                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
316                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
317                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
318
319                 // Search using a single term
320
321                 // Send the search request and receive a response
322                 res = doSearch(TWO_MORE_KEYWORDS.get(0));
323                 statusCode = res.getStatus();
324
325                 // Check the status code of the response: does it match
326                 // the expected response(s)?
327                 if (logger.isDebugEnabled()) {
328                         logger.debug(testName + ": status = " + statusCode);
329                 }
330                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
331                                 invalidStatusCodeMessage(testRequestType, statusCode));
332                 Assert.assertEquals(statusCode, testExpectedStatusCode);
333
334                 // Verify that the number of resources matched by the search
335                 // is identical to the expected result
336                 NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
337                 numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
338                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
339
340         }
341
342         // @Test(dataProvider="testName",
343         // dataProviderClass=AbstractServiceTestImpl.class)
344         // public void searchWithOneKeywordInRepeatableScalarField(String testName)
345         // throws Exception {
346         // BriefDescriptionList descriptionList = new BriefDescriptionList();
347         // List<String> descriptions = descriptionList.getBriefDescription();
348         // if (TWO_KEYWORDS.size() >= 2) {
349         // descriptions.add(TWO_KEYWORDS.get(0));
350         // descriptions.add(TWO_KEYWORDS.get(1));
351         // }
352         // }
353         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, groups = { "utf8" })
354         public void searchWithUTF8Keyword(String testName) {
355                 // Create one or more keyword retrievable resources, each containing
356                 // two specified keywords.
357                 long numKeywordRetrievableResources = 2;
358                 if (logger.isDebugEnabled()) {
359                         logger.debug("Creating " + numKeywordRetrievableResources
360                                         + " keyword-retrievable resources ...");
361                 }
362                 createCollectionObjects(numKeywordRetrievableResources, UTF8_KEYWORD);
363
364                 // Set the expected status code and group of valid status codes
365                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
366
367                 // Send the search request and receive a response
368                 ClientResponse<AbstractCommonList> res = doSearch(UTF8_KEYWORD);
369                 int statusCode = res.getStatus();
370
371                 // Check the status code of the response: does it match
372                 // the expected response(s)?
373                 if (logger.isDebugEnabled()) {
374                         logger.debug(testName + ": status = " + statusCode);
375                 }
376                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
377                                 invalidStatusCodeMessage(testRequestType, statusCode));
378                 Assert.assertEquals(statusCode, testExpectedStatusCode);
379
380                 // Verify that the number of resources matched by the search
381                 // is identical to the expected result
382                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
383                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
384                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
385         }
386
387         // Failure outcomes
388         // FIXME: Rename to searchWithNonExistentKeyword
389         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
390         public void keywordSearchNonExistentKeyword(String testName)
391                         throws Exception {
392                 // Set the expected status code and group of valid status codes
393                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
394
395                 // Send the search request and receive a response
396                 ClientResponse<AbstractCommonList> res = doSearch(NON_EXISTENT_KEYWORD);
397                 int statusCode = res.getStatus();
398
399                 // Check the status code of the response: does it match
400                 // the expected response(s)?
401                 if (logger.isDebugEnabled()) {
402                         logger.debug(testName + ": status = " + statusCode);
403                 }
404                 Assert.assertTrue(testRequestType.isValidStatusCode(statusCode),
405                                 invalidStatusCodeMessage(testRequestType, statusCode));
406                 Assert.assertEquals(statusCode, testExpectedStatusCode);
407
408                 // Verify that the number of resources matched by the search
409                 // is identical to the expected result
410                 long NUM_MATCHES_EXPECTED = 0;
411                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
412                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
413
414         }
415
416         // ---------------------------------------------------------------
417         // Cleanup of resources created during testing
418         // ---------------------------------------------------------------
419         /**
420          * Deletes all resources created by setup and tests, after all tests have
421          * been run.
422          * 
423          * This cleanup method will always be run, even if one or more tests fail.
424          * For this reason, it attempts to remove all resources created at any point
425          * during testing, even if some of those resources may be expected to be
426          * deleted by certain tests.
427          */
428         @AfterClass(alwaysRun = true)
429         public void cleanUp() {
430                 String noTest = System.getProperty("noTestCleanup");
431                 if (Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
432                         if (logger.isDebugEnabled()) {
433                                 logger.debug("Skipping Cleanup phase ...");
434                         }
435                         return;
436                 }
437                 if (logger.isDebugEnabled()) {
438                         logger.debug("Cleaning up temporary resources created for testing ...");
439                 }
440                 CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
441                 for (String resourceId : allResourceIdsCreated) {
442                         // Note: Any non-success responses are ignored and not reported.
443                         collectionObjectClient.delete(resourceId).releaseConnection();
444                 }
445         }
446
447         // ---------------------------------------------------------------
448         // Utility methods used by tests above
449         // ---------------------------------------------------------------
450         private void createCollectionObjects(long numToCreate, String keyword) {
451                 List keywords = new ArrayList<String>();
452                 keywords.add(keyword);
453                 boolean keywordsInSameField = true;
454                 createCollectionObjects(numToCreate, keywords, keywordsInSameField);
455         }
456
457         private void createCollectionObjects(long numToCreate,
458                         List<String> keywords, boolean keywordsInSameField) {
459                 testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
460                 CollectionObjectClient client = new CollectionObjectClient();
461                 for (long i = 0; i < numToCreate; i++) {
462                         PoxPayloadOut multipart = createCollectionObjectInstance(i,
463                                         keywords, keywordsInSameField);
464                         Response res = client.create(multipart);
465                         try {
466                                 int statusCode = res.getStatus();
467                                 Assert.assertEquals(statusCode, testExpectedStatusCode);
468                                 String id = extractId(res);
469                                 allResourceIdsCreated.add(id);
470                                 if (logger.isDebugEnabled()) {
471                                         logger.debug("Created new resource [" + i + "] with ID "
472                                                         + id);
473                                 }
474                         } finally {
475                                 res.close();
476                         }
477                 }
478         }
479
480         private PoxPayloadOut createCollectionObjectInstance(long i,
481                         List<String> keywords, boolean keywordsInSameField) {
482                 CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
483                 collectionObject.setObjectNumber(createIdentifier());
484                 if (keywordsInSameField) {
485                         collectionObject.setDistinguishingFeatures(listToString(keywords,
486                                         KEYWORD_SEPARATOR));
487                 } else {
488                         if (keywords.size() == 1) {
489                                 collectionObject.setDistinguishingFeatures(keywords.get(0));
490                         } else if (keywords.size() == 2) {
491                                 collectionObject.setDistinguishingFeatures(keywords.get(0));
492                                 collectionObject.setPhysicalDescription(keywords.get(1));
493                         } else {
494                                 Assert.fail("List of keywords must have exactly one or two members.");
495                         }
496                 }
497                 PoxPayloadOut multipart = new PoxPayloadOut(
498                                 CollectionObjectClient.SERVICE_PAYLOAD_NAME);
499                 PayloadOutputPart commonPart = multipart.addPart(collectionObject,
500                                 MediaType.APPLICATION_XML_TYPE);
501                 commonPart.setLabel(new CollectionObjectClient().getCommonPartName());
502                 return multipart;
503         }
504
505         private static String listToString(List<String> list, String separator) {
506                 StringBuffer sb = new StringBuffer();
507                 if (list.size() > 0) {
508                         sb.append(list.get(0));
509                         for (int i = 1; i < list.size(); i++) {
510                                 sb.append(separator);
511                                 sb.append(list.get(i));
512                         }
513                 }
514                 return sb.toString();
515         }
516
517         private ClientResponse<AbstractCommonList> doSearch(List<String> keywords) {
518                 String searchParamValue = listToString(keywords, KEYWORD_SEPARATOR);
519                 return doSearch(searchParamValue);
520         }
521
522         private ClientResponse<AbstractCommonList> doAdvancedSearch(
523                         String propertyName, String propertyValue, String operator) {
524                 if (logger.isDebugEnabled()) {
525                         logger.debug("Searching on property: " + propertyName + "="
526                                         + "'" + propertyValue + "'");
527                 }
528                 String whereClause = propertyName + operator +
529                         "'" + propertyValue + "'";
530                 CollectionObjectClient client = new CollectionObjectClient();
531                 ClientResponse<AbstractCommonList> res = client
532                                 .advancedSearchIncludeDeleted(whereClause, false); // NOT_INCLUDING_DELETED_RESOURCES
533                 return res;
534         }
535
536         private ClientResponse<AbstractCommonList> doSearch(String keyword) {
537                 String searchParamValue = keyword;
538                 if (logger.isDebugEnabled()) {
539                         logger.debug("Searching on keyword(s): " + searchParamValue
540                                         + " ...");
541                 }
542                 CollectionObjectClient client = new CollectionObjectClient();
543                 final boolean NOT_INCLUDING_DELETED_RESOURCES = false;
544                 ClientResponse<AbstractCommonList> res = client
545                                 .keywordSearchIncludeDeleted(searchParamValue,
546                                                 NOT_INCLUDING_DELETED_RESOURCES);
547                 return res;
548         }
549
550         private long getNumMatched(ClientResponse<AbstractCommonList> res,
551                         long numExpectedMatches, String testName) {
552                 AbstractCommonList list = (AbstractCommonList) res
553                                 .getEntity(AbstractCommonList.class);
554                 long numMatched = list.getTotalItems();
555                 if (logger.isDebugEnabled()) {
556                         logger.debug("Keyword search matched " + numMatched
557                                         + " resources, expected to match " + numExpectedMatches);
558                 }
559
560                 // Optionally output additional data about list members for debugging.
561                 if (logger.isTraceEnabled()) {
562                         AbstractCommonListUtils.ListItemsInAbstractCommonList(list, logger,
563                                         testName);
564                 }
565
566                 return numMatched;
567         }
568
569         private void itemizeListItems(AbstractCommonList list) {
570                 List<AbstractCommonList.ListItem> items = list.getListItem();
571                 int i = 0;
572                 for (AbstractCommonList.ListItem item : items) {
573                         logger.debug("list-item["
574                                         + i
575                                         + "] title="
576                                         + AbstractCommonListUtils.ListItemGetElementValue(item,
577                                                         "title"));
578                         logger.debug("list-item["
579                                         + i
580                                         + "] URI="
581                                         + AbstractCommonListUtils.ListItemGetElementValue(item,
582                                                         "uri"));
583                         i++;
584                 }
585         }
586
587         public static String getSystemTimeIdentifier() {
588                 return Long.toString(System.currentTimeMillis());
589         }
590 }