/**
 * JaDOrT: JASMINe Deployment Orchestration Tool
 * Copyright (C) 2008-2009 Bull S.A.S.
 * Copyright (C) 2008-2009 France Telecom R&D
 * Contact: jasmine@ow2.org
 *
 * This library 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 any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id: JadortServiceImplTest.java 3663 2009-05-11 15:57:35Z chahinem $
 * --------------------------------------------------------------------------
 */
package org.ow2.jasmine.jadort.service.implementation;

import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.UUID;

import javax.naming.Context;
import javax.naming.InitialContext;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.ow2.easybeans.component.smartclient.spi.SmartContextFactory;
import org.ow2.jasmine.jadort.api.IJadortService;
import org.ow2.jasmine.jadort.api.JadortServiceException;
import org.ow2.jasmine.jadort.api.IJadortService.OperationType;
import org.ow2.jasmine.jadort.api.entities.deployment.OperationStateBean;
import org.ow2.jasmine.jadort.api.entities.deployment.ServerProgressBean;
import org.ow2.jasmine.jadort.api.entities.deployment.ServerProgressState;
import org.ow2.jasmine.jadort.api.entities.deployment.WorkerProgressBean;
import org.ow2.jasmine.jadort.api.entities.deployment.WorkerProgressState;
import org.ow2.jasmine.jadort.api.entities.deployment.OperationStateBean.ActionState;
import org.ow2.jasmine.jadort.api.entities.deployment.OperationStateBean.Step;
import org.ow2.jasmine.jadort.api.entities.topology.GroupBean;
import org.ow2.jasmine.jadort.api.entities.topology.ServerBean;
import org.ow2.jasmine.jadort.service.action.DummyServerAction;
import org.ow2.jasmine.jadort.service.action.DummyWorkerAction;

/**
 * Tests the JaDOrT service implementation.
 * 
 * @author Malek Chahine
 * @author Remy Bresson
 * @author S. Ali Tokmen
 */
public class JadortServiceImplTest {

    /**
     * If you want to test the whole JaDOrT service for real, set this variable
     * to true. Note that before launching this test in that mode, you must
     * deploy the JaDOrT service on a Java EE server.
     */
    private static final boolean IN_J2EE_SERVER = false;

    /**
     * Timeout (in seconds) for each serverProgress test.
     */
    private static final int TEST_TIMEOUT = 100;

    /**
     * Check period (in milliseconds) for the waitForFinish methods.
     */
    private static final int CHECK_PERIOD = 10;

    private IJadortService jadortService;

    // These need to be static since the test class is recreated at each
    // test but we'd like to keep a state log between tests
    private static String operationName;

    private static OperationStateBean operationBeanForVersion1;

    private static OperationStateBean operationBeanForVersion2;

    private static OperationStateBean operationBeanForMaintainServer1;

    private static OperationStateBean operationBeanForMaintainServer2;

    private static OperationStateBean operationBeanForMaintainNoClusterServer;

    private static IJadortService connectToJadortService() throws Exception {
        IJadortService result;
        if (JadortServiceImplTest.IN_J2EE_SERVER) {
            Hashtable<String, Object> env = new Hashtable<String, Object>();
            env.put(Context.INITIAL_CONTEXT_FACTORY, SmartContextFactory.class.getName());
            Context context = new InitialContext(env);
            result = (IJadortService) context.lookup(IJadortService.EJB_JNDI_NAME);
        } else {
            JadortServiceImpl.DUMMY = true;
            DummyServerAction.MAX_SLEEP = 1;
            DummyWorkerAction.MAX_SLEEP = 1;
            JadortServiceImpl jadortService = new JadortServiceImpl();
            jadortService.em = new DummyEntityManager();
            jadortService.session = new DummyQueueSession(jadortService.em);
            result = jadortService;
        }
        Assert.assertNull(result.getCurrentOperation());
        return result;
    }

    /**
     * @throws java.lang.Exception
     */
    @BeforeClass
    public static void staticSetUp() throws Exception {
        JadortServiceImplTest.operationName = "JadortServiceImplTest#" + UUID.randomUUID();
    }

