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;
73 // Non-existent partial term name (first letters of each of the words
74 // in a pangram for the English alphabet).
75 private static final String TEST_PARTIAL_TERM_NON_EXISTENT = "jlmbsoq";
77 /** The known resource id. */
78 private String knownResourceId = null;
80 /** The known resource ref name. */
81 private String knownResourceRefName = null;
83 /** The known item resource id. */
84 private String knownItemResourceId = null;
86 // The resource ID of an item resource used for partial term matching tests.
87 private String knownItemPartialTermResourceId = null;
89 private List<String> allResourceIdsCreated = new ArrayList<String>();
91 /** The all item resource ids created. */
92 private Map<String, String> allItemResourceIdsCreated =
93 new HashMap<String, String>();
95 // The number of matches expected on each partial term.
96 final int NUM_MATCHES_EXPECTED = 1;
98 // The minimum number of characters that must be included
99 // a partial term, in order to permit matching to occur.
100 final int PARTIAL_TERM_MIN_LENGTH = 1;
103 * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
106 protected CollectionSpaceClient getClientInstance() {
107 return new PersonAuthorityClient();
111 * @see org.collectionspace.services.client.test.BaseServiceTest#getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
114 protected AbstractCommonList getAbstractCommonList(
115 ClientResponse<AbstractCommonList> response) {
116 return response.getEntity(PersonsCommonList.class);
119 private String getPartialTerm() {
120 return TEST_PARTIAL_TERM_FORE_NAME;
123 private String getPartialTermUtf8() {
124 return TEST_PARTIAL_TERM_SUR_NAME;
127 private String getPartialTermNonExistent() {
128 return TEST_PARTIAL_TERM_NON_EXISTENT;
131 private String getPartialTermMinimumLength() {
132 String partialTerm = getPartialTerm();
133 if (partialTerm == null || partialTerm.trim().isEmpty()) {
136 if (getPartialTerm().length() > PARTIAL_TERM_MIN_LENGTH) {
137 return partialTerm.substring(0, PARTIAL_TERM_MIN_LENGTH);
144 public void setup() {
147 } catch (Exception e) {
148 Assert.fail("Could not create new Authority for search tests.", e);
151 createItemInAuthorityForPartialTermMatch(knownResourceId, knownResourceRefName);
152 } catch (Exception e) {
153 Assert.fail("Could not create new item in Authority for search tests.", e);
157 // ---------------------------------------------------------------
158 // CRUD tests : READ_LIST tests by partial term match.
159 // ---------------------------------------------------------------
164 * Reads an item list by partial term.
166 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
167 groups = {"readListByPartialTerm"})
168 public void partialTermMatch(String testName) {
169 if (logger.isDebugEnabled()) {
170 logger.debug(testBanner(testName, CLASS_NAME));
172 int numMatchesFound = 0;
173 String partialTerm = getPartialTerm();
174 if (logger.isDebugEnabled()) {
175 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
177 numMatchesFound = readItemListByPartialTerm(knownResourceId, partialTerm);
178 if (logger.isDebugEnabled()) {
179 logger.debug("Found " + numMatchesFound + " match(es), expected " +
180 NUM_MATCHES_EXPECTED + " match(es).");
182 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
186 * Reads an item list by partial term, with a partial term that consists
187 * of an all-lowercase variation of the expected match, to test case-insensitive
190 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
191 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
192 public void partialTermMatchCaseInsensitiveLowerCase(String testName) {
193 if (logger.isDebugEnabled()) {
194 logger.debug(testBanner(testName, CLASS_NAME));
196 int numMatchesFound = 0;
198 final String partialTerm = getPartialTerm().toLowerCase();
199 if (logger.isDebugEnabled()) {
200 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
203 readItemListByPartialTerm(knownResourceId, partialTerm);
204 if (logger.isDebugEnabled()) {
205 logger.debug("Found " + numMatchesFound + " match(es), expected " +
206 NUM_MATCHES_EXPECTED + " match(es).");
208 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
212 * Reads an item list by partial term, with a partial term that consists
213 * of an all-uppercase variation of the expected match, to test case-insensitive
216 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
217 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
218 public void partialTermMatchCaseInsensitiveUpperCase(String testName) {
219 if (logger.isDebugEnabled()) {
220 logger.debug(testBanner(testName, CLASS_NAME));
222 int numMatchesFound = 0;
224 final String partialTerm = getPartialTerm().toUpperCase();
225 if (logger.isDebugEnabled()) {
226 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
229 readItemListByPartialTerm(knownResourceId, partialTerm);
230 if (logger.isDebugEnabled()) {
231 logger.debug("Found " + numMatchesFound + " match(es), expected " +
232 NUM_MATCHES_EXPECTED + " match(es).");
234 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
238 * Reads an item list by partial term, with a partial term that is of
239 * the minimum character length that may be expected to be matched.
241 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
242 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
243 public void partialTermMatchMinimumLength(String testName) {
244 if (logger.isDebugEnabled()) {
245 logger.debug(testBanner(testName, CLASS_NAME));
247 int numMatchesFound = 0;
248 String partialTerm = getPartialTermMinimumLength();
249 if (logger.isDebugEnabled()) {
250 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
252 numMatchesFound = readItemListByPartialTerm(knownResourceId, partialTerm);
253 // Zero matches are expected on a non-existent term.
254 if (logger.isDebugEnabled()) {
255 logger.debug("Found " + numMatchesFound + " match(es), expected " +
256 NUM_MATCHES_EXPECTED + " match(es).");
258 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
262 * Reads an item list by partial term, with a partial term that contains
263 * at least one Unicode UTF-8 character (outside the USASCII range).
265 // FIXME: Test currently fails with a true UTF-8 String - need to investigate why.
266 // Will be commented out for now until we get this working ...
268 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
269 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
270 public void partialTermMatchUTF8(String testName) {
271 if (logger.isDebugEnabled()) {
272 logger.debug(testBanner(testName, CLASS_NAME));
274 int numMatchesFound = 0;
275 String partialTerm = getPartialTermUtf8();
276 if (logger.isDebugEnabled()) {
277 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
280 readItemListByPartialTerm(knownResourceId, partialTerm);
281 if (logger.isDebugEnabled()) {
282 logger.debug("Found " + numMatchesFound + " match(es), expected " +
283 NUM_MATCHES_EXPECTED + " match(es).");
285 Assert.assertEquals(numMatchesFound, NUM_MATCHES_EXPECTED);
292 * Reads an item list by partial term, with a partial term that is not
293 * expected to be matched by any term in any resource.
295 @Test(dataProvider="testName", dataProviderClass=AbstractServiceTestImpl.class,
296 groups = {"readListByPartialTerm"}, dependsOnMethods = {"partialTermMatch"})
297 public void partialTermMatchOnNonexistentTerm(String testName) {
298 if (logger.isDebugEnabled()) {
299 logger.debug(testBanner(testName, CLASS_NAME));
301 int numMatchesFound = 0;
302 int ZERO_MATCHES_EXPECTED = 0;
303 String partialTerm = getPartialTermNonExistent();
304 if (logger.isDebugEnabled()) {
305 logger.debug("Attempting match on partial term '" + partialTerm + "' ...");
307 numMatchesFound = readItemListByPartialTerm(knownResourceId, partialTerm);
308 // Zero matches are expected on a non-existent term.
309 if (logger.isDebugEnabled()) {
310 logger.debug("Found " + numMatchesFound + " match(es), expected " +
311 ZERO_MATCHES_EXPECTED + " match(es).");
313 Assert.assertEquals(numMatchesFound, ZERO_MATCHES_EXPECTED);
317 * Reads an item list by partial term, given an authority and a term.
319 * @param authorityCsid The CSID of the authority within which partial term matching
321 * @param partialTerm A partial term to match item resources.
322 * @return The number of item resources matched by the partial term.
324 private int readItemListByPartialTerm(String authorityCsid, String partialTerm) {
326 String testName = "readItemListByPartialTerm";
329 int expectedStatusCode = Response.Status.OK.getStatusCode();
330 ServiceRequestType requestType = ServiceRequestType.READ_LIST;
331 testSetup(expectedStatusCode, requestType);
333 // Submit the request to the service and store the response.
334 PersonAuthorityClient client = new PersonAuthorityClient();
335 ClientResponse<PersonsCommonList> res = null;
336 if (authorityCsid != null) {
337 res = client.readItemList(authorityCsid, partialTerm);
339 Assert.fail("readItemListByPartialTerm passed null csid!");
341 PersonsCommonList list = null;
343 int statusCode = res.getStatus();
345 // Check the status code of the response: does it match
346 // the expected response(s)?
347 if(logger.isDebugEnabled()){
348 logger.debug(testName + ": status = " + statusCode);
350 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
351 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
352 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
354 list = res.getEntity();
356 res.releaseConnection();
359 List<PersonsCommonList.PersonListItem> items = list.getPersonListItem();
360 int nItemsReturned = items.size();
362 return nItemsReturned;
365 // ---------------------------------------------------------------
366 // Cleanup of resources created during testing
367 // ---------------------------------------------------------------
370 * Deletes all resources created by tests, after all tests have been run.
372 * This cleanup method will always be run, even if one or more tests fail.
373 * For this reason, it attempts to remove all resources created
374 * at any point during testing, even if some of those resources
375 * may be expected to be deleted by certain tests.
377 @AfterClass(alwaysRun=true)
378 public void cleanUp() {
379 String noTest = System.getProperty("noTestCleanup");
380 if(Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
381 if (logger.isDebugEnabled()) {
382 logger.debug("Skipping Cleanup phase ...");
386 if (logger.isDebugEnabled()) {
387 logger.debug("Cleaning up temporary resources created for testing ...");
389 String parentResourceId;
390 String itemResourceId;
391 PersonAuthorityClient client = new PersonAuthorityClient();
392 parentResourceId = knownResourceId;
393 // Clean up item resources.
394 for (Map.Entry<String, String> entry : allItemResourceIdsCreated.entrySet()) {
395 itemResourceId = entry.getKey();
396 parentResourceId = entry.getValue();
397 // Note: Any non-success responses from the delete operation
398 // below are ignored and not reported.
399 ClientResponse<Response> res =
400 client.deleteItem(parentResourceId, itemResourceId);
401 res.releaseConnection();
403 // Clean up authority resources.
404 for (String resourceId : allResourceIdsCreated) {
405 // Note: Any non-success responses are ignored and not reported.
406 client.delete(resourceId).releaseConnection();
410 // ---------------------------------------------------------------
411 // Utility methods used by tests above
412 // ---------------------------------------------------------------
414 * @see org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
417 public String getServicePathComponent() {
418 return SERVICE_PATH_COMPONENT;
422 // ---------------------------------------------------------------
423 // Utilities: setup routines for search tests
424 // ---------------------------------------------------------------
426 public void createAuthority() throws Exception {
428 String testName = "createAuthority";
431 int expectedStatusCode = Response.Status.CREATED.getStatusCode();
432 ServiceRequestType requestType = ServiceRequestType.CREATE;
433 testSetup(expectedStatusCode, requestType);
435 // Submit the request to the service and store the response.
436 PersonAuthorityClient client = new PersonAuthorityClient();
437 String identifier = createIdentifier();
438 String displayName = "displayName-" + identifier;
439 String baseRefName = PersonAuthorityClientUtils.createPersonAuthRefName(displayName, false);
440 String fullRefName = PersonAuthorityClientUtils.createPersonAuthRefName(displayName, true);
441 MultipartOutput multipart =
442 PersonAuthorityClientUtils.createPersonAuthorityInstance(
443 displayName, fullRefName, client.getCommonPartName());
446 ClientResponse<Response> res = client.create(multipart);
448 int statusCode = res.getStatus();
449 // Check the status code of the response: does it match
450 // the expected response(s)?
451 if(logger.isDebugEnabled()){
452 logger.debug(testName + ": status = " + statusCode);
454 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
455 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
456 Assert.assertEquals(statusCode, this.EXPECTED_STATUS_CODE);
457 newID = PersonAuthorityClientUtils.extractId(res);
459 res.releaseConnection();
461 // Store the refname from the first resource created
462 // for additional tests below.
463 knownResourceRefName = baseRefName;
464 // Store the ID returned from the first resource created
465 // for additional tests below.
466 if (knownResourceId == null){
467 knownResourceId = newID;
468 knownResourceRefName = baseRefName;
471 // Store the IDs from every resource created by tests,
472 // so they can be deleted after tests have been run.
473 allResourceIdsCreated.add(newID);
477 * Creates an item in the authority, used for partial term matching tests.
479 * @param authorityCsid The CSID of the Authority in which the term will be created.
480 * @param authRefName The refName of the Authority in which the term will be created.
482 private void createItemInAuthorityForPartialTermMatch(String authorityCsid, String authRefName)
485 String testName = "createItemInAuthorityForPartialTermMatch";
487 int expectedStatusCode = Response.Status.CREATED.getStatusCode();
488 ServiceRequestType requestType = ServiceRequestType.CREATE;
489 testSetup(expectedStatusCode, requestType);
491 // Submit the request to the service and store the response.
492 PersonAuthorityClient client = new PersonAuthorityClient();
493 String refName = PersonAuthorityClientUtils.createPersonRefName(authRefName,
494 TEST_PARTIAL_TERM_DISPLAY_NAME, true);
495 Map<String, String> partialTermPersonMap = new HashMap<String,String>();
497 // Fill the property map
499 partialTermPersonMap.put(PersonJAXBSchema.DISPLAY_NAME_COMPUTED, "false");
500 partialTermPersonMap.put(PersonJAXBSchema.DISPLAY_NAME, TEST_PARTIAL_TERM_DISPLAY_NAME);
501 partialTermPersonMap.put(PersonJAXBSchema.FORE_NAME, TEST_PARTIAL_TERM_FORE_NAME);
502 partialTermPersonMap.put(PersonJAXBSchema.SUR_NAME, TEST_PARTIAL_TERM_SUR_NAME);
503 partialTermPersonMap.put(PersonJAXBSchema.GENDER, "male");
504 MultipartOutput multipart =
505 PersonAuthorityClientUtils.createPersonInstance(authorityCsid, refName, partialTermPersonMap,
506 client.getItemCommonPartName() );
509 ClientResponse<Response> res = client.createItem(authorityCsid, multipart);
511 int statusCode = res.getStatus();
512 // Check the status code of the response: does it match
513 // the expected response(s)?
514 if(logger.isDebugEnabled()){
515 logger.debug(testName + ": status = " + statusCode);
517 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
518 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
519 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
521 newID = PersonAuthorityClientUtils.extractId(res);
523 res.releaseConnection();
526 // Store the ID returned from the first item resource created
527 // for additional tests below.
528 if (knownItemResourceId == null){
529 knownItemResourceId = newID;
530 if (logger.isDebugEnabled()) {
531 logger.debug(testName + ": knownItemPartialTermResourceId=" + knownItemPartialTermResourceId);
535 // Store the IDs from any item resources created
536 // by tests, along with the IDs of their parents, so these items
537 // can be deleted after all tests have been run.
538 allItemResourceIdsCreated.put(newID, authorityCsid);