You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by aj...@apache.org on 2008/02/13 07:22:49 UTC

svn commit: r627269 [3/3] - in /incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com: ./ ecyrd/ ecyrd/jspwiki/ ecyrd/jspwiki/plugin/ ecyrd/jspwiki/providers/ ecyrd/jspwiki/render/ ecyrd/jspwiki/rss/ ecyrd/jspwiki/search/ ecyrd/jspwiki/ui/ ecyrd/...

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/ApprovalWorkflowTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,288 @@
+package com.ecyrd.jspwiki.workflow;
+
+import java.security.Principal;
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.auth.Users;
+import com.ecyrd.jspwiki.auth.WikiPrincipal;
+import com.ecyrd.jspwiki.filters.BasicPageFilter;
+import com.ecyrd.jspwiki.filters.FilterException;
+
+public class ApprovalWorkflowTest extends TestCase
+{
+    WorkflowBuilder m_builder;
+    TestEngine m_engine;
+    WorkflowManager m_wm;
+    DecisionQueue m_dq;
+    WikiSession m_adminSession;
+    WikiSession m_janneSession;
+
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        Properties props = new Properties();
+        props.load(TestEngine.findTestProperties());
+
+        // Explicitly turn on Admin approvals for page saves and our sample approval workflow
+        props.put("jspwiki.approver.workflow.saveWikiPage", "Admin");
+        props.put( "jspwiki.approver.workflow.approvalWorkflow", Users.JANNE );
+
+        // Start the wiki engine
+        m_engine = new TestEngine(props);
+        m_wm = m_engine.getWorkflowManager();
+        m_adminSession = m_engine.adminSession();
+        m_janneSession = m_engine.janneSession();
+        m_dq = m_wm.getDecisionQueue();
+        m_builder = WorkflowBuilder.getBuilder( m_engine );
+    }
+
+
+    public void testBuildApprovalWorkflow() throws WikiException
+    {
+
+        Principal submitter = new WikiPrincipal( "Submitter" );
+        String workflowApproverKey = "workflow.approvalWorkflow";
+        Task prepTask = new TestPrepTask( "task.preSaveWikiPage" );
+        String decisionKey = "decision.saveWikiPage";
+        Fact[] facts = new Fact[3];
+        facts[0] = new Fact("fact1",new Integer(1));
+        facts[1] = new Fact("fact2","A factual String");
+        facts[2] = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
+        Task completionTask = new TestPrepTask( "task.saveWikiPage" );
+        String rejectedMessageKey = "notification.saveWikiPage.reject";
+
+        Workflow w = m_builder.buildApprovalWorkflow(submitter, workflowApproverKey,
+                                                   prepTask, decisionKey, facts,
+                                                   completionTask, rejectedMessageKey);
+        w.setWorkflowManager( m_engine.getWorkflowManager() );
+
+        // Check to see if the workflow built correctly
+        assertFalse( w.isStarted() || w.isCompleted() || w.isAborted() );
+        assertNull( w.getCurrentStep() );
+        assertEquals( "workflow.approvalWorkflow", w.getMessageKey() );
+        assertEquals( Workflow.CREATED, w.getCurrentState() );
+        assertEquals( new WikiPrincipal("Submitter"), w.getOwner() );
+        assertEquals( m_engine.getWorkflowManager(), w.getWorkflowManager() );
+        assertEquals( 0, w.getHistory().size() );
+
+        // Our dummy "task complete" attributes should still be null
+        assertNull( w.getAttribute( "task.preSaveWikiPage") );
+        assertNull( w.getAttribute( "task.saveWikiPage") );
+
+        // Start the workflow
+        w.start();
+
+        // Presave complete attribute should be set now, and current step should be Decision
+        Step decision = w.getCurrentStep();
+        assertTrue( decision instanceof Decision );
+        assertEquals( 2, w.getHistory().size() );
+        assertEquals( prepTask, w.getHistory().get( 0 ) );
+        assertTrue( w.getHistory().get( 1 ) instanceof Decision );
+        assertNotNull( w.getAttribute( "task.preSaveWikiPage") );
+        assertEquals( new WikiPrincipal( Users.JANNE ), decision.getActor() );
+        assertEquals( decisionKey, decision.getMessageKey() );
+        List decisionFacts = ((Decision)decision).getFacts();
+        assertEquals( 3, decisionFacts.size() );
+        assertEquals( facts[0], decisionFacts.get(0) );
+        assertEquals( facts[1], decisionFacts.get(1) );
+        assertEquals( facts[2], decisionFacts.get(2) );
+
+        // Check that our predecessor/successor relationships are ok
+        assertEquals( decision, prepTask.getSuccessor( Outcome.STEP_COMPLETE ) );
+        assertEquals( null, prepTask.getSuccessor( Outcome.STEP_ABORT ) );
+        assertEquals( null, prepTask.getSuccessor( Outcome.STEP_CONTINUE ) );
+        assertEquals( null, decision.getSuccessor( Outcome.DECISION_ACKNOWLEDGE ) );
+        assertEquals( null, decision.getSuccessor( Outcome.DECISION_HOLD ) );
+        assertEquals( null, decision.getSuccessor( Outcome.DECISION_REASSIGN ) );
+        assertEquals( completionTask, decision.getSuccessor( Outcome.DECISION_APPROVE ) );
+
+        // The "deny" notification should use the right key
+        Step notification = decision.getSuccessor( Outcome.DECISION_DENY );
+        assertNotNull( notification );
+        assertEquals( rejectedMessageKey, notification.getMessageKey() );
+        assertTrue( notification instanceof SimpleNotification );
+
+        // Now, approve the Decision and everything should complete
+        ((Decision)decision).decide( Outcome.DECISION_APPROVE );
+        assertTrue( w.isCompleted() );
+        assertNull( w.getCurrentStep() );
+        assertEquals( 3, w.getHistory().size() );
+        assertEquals( completionTask, w.getHistory().get( 2 ) );
+        assertTrue( completionTask.isCompleted() );
+        assertEquals( Outcome.STEP_COMPLETE, completionTask.getOutcome() );
+    }
+
+    public void testBuildApprovalWorkflowDeny() throws WikiException
+    {
+        Principal submitter = new WikiPrincipal( "Submitter" );
+        String workflowApproverKey = "workflow.approvalWorkflow";
+        Task prepTask = new TestPrepTask( "task.preSaveWikiPage" );
+        String decisionKey = "decision.saveWikiPage";
+        Fact[] facts = new Fact[3];
+        facts[0] = new Fact("fact1",new Integer(1));
+        facts[1] = new Fact("fact2","A factual String");
+        facts[2] = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
+        Task completionTask = new TestPrepTask( "task.saveWikiPage" );
+        String rejectedMessageKey = "notification.saveWikiPage.reject";
+
+        Workflow w = m_builder.buildApprovalWorkflow(submitter, workflowApproverKey,
+                                                   prepTask, decisionKey, facts,
+                                                   completionTask, rejectedMessageKey);
+        w.setWorkflowManager( m_engine.getWorkflowManager() );
+
+        // Start the workflow
+        w.start();
+
+        // Now, deny the Decision and the submitter should see a notification
+        Step step = w.getCurrentStep();
+        assertTrue( step instanceof Decision );
+        Decision decision = (Decision)step;
+        decision.decide( Outcome.DECISION_DENY );
+        assertFalse( w.isCompleted() );
+
+        // Check that the notification is ok, then acknowledge it
+        step = w.getCurrentStep();
+        assertTrue( step instanceof SimpleNotification );
+        assertEquals( rejectedMessageKey, step.getMessageKey() );
+        SimpleNotification notification = (SimpleNotification)step;
+        notification.acknowledge();
+
+        // Workflow should be complete now
+        assertTrue( w.isCompleted() );
+        assertNull( w.getCurrentStep() );
+        assertEquals( 3, w.getHistory().size() );
+        assertEquals( notification, w.getHistory().get( 2 ) );
+    }
+
+    public void testSaveWikiPageWithApproval() throws WikiException
+    {
+        // Create a sample test page and try to save it
+        String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();
+        String text = "This is a test!";
+        try
+        {
+            m_engine.saveTextAsJanne(pageName, text);
+        }
+        catch ( DecisionRequiredException e )
+        {
+            // Swallow exception, because it is expected...
+        }
+
+        // How do we know the workflow works? Well, first of all the page shouldn't exist yet...
+        assertFalse( m_engine.pageExists(pageName));
+
+        // Second, GroupPrincipal Admin should see a Decision in its queue
+        Collection decisions = m_dq.getActorDecisions(m_adminSession);
+        assertEquals(1, decisions.size());
+
+        // Now, approve the decision and it should go away, and page should apppear.
+        Decision decision = (Decision)decisions.iterator().next();
+        decision.decide(Outcome.DECISION_APPROVE);
+        assertTrue( m_engine.pageExists(pageName));
+        decisions = m_dq.getActorDecisions(m_adminSession);
+        assertEquals(0, decisions.size());
+
+        // Delete the page we created
+        m_engine.deletePage( pageName );
+    }
+
+    public void testSaveWikiPageWithRejection() throws WikiException
+    {
+        // Create a sample test page and try to save it
+        String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();
+        String text = "This is a test!";
+        try
+        {
+            m_engine.saveTextAsJanne(pageName, text);
+        }
+        catch ( DecisionRequiredException e )
+        {
+            // Swallow exception, because it is expected...
+        }
+
+        // How do we know the workflow works? Well, first of all the page shouldn't exist yet...
+        assertFalse( m_engine.pageExists(pageName));
+
+        // ...and there should be a Decision in GroupPrincipal Admin's queue
+        Collection decisions = m_dq.getActorDecisions(m_adminSession);
+        assertEquals(1, decisions.size());
+
+        // Now, DENY the decision and the page should still not exist...
+        Decision decision = (Decision)decisions.iterator().next();
+        decision.decide(Outcome.DECISION_DENY);
+        assertFalse( m_engine.pageExists(pageName) );
+
+        // ...but there should also be a notification decision in Janne's queue
+        decisions = m_dq.getActorDecisions(m_janneSession);
+        assertEquals(1, decisions.size());
+        decision = (Decision)decisions.iterator().next();
+        assertEquals(PageManager.SAVE_REJECT_MESSAGE_KEY, decision.getMessageKey());
+
+        // Once Janne disposes of the notification, his queue should be empty
+        decision.decide(Outcome.DECISION_ACKNOWLEDGE);
+        decisions = m_dq.getActorDecisions(m_janneSession);
+        assertEquals(0, decisions.size());
+    }
+
+    public void testSaveWikiPageWithException() throws WikiException
+    {
+        // Add a PageFilter that rejects all save attempts
+        m_engine.getFilterManager().addPageFilter( new AbortFilter(), 0 );
+
+        // Create a sample test page and try to save it
+        String pageName = "SaveWikiPageWorkflow-Test" + System.currentTimeMillis();
+        String text = "This is a test!";
+        try
+        {
+            m_engine.saveTextAsJanne(pageName, text);
+        }
+        catch ( WikiException e )
+        {
+            assertTrue( e instanceof FilterException );
+            assertEquals( "Page save aborted.", e.getMessage() );
+            return;
+        }
+        fail( "Page save should have thrown a FilterException, but didn't." );
+    }
+
+    /**
+     * Sample "prep task" that sets an attribute in the workflow indicating
+     * that it ran successfully,
+     * @author Andrew Jaquith
+     */
+    public static class TestPrepTask extends Task
+    {
+
+        public TestPrepTask( String messageKey )
+        {
+            super( messageKey );
+        }
+
+        public Outcome execute() throws WikiException
+        {
+            getWorkflow().setAttribute( getMessageKey(), "Completed" );
+            setOutcome( Outcome.STEP_COMPLETE );
+            return Outcome.STEP_COMPLETE;
+        }
+
+    }
+
+    /**
+     * Dummy PageFilter that always throws a FilterException during preSave operations.
+     * @author Andrew Jaquith
+     */
+    public static class AbortFilter extends BasicPageFilter
+    {
+        public String preSave(WikiContext wikiContext, String content) throws FilterException
+        {
+            throw new FilterException( "Page save aborted." );
+        }
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/DecisionQueueTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/DecisionQueueTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/DecisionQueueTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/DecisionQueueTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,188 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Copyright (C) 2001-2007 Janne Jalkanen (Janne.Jalkanen@iki.fi)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published by
+    the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package com.ecyrd.jspwiki.workflow;
+
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import com.ecyrd.jspwiki.TestEngine;
+import com.ecyrd.jspwiki.WikiException;
+import com.ecyrd.jspwiki.WikiSession;
+import com.ecyrd.jspwiki.auth.GroupPrincipal;
+import com.ecyrd.jspwiki.auth.WikiPrincipal;
+
+public class DecisionQueueTest extends TestCase
+{
+
+    TestEngine m_engine;
+
+    DecisionQueue m_queue;
+
+    Workflow w;
+
+    Decision d1;
+
+    Decision d2;
+
+    Decision d3;
+
+    WikiSession janneSession;
+
+    WikiSession adminSession;
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        Properties props = new Properties();
+        props.load(TestEngine.findTestProperties());
+        m_engine = new TestEngine(props);
+        m_queue = m_engine.getWorkflowManager().getDecisionQueue();
+        adminSession = m_engine.adminSession();
+        janneSession = m_engine.janneSession();
+        w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
+        w.setWorkflowManager(m_engine.getWorkflowManager());
+        d1 = new SimpleDecision(w, "decision1.key", new GroupPrincipal("Admin"));
+        d2 = new SimpleDecision(w, "decision2.key", new WikiPrincipal("Owner2"));
+        d3 = new SimpleDecision(w, "decision3.key", janneSession.getUserPrincipal());
+        m_queue.add(d1);
+        m_queue.add(d2);
+        m_queue.add(d3);
+    }
+
+    public void testAdd()
+    {
+        Decision[] decisions = m_queue.decisions();
+        assertEquals(d1, decisions[0]);
+        assertEquals(d2, decisions[1]);
+        assertEquals(d3, decisions[2]);
+    }
+
+    public void testRemove()
+    {
+        Decision[] decisions = m_queue.decisions();
+        assertEquals(3, decisions.length);
+
+        m_queue.remove(d2);
+        decisions = m_queue.decisions();
+        assertEquals(2, decisions.length);
+        assertEquals(d1, decisions[0]);
+        assertEquals(d3, decisions[1]);
+
+        m_queue.remove(d1);
+        decisions = m_queue.decisions();
+        assertEquals(1, decisions.length);
+        assertEquals(d3, decisions[0]);
+
+        m_queue.remove(d3);
+        decisions = m_queue.decisions();
+        assertEquals(0, decisions.length);
+    }
+
+    public void testComplete() throws WikiException
+    {
+        assertEquals(3, m_queue.decisions().length);
+
+        // Execute the competion for decision 1 (approve/deny)
+        m_queue.decide(d1, Outcome.DECISION_APPROVE);
+
+        // Decision should be marked completed, and removed from queue
+        assertTrue(d1.isCompleted());
+        assertEquals(2, m_queue.decisions().length);
+
+        // Execute the competion for decision 2 (approve/deny/hold)
+        m_queue.decide(d2, Outcome.DECISION_DENY);
+
+        // Decision should be marked completed, and removed from queue
+        assertTrue(d2.isCompleted());
+        assertEquals(1, m_queue.decisions().length);
+    }
+
+    public void testReassign() throws WikiException
+    {
+        // Janne owns 1 decision (d3)
+        assertEquals(janneSession.getUserPrincipal(), d3.getActor());
+        assertEquals(1, m_queue.getActorDecisions(janneSession).size());
+
+        // Reassign the decision
+        m_queue.reassign(d3, new WikiPrincipal("NewOwner"));
+
+        // d3 should have a different owner now, and it won't show up in
+        // Janne's decision list
+        assertEquals(new WikiPrincipal("NewOwner"), d3.getActor());
+        assertEquals(0, m_queue.getActorDecisions(janneSession).size());
+    }
+
+    public void testDecisions()
+    {
+        Decision[] decisions = m_queue.decisions();
+        assertEquals(3, decisions.length);
+        assertEquals(d1, decisions[0]);
+        assertEquals(d2, decisions[1]);
+        assertEquals(d3, decisions[2]);
+    }
+
+    public void testActorDecisions()
+    {
+        Collection decisions = m_queue.getActorDecisions(adminSession);
+        assertEquals(1, decisions.size());
+
+        decisions = m_queue.getActorDecisions(janneSession);
+        assertEquals(1, decisions.size());
+    }
+
+    public void testDecisionWorkflow() throws WikiException
+    {
+        Principal janne = janneSession.getUserPrincipal();
+
+        // Clean out the queue first
+        m_queue.remove(d1);
+        m_queue.remove(d2);
+        m_queue.remove(d3);
+
+        // Create a workflow with 3 steps, with a Decision for Janne in the middle
+        w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
+        w.setWorkflowManager(m_engine.getWorkflowManager());
+        Step startTask = new TaskTest.NormalTask(w);
+        Step endTask = new TaskTest.NormalTask(w);
+        Decision decision = new SimpleDecision(w, "decision.Actor1Decision", janne);
+        startTask.addSuccessor(Outcome.STEP_COMPLETE, decision);
+        decision.addSuccessor(Outcome.DECISION_APPROVE, endTask);
+        w.setFirstStep(startTask);
+
+        // Start the workflow, and verify that the Decision is the current Step
+        w.start();
+        assertEquals(decision, w.getCurrentStep());
+
+        // Verify that it's also in Janne's DecisionQueue
+        Collection decisions = m_queue.getActorDecisions(janneSession);
+        assertEquals(1, decisions.size());
+        Decision d = (Decision)decisions.iterator().next();
+        assertEquals(decision, d);
+
+        // Make Decision, and verify that it's gone from the queue
+        m_queue.decide(decision, Outcome.DECISION_APPROVE);
+        decisions = m_queue.getActorDecisions(janneSession);
+        assertEquals(0, decisions.size());
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/FactTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/FactTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/FactTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/FactTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,23 @@
+package com.ecyrd.jspwiki.workflow;
+
+import junit.framework.TestCase;
+
+public class FactTest extends TestCase
+{
+
+    public void testCreate()
+    {
+        Fact f1 = new Fact("fact1",new Integer(1));
+        Fact f2 = new Fact("fact2","A factual String");
+        Fact f3 = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
+
+        assertEquals("fact1", f1.getMessageKey());
+        assertEquals("fact2", f2.getMessageKey());
+        assertEquals("fact3", f3.getMessageKey());
+
+        assertEquals(new Integer(1), f1.getValue());
+        assertEquals("A factual String", f2.getValue());
+        assertEquals(Outcome.DECISION_ACKNOWLEDGE, f3.getValue());
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/OutcomeTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/OutcomeTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/OutcomeTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/OutcomeTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,104 @@
+package com.ecyrd.jspwiki.workflow;
+
+import java.util.Locale;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import com.ecyrd.jspwiki.TestEngine;
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.i18n.InternationalizationManager;
+
+public class OutcomeTest extends TestCase
+{
+
+    public void testGetKey()
+    {
+        assertEquals("outcome.decision.approve", Outcome.DECISION_APPROVE.getMessageKey());
+        assertEquals("outcome.decision.hold", Outcome.DECISION_HOLD.getMessageKey());
+        assertEquals("outcome.decision.deny", Outcome.DECISION_DENY.getMessageKey());
+        assertEquals("outcome.decision.reassign", Outcome.DECISION_REASSIGN.getMessageKey());
+    }
+
+    public void testHashCode()
+    {
+        assertEquals("outcome.decision.approve".hashCode(), Outcome.DECISION_APPROVE.hashCode());
+        assertEquals("outcome.decision.hold".hashCode()*2, Outcome.DECISION_HOLD.hashCode());
+        assertEquals("outcome.decision.deny".hashCode(), Outcome.DECISION_DENY.hashCode());
+        assertEquals("outcome.decision.reassign".hashCode()*2, Outcome.DECISION_REASSIGN.hashCode());
+    }
+
+    public void testEquals()
+    {
+        assertEquals(Outcome.DECISION_APPROVE, Outcome.DECISION_APPROVE);
+        assertNotSame(Outcome.DECISION_APPROVE, Outcome.DECISION_REASSIGN);
+    }
+
+    public void testMessage() throws Exception
+    {
+        Properties props = new Properties();
+        props.load(TestEngine.findTestProperties());
+        WikiEngine engine = new TestEngine(props);
+        InternationalizationManager i18n = engine.getInternationalizationManager();
+        String core = InternationalizationManager.CORE_BUNDLE;
+        Locale english = Locale.ENGLISH;
+        Outcome o;
+
+        o = Outcome.DECISION_APPROVE;
+        assertEquals("Approve", i18n.get(core, english, o.getMessageKey()));
+
+        o = Outcome.DECISION_DENY;
+        assertEquals("Deny", i18n.get(core, english, o.getMessageKey()));
+
+        o = Outcome.DECISION_HOLD;
+        assertEquals("Hold", i18n.get(core, english, o.getMessageKey()));
+
+        o = Outcome.DECISION_REASSIGN;
+        assertEquals("Reassign", i18n.get(core, english, o.getMessageKey()));
+    }
+
+    public void testIsCompletion()
+    {
+        assertTrue(Outcome.DECISION_ACKNOWLEDGE.isCompletion());
+        assertTrue(Outcome.DECISION_APPROVE.isCompletion());
+        assertTrue(Outcome.DECISION_DENY.isCompletion());
+        assertFalse(Outcome.DECISION_HOLD.isCompletion());
+        assertFalse(Outcome.DECISION_REASSIGN.isCompletion());
+        assertTrue(Outcome.STEP_ABORT.isCompletion());
+        assertTrue(Outcome.STEP_COMPLETE.isCompletion());
+        assertFalse(Outcome.STEP_CONTINUE.isCompletion());
+    }
+
+    public void testForName()
+    {
+        try
+        {
+            assertEquals(Outcome.DECISION_ACKNOWLEDGE, Outcome.forName("outcome.decision.acknowledge"));
+            assertEquals(Outcome.DECISION_APPROVE, Outcome.forName("outcome.decision.approve"));
+            assertEquals(Outcome.DECISION_DENY, Outcome.forName("outcome.decision.deny"));
+            assertEquals(Outcome.DECISION_HOLD, Outcome.forName("outcome.decision.hold"));
+            assertEquals(Outcome.DECISION_REASSIGN, Outcome.forName("outcome.decision.reassign"));
+            assertEquals(Outcome.STEP_ABORT, Outcome.forName("outcome.step.abort"));
+            assertEquals(Outcome.STEP_COMPLETE, Outcome.forName("outcome.step.complete"));
+            assertEquals(Outcome.STEP_CONTINUE, Outcome.forName("outcome.step.continue"));
+        }
+        catch (NoSuchOutcomeException e)
+        {
+            // We should never get here
+            fail("Could not look up an Outcome...");
+        }
+
+        // Look for a non-existent one
+        try
+        {
+            Outcome.forName("outcome.decision.nonexistent");
+        }
+        catch (NoSuchOutcomeException e)
+        {
+            return;
+        }
+        // We should never get here
+        fail("Could not look up an Outcome...");
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/SimpleDecisionTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/SimpleDecisionTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/SimpleDecisionTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/SimpleDecisionTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,167 @@
+package com.ecyrd.jspwiki.workflow;
+
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import com.ecyrd.jspwiki.WikiException;
+import com.ecyrd.jspwiki.auth.WikiPrincipal;
+
+public class SimpleDecisionTest extends TestCase
+{
+
+    Workflow m_workflow;
+    Decision m_decision;
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        m_workflow = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
+        m_decision = new SimpleDecision(m_workflow, "decision.key", new WikiPrincipal("Actor1"));
+    }
+
+    public void testAddFacts()
+    {
+        Fact f1 = new Fact("fact1",new Integer(1));
+        Fact f2 = new Fact("fact2","A factual String");
+        Fact f3 = new Fact("fact3",Outcome.DECISION_ACKNOWLEDGE);
+        m_decision.addFact(f1);
+        m_decision.addFact(f2);
+        m_decision.addFact(f3);
+
+        // The facts should be available, and returned in order
+        List facts = m_decision.getFacts();
+        assertEquals(f1, facts.get(0));
+        assertEquals(f2, facts.get(1));
+        assertEquals(f3, facts.get(2));
+    }
+
+    public void testGetActor()
+    {
+       assertEquals(new WikiPrincipal("Actor1"), m_decision.getActor());
+    }
+
+    public void testGetDefaultOutcome()
+    {
+        assertEquals(Outcome.DECISION_APPROVE, m_decision.getDefaultOutcome());
+    }
+
+    public void testIsReassignable()
+    {
+        assertTrue(m_decision.isReassignable());
+    }
+
+    public void testReassign()
+    {
+        m_decision.reassign(new WikiPrincipal("Actor2"));
+        assertEquals(new WikiPrincipal("Actor2"), m_decision.getActor());
+    }
+
+    public void testSuccessors()
+    {
+        // If the decision is approved, branch to another decision (d2)
+        Step d2 = new SimpleDecision(m_workflow, "decision2.key", new WikiPrincipal("Actor1"));
+        m_decision.addSuccessor(Outcome.DECISION_APPROVE, d2);
+
+        // If the decision is denied, branch to another decision (d3)
+        Step d3 = new SimpleDecision(m_workflow, "decision3.key", new WikiPrincipal("Actor1"));
+        m_decision.addSuccessor(Outcome.DECISION_DENY, d3);
+
+        assertEquals(d2, m_decision.getSuccessor(Outcome.DECISION_APPROVE));
+        assertEquals(d3, m_decision.getSuccessor(Outcome.DECISION_DENY));
+
+        // The other Outcomes should return null when looked up
+        assertNull(m_decision.getSuccessor(Outcome.DECISION_HOLD));
+        assertNull(m_decision.getSuccessor(Outcome.DECISION_REASSIGN));
+        assertNull(m_decision.getSuccessor(Outcome.STEP_ABORT));
+    }
+
+    public void testErrors()
+    {
+        m_decision.addError("Error deciding something.");
+        m_decision.addError("Error deciding something else.");
+
+        List errors = m_decision.getErrors();
+        assertEquals(2, errors.size());
+        assertEquals("Error deciding something.", errors.get(0));
+        assertEquals("Error deciding something else.", errors.get(1));
+    }
+
+    public void testAvailableOutcomes()
+    {
+        Collection outcomes = m_decision.getAvailableOutcomes();
+        assertTrue(outcomes.contains(Outcome.DECISION_APPROVE));
+        assertTrue(outcomes.contains(Outcome.DECISION_DENY));
+        assertFalse(outcomes.contains(Outcome.DECISION_HOLD));
+        assertFalse(outcomes.contains(Outcome.DECISION_REASSIGN));
+        assertFalse(outcomes.contains(Outcome.STEP_ABORT));
+        assertFalse(outcomes.contains(Outcome.STEP_COMPLETE));
+    }
+
+    public void testGetEndTime() throws WikiException
+    {
+        assertEquals(Workflow.TIME_NOT_SET, m_decision.getEndTime());
+        m_decision.start();
+        m_decision.decide(Outcome.DECISION_APPROVE);
+        assertTrue((Workflow.TIME_NOT_SET  !=  m_decision.getEndTime()));
+    }
+
+    public void testGetMessageKey()
+    {
+        assertEquals("decision.key",m_decision.getMessageKey());
+    }
+
+    public void testGetOutcome() throws WikiException
+    {
+        assertEquals(Outcome.STEP_CONTINUE,m_decision.getOutcome());
+        m_decision.start();
+        m_decision.decide(Outcome.DECISION_APPROVE);
+        assertEquals(Outcome.DECISION_APPROVE, m_decision.getOutcome());
+    }
+
+    public void testGetStartTime() throws WikiException
+    {
+        assertEquals(Workflow.TIME_NOT_SET, m_decision.getStartTime());
+        m_decision.start();
+        m_decision.decide(Outcome.DECISION_APPROVE);
+        assertTrue((Workflow.TIME_NOT_SET  !=  m_decision.getStartTime()));
+    }
+
+    public void testGetWorkflow()
+    {
+        assertEquals(m_workflow, m_decision.getWorkflow());
+    }
+
+    public void testIsCompleted() throws WikiException
+    {
+        assertFalse(m_decision.isCompleted());
+        m_decision.start();
+        m_decision.decide(Outcome.DECISION_APPROVE);
+        assertTrue(m_decision.isCompleted());
+    }
+
+    public void testIsStarted() throws WikiException
+    {
+        assertFalse(m_decision.isStarted());
+        m_decision.start();
+        assertTrue(m_decision.isStarted());
+    }
+
+    public void testStartTwice() throws WikiException
+    {
+        m_decision.start();
+        try
+        {
+            m_decision.start();
+        }
+        catch (IllegalStateException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Decision allowed itself to be started twice!");
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/TaskTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/TaskTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/TaskTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/TaskTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,175 @@
+package com.ecyrd.jspwiki.workflow;
+
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import com.ecyrd.jspwiki.WikiException;
+import com.ecyrd.jspwiki.auth.WikiPrincipal;
+
+public class TaskTest extends TestCase
+{
+
+    Workflow m_workflow;
+    Task m_task;
+
+    /** Sample Task that completes normally. */
+    public static class NormalTask extends Task
+    {
+        public NormalTask(Workflow workflow)
+        {
+            super(workflow, "task.normal");
+        }
+        public Outcome execute() throws WikiException
+        {
+            return Outcome.STEP_COMPLETE;
+        }
+
+    }
+
+    /** Sample Task that encounters an error during processing. */
+    public static class ErrorTask extends Task
+    {
+        public ErrorTask(Workflow workflow)
+        {
+            super(workflow, "task.error");
+        }
+        public Outcome execute() throws WikiException
+        {
+            addError("Found an error.");
+            addError("Found a second one!");
+            return Outcome.STEP_ABORT;
+        }
+
+    }
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        m_workflow = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
+        m_task = new NormalTask(m_workflow);
+    }
+
+    public void testGetActor()
+    {
+       assertNotSame(new WikiPrincipal("Actor1"), m_task.getActor());
+       assertEquals(SystemPrincipal.SYSTEM_USER, m_task.getActor());
+    }
+
+    public void testSuccessors()
+    {
+        // If task finishes normally, branch to a decision (d1)
+        Step d1 = new SimpleDecision(m_workflow, "decision1.key", new WikiPrincipal("Actor1"));
+        m_task.addSuccessor(Outcome.STEP_COMPLETE, d1);
+
+        // If the task aborts, branch to an alternate decision (d2)
+        Step d2 = new SimpleDecision(m_workflow, "decision2.key", new WikiPrincipal("Actor2"));
+        m_task.addSuccessor(Outcome.STEP_ABORT, d2);
+
+        assertEquals(d1, m_task.getSuccessor(Outcome.STEP_COMPLETE));
+        assertEquals(d2, m_task.getSuccessor(Outcome.STEP_ABORT));
+
+        // The other Outcomes should return null when looked up
+        assertNull(m_task.getSuccessor(Outcome.DECISION_APPROVE));
+        assertNull(m_task.getSuccessor(Outcome.DECISION_DENY));
+        assertNull(m_task.getSuccessor(Outcome.DECISION_HOLD));
+        assertNull(m_task.getSuccessor(Outcome.DECISION_REASSIGN));
+        assertNull(m_task.getSuccessor(Outcome.STEP_CONTINUE));
+    }
+
+    public void testErrors()
+    {
+        m_task.addError("Error deciding something.");
+        m_task.addError("Error deciding something else.");
+
+        List errors = m_task.getErrors();
+        assertEquals(2, errors.size());
+        assertEquals("Error deciding something.", errors.get(0));
+        assertEquals("Error deciding something else.", errors.get(1));
+    }
+
+    public void testAvailableOutcomes()
+    {
+        Collection outcomes = m_task.getAvailableOutcomes();
+        assertFalse(outcomes.contains(Outcome.DECISION_APPROVE));
+        assertFalse(outcomes.contains(Outcome.DECISION_DENY));
+        assertFalse(outcomes.contains(Outcome.DECISION_HOLD));
+        assertFalse(outcomes.contains(Outcome.DECISION_REASSIGN));
+        assertTrue(outcomes.contains(Outcome.STEP_ABORT));
+        assertTrue(outcomes.contains(Outcome.STEP_COMPLETE));
+    }
+
+    public void testGetEndTime() throws WikiException
+    {
+        assertEquals(Workflow.TIME_NOT_SET, m_task.getEndTime());
+        m_task.start();
+        m_task.setOutcome(m_task.execute());
+        assertTrue((Workflow.TIME_NOT_SET  !=  m_task.getEndTime()));
+    }
+
+    public void testGetMessageKey()
+    {
+        assertEquals("task.normal",m_task.getMessageKey());
+    }
+
+    public void testGetOutcome() throws WikiException
+    {
+        assertEquals(Outcome.STEP_CONTINUE,m_task.getOutcome());
+        m_task.start();
+        m_task.setOutcome(m_task.execute());
+        assertEquals(Outcome.STEP_COMPLETE, m_task.getOutcome());
+
+        // Test the "error task"
+        m_task = new ErrorTask(m_workflow);
+        assertEquals(Outcome.STEP_CONTINUE,m_task.getOutcome());
+        m_task.start();
+        m_task.setOutcome(m_task.execute());
+        assertEquals(Outcome.STEP_ABORT, m_task.getOutcome());
+    }
+
+    public void testGetStartTime() throws WikiException
+    {
+        assertEquals(Workflow.TIME_NOT_SET, m_task.getStartTime());
+        m_task.start();
+        m_task.execute();
+        assertTrue((Workflow.TIME_NOT_SET  !=  m_task.getStartTime()));
+    }
+
+    public void testGetWorkflow()
+    {
+        assertEquals(m_workflow, m_task.getWorkflow());
+    }
+
+    public void testIsCompleted() throws WikiException
+    {
+        assertFalse(m_task.isCompleted());
+        m_task.start();
+        m_task.setOutcome(m_task.execute());
+        assertTrue(m_task.isCompleted());
+    }
+
+    public void testIsStarted() throws WikiException
+    {
+        assertFalse(m_task.isStarted());
+        m_task.start();
+        assertTrue(m_task.isStarted());
+    }
+
+    public void testStartTwice() throws WikiException
+    {
+        m_task.start();
+        try
+        {
+            m_task.start();
+        }
+        catch (IllegalStateException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Decision allowed itself to be started twice!");
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowManagerTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowManagerTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowManagerTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,100 @@
+package com.ecyrd.jspwiki.workflow;
+
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import com.ecyrd.jspwiki.TestEngine;
+import com.ecyrd.jspwiki.WikiEngine;
+import com.ecyrd.jspwiki.WikiException;
+import com.ecyrd.jspwiki.auth.GroupPrincipal;
+import com.ecyrd.jspwiki.auth.WikiPrincipal;
+
+public class WorkflowManagerTest extends TestCase
+{
+    protected Workflow w;
+    protected WorkflowManager wm;
+    protected WikiEngine m_engine;
+    
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        Properties props = new Properties();
+        props.load(TestEngine.findTestProperties());
+        m_engine = new TestEngine(props);
+        wm = m_engine.getWorkflowManager();
+        // Create a workflow with 3 steps, with a Decision in the middle
+        w = new Workflow("workflow.key", new WikiPrincipal("Owner1"));
+        w.setWorkflowManager(m_engine.getWorkflowManager());
+        Step startTask = new TaskTest.NormalTask(w);
+        Step endTask = new TaskTest.NormalTask(w);
+        Decision decision = new SimpleDecision(w, "decision.editWikiApproval", new WikiPrincipal("Actor1"));
+        startTask.addSuccessor(Outcome.STEP_COMPLETE, decision);
+        decision.addSuccessor(Outcome.DECISION_APPROVE, endTask);
+        w.setFirstStep(startTask);
+        
+        // Add a message argument to the workflow with the page name
+        w.addMessageArgument("MyPage");
+    }
+
+    public void testStart() throws WikiException
+    {
+        // Once we start the workflow, it should show that it's started
+        // and the WM should have assigned it an ID
+        assertEquals(Workflow.ID_NOT_SET, w.getId());
+        assertFalse(w.isStarted());
+        wm.start(w);
+        assertFalse(Workflow.ID_NOT_SET == w.getId());
+        assertTrue(w.isStarted());
+    }
+
+    public void testWorkflows() throws WikiException
+    {
+        // There should be no workflows in the cache, and none in completed list
+        assertEquals(0, wm.getWorkflows().size());
+        assertEquals(0, wm.getCompletedWorkflows().size());
+        
+        // After starting, there should be 1 in the cache, with ID=1
+        wm.start(w);
+        assertEquals(1, wm.getWorkflows().size());
+        assertEquals(0, wm.getCompletedWorkflows().size());
+        Workflow workflow = (Workflow)wm.getWorkflows().iterator().next();
+        assertEquals(w, workflow);
+        assertEquals(1, workflow.getId());
+        
+        // After forcing a decision on step 2, the workflow should complete and vanish from the cache
+        Decision d = (Decision)w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertEquals(0, wm.getWorkflows().size());
+        assertEquals(1, wm.getCompletedWorkflows().size());
+    }
+    
+    public void testRequiresApproval()
+    {
+        // Test properties says we need approvals for workflow.saveWikiPage & workflow.foo
+        assertFalse(wm.requiresApproval("workflow.saveWikiPage"));
+        assertTrue(wm.requiresApproval("workflow.foo"));
+        assertTrue(wm.requiresApproval("workflow.bar"));
+    }
+
+    public void testGetApprover() throws WikiException
+    {
+        // Test properties says workflow.saveWikiPage approver is GP Admin; workflow.foo is 'janne'
+        assertEquals(new WikiPrincipal("janne", WikiPrincipal.LOGIN_NAME), wm.getApprover("workflow.foo"));
+        assertEquals(new GroupPrincipal("Admin"), wm.getApprover("workflow.bar"));
+        
+        // 'saveWikiPage' workflow doesn't require approval, so we will need to catch an Exception
+        try 
+        {
+            assertEquals(new GroupPrincipal("Admin"), wm.getApprover("workflow.saveWikiPage"));
+        }
+        catch (WikiException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Workflow.bar doesn't need approval!");
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/workflow/WorkflowTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,369 @@
+package com.ecyrd.jspwiki.workflow;
+
+import java.math.BigDecimal;
+import java.security.Principal;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+import com.ecyrd.jspwiki.WikiException;
+import com.ecyrd.jspwiki.auth.GroupPrincipal;
+import com.ecyrd.jspwiki.auth.WikiPrincipal;
+
+public class WorkflowTest extends TestCase
+{
+    Workflow w;
+
+    Task initTask;
+
+    Decision decision;
+
+    Task finishTask;
+
+    String ATTR = "TestAttribute";
+
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+
+        // Create workflow; owner is test user
+        w = new Workflow("workflow.myworkflow", new WikiPrincipal("Owner1"));
+
+        // Create custom initialization task
+        initTask = new TaskTest.NormalTask(w);
+
+        // Create finish task
+        finishTask = new TaskTest.NormalTask(w);
+
+        // Create an intermetidate decision step
+        Principal actor = new GroupPrincipal("Admin");
+        decision = new SimpleDecision(w, "decision.AdminDecision", actor);
+
+        // Hook the steps together
+        initTask.addSuccessor(Outcome.STEP_COMPLETE, decision);
+        decision.addSuccessor(Outcome.DECISION_APPROVE, finishTask);
+
+        // Stash page name as message attribute
+        w.addMessageArgument("MyPage");
+
+        // Set workflow's first step
+        w.setFirstStep(initTask);
+    }
+
+    public void testWorkflow()
+    {
+        // Make sure everything is set to their proper default values
+        assertNull(w.getCurrentStep());
+        assertNull(w.getCurrentActor());
+        assertEquals(0, w.getHistory().size());
+        assertEquals(Workflow.ID_NOT_SET, w.getId());
+        assertNull(w.getWorkflowManager());
+        assertEquals(new WikiPrincipal("Owner1"), w.getOwner());
+        assertEquals(Workflow.CREATED, w.getCurrentState());
+        assertEquals(Workflow.TIME_NOT_SET, w.getStartTime());
+        assertEquals(Workflow.TIME_NOT_SET, w.getEndTime());
+    }
+
+    public void testSetWorkflowManager()
+    {
+        assertNull(w.getWorkflowManager());
+        WorkflowManager m = new WorkflowManager();
+        w.setWorkflowManager(m);
+        assertEquals(m, w.getWorkflowManager());
+    }
+
+    public void testGetSetAttribute()
+    {
+        assertNull(w.getAttribute(ATTR));
+        w.setAttribute(ATTR, "Test String");
+        assertNotNull(w.getAttribute(ATTR));
+        assertEquals("Test String", w.getAttribute(ATTR));
+    }
+
+    public void testGetMessageArgs() throws WikiException
+    {
+        Object[] args;
+
+        // Before start, arg1=Owner1, arg2=- (no current actor), arg3=MyPage
+        args = w.getMessageArguments();
+        assertEquals("Owner1", args[0]);
+        assertEquals("-",      args[1]);
+        assertEquals("MyPage", args[2]);
+
+        // After start (at Decision), arg1=Owner1, arg2=Admin, arg3=MyPage
+        w.start();
+        args = w.getMessageArguments();
+        assertEquals("Owner1", args[0]);
+        assertEquals("Admin", args[1]);
+        assertEquals("MyPage", args[2]);
+
+        // After end, arg1=Owner1, arg2=-, arg3=MyPage
+        decision.decide(Outcome.DECISION_APPROVE);
+        args = w.getMessageArguments();
+        assertEquals("Owner1", args[0]);
+        assertEquals("-", args[1]);
+        assertEquals("MyPage", args[2]);
+    }
+
+    public void testGetMessageArgObjects()
+    {
+        // Try passing some valid object types: Date, Number
+        w.addMessageArgument(new Date());
+        w.addMessageArgument(new Integer(1));
+        w.addMessageArgument(new Double(2));
+        w.addMessageArgument(new BigDecimal(3.14));
+
+        // Try passing an invalid one: e.g., a Workflow (it should fail)
+        try
+        {
+            w.addMessageArgument(w);
+        }
+        catch (IllegalArgumentException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Illegal argument passed...");
+    }
+
+    public void testGetMessageKey()
+    {
+        assertEquals("workflow.myworkflow", w.getMessageKey());
+    }
+
+    public void testGetOwner()
+    {
+        assertEquals(new WikiPrincipal("Owner1"), w.getOwner());
+    }
+
+    public void testStart() throws WikiException
+    {
+        assertFalse(w.isStarted());
+        w.start();
+        assertTrue(w.isStarted());
+    }
+
+    public void testWaitstate() throws WikiException
+    {
+        w.start();
+
+        // Default workflow should have hit the Decision step and put itself
+        // into WAITING
+        assertEquals(Workflow.WAITING, w.getCurrentState());
+    }
+
+    public void testRestart() throws WikiException
+    {
+        w.start();
+
+        // Default workflow should have hit the Decision step and put itself
+        // into WAITING
+        assertEquals(Workflow.WAITING, w.getCurrentState());
+        w.restart();
+        assertEquals(Workflow.WAITING, w.getCurrentState());
+    }
+
+    public void testAbortBeforeStart() throws WikiException
+    {
+        // Workflow hasn't been started yet
+        assertFalse(w.isAborted());
+        w.abort();
+        assertTrue(w.isAborted());
+
+        // Try to start anyway
+        try
+        {
+            w.start();
+        }
+        catch (IllegalStateException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Workflow allowed itself to be started even though it was aborted!");
+    }
+
+    public void testAbortDuringWait() throws WikiException
+    {
+        // Start workflow, then abort while in WAITING state
+        assertFalse(w.isAborted());
+        w.start();
+        w.abort();
+        assertTrue(w.isAborted());
+
+        // Try to restart anyway
+        try
+        {
+            w.restart();
+        }
+        catch (IllegalStateException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Workflow allowed itself to be re-started even though it was aborted!");
+    }
+
+    public void testAbortAfterCompletion() throws WikiException
+    {
+        // Start workflow, then abort after completion
+        assertFalse(w.isAborted());
+        w.start();
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+
+        // Try to abort anyway
+        try
+        {
+            w.abort();
+            assertTrue(w.isAborted());
+        }
+        catch (IllegalStateException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Workflow allowed itself to be aborted even though it was completed!");
+    }
+
+    public void testCurrentState() throws WikiException
+    {
+        assertEquals(Workflow.CREATED, w.getCurrentState());
+        w.start();
+        assertEquals(Workflow.WAITING, w.getCurrentState());
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertEquals(Workflow.COMPLETED, w.getCurrentState());
+    }
+
+    public void testCurrentStep() throws WikiException
+    {
+        assertNull(w.getCurrentStep());
+        w.start();
+
+        // Workflow stops at the decision step
+        assertEquals(decision, w.getCurrentStep());
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+
+        // After we decide, it blows through step 3 and leaves us with a null
+        // step (done)
+        assertNull(w.getCurrentStep());
+    }
+
+    public void testPreviousStep() throws WikiException
+    {
+        // If not started, no previous steps available for anything
+        assertNull(w.getPreviousStep());
+        assertEquals(null, w.previousStep(initTask));
+        assertEquals(null, w.previousStep(decision));
+        assertEquals(null, w.previousStep(finishTask));
+
+        // Once we start, initTask and decisions' predecessors are known, but
+        // finish task is indeterminate
+        w.start();
+        assertEquals(null, w.previousStep(initTask));
+        assertEquals(initTask, w.previousStep(decision));
+        assertEquals(null, w.previousStep(finishTask));
+
+        // Once we decide, the finish task returns the correct predecessor
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertEquals(null, w.previousStep(initTask));
+        assertEquals(initTask, w.previousStep(decision));
+        assertEquals(decision, w.previousStep(finishTask));
+    }
+
+    public void testCurrentActor() throws WikiException
+    {
+        // Before starting, actor should be null
+        assertNull(w.getCurrentActor());
+
+        // After starting, actor should be GroupPrincipal Admin
+        w.start();
+        assertEquals(new GroupPrincipal("Admin"), w.getCurrentActor());
+
+        // After decision, actor should be null again
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertNull(w.getCurrentActor());
+    }
+
+    public void testHistory() throws WikiException
+    {
+        assertEquals(0, w.getHistory().size());
+        w.start();
+        assertEquals(2, w.getHistory().size());
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertEquals(3, w.getHistory().size());
+    }
+
+    public void testGetStartTime() throws WikiException
+    {
+        // Start time should be not be set until we start the workflow
+        assertEquals(Workflow.TIME_NOT_SET, w.getStartTime());
+        w.start();
+        assertFalse(Workflow.TIME_NOT_SET == w.getStartTime());
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertFalse(Workflow.TIME_NOT_SET == w.getStartTime());
+    }
+
+    public void testGetEndTime() throws WikiException
+    {
+        // End time should be not set until we finish all 3 steps
+        assertEquals(Workflow.TIME_NOT_SET, w.getEndTime());
+        w.start();
+        assertEquals(Workflow.TIME_NOT_SET, w.getEndTime());
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertFalse(Workflow.TIME_NOT_SET == w.getEndTime());
+    }
+
+    public void testIsCompleted() throws WikiException
+    {
+        // Workflow isn't completed until we finish all 3 steps
+        assertFalse(w.isCompleted());
+        w.start();
+        assertFalse(w.isCompleted());
+        Decision d = (Decision) w.getCurrentStep();
+        d.decide(Outcome.DECISION_APPROVE);
+        assertTrue(w.isCompleted());
+    }
+
+    public void testIsStarted() throws WikiException
+    {
+        assertFalse(w.isStarted());
+        w.start();
+        assertTrue(w.isStarted());
+    }
+
+    public void testStartTwice() throws WikiException
+    {
+        w.start();
+        try
+        {
+            w.start();
+        }
+        catch (IllegalStateException e)
+        {
+            // Swallow
+            return;
+        }
+        // We should never get here
+        fail("Workflow allowed itself to be started twice!");
+    }
+
+    public void testSetId()
+    {
+        assertEquals(Workflow.ID_NOT_SET, w.getId());
+        w.setId(1001);
+        assertEquals(1001, w.getId());
+    }
+
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/AllTests.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/AllTests.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/AllTests.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/AllTests.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,21 @@
+
+package com.ecyrd.jspwiki.xmlrpc;
+
+import junit.framework.*;
+
+public class AllTests extends TestCase
+{
+    public AllTests( String s )
+    {
+        super( s );
+    }
+
+    public static Test suite()
+    {
+        TestSuite suite = new TestSuite("XMLRPC tests");
+
+        suite.addTest( RPCHandlerTest.suite() );
+
+        return suite;
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/RPCHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/RPCHandlerTest.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/RPCHandlerTest.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/ecyrd/jspwiki/xmlrpc/RPCHandlerTest.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,215 @@
+
+package com.ecyrd.jspwiki.xmlrpc;
+
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.attachment.Attachment;
+import junit.framework.*;
+import java.util.*;
+import org.apache.xmlrpc.*;
+import com.ecyrd.jspwiki.xmlrpc.RPCHandler;
+
+public class RPCHandlerTest extends TestCase
+{
+    TestEngine m_engine;
+    RPCHandler m_handler;
+    Properties m_props;
+
+    static final String NAME1 = "Test";
+
+    public RPCHandlerTest( String s )
+    {
+        super( s );
+    }
+
+    public void setUp()
+        throws Exception
+    {
+        m_props = new Properties();
+        m_props.load( TestEngine.findTestProperties() );
+
+        m_engine = new TestEngine( m_props );
+
+        m_handler = new RPCHandler();
+        WikiContext ctx = m_engine.getWikiActionBeanFactory().newViewActionBean( new WikiPage(m_engine, "Dummy") );
+        m_handler.initialize( ctx );
+    }
+
+    public void tearDown()
+    {
+        TestEngine.deleteTestPage( NAME1 );
+        m_engine.deleteAttachments( NAME1 );
+        TestEngine.emptyWorkDir();
+    }
+
+    public void testNonexistantPage()
+    {
+        try
+        {
+            m_handler.getPage( "NoSuchPage" );
+            fail("No exception for missing page.");
+        }
+        catch( XmlRpcException e )
+        {
+            assertEquals( "Wrong error code.", RPCHandler.ERR_NOPAGE, e.code );
+        }
+    }
+
+    public void testRecentChanges()
+        throws Exception
+    {
+        Date time = getCalendarTime( Calendar.getInstance().getTime() );
+        Vector previousChanges = m_handler.getRecentChanges( time );
+
+        m_engine.saveText( NAME1, "Foo" );
+        WikiPage directInfo = m_engine.getPage( NAME1 );
+        time = getCalendarTime( directInfo.getLastModified() );
+        Vector recentChanges = m_handler.getRecentChanges( time );
+
+        assertEquals( "wrong number of changes", 1, recentChanges.size() - previousChanges.size() );
+    }
+
+    public void testRecentChangesWithAttachments()
+        throws Exception
+    {
+        Date time = getCalendarTime( Calendar.getInstance().getTime() );
+        Vector previousChanges = m_handler.getRecentChanges( time );
+
+        m_engine.saveText( NAME1, "Foo" );
+        Attachment att = new Attachment( m_engine, NAME1, "TestAtt.txt" );
+        att.setAuthor( "FirstPost" );
+        m_engine.getAttachmentManager().storeAttachment( att, m_engine.makeAttachmentFile() );
+        WikiPage directInfo = m_engine.getPage( NAME1 );
+        time = getCalendarTime( directInfo.getLastModified() );
+        Vector recentChanges = m_handler.getRecentChanges( time );
+
+        assertEquals( "wrong number of changes", 1, recentChanges.size() - previousChanges.size() );
+    }
+
+    public void testPageInfo()
+        throws Exception
+    {
+        m_engine.saveText( NAME1, "Foobar.[{ALLOW view Anonymous}]" );
+        WikiPage directInfo = m_engine.getPage( NAME1 );
+
+        Hashtable ht = m_handler.getPageInfo( NAME1 );
+        assertEquals( "name", (String)ht.get( "name" ), NAME1 );
+
+        Date d = (Date) ht.get( "lastModified" );
+
+        Calendar cal = Calendar.getInstance();
+        cal.setTime( d );
+
+        System.out.println("Real: "+directInfo.getLastModified() );
+        System.out.println("RPC:  "+d );
+
+        // Offset the ZONE offset and DST offset away.  DST only
+        // if we're actually in DST.
+        cal.add( Calendar.MILLISECOND,
+                 (cal.get( Calendar.ZONE_OFFSET )+
+                  (cal.getTimeZone().inDaylightTime( d ) ? cal.get( Calendar.DST_OFFSET ) : 0 ) ) );
+        System.out.println("RPC2: "+cal.getTime() );
+
+        assertEquals( "date", cal.getTime().getTime(),
+                      directInfo.getLastModified().getTime() );
+    }
+
+    /**
+     *  Tests if listLinks() works with a single, non-existant local page.
+     */
+    public void testListLinks()
+        throws Exception
+    {
+        String text = "[Foobar]";
+        String pageName = NAME1;
+
+        m_engine.saveText( pageName, text );
+
+        Vector links = m_handler.listLinks( pageName );
+
+        assertEquals( "link count", 1, links.size() );
+
+        Hashtable linkinfo = (Hashtable) links.elementAt(0);
+
+        assertEquals( "name", "Foobar", linkinfo.get("page") );
+        assertEquals( "type", "local",  linkinfo.get("type") );
+        assertEquals( "href", "http://localhost/Edit.jsp?page=Foobar", linkinfo.get("href") );
+    }
+
+
+    public void testListLinksWithAttachments()
+        throws Exception
+    {
+        String text = "[Foobar] [Test/TestAtt.txt]";
+        String pageName = NAME1;
+
+        m_engine.saveText( pageName, text );
+
+        Attachment att = new Attachment( m_engine, NAME1, "TestAtt.txt" );
+        att.setAuthor( "FirstPost" );
+        m_engine.getAttachmentManager().storeAttachment( att, m_engine.makeAttachmentFile() );
+
+        // Test.
+
+        Vector links = m_handler.listLinks( pageName );
+
+        assertEquals( "link count", 2, links.size() );
+
+        Hashtable linkinfo = (Hashtable) links.elementAt(0);
+
+        assertEquals( "edit name", "Foobar", linkinfo.get("page") );
+        assertEquals( "edit type", "local",  linkinfo.get("type") );
+        assertEquals( "edit href", "http://localhost/Edit.jsp?page=Foobar", linkinfo.get("href") );
+
+        linkinfo = (Hashtable) links.elementAt(1);
+
+        assertEquals( "att name", NAME1+"/TestAtt.txt", linkinfo.get("page") );
+        assertEquals( "att type", "local", linkinfo.get("type") );
+        assertEquals( "att href", "http://localhost/attach/"+NAME1+"/TestAtt.txt", linkinfo.get("href") );
+    }
+
+    private Date getCalendarTime( Date modifiedDate )
+    {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime( modifiedDate );
+        cal.add( Calendar.HOUR, -1 );
+
+        // Go to UTC
+        // Offset the ZONE offset and DST offset away.  DST only
+        // if we're actually in DST.
+        cal.add( Calendar.MILLISECOND,
+                 -(cal.get( Calendar.ZONE_OFFSET )+
+                  (cal.getTimeZone().inDaylightTime( modifiedDate ) ? cal.get( Calendar.DST_OFFSET ) : 0 ) ) );
+
+        return cal.getTime();
+    }
+
+    /*
+     * TODO: ENABLE
+    public void testPermissions()
+        throws Exception
+    {
+        String text ="Blaa. [{DENY view Guest}] [{ALLOW view NamedGuest}]";
+
+        m_engine.saveText( NAME1, text );
+
+        try
+        {
+            Vector links = m_handler.listLinks( NAME1 );
+            fail("Didn't get an exception in listLinks()");
+        }
+        catch( XmlRpcException e ) {}
+
+        try
+        {
+            Hashtable ht = m_handler.getPageInfo( NAME1 );
+            fail("Didn't get an exception in getPageInfo()");
+        }
+        catch( XmlRpcException e ) {}
+    }
+*/
+
+    public static Test suite()
+    {
+        return new TestSuite( RPCHandlerTest.class );
+    }
+}

Added: incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/foo/SamplePlugin3.java
URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/foo/SamplePlugin3.java?rev=627269&view=auto
==============================================================================
--- incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/foo/SamplePlugin3.java (added)
+++ incubator/jspwiki/branches/JSPWIKI_STRIPES_BRANCH/tests/com/foo/SamplePlugin3.java Tue Feb 12 22:22:45 2008
@@ -0,0 +1,28 @@
+package com.foo;
+
+import com.ecyrd.jspwiki.*;
+import com.ecyrd.jspwiki.plugin.*;
+import java.util.*;
+
+/**
+ *  Implements a simple plugin that just returns its text.
+ *  <P>
+ *  Parameters: text - text to return.
+ *
+ *  @author Janne Jalkanen
+ */
+public class SamplePlugin3
+    implements WikiPlugin
+{
+    public void initialize( WikiEngine engine )
+        throws PluginException
+    {
+    }
+
+    public String execute( WikiContext context, Map params )
+        throws PluginException
+    {
+        return (String)params.get("text");
+    }
+
+}