/* * org.openmicroscopy.shoola.util.concur.tasks.TestCompositeTask * *------------------------------------------------------------------------------ * Copyright (C) 2006 University of Dundee. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.util.concur.tasks; //Java imports import java.util.ArrayList; import java.util.Iterator; import java.util.List; //Third-party libraries import junit.framework.TestCase; //Application-internal dependencies /** * Basic tests to verify the execution algorithm of <code>CompositeTask</code>. * We first use flat trees with a root node and only leaf nodes below it and * verify how each tree behaves when in the <i>Iterating</i> state. We then * switch to more elaborate trees. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author <br>Andrea Falconi      * <a href="mailto:a.falconi@dundee.ac.uk"> * a.falconi@dundee.ac.uk</a> * @version 2.2 * <small> * (<b>Internal version:</b> $Revision$ $Date$) * </small> * @since OME2.2 */ public class TestCompositeTask extends TestCase { //Helper class to configure a MockMultiStepTask to run within doTest(). //Pass the number of steps the task is supposed to execute and get a //mock task with all calls already set up for running within doTest(). //The mock will be in verification mode. private class TaskConfig { final int steps; final MockMultiStepTask task; TaskConfig(int steps) { if (steps <= 0) throw new IllegalArgumentException( "Number of steps must be positive."); this.steps = steps; task = new MockMultiStepTask(); //Set up expected calls -- see doTest(). for (int i = 0; i < steps; ++i) { task.isDone(false, null); //Triggered by target.isDone(). task.isDone(false, null); //Triggered by target.getCurChild(). task.doStep(null, null); //Triggered by target.doStep(). } task.isDone(true, null); //Triggered by target.isDone() w/in the //loop of the next task or by the last //call to target.isDone if this is the //last task. //Transition the mock to verification mode. task.activate(); } } //Object under test, root of the tree. private CompositeTask target; //Mirrors the sub-list of target.children composed of all not-done tasks. //That is, all tasks whose isDone method returns false. These are all of //the tasks that were added by addTask(). Each element is a TaskConfig //which wraps the original mock task and keeps track of how many steps the //task is supposed to carry out. //For example, if target.children is the list <d1, d2, t1, t2, d3, t3> //(d stands for done task added by addDoneTask, t for mock task added by //addTask), then actualTasks would be <tc1, tc2, tc3> (tc is a TaskConfig) //and tc(i).task == t(i). private List actualTasks; protected void setUp() { target = new CompositeTask(); actualTasks = new ArrayList(); } //Adds a task leaf node to the root. //Pass the number of steps the task is supposed to carry out. protected void addTask(int steps) { TaskConfig tc = new TaskConfig(steps); target.add(tc.task); actualTasks.add(tc); } //Adds a done task leaf node to the root. protected void addDoneTask() { target.add(new NullMultiStepTask()); } //Runs the test. //The test consists in simulating the execution loop run by a CmdProcessor. //We verify that all tasks added by addTask() are executed in the same //order as they were added. //Call this method after you've built the tree (add methods). protected void doTest() throws Exception { TaskConfig tc; Iterator tasksIter = actualTasks.iterator(); while (tasksIter.hasNext()) { //Get next TaskConfig. Call expectations on its mock task have //already been set up and and the mock is in verification mode. tc = (TaskConfig) tasksIter.next(); //Execute every task's step. for (int i = 0; i < tc.steps; ++i) { //First call isDone(). This has to result in the target's //execution algo advancing to tc.task (i=0) or staying on it //until it's done. Advancing to tc.task involves a call to //tc.task.isDone which returns false. Also, if tc is not the //first element of activationList, then its predecessor's task //will receive a call to isDone, which has to return true. assertFalse("Task wasn't done yet <"+tc.task+">.", target.isDone()); //Verify overall execution order and execute step. assertSame("Wrong execution order; execution algo didn't "+ "rispect the order in which the tasks were added.", tc.task, target.getCurChild()); target.doStep(); } } //Last call to target.isDone. This will result in a call to ltc.isDone //which has to return true -- ltc is the last tc in activationList. assertTrue("Should have been finished.", target.isDone()); //Verify that all expected calls where performed. tasksIter = actualTasks.iterator(); while (tasksIter.hasNext()) { tc = (TaskConfig) tasksIter.next(); tc.task.verify(); } } public void test1() throws Exception { //Build the tree. addTask(1); //t1 - [steps=1] //Run the test. doTest(); } public void test2() throws Exception { //Build the tree. addDoneTask(); //d1 addTask(1); //t1 - [steps=1] //Run the test. doTest(); } public void test3() throws Exception { //Build the tree. addTask(3); //t1 - [steps=1] addDoneTask(); //d1 //Run the test. doTest(); } public void test4() throws Exception { //Build the tree. addDoneTask(); //d1 addDoneTask(); //d2 addTask(1); //t1 - [steps=1] addTask(2); //t2 - [steps=2] addDoneTask(); //d3 addTask(2); //t3 - [steps=1] //Run the test. doTest(); } public void test5() throws Exception { //Build the tree. addDoneTask(); //d1 addDoneTask(); //d2 addTask(5); //t1 - [steps=5] addTask(2); //t2 - [steps=2] addDoneTask(); //d3 addTask(4); //t3 - [steps=1] addDoneTask(); //d4 //Run the test. doTest(); } /* Following tree: * R * |--- I1 * | |--- I11 * | | |--- L1 (2 steps) * | | * | |--- I12 * | | |--- L2 (1 step) * | * |--- I2 (empty) * | * |--- I3 * |--- L3 (1 step) * |--- L4 (3 steps) */ public void test6() throws Exception { //---------------- BUILD TREE ------------------------------------------ //Create root and internal nodes. CompositeTask R = new CompositeTask(); //Root. CompositeTask I1 = new CompositeTask(), //1st-level internal nodes. I11 = new CompositeTask(), //2nd-level nodes. I12 = new CompositeTask(), I2 = new CompositeTask(), I3 = new CompositeTask(); //Link internal nodes. R.add(I1); R.add(I2); R.add(I3); I1.add(I11); I1.add(I12); //Set leaves. Share convenience mock. (Avoids one mock for each leaf.) MockMultiStepTask task = new MockMultiStepTask(); I11.add(task); //L1 - [steps=2] task.isDone(false, null); task.doStep(null, null); task.isDone(false, null); task.doStep(null, null); task.isDone(true, null); I12.add(task); //L2 - [steps=1] task.isDone(false, null); task.doStep(null, null); task.isDone(true, null); I3.add(task); //L3 - [steps=1] task.isDone(false, null); task.doStep(null, null); task.isDone(true, null); I3.add(task); //L4 - [steps=3] task.isDone(false, null); task.doStep(null, null); task.isDone(false, null); task.doStep(null, null); task.isDone(false, null); task.doStep(null, null); task.isDone(true, null); //------------- TEST --------------------------------------------------- task.activate(); while (!R.isDone()) R.doStep(); task.verify(); } }