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 // Non-existent partial term name (first letters of each of the words
77 // in a pangram for the English alphabet).
78 private static final String TEST_PARTIAL_TERM_NON_EXISTENT = "jlmbsoq";
80 /** The known resource id. */
81 private String knownResourceId = null;
83 /** The known resource ref name. */
84 private String knownResourceRefName = null;
86 /** The known item resource id. */
87 private String knownItemResourceId = null;
89 // The resource ID of an item resource used for partial term matching tests.
90 private String knownItemPartialTermResourceId = null;
92 private List<String> allResourceIdsCreated = new ArrayList<String>();
94 /** The all item resource ids created. */
95 private Map<String, String> allItemResourceIdsCreated =
96 new HashMap<String, String>();
98 // The number of matches expected on each partial term.
99 final int NUM_MATCHES_EXPECTED = 1;
101 // The minimum number of characters that must be included
102 // a partial term, in order to permit matching to occur.
103 final int PARTIAL_TERM_MIN_LENGTH = 1;
106 * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
109 protected CollectionSpaceClient getClientInstance() {
110 return new PersonAuthorityClient();
114 * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
117 protected AbstractCommonList getAbstractCommonList(
118 ClientResponse<AbstractCommonList> response) {
119 return response.getEntity(PersonsCommonList.class);
122 private String getPartialTerm() {
123 return TEST_PARTIAL_TERM_FORE_NAME;
126 private String getPartialTermUtf8() {
127 return TEST_PARTIAL_TERM_SUR_NAME;
130 private String getPartialTermNonExistent() {
131 return TEST_PARTIAL_TERM_NON_EXISTENT;
134 private String getPartialTermMinimumLength() {
135 String partialTerm = getPartialTerm();
136 if (partialTerm == null || partialTerm.trim().isEmpty()) {
139 if (getPartialTerm().length() > PARTIAL_TERM_MIN_LENGTH) {
140 return partialTerm.substring(0, PARTIAL_TERM_MIN_LENGTH);
147 public void setup() {
150 } catch (Exception e) {
151 Assert.fail("Could not create new Authority for search tests.", e);
154 createItemInAuthorityForPartialTermMatch(knownResourceId, knownResourceRefName);
155 } catch (Exception e) {
156 Assert.fail("Could not create new item in Authority for search tests.", e);
160 // ---------------------------------------------------------------
161 // CRUD tests : READ_LIST tests by partial term match.
162 // ---------------------------------------------------------------
167 * Reads an item list by partial term.
169 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
170 groups = {"readListByPartialTerm"})
171 public void partialTermMatch(String testName) {
172 if (logger.isDebugEnabled()) {
173 logger.debug(testBanner(testName, CLASS_NAME));
175 int numMatchesFound = 0;
176 String partialTerm = getPartialTerm();
177 if (logger.isDebugEnabled()) {
178 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
180 numMatchesFound = readItemListByPartialTerm(knownResourceId, partialTerm);
181 if (logger.isDebugEnabled()) {
182 logger.debug("Found " + numMatchesFound + " match(es), expected " +
183 NUM_MATCHES_EXPECTED + " match(es).");
185 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
189 * Reads an item list by partial term, with a partial term that consists
190 * of an all-lowercase variation of the expected match, to test case-insensitive
193 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
194 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
195 public void partialTermMatchCaseInsensitiveLowerCase(String testName) {
196 if (logger.isDebugEnabled()) {
197 logger.debug(testBanner(testName, CLASS_NAME));
199 int numMatchesFound = 0;
201 final String partialTerm = getPartialTerm().toLowerCase();
202 if (logger.isDebugEnabled()) {
203 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
206 readItemListByPartialTerm(knownResourceId, partialTerm);
207 if (logger.isDebugEnabled()) {
208 logger.debug("Found " + numMatchesFound + " match(es), expected " +
209 NUM_MATCHES_EXPECTED + " match(es).");
211 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
215 * Reads an item list by partial term, with a partial term that consists
216 * of an all-uppercase variation of the expected match, to test case-insensitive
219 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
220 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
221 public void partialTermMatchCaseInsensitiveUpperCase(String testName) {
222 if (logger.isDebugEnabled()) {
223 logger.debug(testBanner(testName, CLASS_NAME));
225 int numMatchesFound = 0;
227 final String partialTerm = getPartialTerm().toUpperCase();
228 if (logger.isDebugEnabled()) {
229 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
232 readItemListByPartialTerm(knownResourceId, partialTerm);
233 if (logger.isDebugEnabled()) {
234 logger.debug("Found " + numMatchesFound + " match(es), expected " +
235 NUM_MATCHES_EXPECTED + " match(es).");
237 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
241 * Reads an item list by partial term, with a partial term that is of
242 * the minimum character length that may be expected to be matched.
244 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
245 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
246 public void partialTermMatchMinimumLength(String testName) {
247 if (logger.isDebugEnabled()) {
248 logger.debug(testBanner(testName, CLASS_NAME));
250 int numMatchesFound = 0;
251 String partialTerm = getPartialTermMinimumLength();
252 if (logger.isDebugEnabled()) {
253 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
255 numMatchesFound = readItemListByPartialTerm(knownResourceId, partialTerm);
256 // Zero matches are expected on a non-existent term.
257 if (logger.isDebugEnabled()) {
258 logger.debug("Found " + numMatchesFound + " match(es), expected " +
259 NUM_MATCHES_EXPECTED + " match(es).");
261 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
265 * Reads an item list by partial term, with a partial term that contains
266 * at least one Unicode UTF-8 character (outside the USASCII range).
268 // FIXME: Test currently fails with a true UTF-8 String - need to investigate why.
269 // Will be commented out for now until we get this working ...
271 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
272 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
273 public void partialTermMatchUTF8(String testName) {
274 if (logger.isDebugEnabled()) {
275 logger.debug(testBanner(testName, CLASS_NAME));
277 int numMatchesFound = 0;
278 String partialTerm = getPartialTermUtf8();
279 if (logger.isDebugEnabled()) {
280 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
283 readItemListByPartialTerm(knownResourceId, partialTerm);
284 if (logger.isDebugEnabled()) {
285 logger.debug("Found " + numMatchesFound + " match(es), expected " +
286 NUM_MATCHES_EXPECTED + " match(es).");
288 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
295 * Reads an item list by partial term, with a partial term that is not
296 * expected to be matched by any term in any resource.
298 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
299 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
300 public void partialTermMatchOnNonexistentTerm(String testName) {
301 if (logger.isDebugEnabled()) {
302 logger.debug(testBanner(testName, CLASS_NAME));
304 int numMatchesFound = 0;
305 int ZERO_MATCHES_EXPECTED = 0;
306 String partialTerm = getPartialTermNonExistent();
307 if (logger.isDebugEnabled()) {
308 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
310 numMatchesFound = readItemListByPartialTerm(knownResourceId, partialTerm);
311 // Zero matches are expected on a non-existent term.
312 if (logger.isDebugEnabled()) {
313 logger.debug("Found " + numMatchesFound + " match(es), expected " +
314 ZERO_MATCHES_EXPECTED + " match(es).");
316 Assert.assertEquals(numMatchesFound, ZERO_MATCHES_EXPECTED);
320 * Reads an item list by partial term, given an authority and a term.
322 * @param authorityCsid The CSID of the authority within which partial term matching
324 * @param partialTerm A partial term to match item resources.
325 * @return The number of item resources matched by the partial term.
327 private int readItemListByPartialTerm(String authorityCsid, String partialTerm) {
329 String testName = "readItemListByPartialTerm";
332 int expectedStatusCode = Response.Status.OK.getStatusCode();
333 ServiceRequestType requestType = ServiceRequestType.READ_LIST;
334 testSetup(expectedStatusCode, requestType);
336 // Submit the request to the service and store the response.
337 PersonAuthorityClient client = new PersonAuthorityClient();
338 ClientResponse<PersonsCommonList> res = null;
339 if (authorityCsid != null) {
340 res = client.readItemList(authorityCsid, partialTerm);
342 Assert.fail("readItemListByPartialTerm passed null csid!");
344 PersonsCommonList list = null;
346 int statusCode = res.getStatus();
348 // Check the status code of the response: does it match
349 // the expected response(s)?
350 if(logger.isDebugEnabled()){
351 logger.debug(testName + ": status = " + statusCode);
353 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
354 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
355 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
357 list = res.getEntity();
359 res.releaseConnection();
362 List<PersonsCommonList.PersonListItem> items = list.getPersonListItem();
363 int nItemsReturned = items.size();
365 return nItemsReturned;
368 // ---------------------------------------------------------------
369 // Cleanup of resources created during testing
370 // ---------------------------------------------------------------
373 * Deletes all resources created by tests, after all tests have been run.
375 * This cleanup method will always be run, even if one or more tests fail.
376 * For this reason, it attempts to remove all resources created
377 * at any point during testing, even if some of those resources
378 * may be expected to be deleted by certain tests.
380 @AfterClass(alwaysRun=true)
381 public void cleanUp() {
382 String noTest = System.getProperty("noTestCleanup");
383 if(Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
384 if (logger.isDebugEnabled()) {
385 logger.debug("Skipping Cleanup phase ...");
389 if (logger.isDebugEnabled()) {
390 logger.debug("Cleaning up temporary resources created for testing ...");
392 String parentResourceId;
393 String itemResourceId;
394 PersonAuthorityClient client = new PersonAuthorityClient();
395 parentResourceId = knownResourceId;
396 // Clean up item resources.
397 for (Map.Entry<String, String> entry : allItemResourceIdsCreated.entrySet()) {
398 itemResourceId = entry.getKey();
399 parentResourceId = entry.getValue();
400 // Note: Any non-success responses from the delete operation
401 // below are ignored and not reported.
402 ClientResponse<Response> res =
403 client.deleteItem(parentResourceId, itemResourceId);
404 res.releaseConnection();
406 // Clean up authority resources.
407 for (String resourceId : allResourceIdsCreated) {
408 // Note: Any non-success responses are ignored and not reported.
409 client.delete(resourceId).releaseConnection();
413 // ---------------------------------------------------------------
414 // Utility methods used by tests above
415 // ---------------------------------------------------------------
417 * @see org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
420 public String getServicePathComponent() {
421 return SERVICE_PATH_COMPONENT;
425 // ---------------------------------------------------------------
426 // Utilities: setup routines for search tests
427 // ---------------------------------------------------------------
429 public void createAuthority() throws Exception {
431 String testName = "createAuthority";
434 int expectedStatusCode = Response.Status.CREATED.getStatusCode();
435 ServiceRequestType requestType = ServiceRequestType.CREATE;
436 testSetup(expectedStatusCode, requestType);
438 // Submit the request to the service and store the response.
439 PersonAuthorityClient client = new PersonAuthorityClient();
440 String shortId = createIdentifier();
441 String displayName = "displayName-" + shortId;
442 String baseRefName = PersonAuthorityClientUtils.createPersonAuthRefName(shortId, null);
443 MultipartOutput multipart =
444 PersonAuthorityClientUtils.createPersonAuthorityInstance(
445 displayName, shortId, client.getCommonPartName());
448 ClientResponse<Response> res = client.create(multipart);
450 int statusCode = res.getStatus();
451 // Check the status code of the response: does it match
452 // the expected response(s)?
453 if(logger.isDebugEnabled()){
454 logger.debug(testName + ": status = " + statusCode);
456 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
457 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
458 Assert.assertEquals(statusCode, this.EXPECTED_STATUS_CODE);
459 newID = PersonAuthorityClientUtils.extractId(res);
461 res.releaseConnection();
463 // Store the refname from the first resource created
464 // for additional tests below.
465 knownResourceRefName = baseRefName;
466 // Store the ID returned from the first resource created
467 // for additional tests below.
468 if (knownResourceId == null){
469 knownResourceId = newID;
470 knownResourceRefName = baseRefName;
473 // Store the IDs from every resource created by tests,
474 // so they can be deleted after tests have been run.
475 allResourceIdsCreated.add(newID);
479 * Creates an item in the authority, used for partial term matching tests.
481 * @param authorityCsid The CSID of the Authority in which the term will be created.
482 * @param authRefName The refName of the Authority in which the term will be created.
484 private void createItemInAuthorityForPartialTermMatch(
485 String authorityCsid, String authRefName)
488 String testName = "createItemInAuthorityForPartialTermMatch";
490 int expectedStatusCode = Response.Status.CREATED.getStatusCode();
491 ServiceRequestType requestType = ServiceRequestType.CREATE;
492 testSetup(expectedStatusCode, requestType);
494 // Submit the request to the service and store the response.
495 PersonAuthorityClient client = new PersonAuthorityClient();
496 Map<String, String> partialTermPersonMap = new HashMap<String,String>();
498 // Fill the property map
500 partialTermPersonMap.put(PersonJAXBSchema.SHORT_IDENTIFIER, TEST_SHORT_ID );
501 partialTermPersonMap.put(PersonJAXBSchema.DISPLAY_NAME_COMPUTED, "false");
502 partialTermPersonMap.put(PersonJAXBSchema.DISPLAY_NAME, TEST_PARTIAL_TERM_DISPLAY_NAME);
503 partialTermPersonMap.put(PersonJAXBSchema.FORE_NAME, TEST_PARTIAL_TERM_FORE_NAME);
504 partialTermPersonMap.put(PersonJAXBSchema.SUR_NAME, TEST_PARTIAL_TERM_SUR_NAME);
505 partialTermPersonMap.put(PersonJAXBSchema.GENDER, "male");
506 MultipartOutput multipart =
507 PersonAuthorityClientUtils.createPersonInstance(authorityCsid, authRefName, partialTermPersonMap,
508 client.getItemCommonPartName() );
511 ClientResponse<Response> res = client.createItem(authorityCsid, multipart);
513 int statusCode = res.getStatus();
514 // Check the status code of the response: does it match
515 // the expected response(s)?
516 if(logger.isDebugEnabled()){
517 logger.debug(testName + ": status = " + statusCode);
519 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
520 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
521 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
523 newID = PersonAuthorityClientUtils.extractId(res);
525 res.releaseConnection();
528 // Store the ID returned from the first item resource created
529 // for additional tests below.
530 if (knownItemResourceId == null){
531 knownItemResourceId = newID;
532 if (logger.isDebugEnabled()) {
533 logger.debug(testName + ": knownItemPartialTermResourceId=" + knownItemPartialTermResourceId);
537 // Store the IDs from any item resources created
538 // by tests, along with the IDs of their parents, so these items
539 // can be deleted after all tests have been run.
540 allItemResourceIdsCreated.put(newID, authorityCsid);