org.hobbit.core.components.BenchmarkControllerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.hobbit.core.components.BenchmarkControllerTest.java

Source

/**
 * This file is part of core.
 *
 * core 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 3 of the License, or
 * (at your option) any later version.
 *
 * core 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 core.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.hobbit.core.components;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Semaphore;

import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.jena.rdf.model.ModelFactory;
import org.hobbit.core.Commands;
import org.hobbit.core.Constants;
import org.hobbit.core.TestConstants;
import org.hobbit.core.components.dummy.DummyComponentExecutor;
import org.hobbit.core.rabbit.RabbitMQUtils;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.EnvironmentVariables;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.MessageProperties;

@RunWith(Parameterized.class)
public class BenchmarkControllerTest extends AbstractBenchmarkController {

    private static final Logger LOGGER = LoggerFactory.getLogger(BenchmarkControllerTest.class);

    private static final String HOBBIT_SESSION_ID = "123";
    private static final String SYSTEM_CONTAINER_ID = "systemContainerId";
    private static final String DATA_GEN_IMAGE = "datagenimage";
    private static final String TASK_GEN_IMAGE = "taskgenimage";
    private static final String EVAL_IMAGE = "evaluationimage";

    @Parameters
    public static Collection<Object[]> data() {
        List<Object[]> testConfigs = new ArrayList<Object[]>();
        testConfigs.add(new Object[] { 1, 1 });
        testConfigs.add(new Object[] { 1, 10 });
        testConfigs.add(new Object[] { 10, 1 });
        testConfigs.add(new Object[] { 10, 10 });
        return testConfigs;
    }

    @Rule
    public final EnvironmentVariables environmentVariables = new EnvironmentVariables();

    private int numberOfDataGenerators;
    private int numberOfTaskGenerators;
    private String sessionId;

    public BenchmarkControllerTest(int numberOfDataGenerators, int numberOfTaskGenerators) {
        this.numberOfDataGenerators = numberOfDataGenerators;
        this.numberOfTaskGenerators = numberOfTaskGenerators;
        this.sessionId = HOBBIT_SESSION_ID + Integer.toString(numberOfDataGenerators)
                + Integer.toString(numberOfTaskGenerators);
    }

    @Test
    public void test() throws Exception {
        environmentVariables.set(Constants.RABBIT_MQ_HOST_NAME_KEY, TestConstants.RABBIT_HOST);
        environmentVariables.set(Constants.HOBBIT_SESSION_ID_KEY, sessionId);
        environmentVariables.set(Constants.BENCHMARK_PARAMETERS_MODEL_KEY,
                "{ \"@id\" : \"http://w3id.org/hobbit/experiments#New\", \"@type\" : \"http://w3id.org/hobbit/vocab#Experiment\" }");
        environmentVariables.set(Constants.HOBBIT_EXPERIMENT_URI_KEY, Constants.EXPERIMENT_URI_NS + sessionId);
        // Needed for the generators
        environmentVariables.set(Constants.GENERATOR_ID_KEY, "0");
        environmentVariables.set(Constants.GENERATOR_COUNT_KEY, "1");

        final DummyPlatformController dummyPlatformController = new DummyPlatformController(sessionId);
        try {
            DummyComponentExecutor dummyPlatformExecutor = new DummyComponentExecutor(dummyPlatformController);
            Thread dummyPlatformThread = new Thread(dummyPlatformExecutor);
            dummyPlatformThread.start();
            dummyPlatformController.waitForControllerBeingReady();

            AbstractBenchmarkController controller = this;
            DummyComponentExecutor controllerExecutor = new DummyComponentExecutor(controller);
            Thread controllerThread = new Thread(controllerExecutor);
            controllerThread.start();
            // wait for the benchmark controller to start

            Thread.sleep(10000);
            dummyPlatformController.sendToCmdQueue(Constants.HOBBIT_SESSION_ID_FOR_BROADCASTS,
                    Commands.DOCKER_CONTAINER_TERMINATED,
                    RabbitMQUtils.writeByteArrays(null,
                            new byte[][] { RabbitMQUtils.writeString(SYSTEM_CONTAINER_ID) },
                            new byte[] { (byte) 0 }),
                    null);
            Thread.sleep(10000);

            for (Thread t : dummyPlatformController.dataGenThreads) {
                t.join(10000);
                Assert.assertFalse(t.isAlive());
            }
            for (Thread t : dummyPlatformController.taskGenThreads) {
                t.join(10000);
                Assert.assertFalse(t.isAlive());
            }

            for (DummyComponentExecutor executor : dummyPlatformController.dataGenExecutors) {
                Assert.assertTrue(executor.isSuccess());
            }
            for (DummyComponentExecutor executor : dummyPlatformController.taskGenExecutors) {
                Assert.assertTrue(executor.isSuccess());
            }

            // Make sure that the benchmark controller terminates during the
            // next seconds
            controllerThread.join(5000);
            Assert.assertFalse(controllerThread.isAlive());
        } finally {
            dummyPlatformController.terminate();
            for (DummyComponentExecutor executor : dummyPlatformController.dataGenExecutors) {
                try {
                    IOUtils.closeQuietly(executor.getComponent());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            for (DummyComponentExecutor executor : dummyPlatformController.taskGenExecutors) {
                try {
                    IOUtils.closeQuietly(executor.getComponent());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            close();
        }
    }

    @Override
    public void init() throws Exception {
        super.init();

        // create data generators
        createDataGenerators(DATA_GEN_IMAGE, numberOfDataGenerators, null);

        // Create task generators
        createTaskGenerators(TASK_GEN_IMAGE, numberOfTaskGenerators, null);

        // Create evaluation storage
        createEvaluationStorage(EVAL_IMAGE, null);

        // Wait for all components to finish their initialization
        waitForComponentsToInitialize();
    }

    @Override
    protected void executeBenchmark() throws Exception {
        // give the start signals
        sendToCmdQueue(Commands.TASK_GENERATOR_START_SIGNAL);
        sendToCmdQueue(Commands.DATA_GENERATOR_START_SIGNAL);

        // wait for the data generators to finish their work
        waitForDataGenToFinish();

        // wait for the task generators to finish their work
        waitForTaskGenToFinish();

        // wait for the system to terminate
        waitForSystemToFinish();

        // Create the evaluation module

        // wait for the evaluation to finish
        // waitForEvalComponentsToFinish();

        // the evaluation module should have sent an RDF model containing the
        // results. We should add the configuration of the benchmark to this
        // model.
        // this.resultModel.add(...);

        // Send the resultModul to the platform controller and terminate
        sendResultModel(ModelFactory.createDefaultModel());
    }

    protected static class DummyPlatformController extends AbstractCommandReceivingComponent {

        public List<DummyComponentExecutor> dataGenExecutors = new ArrayList<DummyComponentExecutor>();
        public List<Thread> dataGenThreads = new ArrayList<>();
        public List<DummyComponentExecutor> taskGenExecutors = new ArrayList<DummyComponentExecutor>();
        public List<Thread> taskGenThreads = new ArrayList<>();
        public Random random = new Random();
        private boolean readyFlag = false;

        private String sessionId;
        private Semaphore terminationMutex = new Semaphore(0);

        public DummyPlatformController(String sessionId) {
            super();
            this.sessionId = sessionId;
        }

        protected void handleCmd(byte bytes[], String replyTo) {
            ByteBuffer buffer = ByteBuffer.wrap(bytes);
            int idLength = buffer.getInt();
            byte sessionIdBytes[] = new byte[idLength];
            buffer.get(sessionIdBytes);
            String sessionId = new String(sessionIdBytes, Charsets.UTF_8);
            byte command = buffer.get();
            byte remainingData[];
            if (buffer.remaining() > 0) {
                remainingData = new byte[buffer.remaining()];
                buffer.get(remainingData);
            } else {
                remainingData = new byte[0];
            }
            receiveCommand(command, remainingData, sessionId, replyTo);
        }

        public void receiveCommand(byte command, byte[] data, String sessionId, String replyTo) {
            LOGGER.info("received command: session={}, command={}, data={}", sessionId, Commands.toString(command),
                    data != null ? RabbitMQUtils.readString(data) : "null");
            if (command == Commands.BENCHMARK_READY_SIGNAL) {
                System.out.println("Benchmark Ready!");
                try {
                    sendToCmdQueue(sessionId, Commands.START_BENCHMARK_SIGNAL,
                            RabbitMQUtils.writeString(SYSTEM_CONTAINER_ID), null);
                } catch (IOException e) {
                    e.printStackTrace();
                    Assert.fail(e.getLocalizedMessage());
                }
            } else if (command == Commands.DOCKER_CONTAINER_START) {
                try {
                    String startCommandJson = RabbitMQUtils.readString(data);
                    final String containerId = Integer.toString(random.nextInt());

                    if (startCommandJson.contains(DATA_GEN_IMAGE)) {
                        // Create data generators that are waiting for a random
                        // amount of time and terminate after that
                        DummyComponentExecutor dataGenExecutor = new DummyComponentExecutor(
                                new AbstractDataGenerator() {
                                    @Override
                                    protected void generateData() throws Exception {
                                        LOGGER.debug("Data Generator started...");
                                        Thread.sleep(1000 + random.nextInt(1000));
                                    }
                                }) {
                            @Override
                            public void run() {
                                super.run();
                                try {
                                    sendToCmdQueue(Constants.HOBBIT_SESSION_ID_FOR_BROADCASTS,
                                            Commands.DOCKER_CONTAINER_TERMINATED,
                                            RabbitMQUtils.writeByteArrays(null,
                                                    new byte[][] { RabbitMQUtils.writeString(containerId) },
                                                    new byte[] { (byte) 0 }),
                                            null);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    success = false;
                                }
                            }
                        };
                        dataGenExecutors.add(dataGenExecutor);
                        Thread t = new Thread(dataGenExecutor);
                        dataGenThreads.add(t);
                        t.start();
                        cmdChannel.basicPublish("", replyTo, MessageProperties.PERSISTENT_BASIC,
                                RabbitMQUtils.writeString(containerId));
                    } else if (startCommandJson.contains(TASK_GEN_IMAGE)) {
                        // Create task generators that are waiting for a random
                        // amount of
                        // time and terminate after that
                        DummyComponentExecutor taskGenExecutor = new DummyComponentExecutor(
                                new AbstractTaskGenerator() {
                                    @Override
                                    public void run() throws Exception {
                                        LOGGER.debug("Task Generator started...");
                                        super.run();
                                    }

                                    @Override
                                    protected void generateTask(byte[] data) throws Exception {
                                    }
                                }) {
                            @Override
                            public void run() {
                                super.run();
                                try {
                                    sendToCmdQueue(Constants.HOBBIT_SESSION_ID_FOR_BROADCASTS,
                                            Commands.DOCKER_CONTAINER_TERMINATED,
                                            RabbitMQUtils.writeByteArrays(null,
                                                    new byte[][] { RabbitMQUtils.writeString(containerId) },
                                                    new byte[] { (byte) 0 }),
                                            null);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    success = false;
                                }
                            }
                        };
                        taskGenExecutors.add(taskGenExecutor);
                        Thread t = new Thread(taskGenExecutor);
                        taskGenThreads.add(t);
                        t.start();
                        cmdChannel.basicPublish("", replyTo, MessageProperties.PERSISTENT_BASIC,
                                RabbitMQUtils.writeString(containerId));
                    } else if (startCommandJson.contains(EVAL_IMAGE)) {
                        cmdChannel.basicPublish("", replyTo, MessageProperties.PERSISTENT_BASIC,
                                RabbitMQUtils.writeString(containerId));
                        sendToCmdQueue(this.sessionId, Commands.EVAL_STORAGE_READY_SIGNAL, null, null);
                    } else {
                        LOGGER.error("Got unknown start command. Ignoring it.");
                    }
                } catch (IOException e) {
                    LOGGER.error("Exception while trying to respond to a container creation command.", e);
                }
            }
        }

        public void waitForControllerBeingReady() throws InterruptedException {
            while (!readyFlag) {
                Thread.sleep(500);
            }
        }

        public void sendToCmdQueue(String address, byte command, byte data[], BasicProperties props)
                throws IOException {
            byte sessionIdBytes[] = RabbitMQUtils.writeString(address);
            // + 5 because 4 bytes for the session ID length and 1 byte for the
            // command
            int dataLength = sessionIdBytes.length + 5;
            boolean attachData = (data != null) && (data.length > 0);
            if (attachData) {
                dataLength += data.length;
            }
            ByteBuffer buffer = ByteBuffer.allocate(dataLength);
            buffer.putInt(sessionIdBytes.length);
            buffer.put(sessionIdBytes);
            buffer.put(command);
            if (attachData) {
                buffer.put(data);
            }
            cmdChannel.basicPublish(Constants.HOBBIT_COMMAND_EXCHANGE_NAME, "", props, buffer.array());
        }

        @Override
        public void receiveCommand(byte command, byte[] data) {
        }

        @Override
        public void run() throws Exception {
            readyFlag = true;
            terminationMutex.acquire();
        }

        public void terminate() {
            terminationMutex.release();
        }

    }
}