All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.arquillian.cube.impl.client.CubeSuiteLifecycleController Maven / Gradle / Ivy

package org.arquillian.cube.impl.client;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import org.arquillian.cube.impl.docker.DockerClientExecutor;
import org.arquillian.cube.impl.util.AutoStartOrderUtil;
import org.arquillian.cube.spi.event.CreateCube;
import org.arquillian.cube.spi.event.CubeControlEvent;
import org.arquillian.cube.spi.event.DestroyCube;
import org.arquillian.cube.spi.event.PreRunningCube;
import org.arquillian.cube.spi.event.StartCube;
import org.arquillian.cube.spi.event.StopCube;
import org.jboss.arquillian.core.api.Event;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.core.api.threading.ExecutorService;
import org.jboss.arquillian.test.spi.event.suite.AfterSuite;
import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;

public class CubeSuiteLifecycleController {

    @Inject
    private Event controlEvent;

    @Inject
    private Instance dockerClientExecutor;

    @Inject
    private Instance executorServiceInst;

    public void startAutoContainers(@Observes(precedence = 100) BeforeSuite event, final CubeConfiguration configuration) {
        List autoStartSteps = AutoStartOrderUtil.getAutoStartOrder(configuration);
        startAllSteps(autoStartSteps, configuration.getConnectionMode());
    }

    public void stopAutoContainers(@Observes(precedence = -100) AfterSuite event, CubeConfiguration configuration) {
        List autoStopSteps = AutoStartOrderUtil.getAutoStopOrder(configuration);
        stopAllSteps(autoStopSteps);
    }

    private void startAllSteps(List autoStartSteps, ConnectionMode connectionMode) {
        for(final String[] cubeIds : autoStartSteps) {
            Map> stepStatus = new HashMap<>();

            // Start
            for(final String cubeId : cubeIds) {
                Future result = executorServiceInst.get().submit(new StartCubes(cubeId, connectionMode));
                stepStatus.put(cubeId, result);
            }

            waitForCompletion(stepStatus, "Could not auto start container");
        }
    }

    private void stopAllSteps(List autoStopSteps) {
        for(final String[] cubeIds : autoStopSteps) {
            Map> stepStatus = new HashMap<>();

            // Start
            for(final String cubeId : cubeIds) {
                Future result = executorServiceInst.get().submit(new StopCubes(cubeId));
                stepStatus.put(cubeId, result);
            }

            // wait
            waitForCompletion(stepStatus, "Could not auto stop container");
        }
    }

    private void waitForCompletion(Map> stepStatus, String message) {
        for(final Map.Entry> result: stepStatus.entrySet()) {
            try {
                RuntimeException e = result.getValue().get();
                if(e != null) {
                    throw e;
                }
            } catch (Exception e) {
                throw new RuntimeException(message + " " + result.getKey(), e);
            }
        }
    }

    private boolean isCubeRunning(String cube) {
        //TODO should we create an adapter class so we don't expose client classes in this part?
        List runningContainers = dockerClientExecutor.get().listRunningContainers();
        for (com.github.dockerjava.api.model.Container container : runningContainers) {
            for (String name : container.getNames()) {
                if(name.startsWith("/")) name = name.substring(1); //Names array adds an slash to the docker name container.
                if(name.equals(cube)) { //cube id is the container name in docker0 Id in docker is the hash that identifies it.
                    return true;
                }
            }
        }
        return false;
    }

    private final class StartCubes implements Callable {
        private final ConnectionMode connectionMode;
        private final String cubeId;

        private StartCubes(String cubeId, ConnectionMode connectionMode) {
            this.cubeId = cubeId;
            this.connectionMode = connectionMode;
        }

        @Override
        public RuntimeException call() throws Exception {
            try {
                if(connectionMode.isAllowReconnect() && isCubeRunning(cubeId)) {
                    controlEvent.fire(new PreRunningCube(cubeId));
                    return null;
                }
                controlEvent.fire(new CreateCube(cubeId));
                controlEvent.fire(new StartCube(cubeId));

                if(connectionMode.isAllowReconnect() && !connectionMode.isStoppable()) {
                 // If we allow reconnections and containers are none stoppable which means that they will be able to be
                 // reused in next executions then at this point we can assume that the container is a prerunning container.
                 controlEvent.fire(new PreRunningCube(cubeId));
                }
            } catch(RuntimeException e) {
                return e;
            }
            return null;
        }
    }

    private final class StopCubes implements Callable {
        private final String cubeId;

        private StopCubes(String cubeId) {
            this.cubeId = cubeId;
        }

        @Override
        public RuntimeException call() throws Exception {
            try {
                controlEvent.fire(new StopCube(cubeId));
                controlEvent.fire(new DestroyCube(cubeId));
            } catch(RuntimeException e) {
                return e;
            }
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy