001: package com.ecyrd.jspwiki.workflow;
002:
003: import java.security.Principal;
004: import java.util.Collection;
005: import java.util.List;
006: import java.util.Properties;
007:
008: import junit.framework.TestCase;
009:
010: import com.ecyrd.jspwiki.*;
011: import com.ecyrd.jspwiki.auth.Users;
012: import com.ecyrd.jspwiki.auth.WikiPrincipal;
013: import com.ecyrd.jspwiki.filters.BasicPageFilter;
014: import com.ecyrd.jspwiki.filters.FilterException;
015:
016: public class ApprovalWorkflowTest extends TestCase {
017: WorkflowBuilder m_builder;
018: TestEngine m_engine;
019: WorkflowManager m_wm;
020: DecisionQueue m_dq;
021: WikiSession m_adminSession;
022: WikiSession m_janneSession;
023:
024: protected void setUp() throws Exception {
025: super .setUp();
026: Properties props = new Properties();
027: props.load(TestEngine.findTestProperties());
028:
029: // Explicitly turn on Admin approvals for page saves and our sample approval workflow
030: props.put("jspwiki.approver.workflow.saveWikiPage", "Admin");
031: props.put("jspwiki.approver.workflow.approvalWorkflow",
032: Users.JANNE);
033:
034: // Start the wiki engine
035: m_engine = new TestEngine(props);
036: m_wm = m_engine.getWorkflowManager();
037: m_adminSession = m_engine.adminSession();
038: m_janneSession = m_engine.janneSession();
039: m_dq = m_wm.getDecisionQueue();
040: m_builder = WorkflowBuilder.getBuilder(m_engine);
041: }
042:
043: public void testBuildApprovalWorkflow() throws WikiException {
044:
045: Principal submitter = new WikiPrincipal("Submitter");
046: String workflowApproverKey = "workflow.approvalWorkflow";
047: Task prepTask = new TestPrepTask("task.preSaveWikiPage");
048: String decisionKey = "decision.saveWikiPage";
049: Fact[] facts = new Fact[3];
050: facts[0] = new Fact("fact1", new Integer(1));
051: facts[1] = new Fact("fact2", "A factual String");
052: facts[2] = new Fact("fact3", Outcome.DECISION_ACKNOWLEDGE);
053: Task completionTask = new TestPrepTask("task.saveWikiPage");
054: String rejectedMessageKey = "notification.saveWikiPage.reject";
055:
056: Workflow w = m_builder.buildApprovalWorkflow(submitter,
057: workflowApproverKey, prepTask, decisionKey, facts,
058: completionTask, rejectedMessageKey);
059: w.setWorkflowManager(m_engine.getWorkflowManager());
060:
061: // Check to see if the workflow built correctly
062: assertFalse(w.isStarted() || w.isCompleted() || w.isAborted());
063: assertNull(w.getCurrentStep());
064: assertEquals("workflow.approvalWorkflow", w.getMessageKey());
065: assertEquals(Workflow.CREATED, w.getCurrentState());
066: assertEquals(new WikiPrincipal("Submitter"), w.getOwner());
067: assertEquals(m_engine.getWorkflowManager(), w
068: .getWorkflowManager());
069: assertEquals(0, w.getHistory().size());
070:
071: // Our dummy "task complete" attributes should still be null
072: assertNull(w.getAttribute("task.preSaveWikiPage"));
073: assertNull(w.getAttribute("task.saveWikiPage"));
074:
075: // Start the workflow
076: w.start();
077:
078: // Presave complete attribute should be set now, and current step should be Decision
079: Step decision = w.getCurrentStep();
080: assertTrue(decision instanceof Decision);
081: assertEquals(2, w.getHistory().size());
082: assertEquals(prepTask, w.getHistory().get(0));
083: assertTrue(w.getHistory().get(1) instanceof Decision);
084: assertNotNull(w.getAttribute("task.preSaveWikiPage"));
085: assertEquals(new WikiPrincipal(Users.JANNE), decision
086: .getActor());
087: assertEquals(decisionKey, decision.getMessageKey());
088: List decisionFacts = ((Decision) decision).getFacts();
089: assertEquals(3, decisionFacts.size());
090: assertEquals(facts[0], decisionFacts.get(0));
091: assertEquals(facts[1], decisionFacts.get(1));
092: assertEquals(facts[2], decisionFacts.get(2));
093:
094: // Check that our predecessor/successor relationships are ok
095: assertEquals(decision, prepTask
096: .getSuccessor(Outcome.STEP_COMPLETE));
097: assertEquals(null, prepTask.getSuccessor(Outcome.STEP_ABORT));
098: assertEquals(null, prepTask.getSuccessor(Outcome.STEP_CONTINUE));
099: assertEquals(null, decision
100: .getSuccessor(Outcome.DECISION_ACKNOWLEDGE));
101: assertEquals(null, decision.getSuccessor(Outcome.DECISION_HOLD));
102: assertEquals(null, decision
103: .getSuccessor(Outcome.DECISION_REASSIGN));
104: assertEquals(completionTask, decision
105: .getSuccessor(Outcome.DECISION_APPROVE));
106:
107: // The "deny" notification should use the right key
108: Step notification = decision
109: .getSuccessor(Outcome.DECISION_DENY);
110: assertNotNull(notification);
111: assertEquals(rejectedMessageKey, notification.getMessageKey());
112: assertTrue(notification instanceof SimpleNotification);
113:
114: // Now, approve the Decision and everything should complete
115: ((Decision) decision).decide(Outcome.DECISION_APPROVE);
116: assertTrue(w.isCompleted());
117: assertNull(w.getCurrentStep());
118: assertEquals(3, w.getHistory().size());
119: assertEquals(completionTask, w.getHistory().get(2));
120: assertTrue(completionTask.isCompleted());
121: assertEquals(Outcome.STEP_COMPLETE, completionTask.getOutcome());
122: }
123:
124: public void testBuildApprovalWorkflowDeny() throws WikiException {
125: Principal submitter = new WikiPrincipal("Submitter");
126: String workflowApproverKey = "workflow.approvalWorkflow";
127: Task prepTask = new TestPrepTask("task.preSaveWikiPage");
128: String decisionKey = "decision.saveWikiPage";
129: Fact[] facts = new Fact[3];
130: facts[0] = new Fact("fact1", new Integer(1));
131: facts[1] = new Fact("fact2", "A factual String");
132: facts[2] = new Fact("fact3", Outcome.DECISION_ACKNOWLEDGE);
133: Task completionTask = new TestPrepTask("task.saveWikiPage");
134: String rejectedMessageKey = "notification.saveWikiPage.reject";
135:
136: Workflow w = m_builder.buildApprovalWorkflow(submitter,
137: workflowApproverKey, prepTask, decisionKey, facts,
138: completionTask, rejectedMessageKey);
139: w.setWorkflowManager(m_engine.getWorkflowManager());
140:
141: // Start the workflow
142: w.start();
143:
144: // Now, deny the Decision and the submitter should see a notification
145: Step step = w.getCurrentStep();
146: assertTrue(step instanceof Decision);
147: Decision decision = (Decision) step;
148: decision.decide(Outcome.DECISION_DENY);
149: assertFalse(w.isCompleted());
150:
151: // Check that the notification is ok, then acknowledge it
152: step = w.getCurrentStep();
153: assertTrue(step instanceof SimpleNotification);
154: assertEquals(rejectedMessageKey, step.getMessageKey());
155: SimpleNotification notification = (SimpleNotification) step;
156: notification.acknowledge();
157:
158: // Workflow should be complete now
159: assertTrue(w.isCompleted());
160: assertNull(w.getCurrentStep());
161: assertEquals(3, w.getHistory().size());
162: assertEquals(notification, w.getHistory().get(2));
163: }
164:
165: public void testSaveWikiPageWithApproval() throws WikiException {
166: // Create a sample test page and try to save it
167: String pageName = "SaveWikiPageWorkflow-Test"
168: + System.currentTimeMillis();
169: String text = "This is a test!";
170: try {
171: m_engine.saveTextAsJanne(pageName, text);
172: } catch (DecisionRequiredException e) {
173: // Swallow exception, because it is expected...
174: }
175:
176: // How do we know the workflow works? Well, first of all the page shouldn't exist yet...
177: assertFalse(m_engine.pageExists(pageName));
178:
179: // Second, GroupPrincipal Admin should see a Decision in its queue
180: Collection decisions = m_dq.getActorDecisions(m_adminSession);
181: assertEquals(1, decisions.size());
182:
183: // Now, approve the decision and it should go away, and page should apppear.
184: Decision decision = (Decision) decisions.iterator().next();
185: decision.decide(Outcome.DECISION_APPROVE);
186: assertTrue(m_engine.pageExists(pageName));
187: decisions = m_dq.getActorDecisions(m_adminSession);
188: assertEquals(0, decisions.size());
189:
190: // Delete the page we created
191: m_engine.deletePage(pageName);
192: }
193:
194: public void testSaveWikiPageWithRejection() throws WikiException {
195: // Create a sample test page and try to save it
196: String pageName = "SaveWikiPageWorkflow-Test"
197: + System.currentTimeMillis();
198: String text = "This is a test!";
199: try {
200: m_engine.saveTextAsJanne(pageName, text);
201: } catch (DecisionRequiredException e) {
202: // Swallow exception, because it is expected...
203: }
204:
205: // How do we know the workflow works? Well, first of all the page shouldn't exist yet...
206: assertFalse(m_engine.pageExists(pageName));
207:
208: // ...and there should be a Decision in GroupPrincipal Admin's queue
209: Collection decisions = m_dq.getActorDecisions(m_adminSession);
210: assertEquals(1, decisions.size());
211:
212: // Now, DENY the decision and the page should still not exist...
213: Decision decision = (Decision) decisions.iterator().next();
214: decision.decide(Outcome.DECISION_DENY);
215: assertFalse(m_engine.pageExists(pageName));
216:
217: // ...but there should also be a notification decision in Janne's queue
218: decisions = m_dq.getActorDecisions(m_janneSession);
219: assertEquals(1, decisions.size());
220: decision = (Decision) decisions.iterator().next();
221: assertEquals(PageManager.SAVE_REJECT_MESSAGE_KEY, decision
222: .getMessageKey());
223:
224: // Once Janne disposes of the notification, his queue should be empty
225: decision.decide(Outcome.DECISION_ACKNOWLEDGE);
226: decisions = m_dq.getActorDecisions(m_janneSession);
227: assertEquals(0, decisions.size());
228: }
229:
230: public void testSaveWikiPageWithException() throws WikiException {
231: // Add a PageFilter that rejects all save attempts
232: m_engine.getFilterManager().addPageFilter(new AbortFilter(), 0);
233:
234: // Create a sample test page and try to save it
235: String pageName = "SaveWikiPageWorkflow-Test"
236: + System.currentTimeMillis();
237: String text = "This is a test!";
238: try {
239: m_engine.saveTextAsJanne(pageName, text);
240: } catch (WikiException e) {
241: assertTrue(e instanceof FilterException);
242: assertEquals("Page save aborted.", e.getMessage());
243: return;
244: }
245: fail("Page save should have thrown a FilterException, but didn't.");
246: }
247:
248: /**
249: * Sample "prep task" that sets an attribute in the workflow indicating
250: * that it ran successfully,
251: * @author Andrew Jaquith
252: */
253: public static class TestPrepTask extends Task {
254:
255: public TestPrepTask(String messageKey) {
256: super (messageKey);
257: }
258:
259: public Outcome execute() throws WikiException {
260: getWorkflow().setAttribute(getMessageKey(), "Completed");
261: setOutcome(Outcome.STEP_COMPLETE);
262: return Outcome.STEP_COMPLETE;
263: }
264:
265: }
266:
267: /**
268: * Dummy PageFilter that always throws a FilterException during preSave operations.
269: * @author Andrew Jaquith
270: */
271: public static class AbortFilter extends BasicPageFilter {
272: public String preSave(WikiContext wikiContext, String content)
273: throws FilterException {
274: throw new FilterException("Page save aborted.");
275: }
276: }
277:
278: }
|