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:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright (c)) 2009 Regents of the University of California
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
15 * https://source.collectionspace.org/collection-space/LICENSE.txt
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.
23 package org.collectionspace.services.client.test;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
29 import javax.ws.rs.core.Response;
31 import org.collectionspace.services.PersonJAXBSchema;
32 import org.collectionspace.services.client.CollectionSpaceClient;
33 import org.collectionspace.services.client.PersonAuthorityClient;
34 import org.collectionspace.services.client.PersonAuthorityClientUtils;
35 import org.collectionspace.services.jaxb.AbstractCommonList;
36 import org.collectionspace.services.person.PersonsCommonList;
37 import org.jboss.resteasy.client.ClientResponse;
38 import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput;
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;
47 * PersonAuthoritySearchTest, carries out search (e.g. partial
48 * term matching) tests against a deployed and running PersonAuthority Service.
50 * $LastChangedRevision: 753 $
51 * $LastChangedDate: 2009-09-23 11:03:36 -0700 (Wed, 23 Sep 2009) $
53 public class PersonAuthoritySearchTest extends BaseServiceTest {
55 private final String CLASS_NAME = PersonAuthoritySearchTest.class.getName();
56 private final Logger logger = LoggerFactory.getLogger(CLASS_NAME);
58 /** The service path component. */
59 final String SERVICE_PATH_COMPONENT = "personauthorities";
61 // Test name for partial term matching: Lech Walesa
64 final String TEST_PARTIAL_TERM_FORE_NAME = "Lech";
66 // Surname (contains two non-USASCII range Unicode UTF-8 characters)
67 final String TEST_PARTIAL_TERM_SUR_NAME = "Wa" + "\u0142" + "\u0119" + "sa";
70 final String TEST_PARTIAL_TERM_DISPLAY_NAME =
71 TEST_PARTIAL_TERM_FORE_NAME + " " + TEST_PARTIAL_TERM_SUR_NAME;
74 final String TEST_SHORT_ID = "lechWalesa";
76 final String TEST_KWD_BIRTH_PLACE = "Gdansk"; // Probably wrong on facts
78 final String TEST_KWD_NO_MATCH = "Foobar";
80 // Non-existent partial term name (first letters of each of the words
81 // in a pangram for the English alphabet).
82 private static final String TEST_PARTIAL_TERM_NON_EXISTENT = "jlmbsoq";
84 /** The known resource id. */
85 private String knownResourceId = null;
87 /** The known resource ref name. */
88 private String knownResourceRefName = null;
90 /** The known item resource id. */
91 private String knownItemResourceId = null;
93 // The resource ID of an item resource used for partial term matching tests.
94 private String knownItemPartialTermResourceId = null;
96 private List<String> allResourceIdsCreated = new ArrayList<String>();
98 /** The all item resource ids created. */
99 private Map<String, String> allItemResourceIdsCreated =
100 new HashMap<String, String>();
102 // The number of matches expected on each partial term.
103 final int NUM_MATCHES_EXPECTED = 1;
105 // The minimum number of characters that must be included
106 // a partial term, in order to permit matching to occur.
107 final int PARTIAL_TERM_MIN_LENGTH = 1;
110 * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
113 protected CollectionSpaceClient getClientInstance() {
114 return new PersonAuthorityClient();
118 * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
121 protected AbstractCommonList getAbstractCommonList(
122 ClientResponse<AbstractCommonList> response) {
123 return response.getEntity(PersonsCommonList.class);
126 private String getPartialTerm() {
127 return TEST_PARTIAL_TERM_FORE_NAME;
130 private String getPartialTermUtf8() {
131 return TEST_PARTIAL_TERM_SUR_NAME;
134 private String getPartialTermNonExistent() {
135 return TEST_PARTIAL_TERM_NON_EXISTENT;
138 private String getPartialTermMinimumLength() {
139 String partialTerm = getPartialTerm();
140 if (partialTerm == null || partialTerm.trim().isEmpty()) {
143 if (getPartialTerm().length() > PARTIAL_TERM_MIN_LENGTH) {
144 return partialTerm.substring(0, PARTIAL_TERM_MIN_LENGTH);
150 private String getKwdTerm() {
151 return TEST_KWD_BIRTH_PLACE;
154 private String getKwdTermNonExistent() {
155 return TEST_KWD_NO_MATCH;
159 public void setup() {
162 } catch (Exception e) {
163 Assert.fail("Could not create new Authority for search tests.", e);
166 createItemInAuthorityForPartialTermMatch(knownResourceId, knownResourceRefName);
167 } catch (Exception e) {
168 Assert.fail("Could not create new item in Authority for search tests.", e);
172 // ---------------------------------------------------------------
173 // CRUD tests : READ_LIST tests by partial term match.
174 // ---------------------------------------------------------------
179 * Reads an item list by partial term.
181 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
182 groups = {"readListByPartialTerm"})
183 public void partialTermMatch(String testName) {
184 if (logger.isDebugEnabled()) {
185 logger.debug(testBanner(testName, CLASS_NAME));
187 int numMatchesFound = 0;
188 String partialTerm = getPartialTerm();
189 if (logger.isDebugEnabled()) {
190 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
192 numMatchesFound = readItemListWithFilters(testName, knownResourceId, partialTerm, null);
193 if (logger.isDebugEnabled()) {
194 logger.debug("Found " + numMatchesFound + " match(es), expected " +
195 NUM_MATCHES_EXPECTED + " match(es).");
197 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
201 * Reads an item list by partial term, with a partial term that consists
202 * of an all-lowercase variation of the expected match, to test case-insensitive
205 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
206 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
207 public void partialTermMatchCaseInsensitiveLowerCase(String testName) {
208 if (logger.isDebugEnabled()) {
209 logger.debug(testBanner(testName, CLASS_NAME));
211 int numMatchesFound = 0;
213 final String partialTerm = getPartialTerm().toLowerCase();
214 if (logger.isDebugEnabled()) {
215 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
218 readItemListWithFilters(testName, knownResourceId, partialTerm, null);
219 if (logger.isDebugEnabled()) {
220 logger.debug("Found " + numMatchesFound + " match(es), expected " +
221 NUM_MATCHES_EXPECTED + " match(es).");
223 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
227 * Reads an item list by partial term, with a partial term that consists
228 * of an all-uppercase variation of the expected match, to test case-insensitive
231 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
232 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
233 public void partialTermMatchCaseInsensitiveUpperCase(String testName) {
234 if (logger.isDebugEnabled()) {
235 logger.debug(testBanner(testName, CLASS_NAME));
237 int numMatchesFound = 0;
239 final String partialTerm = getPartialTerm().toUpperCase();
240 if (logger.isDebugEnabled()) {
241 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
244 readItemListWithFilters(testName, knownResourceId, partialTerm, null);
245 if (logger.isDebugEnabled()) {
246 logger.debug("Found " + numMatchesFound + " match(es), expected " +
247 NUM_MATCHES_EXPECTED + " match(es).");
249 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
253 * Reads an item list by partial term, with a partial term that is of
254 * the minimum character length that may be expected to be matched.
256 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
257 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
258 public void partialTermMatchMinimumLength(String testName) {
259 if (logger.isDebugEnabled()) {
260 logger.debug(testBanner(testName, CLASS_NAME));
262 int numMatchesFound = 0;
263 String partialTerm = getPartialTermMinimumLength();
264 if (logger.isDebugEnabled()) {
265 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
267 numMatchesFound = readItemListWithFilters(testName, knownResourceId, partialTerm, null);
268 // Zero matches are expected on a non-existent term.
269 if (logger.isDebugEnabled()) {
270 logger.debug("Found " + numMatchesFound + " match(es), expected " +
271 NUM_MATCHES_EXPECTED + " match(es).");
273 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
277 * Reads an item list by partial term, with a partial term that contains
278 * at least one Unicode UTF-8 character (outside the USASCII range).
280 // FIXME: Test currently fails with a true UTF-8 String - need to investigate why.
281 // Will be commented out for now until we get this working ...
283 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
284 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
285 public void partialTermMatchUTF8(String testName) {
286 if (logger.isDebugEnabled()) {
287 logger.debug(testBanner(testName, CLASS_NAME));
289 int numMatchesFound = 0;
290 String partialTerm = getPartialTermUtf8();
291 if (logger.isDebugEnabled()) {
292 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
295 readItemListByPartialTerm(knownResourceId, partialTerm);
296 if (logger.isDebugEnabled()) {
297 logger.debug("Found " + numMatchesFound + " match(es), expected " +
298 NUM_MATCHES_EXPECTED + " match(es).");
300 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
304 * Reads an item list by partial term.
306 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
307 groups = {"readListByKwdTerm"}, dependsOnGroups = {"readListByPartialTerm"})
308 public void keywordTermMatch(String testName) {
309 if (logger.isDebugEnabled()) {
310 logger.debug(testBanner(testName, CLASS_NAME));
312 int numMatchesFound = 0;
313 String kwdTerm = getKwdTerm();
314 if (logger.isDebugEnabled()) {
315 logger.debug("Attempting match on kwd term '" + kwdTerm + "' ...");
317 numMatchesFound = readItemListWithFilters(testName, knownResourceId, null, kwdTerm);
318 if (logger.isDebugEnabled()) {
319 logger.debug("Found " + numMatchesFound + " match(es), expected " +
320 NUM_MATCHES_EXPECTED + " match(es).");
322 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
329 * Reads an item list by partial term, with a partial term that is not
330 * expected to be matched by any term in any resource.
332 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
333 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
334 public void partialTermMatchOnNonexistentTerm(String testName) {
335 if (logger.isDebugEnabled()) {
336 logger.debug(testBanner(testName, CLASS_NAME));
338 int numMatchesFound = 0;
339 int ZERO_MATCHES_EXPECTED = 0;
340 String partialTerm = getPartialTermNonExistent();
341 if (logger.isDebugEnabled()) {
342 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
344 numMatchesFound = readItemListWithFilters(testName, knownResourceId, partialTerm, null);
345 // Zero matches are expected on a non-existent term.
346 if (logger.isDebugEnabled()) {
347 logger.debug("Found " + numMatchesFound + " match(es), expected " +
348 ZERO_MATCHES_EXPECTED + " match(es).");
350 Assert.assertEquals(numMatchesFound, ZERO_MATCHES_EXPECTED);
354 * Reads an item list by partial term, with a partial term that is not
355 * expected to be matched by any term in any resource.
357 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
358 groups = {"readListByKwdTerm"}, dependsOnMethods = {"keywordTermMatch"})
359 public void keywordTermMatchOnNonexistentTerm(String testName) {
360 if (logger.isDebugEnabled()) {
361 logger.debug(testBanner(testName, CLASS_NAME));
363 int numMatchesFound = 0;
364 int ZERO_MATCHES_EXPECTED = 0;
365 String kwdTerm = getKwdTermNonExistent();
366 if (logger.isDebugEnabled()) {
367 logger.debug("Attempting match on kwd term '" + kwdTerm + "' ...");
369 numMatchesFound = readItemListWithFilters(testName, knownResourceId, null, kwdTerm);
370 // Zero matches are expected on a non-existent term.
371 if (logger.isDebugEnabled()) {
372 logger.debug("Found " + numMatchesFound + " match(es), expected " +
373 ZERO_MATCHES_EXPECTED + " match(es).");
375 Assert.assertEquals(numMatchesFound, ZERO_MATCHES_EXPECTED);
379 * Reads an item list by partial term or keywords, given an authority and a term.
380 * Only one of partialTerm or keywords should be specified.
381 * If both are specified, keywords will be ignored.
383 * @param testName Calling test name
384 * @param authorityCsid The CSID of the authority within which partial term matching
386 * @param partialTerm A partial term to match item resources.
387 * @param partialTerm A keyword list to match item resources.
388 * @return The number of item resources matched by the partial term.
390 private int readItemListWithFilters(String testName,
391 String authorityCsid, String partialTerm, String keywords) {
394 int expectedStatusCode = Response.Status.OK.getStatusCode();
395 ServiceRequestType requestType = ServiceRequestType.READ_LIST;
396 testSetup(expectedStatusCode, requestType);
398 // Submit the request to the service and store the response.
399 PersonAuthorityClient client = new PersonAuthorityClient();
400 ClientResponse<PersonsCommonList> res = null;
401 if (authorityCsid != null) {
402 res = client.readItemList(authorityCsid, partialTerm, keywords);
404 Assert.fail("readItemListByPartialTerm passed null csid!");
406 PersonsCommonList list = null;
408 int statusCode = res.getStatus();
410 // Check the status code of the response: does it match
411 // the expected response(s)?
412 if(logger.isDebugEnabled()){
413 logger.debug(testName + ": status = " + statusCode);
415 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
416 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
417 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
419 list = res.getEntity();
421 res.releaseConnection();
424 List<PersonsCommonList.PersonListItem> items = list.getPersonListItem();
425 int nItemsReturned = items.size();
427 return nItemsReturned;
430 // ---------------------------------------------------------------
431 // Cleanup of resources created during testing
432 // ---------------------------------------------------------------
435 * Deletes all resources created by tests, after all tests have been run.
437 * This cleanup method will always be run, even if one or more tests fail.
438 * For this reason, it attempts to remove all resources created
439 * at any point during testing, even if some of those resources
440 * may be expected to be deleted by certain tests.
442 @AfterClass(alwaysRun=true)
443 public void cleanUp() {
444 String noTest = System.getProperty("noTestCleanup");
445 if(Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
446 if (logger.isDebugEnabled()) {
447 logger.debug("Skipping Cleanup phase ...");
451 if (logger.isDebugEnabled()) {
452 logger.debug("Cleaning up temporary resources created for testing ...");
454 String parentResourceId;
455 String itemResourceId;
456 PersonAuthorityClient client = new PersonAuthorityClient();
457 parentResourceId = knownResourceId;
458 // Clean up item resources.
459 for (Map.Entry<String, String> entry : allItemResourceIdsCreated.entrySet()) {
460 itemResourceId = entry.getKey();
461 parentResourceId = entry.getValue();
462 // Note: Any non-success responses from the delete operation
463 // below are ignored and not reported.
464 ClientResponse<Response> res =
465 client.deleteItem(parentResourceId, itemResourceId);
466 res.releaseConnection();
468 // Clean up authority resources.
469 for (String resourceId : allResourceIdsCreated) {
470 // Note: Any non-success responses are ignored and not reported.
471 client.delete(resourceId).releaseConnection();
475 // ---------------------------------------------------------------
476 // Utility methods used by tests above
477 // ---------------------------------------------------------------
479 * @see org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
482 public String getServicePathComponent() {
483 return SERVICE_PATH_COMPONENT;
487 // ---------------------------------------------------------------
488 // Utilities: setup routines for search tests
489 // ---------------------------------------------------------------
491 public void createAuthority() throws Exception {
493 String testName = "createAuthority";
496 int expectedStatusCode = Response.Status.CREATED.getStatusCode();
497 ServiceRequestType requestType = ServiceRequestType.CREATE;
498 testSetup(expectedStatusCode, requestType);
500 // Submit the request to the service and store the response.
501 PersonAuthorityClient client = new PersonAuthorityClient();
502 String shortId = createIdentifier();
503 String displayName = "displayName-" + shortId;
504 String baseRefName = PersonAuthorityClientUtils.createPersonAuthRefName(shortId, null);
505 MultipartOutput multipart =
506 PersonAuthorityClientUtils.createPersonAuthorityInstance(
507 displayName, shortId, client.getCommonPartName());
510 ClientResponse<Response> res = client.create(multipart);
512 int statusCode = res.getStatus();
513 // Check the status code of the response: does it match
514 // the expected response(s)?
515 if(logger.isDebugEnabled()){
516 logger.debug(testName + ": status = " + statusCode);
518 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
519 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
520 Assert.assertEquals(statusCode, this.EXPECTED_STATUS_CODE);
521 newID = PersonAuthorityClientUtils.extractId(res);
523 res.releaseConnection();
525 // Store the refname from the first resource created
526 // for additional tests below.
527 knownResourceRefName = baseRefName;
528 // Store the ID returned from the first resource created
529 // for additional tests below.
530 if (knownResourceId == null){
531 knownResourceId = newID;
532 knownResourceRefName = baseRefName;
535 // Store the IDs from every resource created by tests,
536 // so they can be deleted after tests have been run.
537 allResourceIdsCreated.add(newID);
541 * Creates an item in the authority, used for partial term matching tests.
543 * @param authorityCsid The CSID of the Authority in which the term will be created.
544 * @param authRefName The refName of the Authority in which the term will be created.
546 private void createItemInAuthorityForPartialTermMatch(
547 String authorityCsid, String authRefName)
550 String testName = "createItemInAuthorityForPartialTermMatch";
552 int expectedStatusCode = Response.Status.CREATED.getStatusCode();
553 ServiceRequestType requestType = ServiceRequestType.CREATE;
554 testSetup(expectedStatusCode, requestType);
556 // Submit the request to the service and store the response.
557 PersonAuthorityClient client = new PersonAuthorityClient();
558 Map<String, String> partialTermPersonMap = new HashMap<String,String>();
560 // Fill the property map
562 partialTermPersonMap.put(PersonJAXBSchema.SHORT_IDENTIFIER, TEST_SHORT_ID );
563 partialTermPersonMap.put(PersonJAXBSchema.DISPLAY_NAME_COMPUTED, "false");
564 partialTermPersonMap.put(PersonJAXBSchema.DISPLAY_NAME, TEST_PARTIAL_TERM_DISPLAY_NAME);
565 partialTermPersonMap.put(PersonJAXBSchema.FORE_NAME, TEST_PARTIAL_TERM_FORE_NAME);
566 partialTermPersonMap.put(PersonJAXBSchema.SUR_NAME, TEST_PARTIAL_TERM_SUR_NAME);
567 partialTermPersonMap.put(PersonJAXBSchema.BIRTH_PLACE, TEST_KWD_BIRTH_PLACE);
568 partialTermPersonMap.put(PersonJAXBSchema.GENDER, "male");
569 MultipartOutput multipart =
570 PersonAuthorityClientUtils.createPersonInstance(authorityCsid, authRefName, partialTermPersonMap,
571 client.getItemCommonPartName() );
574 ClientResponse<Response> res = client.createItem(authorityCsid, multipart);
576 int statusCode = res.getStatus();
577 // Check the status code of the response: does it match
578 // the expected response(s)?
579 if(logger.isDebugEnabled()){
580 logger.debug(testName + ": status = " + statusCode);
582 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
583 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
584 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
586 newID = PersonAuthorityClientUtils.extractId(res);
588 res.releaseConnection();
591 // Store the ID returned from the first item resource created
592 // for additional tests below.
593 if (knownItemResourceId == null){
594 knownItemResourceId = newID;
595 if (logger.isDebugEnabled()) {
596 logger.debug(testName + ": knownItemPartialTermResourceId=" + knownItemPartialTermResourceId);
600 // Store the IDs from any item resources created
601 // by tests, along with the IDs of their parents, so these items
602 // can be deleted after all tests have been run.
603 allItemResourceIdsCreated.put(newID, authorityCsid);