View Javadoc
1   /**
2    * Copyright 2005-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.routeheader;
17  
18  import org.joda.time.DateTime;
19  import org.junit.Test;
20  import org.kuali.rice.kew.api.KewApiConstants;
21  import org.kuali.rice.kew.api.KewApiServiceLocator;
22  import org.kuali.rice.kew.api.WorkflowDocument;
23  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
24  import org.kuali.rice.kew.api.WorkflowRuntimeException;
25  import org.kuali.rice.kew.api.action.ActionRequest;
26  import org.kuali.rice.kew.api.action.ActionRequestType;
27  import org.kuali.rice.kew.api.action.AdHocToPrincipal;
28  import org.kuali.rice.kew.api.action.RequestedActions;
29  import org.kuali.rice.kew.api.document.Document;
30  import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
31  import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
32  import org.kuali.rice.kew.doctype.bo.DocumentType;
33  import org.kuali.rice.kew.impl.document.WorkflowDocumentImpl;
34  import org.kuali.rice.kew.impl.document.WorkflowDocumentPrototype;
35  import org.kuali.rice.kew.service.KEWServiceLocator;
36  import org.kuali.rice.kew.test.KEWTestCase;
37  import org.kuali.rice.kim.api.identity.Person;
38  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
39  import org.kuali.rice.krad.util.KRADUtils;
40  
41  import java.util.List;
42  import java.util.Set;
43  
44  import static org.junit.Assert.*;
45  
46  public class AppDocStatusTest extends KEWTestCase {
47      	    
48      protected void loadTestData() throws Exception {
49      	super.loadTestData();
50          loadXmlFile("AppDocStatusTestConfig.xml");
51      }
52          
53      /**
54       * 
55       * This method performs several positive tests related to Application Document Status
56       * For these tests the doctype definition defines a valid set of statuses.
57       * It also defines two status transitions in the route path
58       * It tests:
59       * 	- That the AppDocStatus is properly set by the workflow engine during
60       *    appropriate transitions.
61       *  - That the AppDocStatus may be retrieved by the client API
62       *  - That the AppDocStatus may be set by the client API
63       *  - That a history of AppDocStatus transitions is created.
64       * 
65       */
66      @Test public void testValidAppDocStatus() throws Exception {
67      	// Create document
68      	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestAppDocStatusDoc2");
69      	document.saveDocumentData();
70      	assertNotNull(document.getDocumentId());
71      	assertTrue("Document should be initiatied", document.isInitiated());
72      	assertTrue("Invalid route level.", document.getNodeNames().contains("Initiated"));
73      	
74      	// route document to first stop and check status, etc.
75      	document.route("Test Routing.");    	
76      	String appDocStatus = document.getDocument().getApplicationDocumentStatus();
77      	assertTrue("Application Document Status:" + appDocStatus +" is invalid", "Approval in Progress".equalsIgnoreCase(appDocStatus));
78          
79          // should have generated a request to "bmcgough"
80      	document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("bmcgough"), document.getDocumentId());
81          assertTrue("Document should be enroute", document.isEnroute());
82      	Set<String> nodeNames = document.getNodeNames();
83      	assertEquals("Wrong number of node names.", 1, nodeNames.size());
84      	assertTrue("Wrong node name.", document.getNodeNames().contains("DestinationApproval"));
85  
86      	// check action request
87          List<ActionRequest> requests = document.getRootActionRequests();
88          assertEquals(1, requests.size());
89          ActionRequest request = requests.get(0);
90          assertEquals(getPrincipalIdForName("bmcgough"), request.getPrincipalId());
91          assertEquals(ActionRequestType.APPROVE, request.getActionRequested());
92          assertEquals("DestinationApproval", request.getNodeName());
93          assertTrue(document.isApprovalRequested());
94          
95          // approve the document to send it to its next route node
96          document.approve("Test approve by bmcgough");
97          
98          // check status 
99          document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), document.getDocumentId());
100         Document rh = document.getDocument();
101     	appDocStatus = rh.getApplicationDocumentStatus();
102     	assertTrue("Application Document Status:" + appDocStatus +" is invalid", "Submitted".equalsIgnoreCase(appDocStatus));
103         
104         // should have generated a request to "temay"
105     	assertTrue("Document should be enroute", document.isEnroute());
106     	nodeNames = document.getNodeNames();
107     	assertEquals("Wrong number of node names.", 1, nodeNames.size());
108     	assertTrue("Wrong node name.", nodeNames.contains("TravelerApproval"));
109     	document.approve("Test approve by temay");
110     	
111     	// update the AppDocStatus via client API
112         document.setApplicationDocumentStatus("Completed");
113         document.saveDocumentData();
114 
115         // get a refreshed document and check it out
116         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), document.getDocumentId());
117 //        assertTrue("Document should be processed.", document.isProcessed());        
118         rh = document.getDocument();
119     	appDocStatus = rh.getApplicationDocumentStatus();
120     	assertTrue("Application Document Status:" + appDocStatus +" is invalid", "Completed".equalsIgnoreCase(appDocStatus));
121     	
122         // check app doc status transition history
123         List<org.kuali.rice.kew.api.document.DocumentStatusTransition> history = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatusTransitionHistory(
124                 document.getDocumentId());
125         
126         assertEquals(3, history.size());
127     	assertTrue("First History record has incorrect status", "Approval In Progress".equalsIgnoreCase(history.get(0).getNewStatus()));
128     	assertTrue("Second History record has incorrect old status", "Approval In Progress".equalsIgnoreCase(
129                 history.get(1).getOldStatus()));
130     	assertTrue("Second History record has incorrect new status", "Submitted".equalsIgnoreCase(history.get(1).getNewStatus()));
131     	assertTrue("Third History record has incorrect old status", "Submitted".equalsIgnoreCase(history.get(2).getOldStatus()));
132     	assertTrue("Third History record has incorrect new status", "Completed".equalsIgnoreCase(history.get(2).getNewStatus()));
133                
134     	// TODO when we are able to, we should also verify the RouteNodeInstances are correct
135         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
136     	assertTrue("Document should be final.", document.isFinal());
137     }        
138 
139     /**
140      * 
141      * This method is similar to the above test, except that the doctype definition
142      * does NOT specify a valid set of values.  This means that the value can be any valid string.
143      * 
144      * @throws Exception
145      */
146     @Test public void testAppDocStatusValuesNotDefined() throws Exception {
147     	// Create document
148     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestAppDocStatusDoc1");
149     	document.saveDocumentData();
150     	assertNotNull(document.getDocumentId());
151     	assertTrue("Document should be initiatied", document.isInitiated());
152     	assertTrue("Invalid route level.", document.getNodeNames().contains("Initiated"));
153     	
154     	// route document to first stop and check status, etc.
155     	document.route("Test Routing.");    	
156     	Document rh = document.getDocument();
157     	String appDocStatus = rh.getApplicationDocumentStatus();
158     	assertTrue("Application Document Status:" + appDocStatus +" is invalid", "Approval in Progress".equalsIgnoreCase(appDocStatus));
159         
160         // should have generated a request to "bmcgough"
161     	document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("bmcgough"), document.getDocumentId());
162         assertTrue("Document should be enroute", document.isEnroute());
163     	Set<String> nodeNames = document.getNodeNames();
164     	assertEquals("Wrong number of node names.", 1, nodeNames.size());
165     	assertTrue("Wrong node name.", nodeNames.contains("step1"));
166 
167     	// check action request
168         List<ActionRequest> requests = document.getRootActionRequests();
169         assertEquals(1, requests.size());
170         ActionRequest request = requests.get(0);
171         assertEquals(getPrincipalIdForName("bmcgough"), request.getPrincipalId());
172         assertEquals(ActionRequestType.APPROVE, request.getActionRequested());
173         assertEquals("step1", request.getNodeName());
174         assertTrue(document.isApprovalRequested());
175         
176         // approve the document to send it to its next route node
177         document.approve("Test approve by bmcgough");
178         
179         // check status 
180         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), document.getDocumentId());
181         rh = document.getDocument();
182     	appDocStatus = rh.getApplicationDocumentStatus();
183     	assertTrue("Application Document Status:" + appDocStatus +" is invalid", "Submitted".equalsIgnoreCase(appDocStatus));
184         
185         // should have generated a request to "temay"
186     	assertTrue("Document should be enroute", document.isEnroute());
187     	nodeNames = document.getNodeNames();
188     	assertEquals("Wrong number of node names.", 1, nodeNames.size());
189     	assertTrue("Wrong node name.", nodeNames.contains("step2"));
190     	document.approve("Test approve by temay");
191     	
192     	// update the AppDocStatus via client API
193         document.setApplicationDocumentStatus("Some Random Value");
194         document.saveDocumentData();
195 
196         // get a refreshed document and check it out
197         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("temay"), document.getDocumentId());
198 //        assertTrue("Document should be processed.", document.isProcessed());        
199         rh = document.getDocument();
200     	appDocStatus = rh.getApplicationDocumentStatus();
201     	assertTrue("Application Document Status:" + appDocStatus +" is invalid", "Some Random Value".equalsIgnoreCase(appDocStatus));
202     	
203         // check app doc status transition history
204         List<org.kuali.rice.kew.api.document.DocumentStatusTransition> history = KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatusTransitionHistory(
205                 document.getDocumentId());
206         
207         assertEquals(3, history.size());
208     	assertTrue("First History record has incorrect status", "Approval In Progress".equalsIgnoreCase(history.get(0)
209                 .getNewStatus()));
210     	assertTrue("Second History record has incorrect old status", "Approval In Progress".equalsIgnoreCase(
211                 history.get(1).getOldStatus()));
212     	assertTrue("Second History record has incorrect new status", "Submitted".equalsIgnoreCase(history.get(1)
213                 .getNewStatus()));
214     	assertTrue("Third History record has incorrect old status", "Submitted".equalsIgnoreCase(history.get(2).getOldStatus()));
215     	assertTrue("Third History record has incorrect new status", "Some Random Value".equalsIgnoreCase(history.get(2)
216                 .getNewStatus()));
217                
218     	// TODO when we are able to, we should also verify the RouteNodeInstances are correct
219         document = WorkflowDocumentFactory.loadDocument(getPrincipalIdForName("ewestfal"), document.getDocumentId());
220     	assertTrue("Document should be final.", document.isFinal());
221     }        
222 
223     /**
224      * 
225      * This test attempts to set an invalid status value for a document that has a valid set
226      * of statuses defined.
227      * It expects to throw a WorkflowRuntimeException when attempting to set the invalid status value.
228      * 
229      * @throws Exception
230      */
231     @Test public void testInvalidAppDocStatusValue() throws Exception {
232     	WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestAppDocStatusDoc2");
233     	document.saveDocumentData();
234     	assertNotNull(document.getDocumentId());
235     	assertTrue("Document should be initiatied", document.isInitiated());
236     	assertTrue("Invalid route level.", document.getNodeNames().contains("Initiated"));
237     	    	
238     	// update the AppDocStatus via client API
239     	boolean gotException = false;
240     	try {
241     		document.setApplicationDocumentStatus("BAD STATUS");
242     		document.saveDocumentData();
243     	} catch (Throwable t){
244     		gotException = true;
245     		WorkflowRuntimeException ex = new WorkflowRuntimeException();
246     		assertEquals("WrongExceptionType", t.getClass(), ex.getClass());
247     	} finally {
248     		assertTrue("Expected WorkflowRuntimeException not thrown.", gotException);
249     		
250     	}
251     }
252 
253     /**
254      *
255      * This method is similar to the above test, except that the doctype definition
256      * INHERITS a valid set of application document status values.
257      *
258      * @throws Exception
259      */
260     @Test public void testValidInheritedAppDocStatus() throws Exception {
261         // Create document
262         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestAppDocStatusDoc3");
263         document.saveDocumentData();
264         assertNotNull(document.getDocumentId());
265         assertTrue("Document should be initiatied", document.isInitiated());
266         assertTrue("Invalid route level.", document.getNodeNames().contains("Initiated"));
267         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName("TestAppDocStatusDoc3");
268         assertTrue(KRADUtils.isNotNull(documentType));
269         assertTrue(KRADUtils.isNotNull(documentType.getValidApplicationStatuses()));
270         assertEquals(6,documentType.getValidApplicationStatuses().size());
271         LOG.info("valid application status size: " + documentType.getValidApplicationStatuses().size());
272         assertTrue(KRADUtils.isNotNull(documentType.getApplicationStatusCategories()));
273         assertEquals(0,documentType.getApplicationStatusCategories().size());
274     }
275 
276     /**
277      *
278      * This method an inherited valid set of values and categories.
279      *
280      * @throws Exception
281      */
282     @Test public void testValidInheritedAppDocStatusWithCategories() throws Exception {
283         // Create document
284         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestAppDocStatusDoc5");
285         document.saveDocumentData();
286         assertNotNull(document.getDocumentId());
287         assertTrue("Document should be initiatied", document.isInitiated());
288         assertTrue("Invalid route level.", document.getNodeNames().contains("Initiated"));
289         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName("TestAppDocStatusDoc5");
290         assertTrue(KRADUtils.isNotNull(documentType));
291         assertTrue(KRADUtils.isNotNull(documentType.getValidApplicationStatuses()));
292         LOG.info("valid application status size: " + documentType.getValidApplicationStatuses().size());
293         assertEquals(6,documentType.getValidApplicationStatuses().size());
294         assertTrue(KRADUtils.isNotNull(documentType.getApplicationStatusCategories()));
295         assertEquals(2,documentType.getApplicationStatusCategories().size());
296     }
297 
298     /**
299      *
300      * This method tests a valid set of application document status values that are not inherited due to KEW status (KULRICE-8943).
301      *
302      * @throws Exception
303      */
304     @Test public void testInheritedAppDocStatusWithKEWStatus() throws Exception {
305         // Create document
306         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"), "TestAppDocStatusDoc6");
307         document.saveDocumentData();
308         assertNotNull(document.getDocumentId());
309         assertTrue("Document should be initiatied", document.isInitiated());
310         assertTrue("Invalid route level.", document.getNodeNames().contains("Initiated"));
311         DocumentType documentType = KEWServiceLocator.getDocumentTypeService().findByName("TestAppDocStatusDoc6");
312         assertTrue(KRADUtils.isNotNull(documentType));
313         assertTrue(KRADUtils.isNotNull(documentType.getValidApplicationStatuses()));
314         assertEquals(0,documentType.getValidApplicationStatuses().size());
315         LOG.info("valid application status size: " + documentType.getValidApplicationStatuses().size());
316         assertTrue(KRADUtils.isNotNull(documentType.getApplicationStatusCategories()));
317         assertEquals(0,documentType.getApplicationStatusCategories().size());
318     }
319 
320     @Test public void testSearching() throws InterruptedException {
321         String documentTypeName = "TestAppDocStatusDoc1";
322 
323         String initiatorNetworkId = "rkirkend";
324         Person initiator = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(initiatorNetworkId);
325         String approverNetworkId = "bmcgough";
326         Person approver = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(approverNetworkId);
327         String travelerNetworkId = "temay";
328         Person traveler = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(travelerNetworkId);
329 
330         WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(initiator.getPrincipalId(), documentTypeName);
331         workflowDocument.setTitle("Routing style");
332 
333         // no status, not routed
334         assertAppDocStatuses(workflowDocument.getDocumentId(), new String [] { });
335         assertSearchStatus(documentTypeName, initiator, "Approval in Progress", 0, 0);
336         assertSearchStatus(documentTypeName, initiator, "Submitted", 0, 0);
337 
338         workflowDocument.route("routing this document.");
339 
340         DocumentRouteHeaderValue drhv = KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getDocumentId());
341         
342         // should be in approval status
343         assertAppDocStatuses(workflowDocument.getDocumentId(), new String [] { "Approval in Progress" });
344         assertSearchStatus(documentTypeName, initiator, "Approval in Progress", 1, 0); // one document currently in "Approval in Progress" status
345         assertSearchStatus(documentTypeName, initiator, "Approval in Progress", 1, drhv.getRouteStatusDate().getTime()); // one transition to "Approval in Progress" status around the time of routing
346         assertSearchStatus(documentTypeName, initiator, "Submitted", 0, 0); // none in "Submitted" status
347 
348         // approve it out of the "Approval in Progress" state
349         workflowDocument = WorkflowDocumentFactory.loadDocument(approver.getPrincipalId(), workflowDocument.getDocumentId());
350         RequestedActions actions = workflowDocument.getRequestedActions();
351         assertTrue(actions.isApproveRequested());
352         workflowDocument.approve("destination approval");
353 
354         assertAppDocStatuses(workflowDocument.getDocumentId(), new String [] { "Approval in Progress", "Submitted" });
355         assertSearchStatus(documentTypeName, approver, "Approval in Progress", 0, 0); // no documents currently in "Approval in Progress" status
356         assertSearchStatus(documentTypeName, approver, "Approval in Progress", 1, drhv.getRouteStatusDate().getTime()); // one transition to "Approval in Progress" status around the time of routing
357         assertSearchStatus(documentTypeName, approver, "Submitted", 1, 0); // one document currently in "Submitted" status
358         assertSearchStatus(documentTypeName, approver, "Submitted", 1, drhv.getDateLastModified().getMillis()); // one transition to "Submitted" status around the time of approval
359 
360         // approve it out of the "Approval in Progress" state
361         workflowDocument = WorkflowDocumentFactory.loadDocument(traveler.getPrincipalId(), workflowDocument.getDocumentId());
362         actions = workflowDocument.getRequestedActions();
363         assertTrue(actions.isApproveRequested());
364         workflowDocument.approve("travel approval");
365 
366         // no final status, so no transition
367         assertAppDocStatuses(workflowDocument.getDocumentId(), new String [] { "Approval in Progress", "Submitted" });
368         assertSearchStatus(documentTypeName, traveler, "Approval in Progress", 0, 0); // no documents currently in "Approval in Progress" status
369         assertSearchStatus(documentTypeName, traveler, "Approval in Progress", 1, drhv.getRouteStatusDate().getTime()); // one transition to "Approval in Progress" status around the time of routing
370         assertSearchStatus(documentTypeName, traveler, "Submitted", 1, 0); // one document currently in "Submitted" status
371         assertSearchStatus(documentTypeName, traveler, "Submitted", 1, drhv.getDateLastModified().getMillis()); // one transition to "Submitted" status around the time of approval
372     }
373     
374     @Test public void testAppDocResetAfterAdHoc() throws Exception {
375         String documentTypeName = "TestAppDocStatusDoc1";
376 
377         String initiatorNetworkId = "rkirkend";
378         String approverNetworkId = "bmcgough";
379         String travelerNetworkId = "temay";
380 
381         Person initiator = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(initiatorNetworkId);
382         Person approver = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(approverNetworkId);
383         Person traveler = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(travelerNetworkId);
384 
385         WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(initiator.getPrincipalId(), documentTypeName);
386         workflowDocument.setTitle("Routing style");
387         workflowDocument.route("routing this document.");
388 
389         //DocumentRouteHeaderValue drhv = KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getDocumentId());
390         
391         // should be in approval status
392         assertAppDocStatuses(workflowDocument.getDocumentId(), new String [] { "Approval in Progress" });
393 
394         // approve it out of the "Approval in Progress" state
395         
396         workflowDocument = WorkflowDocumentFactory.loadDocument(approver.getPrincipalId(), workflowDocument.getDocumentId());
397         Document staleWorkflowDocument = KewApiServiceLocator.getWorkflowDocumentService().getDocument(workflowDocument.getDocumentId());
398         
399         assertEquals( "app doc status incorrect before final approval: " + staleWorkflowDocument, "Approval in Progress", staleWorkflowDocument.getApplicationDocumentStatus() );
400 
401         RequestedActions actions = workflowDocument.getRequestedActions();
402         assertTrue(actions.isApproveRequested());
403         workflowDocument.approve("destination approval");
404 
405 
406         // approve it out of the "Approval in Progress" state
407         workflowDocument = WorkflowDocumentFactory.loadDocument(traveler.getPrincipalId(), workflowDocument.getDocumentId());
408         assertEquals( "current app doc status incorrect after 1st approval", "Submitted", workflowDocument.getApplicationDocumentStatus() );
409 
410         actions = workflowDocument.getRequestedActions();
411         assertTrue(actions.isApproveRequested());
412         workflowDocument.approve("travel approval");
413 
414         workflowDocument = WorkflowDocumentFactory.loadDocument(traveler.getPrincipalId(), workflowDocument.getDocumentId());
415 
416         assertEquals( "app doc status in 'stale' WorkflowDocument retrieved before approval should still have original status", "Approval in Progress", staleWorkflowDocument.getApplicationDocumentStatus() );
417         
418         Document newWorkflowDocument = KewApiServiceLocator.getWorkflowDocumentService().getDocument(workflowDocument.getDocumentId());
419         
420         assertEquals( "current API app doc status incorrect after 2nd approval", "Submitted", newWorkflowDocument.getApplicationDocumentStatus() );
421         
422         WorkflowDocumentPrototype prototype = KEWServiceLocator.getWorkflowDocumentPrototype();
423         prototype.init(traveler.getPrincipalId(), staleWorkflowDocument);
424         prototype.setTitle(prototype.getTitle());
425         prototype.adHocToPrincipal(AdHocToPrincipal.Builder.create(ActionRequestType.FYI, null, initiator.getPrincipalId()).build(), "FYI to initiator");
426         
427         workflowDocument = WorkflowDocumentFactory.loadDocument(traveler.getPrincipalId(), workflowDocument.getDocumentId());
428 
429         assertEquals( "current app doc status incorrect after adhoc", "Submitted", workflowDocument.getApplicationDocumentStatus() );
430     }
431 
432     /**
433      * Verifies the DocumentSearchService finds documents with a given app document status
434      * @param documentTypeName the doc type
435      * @param user user for lookup
436      * @param appDocStatus the app doc status target
437      * @param expected the expected number of results
438      * @param changed the time the transition occurred (used for from/to range)
439      */
440     protected void assertSearchStatus(String documentTypeName, Person user, String appDocStatus, int expected, long changed) {
441         DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create();
442         criteria.setDocumentTypeName(documentTypeName);
443         criteria.setApplicationDocumentStatus(appDocStatus);
444         if (changed != 0) {
445             criteria.setDateApplicationDocumentStatusChangedFrom(new DateTime(changed - 200));
446             criteria.setDateApplicationDocumentStatusChangedTo(new DateTime(changed + 200));
447         }
448         DocumentSearchResults results = KEWServiceLocator.getDocumentSearchService().lookupDocuments(user.getPrincipalId(), criteria.build());
449         assertEquals("Search results should have " + expected + " documents.", expected, results.getSearchResults().size());
450     }
451 
452     /**
453      * Verifies the document application document status history
454      * @param documentId the doc id
455      * @param appDocStatuses list of app doc statuses in chronological order
456      */
457     protected void assertAppDocStatuses(String documentId, String[] appDocStatuses) {
458         DocumentRouteHeaderValue drhv = KEWServiceLocator.getRouteHeaderService().getRouteHeader(documentId);
459 
460         String curStatus = KewApiConstants.UNKNOWN_STATUS;
461         if (appDocStatuses.length > 0) {
462             curStatus = appDocStatuses[appDocStatuses.length - 1];
463         }
464         assertEquals(curStatus, drhv.getAppDocStatus());
465 
466         List<DocumentStatusTransition> transitions = drhv.getAppDocStatusHistory();
467         assertEquals(appDocStatuses.length, transitions.size());
468         for (int i = 0; i < appDocStatuses.length; i++) {
469             DocumentStatusTransition trans = transitions.get(i);
470             assertEquals(appDocStatuses[i], trans.getNewAppDocStatus());
471             String prevStatus = null;
472             if (i > 0) {
473                 prevStatus = appDocStatuses[i - 1];
474             }
475             assertEquals(prevStatus, trans.getOldAppDocStatus());
476         }
477     }
478 }