    /**
     * @throws java.lang.Exception
     */
    @AfterClass
    public static void staticTearDown() throws Exception {
        IJadortService jadortService = JadortServiceImplTest.connectToJadortService();

        List<OperationStateBean> ops = jadortService.getOperationsList();
        for (OperationStateBean op : ops) {
            if (op.getName().equals(JadortServiceImplTest.operationName)) {
                jadortService.deleteOperation(op);
                // Don't break: each test has created an operation and the same
                // name is used each time.
            }
        }

        JadortServiceImplTest.operationName = null;
    }

    /**
     * @throws java.lang.Exception
     */
    @Before
    public void setUp() throws Exception {
        this.jadortService = JadortServiceImplTest.connectToJadortService();
    }

    /**
     * @throws java.lang.Exception
     */
    @After
    public void tearDown() throws Exception {
        this.jadortService = null;
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#createNewOperation(String)}
     * .
     */
    @Test
    public void testCreateNewOperation() throws Exception {
        this.jadortService.createNewOperation(JadortServiceImplTest.operationName);
        Assert.assertNotNull(this.jadortService.getCurrentOperation());
        Assert.assertEquals(JadortServiceImplTest.operationName, this.jadortService.getCurrentOperation().getName());
        Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#selectOperation(OperationStateBean)}
     * .
     */
    @Test
    public void testSelectOperation() throws Exception {
        List<OperationStateBean> ops = this.jadortService.getOperationsList();
        for (OperationStateBean op : ops) {
            if (op.getName().equals(JadortServiceImplTest.operationName)) {
                this.jadortService.selectOperation(op);
                Assert.assertEquals(JadortServiceImplTest.operationName, this.jadortService.getCurrentOperation().getName());
                Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
                return;
            }
        }

        Assert.fail("Cannot find operation named \"" + JadortServiceImplTest.operationName + "\"");
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#getCurrentOperation()}
     * .
     */
    @Test
    public void testGetCurrentOperation() throws Exception {
        this.testSelectOperation();

        this.jadortService.getCurrentOperation();
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a valid and mixed topology file.
     */
    @Test
    public void testValidTopology_manyServers() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOK_manyServers.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());

        // Don't go next, we don't have that many servers in the CI !!
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a valid topology file with managers and targets.
     */
    @Test
    public void testValidTopology_manager() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOK_manager.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
        this.jadortService.next();

        ServerBean server = this.jadortService.getCurrentOperation().getTopology().getGroups().get(0).getServers().get(0);
        Assert.assertEquals(ServerBean.Type.DUMMY, server.getType());
        Assert.assertEquals("weblogic1", server.getName());
        Assert.assertNull(server.getManagerConnector());

        Assert.assertEquals(ServerBean.Type.DUMMY, server.getTarget().getType());
        Assert.assertEquals("jonas1", server.getTarget().getName());
        Assert.assertNotNull(server.getTarget().getManagerConnector());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a valid and minimal topology file.
     */
    @Test
    public void testValidTopology_minimal() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOK_minimal.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a valid and minimal topology file.
     */
    @Test
    public void testValidTopology_VM() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOK_VM.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a valid and maximal topology file.
     */
    @Test
    public void testValidTopology_maximal() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOK_maximal.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a valid topology file with no cluster .
     */
    @Test
    public void testValidTopology_noCluster() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOK_noCluster.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a topology file that's in the JASMINe Deploy ME format.
     */
    @Test
    public void testTopology_DeployME() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOKDeployME.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());

        List<GroupBean> groups = this.jadortService.getCurrentOperation().getTopology().getGroups();
        Assert.assertEquals(1, groups.size());
        GroupBean domain = groups.get(0);
        Assert.assertFalse(domain.getClustered());
        List<ServerBean> servers = domain.getServers();
        Assert.assertEquals(2, servers.size());

        Assert.assertEquals("service:jmx:iiop://testHost/jndi/iiop://testHost:1000/iiopconnector_jonas1", servers.get(0)
            .getServerConnector().getConnectorUrl());
        Assert.assertEquals("service:jmx:rmi://otherHost/jndi/rmi://otherHost:1001/jrmpconnector_jonas2", servers.get(1)
            .getServerConnector().getConnectorUrl());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a topology file that's in the JASMINe Deploy ME format.
     */
    @Test
    public void testTopology_DeployMEClustered() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOKDeployME_clustered.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());

        List<GroupBean> groups = this.jadortService.getCurrentOperation().getTopology().getGroups();
        Assert.assertEquals(1, groups.size());
        GroupBean domain = groups.get(0);
        Assert.assertTrue(domain.getClustered());
        List<ServerBean> servers = domain.getServers();
        Assert.assertEquals(2, servers.size());

        Assert.assertEquals("service:jmx:iiop://testHost/jndi/iiop://testHost:1000/iiopconnector_jonas1", servers.get(0)
            .getServerConnector().getConnectorUrl());
        Assert.assertEquals("service:jmx:rmi://otherHost/jndi/rmi://otherHost:1001/jrmpconnector_jonas2", servers.get(1)
            .getServerConnector().getConnectorUrl());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a topology file that's in the JASMINe Deploy ME format.
     */
    @Test
    public void testTopology_DeployMEWithClusterDaemon() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyOKDeployME_cd.xml");
        this.jadortService.loadTopology(new File(topo.toURI()));
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());

