001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.doctype;
018:
019: import java.util.ArrayList;
020: import java.util.HashSet;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Set;
024:
025: import org.apache.log4j.Logger;
026: import org.junit.Test;
027: import org.kuali.rice.core.Core;
028: import org.kuali.workflow.test.WorkflowTestCase;
029:
030: import edu.iu.uis.eden.KEWServiceLocator;
031: import edu.iu.uis.eden.clientapp.WorkflowDocument;
032: import edu.iu.uis.eden.clientapp.WorkflowInfo;
033: import edu.iu.uis.eden.clientapp.vo.NetworkIdVO;
034: import edu.iu.uis.eden.engine.node.NodeType;
035: import edu.iu.uis.eden.engine.node.Process;
036: import edu.iu.uis.eden.engine.node.RouteNode;
037: import edu.iu.uis.eden.export.ExportDataSet;
038: import edu.iu.uis.eden.export.ExportFormat;
039: import edu.iu.uis.eden.test.TestUtilities;
040: import edu.iu.uis.eden.util.XmlHelper;
041: import edu.iu.uis.eden.workgroup.GroupNameId;
042: import edu.iu.uis.eden.workgroup.Workgroup;
043: import edu.iu.uis.eden.xml.export.DocumentTypeXmlExporter;
044:
045: public class DocumentTypeTest extends WorkflowTestCase {
046: private static final Logger LOG = Logger
047: .getLogger(DocumentTypeTest.class);
048:
049: protected void loadTestData() throws Exception {
050: Core.getCurrentContextConfig().overrideProperty(
051: "test.doctype.workgroup", "TestWorkgroup");
052: loadXmlFile("DoctypeConfig.xml");
053: }
054:
055: /**
056: * Verify that enroute documents are not affected if you edit their document type.
057: * @throws Exception
058: */
059: @Test
060: public void testChangingDocumentTypeOnEnrouteDocument()
061: throws Exception {
062: WorkflowDocument document = new WorkflowDocument(
063: new NetworkIdVO("user1"), "DocumentType");
064: document.setTitle("");
065: document.routeDocument("");
066:
067: document = new WorkflowDocument(new NetworkIdVO("rkirkend"),
068: document.getRouteHeaderId());
069: assertTrue("rkirkend should have an approve request", document
070: .isApprovalRequested());
071:
072: WorkflowInfo info = new WorkflowInfo();
073: Integer version1 = info.getDocType(document.getDocumentType())
074: .getDocTypeVersion();
075:
076: //update the document type
077: loadXmlFile("DoctypeSecondVersion.xml");
078:
079: //verify that we have a new documenttypeid and its a newer version
080: Integer version2 = info.getDocType(document.getDocumentType())
081: .getDocTypeVersion();
082:
083: assertTrue("Version2 should be larger than verison1", version2
084: .intValue() > version1.intValue());
085:
086: //the new version would take the document final
087: document = new WorkflowDocument(new NetworkIdVO("rkirkend"),
088: document.getRouteHeaderId());
089: assertTrue("rkirkend should have an approve request", document
090: .isApprovalRequested());
091:
092: document.approve("");
093:
094: document = new WorkflowDocument(new NetworkIdVO("user2"),
095: document.getRouteHeaderId());
096: Integer versionDocument = info.getDocType(
097: document.getRouteHeader().getDocTypeId())
098: .getDocTypeVersion();
099:
100: assertTrue("user2 should have an approve request", document
101: .isApprovalRequested());
102: //make sure our document still represents the accurate version
103: assertEquals("Document has the wrong document type version",
104: version1, versionDocument);
105: }
106:
107: /**
108: * this test will verify that finalapprover node policies work
109: *
110: * @throws Exception
111: */
112: @Test
113: public void testFinalApproverRouting() throws Exception {
114:
115: WorkflowDocument document = new WorkflowDocument(
116: new NetworkIdVO("user1"), "FinalApproverDocumentType");
117: document.setTitle("");
118: document.routeDocument("");
119: document = new WorkflowDocument(new NetworkIdVO("rkirkend"),
120: document.getRouteHeaderId());
121: try {
122: document.approve("");
123: fail("document should have thrown routing exception");
124: } catch (Exception e) {
125: //deal with single transaction issue in test.
126: TestUtilities.getExceptionThreader().join();
127: document = new WorkflowDocument(
128: new NetworkIdVO("rkirkend"), document
129: .getRouteHeaderId());
130: assertTrue("Document should be in exception routing",
131: document.stateIsException());
132: }
133: }
134:
135: /**
136: * Tests that route nodes mark as mandatory send out approve requests
137: * @throws Exception
138: */
139: @Test
140: public void testMandatoryRoute() throws Exception {
141: WorkflowDocument document = new WorkflowDocument(
142: new NetworkIdVO("user1"), "MandatoryRouteDocumentType");
143: document.setTitle("");
144: try {
145: document.routeDocument("");
146: } catch (Exception e) {
147: //deal with single transaction issue in test.
148: TestUtilities.getExceptionThreader().join();
149: document = new WorkflowDocument(new NetworkIdVO("user1"),
150: document.getRouteHeaderId());
151: assertTrue("Document should be in exception routing",
152: document.stateIsException());
153: }
154: }
155:
156: /**
157: * Makes sure the DocumentTypeXmlParser is working. Compare the parsed 'DocumentType' doctype to it's expected values.
158: * This test does not include multiple processes.
159: *
160: * @throws Exception
161: */
162: @Test
163: public void testDocumentTypeXmlParser() throws Exception {
164: Core.getCurrentContextConfig().overrideProperty(
165: "test.base.url", "http://someurl/path");
166: DocumentType parsedDocument = KEWServiceLocator
167: .getDocumentTypeService().findByName("DocumentType");
168: assertEquals("Wrong name", "DocumentType", parsedDocument
169: .getName());
170: assertEquals("Wrong description", "TestDocumentType",
171: parsedDocument.getDescription());
172: assertEquals("Wrong label", "TestDocumentType", parsedDocument
173: .getLabel());
174: assertEquals("Wrong postprocessor",
175: "edu.iu.uis.eden.postprocessor.DefaultPostProcessor",
176: parsedDocument.getPostProcessorName());
177: assertEquals("Wrong su workgroup", "TestWorkgroup",
178: parsedDocument.getSuperUserWorkgroup().getDisplayName());
179: // roundabout way of testing to see if the exception workgroup has been processed properly
180: DocumentTypeXmlExporter exporter = new DocumentTypeXmlExporter();
181: ExportDataSet dataSet = new ExportDataSet(ExportFormat.XML);
182: dataSet.getDocumentTypes().add(parsedDocument);
183: assertTrue(XmlHelper
184: .jotNode(exporter.export(dataSet))
185: .matches(
186: "(?s).*<defaultExceptionWorkgroupName>TestWorkgroup</defaultExceptionWorkgroupName>.*"));
187: //assertNotNull(parsedDocument.getDefaultExceptionWorkgroup());
188: //assertEquals("Wrong default exception workgroup", "TestWorkgroup", parsedDocument.getDefaultExceptionWorkgroup().getDisplayName());
189: assertEquals("Wrong doc handler url",
190: "http://someurl/path/_blank", parsedDocument
191: .getDocHandlerUrl());
192: assertEquals("Wrong blanketApprover workgroup",
193: "TestWorkgroup", parsedDocument
194: .getBlanketApproveWorkgroup().getDisplayName());
195: assertEquals("Wrong blanketApprove policy", null,
196: parsedDocument.getBlanketApprovePolicy());
197: assertEquals("Wrong PRE_APPROVE policy value", Boolean.FALSE,
198: parsedDocument.getPreApprovePolicy().getPolicyValue());
199: assertEquals("Wrong DEFAULT_APPROVE policy value",
200: Boolean.FALSE, parsedDocument.getDefaultApprovePolicy()
201: .getPolicyValue());
202: assertEquals("Wrong LOOK_FUTURE", Boolean.TRUE, parsedDocument
203: .getLookIntoFuturePolicy().getPolicyValue());
204:
205: List processes = parsedDocument.getProcesses();
206: assertEquals("Should only be 1 process", 1, processes.size());
207:
208: //this is going against the intended structure and is very brittle
209:
210: Process process = (Process) processes.get(0);
211: List flattenedNodeList = KEWServiceLocator
212: .getRouteNodeService().getFlattenedNodes(process);
213: assertEquals("Should be 6 total route nodes", 6,
214: flattenedNodeList.size());
215:
216: RouteNode adHocNode = process.getInitialRouteNode();
217: assertEquals("Wrong node name should be 'AdHoc'", "AdHoc",
218: adHocNode.getRouteNodeName());
219: assertTrue("Wrong node type", NodeType.START
220: .isAssignableFrom(Class
221: .forName(adHocNode.getNodeType())));
222: assertEquals("Default Exception workgroup not propagated",
223: "TestWorkgroup", adHocNode.getExceptionWorkgroup()
224: .getDisplayName());
225:
226: RouteNode split = (RouteNode) adHocNode.getNextNodes().get(0);
227: assertEquals("Wrong node name", "Split", split
228: .getRouteNodeName());
229: assertTrue("Wrong node type", NodeType.SPLIT
230: .isAssignableFrom(Class.forName(split.getNodeType())));
231: assertEquals("Default Exception workgroup not propagated",
232: "TestWorkgroup", split.getExceptionWorkgroup()
233: .getDisplayName());
234:
235: RouteNode ruleTemplate1 = (RouteNode) split.getNextNodes().get(
236: 0);
237: assertEquals("Wrong node name", "RuleTemplate1", ruleTemplate1
238: .getRouteNodeName());
239: assertTrue("Wrong node type", NodeType.REQUESTS
240: .isAssignableFrom(Class.forName(ruleTemplate1
241: .getNodeType())));
242: assertEquals("Wrong branch name", "B1", ruleTemplate1
243: .getBranch().getName());
244: assertEquals("Default Exception workgroup not propagated",
245: "TestWorkgroup", ruleTemplate1.getExceptionWorkgroup()
246: .getDisplayName());
247:
248: RouteNode ruleTemplate2 = (RouteNode) split.getNextNodes().get(
249: 1);
250: assertEquals("Wrong node name", "RuleTemplate2", ruleTemplate2
251: .getRouteNodeName());
252: assertTrue("Wrong node type", NodeType.REQUESTS
253: .isAssignableFrom(Class.forName(ruleTemplate2
254: .getNodeType())));
255: assertEquals("Wrong branch name", "B2", ruleTemplate2
256: .getBranch().getName());
257: assertEquals("Default Exception workgroup not propagated",
258: "TestWorkgroup", ruleTemplate2.getExceptionWorkgroup()
259: .getDisplayName());
260:
261: RouteNode join = (RouteNode) ruleTemplate2.getNextNodes()
262: .get(0);
263: assertEquals("Wrong node name", "Join", join.getRouteNodeName());
264: assertTrue("Wrong node type", NodeType.JOIN
265: .isAssignableFrom(Class.forName(join.getNodeType())));
266: assertEquals("Default Exception workgroup not propagated",
267: "TestWorkgroup", join.getExceptionWorkgroup()
268: .getDisplayName());
269:
270: RouteNode ruleTemplate3 = (RouteNode) join.getNextNodes()
271: .get(0);
272: assertEquals("Wrong node name", "RuleTemplate3", ruleTemplate3
273: .getRouteNodeName());
274: assertTrue("Wrong node type", NodeType.REQUESTS
275: .isAssignableFrom(Class.forName(ruleTemplate3
276: .getNodeType())));
277: assertEquals("Default Exception workgroup not propagated",
278: "TestWorkgroup", ruleTemplate3.getExceptionWorkgroup()
279: .getDisplayName());
280: }
281:
282: /**
283: * verify that saved documents are impacting the documents in the rest of they're hierarhy.
284: * This means cache notification by document type will work.
285: *
286: * @throws Exception
287: */
288: @Test
289: public void testDocumentTypeServiceCacheInteractions()
290: throws Exception {
291: DocumentType child = KEWServiceLocator.getDocumentTypeService()
292: .findByName("SaveTestDocumentTypeChild1");
293: DocumentType childDeux = KEWServiceLocator
294: .getDocumentTypeService().findById(
295: child.getDocumentTypeId());
296: System.out.println(child == childDeux);
297: assertEquals("Names should be the same.", child.getName(),
298: childDeux.getName());
299: assertEquals("Versions should be the same.",
300: child.getVersion(), childDeux.getVersion());
301:
302: // verify that the entry exists in OSCache
303: String childIdKey = DocumentTypeServiceImpl.DOCUMENT_TYPE_ID_CACHE_PREFIX
304: + child.getDocumentTypeId().toString();
305: String childNameKey = DocumentTypeServiceImpl.DOCUMENT_TYPE_NAME_CACHE_PREFIX
306: + child.getName();
307: assertNotNull("No entry was found in the id cache.",
308: KEWServiceLocator.getCacheAdministrator().getFromCache(
309: childIdKey));
310: assertNotNull("No entry was found in the name cache.",
311: KEWServiceLocator.getCacheAdministrator().getFromCache(
312: childNameKey));
313:
314: // the parent document type should not be in the cache yet
315: String parentIdKey = DocumentTypeServiceImpl.DOCUMENT_TYPE_ID_CACHE_PREFIX
316: + child.getDocTypeParentId();
317: assertNull(
318: "Entry for parent should not have found in the id cache.",
319: KEWServiceLocator.getCacheAdministrator().getFromCache(
320: parentIdKey));
321:
322: DocumentType parent = child.getParentDocType();
323: // the act of fetching the parent from the child should result in the parent being cached
324: assertNotNull(
325: "Entry for parent should have been found in the id cache.",
326: KEWServiceLocator.getCacheAdministrator().getFromCache(
327: parentIdKey));
328:
329: // now flush the cache, there should be no entries
330: KEWServiceLocator.getCacheAdministrator().flushAll();
331: assertNull(KEWServiceLocator.getCacheAdministrator()
332: .getFromCache(childIdKey));
333: assertNull(KEWServiceLocator.getCacheAdministrator()
334: .getFromCache(childNameKey));
335:
336: DocumentType child2 = null;
337: for (Iterator iter = parent.getChildrenDocTypes().iterator(); iter
338: .hasNext();) {
339: DocumentType childTmp = (DocumentType) iter.next();
340: if (childTmp.getName().equals("SaveTestDocumentTypeChild2")) {
341: child2 = childTmp;
342: }
343: }
344:
345: //update the first child and verify that everything we fetch is a different object - ie it's been refetched
346: //from the db
347: DocumentType childEdit = new DocumentType();
348: childEdit.setName(child.getName());
349: childEdit.setActiveInd(Boolean.TRUE);
350: Workgroup workflowAdmin = KEWServiceLocator
351: .getWorkgroupService().getWorkgroup(
352: new GroupNameId("WorkflowAdmin"));
353: childEdit.setBlanketApproveWorkgroup(workflowAdmin);
354: childEdit.setDefaultExceptionWorkgroup(workflowAdmin);
355: childEdit.setDescription("desc");
356: childEdit.setDocHandlerUrl("url");
357: childEdit.setLabel("lable");
358: childEdit.setPolicies(new ArrayList());
359: childEdit.setRoutingVersion("1");
360: childEdit.setDocTypeParentId(child.getDocTypeParentId());
361: childEdit.setPostProcessorName("somename");
362: childEdit.setSuperUserWorkgroup(workflowAdmin);
363:
364: KEWServiceLocator.getDocumentTypeService().versionAndSave(
365: childEdit);
366:
367: DocumentType child1Ver2 = KEWServiceLocator
368: .getDocumentTypeService().findByName(
369: "SaveTestDocumentTypeChild1");
370: assertTrue(
371: "the fetched document should a document type version number 1 larger than the previous version",
372: child.getVersion().intValue() + 1 == child1Ver2
373: .getVersion().intValue());
374: DocumentType previousVersion = child1Ver2.getPreviousVersion();
375: //refetch to make sure the previous version diddn't get put in our name catch
376: DocumentType child1Ver2_2 = KEWServiceLocator
377: .getDocumentTypeService().findByName(
378: "SaveTestDocumentTypeChild1");
379: assertEquals(
380: "DocumentType should have been fetched from cache",
381: child1Ver2, child1Ver2_2);
382: assertFalse(
383: "Previous Version should not be an object already fetched from cache",
384: previousVersion.equals(child1Ver2));
385: assertEquals("Fetched wrong previous document type ",
386: previousVersion.getDocumentTypeId(), child
387: .getDocumentTypeId());
388:
389: DocumentType parentV2 = child1Ver2.getParentDocType();
390: assertFalse("These should be different objects", parentV2
391: .equals(parent));
392:
393: DocumentType child2V2 = null;
394: for (Iterator iter = parentV2.getChildrenDocTypes().iterator(); iter
395: .hasNext();) {
396: DocumentType childTmp = (DocumentType) iter.next();
397: if (!childTmp.equals(child1Ver2)) {
398: child2V2 = childTmp;
399: assertFalse("These should be different objects",
400: child2V2.equals(child2));
401: }
402: }
403: }
404:
405: @Test
406: public void testAttributeSaveClearsCache() throws Exception {
407: super .loadXmlFile("DocTypeWithSearchableAttributes.xml");
408: //fetch our document types out of the document service and therefore the cache
409: DocumentType shouldClearedFromCache = KEWServiceLocator
410: .getDocumentTypeService().findByName("DocumentType");
411: DocumentType clearedFromCacheDuex = KEWServiceLocator
412: .getDocumentTypeService()
413: .findByName("DocumentTypeDuex");
414:
415: //upload the new xml
416: super .loadXmlFile("DocTypeRelatedAttributes.xml");
417: DocumentType documentType = KEWServiceLocator
418: .getDocumentTypeService().findByName("DocumentType");
419: DocumentType documentTypeDuex = KEWServiceLocator
420: .getDocumentTypeService()
421: .findByName("DocumentTypeDuex");
422: assertFalse(
423: "This documenttype should have been cleared from the cache",
424: shouldClearedFromCache.equals(documentType));
425: assertFalse(
426: "This documenttype should have been cleared from the cache",
427: clearedFromCacheDuex.equals(documentTypeDuex));
428: }
429:
430: //verifies the documenttype hierarchy is intact after multiple uploads
431: @Test
432: public void testHierarchyUpload() throws Exception {
433: super .loadXmlFile("ParentWithChildrenDocTypeConfiguration.xml");
434: DocumentType parent = KEWServiceLocator
435: .getDocumentTypeService().findByName("UGSDocumentType");
436: boolean foundRemonstrance = false;
437: boolean foundNewCourse = false;
438: boolean foundDelete = false;
439: for (Iterator iter = parent.getChildrenDocTypes().iterator(); iter
440: .hasNext();) {
441: DocumentType childDocType = (DocumentType) iter.next();
442: assertTrue("child documenttype should be current",
443: childDocType.getCurrentInd().booleanValue());
444: if (childDocType.getName().equals(
445: "CourseRemonstranceProcess")) {
446: foundRemonstrance = true;
447: } else if (childDocType.getName()
448: .equals("NewCourseRequest")) {
449: foundNewCourse = true;
450: } else if (childDocType.getName().equals(
451: "DeleteCourseRequest")) {
452: foundDelete = true;
453: }
454: }
455:
456: assertTrue("Didn't find CourseRemonstraneProcess",
457: foundRemonstrance);
458: assertTrue("Didn't find NewCourseRequest", foundNewCourse);
459: assertTrue("Didn't find DeleteCourseRequest", foundDelete);
460:
461: //reload and verify that the structure looks the same - the below is missing one of the children document types
462: //to verify that a partial upload of the hierarchy doesn't kill the entire hierarchy
463: super
464: .loadXmlFile("ParentWithChildrenDocTypeConfiguration2.xml");
465:
466: parent = KEWServiceLocator.getDocumentTypeService().findByName(
467: "UGSDocumentType");
468: foundRemonstrance = false;
469: foundNewCourse = false;
470: foundDelete = false;
471: int i = 0;
472: for (Iterator iter = parent.getChildrenDocTypes().iterator(); iter
473: .hasNext(); i++) {
474: DocumentType childDocType = (DocumentType) iter.next();
475: assertTrue("child documenttype should be current",
476: childDocType.getCurrentInd().booleanValue());
477: if (childDocType.getName().equals(
478: "CourseRemonstranceProcess")) {
479: foundRemonstrance = true;
480: } else if (childDocType.getName()
481: .equals("NewCourseRequest")) {
482: foundNewCourse = true;
483: } else if (childDocType.getName().equals(
484: "DeleteCourseRequest")) {
485: foundDelete = true;
486: }
487: }
488: assertTrue("Didn't find CourseRemonstranceProcess",
489: foundRemonstrance);
490: assertTrue("Didn't find NewCourseRequest", foundNewCourse);
491: assertTrue("Didn't find DeleteCourseRequest", foundDelete);
492: }
493:
494: //verifies documenttype hierarchy is intact after uploading a series of documenttypes and then
495: //uploading a parent onto those document types
496: @Test
497: public void testHierarchyUpload2() throws Exception {
498: super .loadXmlFile("DocTypesWithoutParent.xml");
499: //Verify that the document types are there
500: DocumentType courseRemonstrance1 = KEWServiceLocator
501: .getDocumentTypeService().findByName(
502: "CourseRemonstranceProcess");
503: DocumentType newCourseRequest1 = KEWServiceLocator
504: .getDocumentTypeService()
505: .findByName("NewCourseRequest");
506: DocumentType deleteCourse1 = KEWServiceLocator
507: .getDocumentTypeService().findByName(
508: "DeleteCourseRequest");
509:
510: //upload the new config with the parent and verify we are getting new document types with new versions
511: super .loadXmlFile("ParentWithChildrenDocTypeConfiguration.xml");
512: DocumentType courseRemonstrance2 = null;
513: DocumentType newCourseRequest2 = null;
514: DocumentType deleteCourse2 = null;
515:
516: DocumentType ugsDocumentType = KEWServiceLocator
517: .getDocumentTypeService().findByName("UGSDocumentType");
518: for (Iterator iter = ugsDocumentType.getChildrenDocTypes()
519: .iterator(); iter.hasNext();) {
520: DocumentType childDocType = (DocumentType) iter.next();
521: if (childDocType.getName().equals(
522: "CourseRemonstranceProcess")) {
523: courseRemonstrance2 = childDocType;
524: } else if (childDocType.getName()
525: .equals("NewCourseRequest")) {
526: newCourseRequest2 = childDocType;
527: } else if (childDocType.getName().equals(
528: "DeleteCourseRequest")) {
529: deleteCourse2 = childDocType;
530: }
531: }
532:
533: assertNotNull(courseRemonstrance2);
534: assertNotNull(newCourseRequest2);
535: assertNotNull(deleteCourse2);
536:
537: assertTrue(
538: "Version didn't get incremented",
539: courseRemonstrance1.getVersion().intValue() < courseRemonstrance2
540: .getVersion().intValue());
541: assertTrue("Version didn't increment", newCourseRequest1
542: .getVersion().intValue() < newCourseRequest2
543: .getVersion().intValue());
544: assertTrue("Version didn't increment", deleteCourse1
545: .getVersion().intValue() < deleteCourse2.getVersion()
546: .intValue());
547: }
548:
549: /**
550: * Tests that the document type ingestion will not create a brand new
551: * document when only label or description field changes. Relates to
552: * JIRA's EN-318 and KULOWF-147.
553: *
554: * @throws Exception
555: */
556: @Test
557: public void testDocumentTypeIngestion() throws Exception {
558: // first ingestion
559: super .loadXmlFile("DocTypeIngestTestConfig1.xml"); // original document
560: super .loadXmlFile("DocTypeIngestTestConfig2.xml"); // document with changed label and description fields
561:
562: DocumentType secondIngestDoc = KEWServiceLocator
563: .getDocumentTypeService().findByName(
564: "IngestTestDocumentType");
565: assertNotNull(
566: "Second ingested document has empty Previous Version ID after first ingest",
567: secondIngestDoc.getPreviousVersionId());
568: DocumentType firstIngestDoc = KEWServiceLocator
569: .getDocumentTypeService().findById(
570: secondIngestDoc.getPreviousVersionId());
571:
572: // the second ingested document should now be set to Current with the first ingested document should no longer be set to Current
573: assertEquals(
574: "First ingested document is still set to Current after first ingest",
575: Boolean.FALSE, firstIngestDoc.getCurrentInd());
576: assertEquals(
577: "Second ingested document is not set to Current after first ingest",
578: Boolean.TRUE, secondIngestDoc.getCurrentInd());
579:
580: // second ingestion
581: super .loadXmlFile("DocTypeIngestTestConfig3.xml"); // document setting active to false
582:
583: firstIngestDoc = null;
584: secondIngestDoc = null;
585: DocumentType thirdIngestDoc = KEWServiceLocator
586: .getDocumentTypeService().findByName(
587: "IngestTestDocumentType");
588: assertNotNull(
589: "Third ingested document has empty Previous Version ID after second ingest",
590: thirdIngestDoc.getPreviousVersionId());
591: secondIngestDoc = KEWServiceLocator.getDocumentTypeService()
592: .findById(thirdIngestDoc.getPreviousVersionId());
593: assertNotNull(
594: "Second ingested document has empty Previous Version ID after second ingest",
595: secondIngestDoc.getPreviousVersionId());
596: firstIngestDoc = KEWServiceLocator.getDocumentTypeService()
597: .findById(secondIngestDoc.getPreviousVersionId());
598:
599: // the third ingested document should now be set to Current and Inactive... all others should not be set to Current
600: assertEquals(
601: "First ingested document is set to Current after second ingest",
602: Boolean.FALSE, firstIngestDoc.getCurrentInd());
603: assertEquals(
604: "Second ingested document is set to Current after second ingest",
605: Boolean.FALSE, secondIngestDoc.getCurrentInd());
606: assertEquals(
607: "Third ingested document is not set to Inactive after second ingest",
608: Boolean.FALSE, thirdIngestDoc.getActiveInd());
609: assertEquals(
610: "Third ingested document is not set to Current after second ingest",
611: Boolean.TRUE, thirdIngestDoc.getCurrentInd());
612:
613: // third ingestion
614: super .loadXmlFile("DocTypeIngestTestConfig4.xml"); // document setting active to true
615:
616: firstIngestDoc = null;
617: secondIngestDoc = null;
618: thirdIngestDoc = null;
619: DocumentType fourthIngestDoc = KEWServiceLocator
620: .getDocumentTypeService().findByName(
621: "IngestTestDocumentType");
622: assertNotNull(
623: "Fourth ingested document has empty Previous Version ID after third ingest",
624: fourthIngestDoc.getPreviousVersionId());
625: thirdIngestDoc = KEWServiceLocator.getDocumentTypeService()
626: .findById(fourthIngestDoc.getPreviousVersionId());
627: assertNotNull(
628: "Third ingested document has empty Previous Version ID after third ingest",
629: thirdIngestDoc.getPreviousVersionId());
630: secondIngestDoc = KEWServiceLocator.getDocumentTypeService()
631: .findById(thirdIngestDoc.getPreviousVersionId());
632: assertNotNull(
633: "Second ingested document has empty Previous Version ID after third ingest",
634: secondIngestDoc.getPreviousVersionId());
635: firstIngestDoc = KEWServiceLocator.getDocumentTypeService()
636: .findById(secondIngestDoc.getPreviousVersionId());
637:
638: // the fourth ingested document should now be set to Current and Active... all others should not be set to Current
639: assertEquals(
640: "First ingested document is set to Current after third ingest",
641: Boolean.FALSE, firstIngestDoc.getCurrentInd());
642: assertEquals(
643: "Second ingested document is set to Current after third ingest",
644: Boolean.FALSE, secondIngestDoc.getCurrentInd());
645: assertEquals(
646: "Third ingested document is set to Current after third ingest",
647: Boolean.FALSE, thirdIngestDoc.getCurrentInd());
648: assertEquals(
649: "Fourth ingested document is not set to Active after third ingest",
650: Boolean.TRUE, fourthIngestDoc.getActiveInd());
651: assertEquals(
652: "Fourth ingested document is not set to Current after third ingest",
653: Boolean.TRUE, fourthIngestDoc.getCurrentInd());
654: }
655:
656: @Test
657: public void testDocumentTypeParentChildLinking() throws Exception {
658: super .loadXmlFile("ParentWithChildrenDocTypeConfiguration.xml");
659: verifyDocumentTypeLinking();
660:
661: // scenario 1, update the parent document type and verify that all linking is correct
662: super
663: .loadXmlFile("ParentWithChildrenDocTypeConfigurationUpdate1.xml");
664: verifyDocumentTypeLinking();
665:
666: // scenario 2, update a child document type and verify that all linking is correct
667: super
668: .loadXmlFile("ParentWithChildrenDocTypeConfigurationUpdate2.xml");
669: verifyDocumentTypeLinking();
670:
671: // let's reimport from the beginning as well
672: super .loadXmlFile("ParentWithChildrenDocTypeConfiguration.xml");
673: verifyDocumentTypeLinking();
674:
675: // scenario 3, try an xml file with child doctype listed first
676: super
677: .loadXmlFile("ParentWithChildrenDocTypeConfigurationUpdate3.xml");
678: verifyDocumentTypeLinking();
679:
680: // try loading each of these in parallel threads to verify caching can
681: // handle concurrency situations
682: int num = 7;
683: Thread[] threads = new Thread[num];
684: Callback[] callbacks = new Callback[num];
685: for (int i = 0; i < num; i++) {
686: callbacks[i] = new Callback();
687: }
688: threads[0] = new Thread(new LoadXml(
689: "ParentWithChildrenDocTypeConfiguration.xml",
690: callbacks[0]));
691: threads[1] = new Thread(new LoadXml(
692: "DocTypeIngestTestConfig1.xml", callbacks[1]));
693: threads[2] = new Thread(new LoadXml(
694: "DocumentTypeAttributeFetchTest.xml", callbacks[2]));
695: threads[3] = new Thread(new LoadXml("ChildDocType1.xml",
696: callbacks[3]));
697: threads[4] = new Thread(new LoadXml("ChildDocType2.xml",
698: callbacks[4]));
699: threads[5] = new Thread(new LoadXml("ChildDocType3.xml",
700: callbacks[5]));
701: threads[6] = new Thread(new LoadXml("ChildDocType4.xml",
702: callbacks[6]));
703: for (Thread thread : threads) {
704: thread.start();
705: }
706: for (Thread thread : threads) {
707: thread.join(2 * 60 * 1000);
708: }
709: // what should have happened here was an optimistic lock being thrown from the
710: // document type XML import. Currently that code is catching and just logging
711: // those errors (not rethrowing) so there's no way for us to check that the
712: // optimistic lock was thrown however the verifyDocumentTypeLinking should pass
713: // because the update was never made
714: for (Callback callback : callbacks) {
715: callback.assertXmlLoaded();
716: }
717: verifyDocumentTypeLinking();
718:
719: // reload again for good measure
720: super .loadXmlFile("ParentWithChildrenDocTypeConfiguration.xml");
721: verifyDocumentTypeLinking();
722:
723: }
724:
725: protected void verifyDocumentTypeLinking() throws Exception {
726: DocumentTypeService service = KEWServiceLocator
727: .getDocumentTypeService();
728: List rootDocs = service.findAllCurrentRootDocuments();
729: int numRoots = rootDocs.size();
730: List documentTypes = service.findAllCurrent();
731: List<DocumentType> leafs = new ArrayList<DocumentType>();
732: for (Iterator iterator = documentTypes.iterator(); iterator
733: .hasNext();) {
734: DocumentType documentType = (DocumentType) iterator.next();
735: List children = service.getChildDocumentTypes(documentType);
736: if (children.isEmpty()) {
737: leafs.add(documentType);
738: }
739: }
740: Set<Long> rootDocIds = new HashSet<Long>();
741: // verify the hierarchy
742: for (DocumentType leaf : leafs) {
743: verifyHierarchy(leaf, rootDocIds);
744: }
745: for (DocumentType leaf : leafs) {
746: verifyHierarchy(leaf, rootDocIds);
747: }
748: // we should have the same number of roots as we did from the original roots query
749: assertEquals("Should have the same number of roots", numRoots,
750: rootDocIds.size());
751: }
752:
753: protected void verifyHierarchy(DocumentType docType,
754: Set<Long> rootDocIds) {
755: assertTrue("DocumentType " + docType.getName()
756: + " should be current.", docType.getCurrentInd()
757: .booleanValue());
758: if (docType.getParentDocType() == null) {
759: rootDocIds.add(docType.getDocumentTypeId());
760: } else {
761: verifyHierarchy(docType.getParentDocType(), rootDocIds);
762: }
763: }
764:
765: protected void flushCache() {
766: // invalidate locally because if we're doing an upload of a document hierarchy we can't wait the 5 secs for this nodes cache
767: //to be accurate-the data going in the db depends on it being accurate now. This means the cache will be cleared multiple times
768: //over during an upload and the subsequent notification to this node.
769: LOG.info("clearing DocumentType cache because of local update");
770: KEWServiceLocator.getCacheAdministrator().flushGroup(
771: DocumentTypeServiceImpl.DOCUMENT_TYPE_ID_CACHE_GROUP);
772: KEWServiceLocator.getCacheAdministrator().flushGroup(
773: DocumentTypeServiceImpl.DOCUMENT_TYPE_NAME_CACHE_GROUP);
774: KEWServiceLocator.getCacheAdministrator().flushEntry(
775: DocumentTypeServiceImpl.CURRENT_ROOTS_IN_CACHE_KEY);
776: }
777:
778: private class LoadXml implements Runnable {
779:
780: private String xmlFile;
781: private Callback callback;
782:
783: public LoadXml(String xmlFile, Callback callback) {
784: this .xmlFile = xmlFile;
785: this .callback = callback;
786: }
787:
788: public void run() {
789: try {
790: loadXmlFile(xmlFile);
791: } catch (Throwable t) {
792: callback.record(xmlFile, t);
793: }
794: }
795:
796: }
797:
798: private class Callback {
799: private String xmlFile;
800: private Throwable t;
801:
802: public void record(String xmlFile, Throwable t) {
803: this .xmlFile = xmlFile;
804: this .t = t;
805: }
806:
807: public void assertXmlLoaded() {
808: if (t != null) {
809: t.printStackTrace();
810: fail("Failed to load xml file " + xmlFile);
811: }
812: }
813: }
814: }
|