        List<GroupBean> groups = this.jadortService.getCurrentOperation().getTopology().getGroups();
        Assert.assertEquals(1, groups.size());
        GroupBean domain = groups.get(0);
        Assert.assertFalse(domain.getClustered());
        List<ServerBean> servers = domain.getServers();
        Assert.assertEquals(1, servers.size());

        Assert.assertEquals("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jrmpconnector_someRandomServerNamePrefix1",
            servers.get(0).getServerConnector().getConnectorUrl());
        Assert.assertEquals("service:jmx:iiop://localhost/jndi/iiop://localhost:2001/iiopconnector_cd1", servers.get(0)
            .getManagerConnector().getConnectorUrl());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a topology file that's in the JASMINe Deploy ME format.
     */
    @Test
    public void testTopology_DeployMEWithClusterDaemonWithInvalidServerList() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyKODeployME_cd.xml");
        try {
            this.jadortService.loadTopology(new File(topo.toURI()));
            Assert.fail("loadTopology has accepted invalid topology!");
        } catch (JadortServiceException e) {
            Assert.assertTrue(e.getMessage().startsWith("Cannot find server"));

            // Do a call on the service to ensure it didn't die
            Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with an invalid topology file (no server URL).
     */
    @Test
    public void testInvalidTopology_noServerURL() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyKO_noServerURL.xml");
        try {
            this.jadortService.loadTopology(new File(topo.toURI()));
            Assert.fail("loadTopology has accepted invalid topology!");
        } catch (JadortServiceException e) {
            // Do a call on the service to ensure it didn't die
            Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with an invalid topology file (no worker URL).
     */
    @Test
    public void testInvalidTopology_noWorkerURL() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyKO_noWorkerURL.xml");
        try {
            this.jadortService.loadTopology(new File(topo.toURI()));
            Assert.fail("loadTopology has accepted invalid topology!");
        } catch (JadortServiceException e) {
            // Do a call on the service to ensure it didn't die
            Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with an invalid topology file (wrong balancer).
     */
    @Test
    public void testInvalidTopology_wrongBalancer() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("src/test/resources/topologyKO_wrongBalancer.xml");
        try {
            this.jadortService.loadTopology(new File(topo.toURI()));
            Assert.fail("loadTopology has accepted invalid topology!");
        } catch (JadortServiceException e) {
            // Do a call on the service to ensure it didn't die
            Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#loadTopology(File)}
     * with a non-existing topology file.
     */
    @Test
    public void testNonExistingTopology() throws Exception {
        this.testCreateNewOperation();

        File topo = new File("/dev/null");
        try {
            this.jadortService.loadTopology(new File(topo.toURI()));
            Assert.fail("loadTopology has accepted a non-existing file!");
        } catch (JadortServiceException e) {
            // Do a call on the service to ensure it didn't die
            Assert.assertEquals(Step.INITIALIZE_TOPOLOGY, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#selectGroup(GroupBean)}
     * with a migration.
     */
    @Test
    public void testSelectGroupMigrate() throws Exception {
        this.testValidTopology_maximal();

        Assert.assertEquals(1, this.jadortService.getCurrentOperation().getTopology().getGroups().size());

        GroupBean toSelect = this.jadortService.getCurrentOperation().getTopology().getGroups().get(0);
        this.jadortService.selectGroup(toSelect);
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_OPERATION_TYPE, this.jadortService.getCurrentOperation().getCurrentStep());
        this.jadortService.selectOperationType(OperationType.MIGRATE);
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_APPLICATION, this.jadortService.getCurrentOperation().getCurrentStep());
        Assert.assertEquals(OperationType.MIGRATE, this.jadortService.getCurrentOperation().getType());
        Assert.assertEquals(toSelect.getId(), this.jadortService.getCurrentOperation().getSelectedGroup().getId());
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#selectApplication(java.net.URL)}
     * with an invalid application file.
     */
    @Test
    public void testCreateInvalidApplication() throws Exception {
        this.testSelectGroupMigrate();

        try {
            this.jadortService.selectApplication(new File("noApplication.war").toURL());
            Assert.fail("selectApplication has accepted invalid application!");
        } catch (JadortServiceException e) {
            // Do a call on the service to ensure it didn't die
            Assert.assertEquals(Step.SELECT_APPLICATION, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#selectApplication(java.net.URL)}
     * with a non-existing application file.
     */
    @Test
    public void testCreateNonExistingApplication() throws Exception {
        this.testSelectGroupMigrate();

        try {
            this.jadortService.selectApplication(new File("/dev/null").toURL());
            Assert.fail("selectApplication has accepted invalid application!");
        } catch (JadortServiceException e) {
            // Do a call on the service to ensure it didn't die
            Assert.assertEquals(Step.SELECT_APPLICATION, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Integration test for application migration (forward).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testDeployVersion1() throws Exception {
        this.deployApplication("src/test/resources/application1v1/application1.ear", false);
        JadortServiceImplTest.operationBeanForVersion1 = this.jadortService.getCurrentOperation();
    }

    /**
     * Integration test for application migration (forward).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testDeployVersion2() throws Exception {
        this.deployApplication("src/test/resources/application1v2/application1.ear", false);
        JadortServiceImplTest.operationBeanForVersion2 = this.jadortService.getCurrentOperation();
    }

    /**
     * Integration test for application migration (backwards).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testUndeployVersion2() throws Exception {
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForVersion2);
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForVersion2.getId());

        this.jadortService.selectOperation(JadortServiceImplTest.operationBeanForVersion2);
        Assert.assertNotNull(this.jadortService.getCurrentOperation());

        this.undeployApplication();
    }

    /**
     * Integration test for application migration (backwards).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testUndeployVersion1() throws Exception {
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForVersion1);
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForVersion1.getId());

        this.jadortService.selectOperation(JadortServiceImplTest.operationBeanForVersion1);
        Assert.assertNotNull(this.jadortService.getCurrentOperation());

        this.undeployApplication();
    }

    /**
     * Integration test for application migration (forward, complete).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testRedeployVersion1() throws Exception {
        this.deployApplication("src/test/resources/application1v1/application1.ear", true);
    }

    /**
     * Integration test for application migration (forward, complete).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testRedeployVersion2() throws Exception {
        this.deployApplication("src/test/resources/application1v2/application1.ear", true);
    }

    private void deployApplication(final String applicationPath, final boolean eraseOld) throws Exception {
        this.testSelectGroupMigrate();

        this.jadortService.selectApplication(new File(applicationPath).toURI().toURL());

        Assert.assertEquals(Step.SELECT_APPLICATION, this.jadortService.getCurrentOperation().getCurrentStep());
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);

        // Upload application
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.UPLOAD_OK, 33);

        // Deploy application
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.DEPLOY_OK, 66);

        // Set application as default
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.SET_DEFAULT_OK, 100);
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());

        if (this.jadortService.getCurrentOperation().getServerProgressList().get(0).getOldDeploymentItem() != null) {
            // Change page
            this.jadortService.next();
            Assert.assertEquals(Step.EXECUTING_MIGRATION_PART2, this.jadortService.getCurrentOperation().getCurrentStep());
            this.waitForFinishAndCheckServerProgressList(ServerProgressState.SET_DEFAULT_OK, 0);

            // Undeploy old version
            this.jadortService.next();
            Assert.assertEquals(Step.EXECUTING_MIGRATION_PART2, this.jadortService.getCurrentOperation().getCurrentStep());
            this.waitForFinishAndCheckServerProgressList(ServerProgressState.UNDEPLOY_OK, 50);

            if (eraseOld) {
                // Erase old version
                this.jadortService.next();
                Assert.assertEquals(Step.EXECUTING_MIGRATION_PART2, this.jadortService.getCurrentOperation().getCurrentStep());
                this.waitForFinishAndCheckServerProgressList(ServerProgressState.ERASE_OK, 100);

                // Change page
                Assert.assertEquals(Step.EXECUTING_MIGRATION_PART2, this.jadortService.getCurrentOperation().getCurrentStep());
                this.jadortService.next();
                Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
            }
        } else {
            // Change page
            this.jadortService.next();
            Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    private void undeployApplication() throws Exception {
        if (this.jadortService.getCurrentOperation().getServerProgressList().get(0).getOldDeploymentItem() != null) {
            Assert.assertEquals(Step.EXECUTING_MIGRATION_PART2, this.jadortService.getCurrentOperation().getCurrentStep());
            this.waitForFinishAndCheckServerProgressList(ServerProgressState.UNDEPLOY_OK, 50);

            // Redeploy old version
            this.jadortService.previous();
            Assert.assertEquals(Step.EXECUTING_MIGRATION_PART2, this.jadortService.getCurrentOperation().getCurrentStep());
            this.waitForFinishAndCheckServerProgressList(ServerProgressState.SET_DEFAULT_OK, 0);
        }

        // Change page
        this.jadortService.previous();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.SET_DEFAULT_OK, 100);

        // Set old version as default
        this.jadortService.previous();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.DEPLOY_OK, 66);
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());

        // Undeploy new version
        this.jadortService.previous();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.UPLOAD_OK, 33);

        // Erase new version
        this.jadortService.previous();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);

        // Change page
        this.jadortService.previous();
        Assert.assertEquals(Step.SELECT_APPLICATION, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    private void waitForFinishAndCheckServerProgressList(final ServerProgressState state, final int progress) throws Exception {
        boolean notFinished = true;
        for (int i = 0; notFinished; i++) {
            notFinished = false;
            for (ServerProgressBean dep : this.jadortService.getCurrentOperation().getServerProgressList()) {
                if (dep.getActionState().equals(ActionState.FINISHED_ERROR)) {
                    throw new Exception("ServerProgressListBean " + dep + " has errors. Log:\n" + dep.getLog());
                } else if (dep.getActionState().equals(ActionState.WAITING)
                    || dep.getActionState().equals(ActionState.FINISHED_OK) || dep.getProgress() == progress
                    || dep.getProgressState().equals(state)) {
                    notFinished = notFinished || false;
                } else {
                    notFinished = notFinished || true;
                }
            }
            if (notFinished) {
                if (!JadortServiceImplTest.IN_J2EE_SERVER && i > JadortServiceImplTest.TEST_TIMEOUT) {
                    throw new IllegalStateException("Timed out!");
                }
                Thread.sleep(JadortServiceImplTest.CHECK_PERIOD);
            }
        }
        for (ServerProgressBean dep : this.jadortService.getCurrentOperation().getServerProgressList()) {
            Assert.assertEquals(ActionState.WAITING, dep.getActionState());
            Assert.assertEquals(state, dep.getProgressState());
            Assert.assertEquals(progress, dep.getProgress());
        }
    }

    /**
     * Test method for
     * {@link org.ow2.jasmine.jadort.service.implementation.JadortServiceImpl#selectGroup(GroupBean)}
     * with a maintenance.
     */
    @Test
    public void testSelectGroupMaintenanceAndUndo() throws Exception {
        this.selectGroupMaintenance(true, true);
    }

    /**
     * Select group with mode "maintenance".
     */
    private void selectGroupMaintenance(final boolean undo, final boolean clustered) throws Exception {
        if (clustered) {
            this.testValidTopology_maximal();
        } else {
            this.testValidTopology_noCluster();
        }

        Assert.assertEquals(1, this.jadortService.getCurrentOperation().getTopology().getGroups().size());

        GroupBean toSelect = this.jadortService.getCurrentOperation().getTopology().getGroups().get(0);
        this.jadortService.selectGroup(toSelect);
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());
        this.jadortService.next();

        Assert.assertEquals(Step.SELECT_OPERATION_TYPE, this.jadortService.getCurrentOperation().getCurrentStep());
        Assert.assertEquals(toSelect, this.jadortService.getCurrentOperation().getSelectedGroup());

        this.jadortService.selectOperationType(OperationType.MAINTAIN);
        this.jadortService.next();

        Assert.assertEquals(OperationType.MAINTAIN, this.jadortService.getCurrentOperation().getType());
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());

        if (undo) {
            this.jadortService.previous();
            Assert.assertEquals(Step.SELECT_OPERATION_TYPE, this.jadortService.getCurrentOperation().getCurrentStep());
        }
    }

    /**
     * Integration test for server maintenance (all servers maintained in one
     * step) (forward).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testMaintainClusterAllServers() throws Exception {
        this.selectGroupMaintenance(false, true);
        JadortServiceImplTest.operationBeanForMaintainServer1 = this.jadortService.getCurrentOperation();

        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>(this.jadortService.getCurrentOperation()
            .getSelectedGroup().getServers());
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    /**
     * Integration test for no clustered servers maintenance (all servers
     * maintained in one step) (forward).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testMaintainNoClusterAllServers() throws Exception {
        this.selectGroupMaintenance(false, false);
        JadortServiceImplTest.operationBeanForMaintainNoClusterServer = this.jadortService.getCurrentOperation();

        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>(this.jadortService.getCurrentOperation()
            .getSelectedGroup().getServers());
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainNoClusterServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    /**
     * Integration test for server maintenance, try to maintain the same server
     * twice to have an error.
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testAttemptToMaintainTwice() throws Exception {
        this.selectGroupMaintenance(false, true);
        JadortServiceImplTest.operationBeanForMaintainServer2 = this.jadortService.getCurrentOperation();

        // Maintain the first server
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(0));
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());

        // Try to maintain the first server again
        serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(0));
        try {
            this.jadortService.selectServers(serversToSelect);
            Assert.fail();
        } catch (JadortServiceException ignored) {
            this.unMaintainServers(false);
        }
    }

    /**
     * Integration test for server maintenance, try to select servers with
     * different progress percentiles to have an error.
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testSelectDifferentProgress() throws Exception {
        this.selectGroupMaintenance(false, true);
        JadortServiceImplTest.operationBeanForMaintainServer2 = this.jadortService.getCurrentOperation();

        // Maintain the first server
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(0));
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());

        // Try to maintain all servers, including the one maintained before
        serversToSelect = new ArrayList<ServerBean>();
        for (int i = 0; i < this.jadortService.getCurrentOperation().getSelectedGroup().getServers().size(); i++) {
            serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(i));
        }
        try {
            this.jadortService.selectServers(serversToSelect);
            Assert.fail();
        } catch (JadortServiceException ignored) {
            this.unMaintainServers(false);
        }
    }

    /**
     * Integration test for server maintenance (servers maintained in two
     * passes) (forward).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testMaintainClusterServersInTwoSteps() throws Exception {
        this.selectGroupMaintenance(false, true);
        JadortServiceImplTest.operationBeanForMaintainServer2 = this.jadortService.getCurrentOperation();

        // Maintain the first server
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(0));
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());

        // Maintain the other servers
        serversToSelect = new ArrayList<ServerBean>();
        for (int i = 1; i < this.jadortService.getCurrentOperation().getSelectedGroup().getServers().size(); i++) {
            serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(i));
        }
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    /**
     * Integration test for server maintenance No cluster (servers maintained in
     * two passes) (forward).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testMaintainNoClusterServersInTwoSteps() throws Exception {
        this.selectGroupMaintenance(false, false);

        // Maintain the first server
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(0));
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainNoClusterServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());

        // Maintain the other servers
        serversToSelect = new ArrayList<ServerBean>();
        for (int i = 1; i < this.jadortService.getCurrentOperation().getSelectedGroup().getServers().size(); i++) {
            serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(i));
        }
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainNoClusterServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    private void maintainServers() throws Exception {
        // In our test topology file we have 2 workers per server
        Assert.assertEquals(2 * this.jadortService.getCurrentOperation().getServerProgressList().size(), this.jadortService
            .getCurrentOperation().getWorkerProgressList().size());

        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.INITIAL, 0);

        // Stop Worker
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 20);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 20);

        // Stop Server
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.STOP_OK, 40);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 40);

        // Maintain Server
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.MAINTAIN_OK, 60);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 60);

        // Stop Server
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 80);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 80);

        // Stop Worker
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 100);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.START_OK, 100);
    }

    private void maintainNoClusterServers() throws Exception {
        // In our test topology file we have 2 workers per server
        Assert.assertEquals(2 * this.jadortService.getCurrentOperation().getServerProgressList().size(), this.jadortService
            .getCurrentOperation().getWorkerProgressList().size());

        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.INITIAL, 0);

        // Stop Worker
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 16);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 16);

        // Stop Server
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.DISABLE_APPLICATIONS_OK, 33);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 33);

        // Maintain Server
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.STOP_OK, 50);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 50);

        // Maintain Server
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.MAINTAIN_OK, 66);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 66);

        // Stop Server
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 83);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 83);

        // Stop Worker
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 100);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.START_OK, 100);
    }

    /**
     * Integration test for server maintenance (backwards).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testUnmaintainClusterServers1() throws Exception {
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForMaintainServer1);
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForMaintainServer1.getId());

        this.jadortService.selectOperation(JadortServiceImplTest.operationBeanForMaintainServer1);
        Assert.assertNotNull(this.jadortService.getCurrentOperation());

        this.unMaintainServers(true);
    }

    /**
     * Integration test for server maintenance (backwards).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testUnmaintainClusterServers2() throws Exception {
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForMaintainServer2);
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForMaintainServer2.getId());

        this.jadortService.selectOperation(JadortServiceImplTest.operationBeanForMaintainServer2);
        Assert.assertNotNull(this.jadortService.getCurrentOperation());

        this.unMaintainServers(true);
    }

    /**
     * Integration test for no cluster servers maintenance (backwards).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testUnmaintainNoClusterServers() throws Exception {
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForMaintainNoClusterServer);
        Assert.assertNotNull(JadortServiceImplTest.operationBeanForMaintainNoClusterServer.getId());

        this.jadortService.selectOperation(JadortServiceImplTest.operationBeanForMaintainNoClusterServer);
        Assert.assertNotNull(this.jadortService.getCurrentOperation());

        this.unMaintainNoClusterServers(true);
    }

    /**
     * Integration test for server maintenance (some of the servers maintained,
     * then everything undone) (forward).
     */
    @Test(timeout = JadortServiceImplTest.TEST_TIMEOUT * 1000)
    public void testMaintainSomeServersThenUnmaintain() throws Exception {
        this.selectGroupMaintenance(false, true);

        // Maintain the first server
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(0));
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());

        // Maintain the second server
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(1));
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        this.maintainServers();

        // Change page
        this.jadortService.next();
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());

        // Start maintaining the third server and undo in the middle
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        serversToSelect = new ArrayList<ServerBean>();
        serversToSelect.add(this.jadortService.getCurrentOperation().getSelectedGroup().getServers().get(2));
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.INITIAL, 0);

        // Stop Worker
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 20);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 20);

        // Undo the third server
        this.jadortService.previous();
        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.INITIAL, 0);

        // Keep on undoing
        this.jadortService.previous();
        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        this.unMaintainServers(false);
    }

    private void unMaintainServers(final boolean finished) throws Exception {
        if (finished) {
            Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
        }

        this.jadortService.previous();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 100);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.START_OK, 100);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Stop Worker
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 80);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 80);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Stop Server
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.MAINTAIN_OK, 60);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 60);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Unmaintain Server
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.STOP_OK, 40);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 40);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Start Server
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 20);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 20);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Start Worker
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.INITIAL, 0);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Previous screen is either SELECT_SERVERS or SELECT_GROUP
        this.jadortService.previous();

        if (this.jadortService.getCurrentOperation().getCurrentStep().equals(Step.SELECT_SERVERS)) {
            this.jadortService.previous();
        }

        Assert.assertEquals(Step.SELECT_OPERATION_TYPE, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    private void unMaintainNoClusterServers(final boolean finished) throws Exception {
        if (finished) {
            Assert.assertEquals(Step.FINISHED, this.jadortService.getCurrentOperation().getCurrentStep());
        }

        this.jadortService.previous();
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 100);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.START_OK, 100);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Stop Server
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.START_OK, 83);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 83);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Stop Worker
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.MAINTAIN_OK, 66);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 66);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Maintain Server
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.STOP_OK, 50);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 50);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Maintain Server
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.DISABLE_APPLICATIONS_OK, 33);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 33);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Start Worker
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 16);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.STOP_OK, 16);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Enable Applications
        this.jadortService.previous();
        this.waitForFinishAndCheckServerProgressList(ServerProgressState.INITIAL, 0);
        this.waitForFinishAndCheckWorkerProgressList(WorkerProgressState.INITIAL, 0);
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_NO_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Previous screen is either SELECT_SERVERS or SELECT_GROUP
        this.jadortService.previous();

        if (this.jadortService.getCurrentOperation().getCurrentStep().equals(Step.SELECT_SERVERS)) {
            this.jadortService.previous();
        }

        Assert.assertEquals(Step.SELECT_OPERATION_TYPE, this.jadortService.getCurrentOperation().getCurrentStep());
    }

    private void waitForFinishAndCheckWorkerProgressList(final WorkerProgressState state, final int progress) throws Exception {
        boolean notFinished = true;
        for (int i = 0; notFinished; i++) {
            notFinished = false;
            for (WorkerProgressBean dep : this.jadortService.getCurrentOperation().getWorkerProgressList()) {
                if (dep.getActionState().equals(ActionState.FINISHED_ERROR)) {
                    throw new Exception("WorkerProgressListBean " + dep + " has errors. Log:\n" + dep.getLog());
                } else if (dep.getActionState().equals(ActionState.WAITING)
                    || dep.getActionState().equals(ActionState.FINISHED_OK) || dep.getProgress() == progress
                    || dep.getProgressState().equals(state)) {
                    notFinished = notFinished || false;
                } else {
                    notFinished = notFinished || true;
                }
            }
            if (notFinished) {
                if (!JadortServiceImplTest.IN_J2EE_SERVER && i > JadortServiceImplTest.TEST_TIMEOUT) {
                    throw new IllegalStateException("Timed out!");
                }
                Thread.sleep(JadortServiceImplTest.CHECK_PERIOD);
            }
        }
        for (WorkerProgressBean dep : this.jadortService.getCurrentOperation().getWorkerProgressList()) {
            Assert.assertEquals(ActionState.WAITING, dep.getActionState());
            Assert.assertEquals(progress, dep.getProgress());
            Assert.assertEquals(state, dep.getProgressState());
        }
    }

    /**
     * Integration test for the delete operation's behavior with migration
     * actions that are in progress.
     */
    @Test
    public void testOperationDeletionNotAllowedWhenMigrating() throws Exception {
        this.testSelectGroupMigrate();

        this.jadortService.selectApplication(new File("src/test/resources/application1v1/application1.ear").toURI().toURL());

        Assert.assertEquals(Step.SELECT_APPLICATION, this.jadortService.getCurrentOperation().getCurrentStep());
        this.jadortService.next();
        Assert.assertEquals(Step.EXECUTING_MIGRATION_PART1, this.jadortService.getCurrentOperation().getCurrentStep());

        // Save current operation and call setUp for reconnection
        OperationStateBean current = this.jadortService.getCurrentOperation();
        this.setUp();
        try {
            this.jadortService.deleteOperation(current);
            Assert.fail("Managed to delete an operation that's migrating!");
        } catch (JadortServiceException ignored) {
            // Expected exception
        }

        // Go to previous step to enable deletion
        Assert.assertNull(this.jadortService.getCurrentOperation());
        this.jadortService.selectOperation(current);
        this.jadortService.previous();
    }

    /**
     * Integration test for the delete operation's behavior with maintenance
     * actions are in progress.
     */
    @Test
    public void testOperationDeletionNotAllowedWhenMaintaining() throws Exception {
        this.selectGroupMaintenance(false, true);

        Assert.assertEquals(Step.SELECT_SERVERS, this.jadortService.getCurrentOperation().getCurrentStep());
        List<ServerBean> serversToSelect = new ArrayList<ServerBean>(this.jadortService.getCurrentOperation()
            .getSelectedGroup().getServers());
        this.jadortService.selectServers(serversToSelect);
        this.jadortService.next();

        Assert.assertEquals(serversToSelect, this.jadortService.getCurrentOperation().getSelectedServers());
        Assert.assertEquals(Step.EXECUTING_MAINTENANCE_CLUSTER, this.jadortService.getCurrentOperation().getCurrentStep());

        // Save current operation and call setUp for reconnection
        OperationStateBean current = this.jadortService.getCurrentOperation();
        this.setUp();
        try {
            this.jadortService.deleteOperation(current);
            Assert.fail("Managed to delete an operation that's maintaining!");
        } catch (JadortServiceException ignored) {
            // Expected exception
        }

        // Go to previous step twice to enable deletion
        Assert.assertNull(this.jadortService.getCurrentOperation());
        this.jadortService.selectOperation(current);
        this.jadortService.previous();
        this.jadortService.previous();
        this.jadortService.previous();
        Assert.assertEquals(Step.SELECT_GROUP, this.jadortService.getCurrentOperation().getCurrentStep());
    }
}
