ch.epfl.leb.sass.server.RPCServerIT.java Source code

Java tutorial

Introduction

Here is the source code for ch.epfl.leb.sass.server.RPCServerIT.java

Source

/*
 * Copyright (C) 2017-2018 Laboratory of Experimental Biophysics
 * Ecole Polytechnique Fdrale de Lausanne
 * 
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */
package ch.epfl.leb.sass.server;

import ch.epfl.leb.sass.IntegrationTest;
import ch.epfl.leb.sass.models.Microscope;
import ch.epfl.leb.sass.models.backgrounds.internal.commands.GenerateUniformBackground;
import ch.epfl.leb.sass.models.components.internal.DefaultCamera;
import ch.epfl.leb.sass.models.components.internal.DefaultLaser;
import ch.epfl.leb.sass.models.components.internal.DefaultObjective;
import ch.epfl.leb.sass.models.components.internal.DefaultStage;
import ch.epfl.leb.sass.models.fluorophores.commands.internal.GenerateFluorophoresGrid2D;
import ch.epfl.leb.sass.models.photophysics.internal.PalmDynamics;
import ch.epfl.leb.sass.models.obstructors.internal.commands.GenerateFiducialsRandom2D;
import ch.epfl.leb.sass.models.psfs.internal.Gaussian2D;
import ch.epfl.leb.sass.utils.RNG;
import ch.epfl.leb.sass.simulator.Simulator;
import ch.epfl.leb.sass.simulator.SimulationManager;
import ch.epfl.leb.sass.simulator.internal.RPCSimulator;
import ch.epfl.leb.sass.simulator.internal.DefaultSimulationManager;
import ch.epfl.leb.sass.client.RPCClient;
import ch.epfl.leb.sass.logging.MessageType;
import ch.epfl.leb.sass.models.illuminations.internal.SquareUniformIllumination;
import ch.epfl.leb.sass.models.samples.RefractiveIndex;
import ch.epfl.leb.sass.models.samples.internal.UniformRefractiveIndex;

import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.After;
import org.junit.experimental.categories.Category;

import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import com.google.gson.JsonObject;
import com.google.gson.JsonElement;

import java.util.List;
import java.util.EnumSet;
import java.util.ArrayList;
import java.util.logging.Logger;
import java.util.logging.Level;
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;

import org.apache.thrift.TException;

/**
 * Integration tests for the RPCServer.
 * 
 * @author Kyle M. Douglass
 */
@Category(IntegrationTest.class)
public class RPCServerIT {

    private final static Logger LOGGER = Logger.getLogger(RPCServerIT.class.getName());

    /**
     * The number of simulations to run.
     */
    private final int NUM_SIMS = 2;

    /**
     * The URL to the server.
     */
    private final String HOST_URL = "localhost";

    /**
     * The port for RPC server communications.
     */
    private final int PORT = 9090;

    /**
     * The simulation manager that the server will interact with.
     */
    private SimulationManager manager;

    /**
     * The ground truth simulation objects.
     */
    private Simulator[] sims = new Simulator[NUM_SIMS];

    /**
     * A RPCServer that will be used to test client/server communications.
     */
    RPCServer rpcServer;

    /**
     * A RPCClient that will be used to test server communications.
     */
    RPCClient rpcClient;

    /**
     * Sets up two different Microscopes for acquisition simulations.
     */
    @Before
    public void setUp() throws InterruptedException {
        // The seed determines the outputs of the random number generator.
        RNG.setSeed(42);

        DefaultCamera.Builder cameraBuilder = new DefaultCamera.Builder();

        cameraBuilder.nX(32); // Number of pixels in x
        cameraBuilder.nY(32); // Number of pixels in y
        cameraBuilder.readoutNoise(1.6); // Standard deviation, electrons
        cameraBuilder.darkCurrent(0.06);
        cameraBuilder.quantumEfficiency(0.8);
        cameraBuilder.aduPerElectron(2.2);
        cameraBuilder.emGain(0); // Set to zero for CMOS cameras
        cameraBuilder.baseline(100); // ADU
        cameraBuilder.pixelSize(6.45); // microns
        cameraBuilder.thermalNoise(0.05); // electrons/frame/pixel

        // DefaultObjective
        DefaultObjective.Builder objectiveBuilder = new DefaultObjective.Builder();

        objectiveBuilder.NA(1.3); // Numerical aperture
        objectiveBuilder.mag(60); // Magnification

        // DefaultLaser
        DefaultLaser.Builder laserBuilder = new DefaultLaser.Builder();

        laserBuilder.currentPower(0.0);
        laserBuilder.minPower(0.0);
        laserBuilder.maxPower(500.0);
        laserBuilder.wavelength(0.642);

        // Illumination profile
        // TODO: Add illumination setup to the GUI
        RefractiveIndex n = new UniformRefractiveIndex(new Complex(1.33));
        SquareUniformIllumination.Builder illumBuilder = new SquareUniformIllumination.Builder();
        illumBuilder.height(32 * 6.45 / 60);
        illumBuilder.orientation(new Vector3D(1.0, 0, 0)); // x-polarized
        illumBuilder.refractiveIndex(n);
        illumBuilder.width(32 * 6.45 / 60);

        // DefaultStage
        DefaultStage.Builder stageBuilder = new DefaultStage.Builder();

        stageBuilder.x(0);
        stageBuilder.y(0);
        stageBuilder.z(0); // Coverslip surface is at z = 0

        // PSF, create a 2D Gaussian point-spread function
        Gaussian2D.Builder psfBuilder = new Gaussian2D.Builder();

        // Fluorophore dynamics and properties; rates are in units of 1/frames
        PalmDynamics.Builder fluorPropBuilder = new PalmDynamics.Builder();

        fluorPropBuilder.signal(2500); // Photons per fluorophore per frame
        fluorPropBuilder.wavelength(0.6); // Wavelength, microns
        fluorPropBuilder.kA(100); // Activation rate
        fluorPropBuilder.kB(0); // Bleaching rate
        fluorPropBuilder.kD1(0.065); // Transition rate to first dark state
        fluorPropBuilder.kD2(0.013); // Transition rate to second dark state
        fluorPropBuilder.kR1(0.004); // Return rate from first dark state
        fluorPropBuilder.kR2(0.157); // Return rate from second dark state

        // Fluorophore positions on a square grid
        GenerateFluorophoresGrid2D.Builder fluorPosBuilder = new GenerateFluorophoresGrid2D.Builder();
        fluorPosBuilder.spacing(4); // pixels

        // Add fiducials to the field of view at a random location
        GenerateFiducialsRandom2D.Builder fidBuilder = new GenerateFiducialsRandom2D.Builder();
        fidBuilder.numFiducials(2);
        fidBuilder.brightness(3000); // photons per frame

        // Add a constant background
        GenerateUniformBackground.Builder backgroundBuilder = new GenerateUniformBackground.Builder();
        backgroundBuilder.backgroundSignal(10); // photons

        // Assemble the microscope and the simulator.
        Microscope microscope1 = new Microscope(cameraBuilder, laserBuilder, objectiveBuilder, psfBuilder,
                stageBuilder, fluorPosBuilder, fluorPropBuilder, fidBuilder, backgroundBuilder, illumBuilder);
        RPCSimulator sim0 = new RPCSimulator(microscope1);
        sims[0] = sim0;

        // Change the number of pixels for the second microscopy
        cameraBuilder.nX(64);
        cameraBuilder.nY(64);
        Microscope microscope2 = new Microscope(cameraBuilder, laserBuilder, objectiveBuilder, psfBuilder,
                stageBuilder, fluorPosBuilder, fluorPropBuilder, fidBuilder, backgroundBuilder, illumBuilder);
        RPCSimulator sim1 = new RPCSimulator(microscope2);
        sims[1] = sim1;

        // Adds the simulations to the manager.
        manager = new DefaultSimulationManager();
        manager.addSimulator(sims[0]);
        manager.addSimulator(sims[1]);

        // Starts the server.
        rpcServer = new RPCServer(manager, PORT);

        Runnable serverRunnable = new Runnable() {
            public void run() {
                rpcServer.serve();
            }
        };
        new Thread(serverRunnable).start();
        Thread.sleep(500); // Give the server time to start
        System.out.println("Server started!");

        // Creates the client.
        rpcClient = new RPCClient(HOST_URL, PORT);
        RemoteSimulationService.Client client = rpcClient.getClient();
    }

    /**
     * Closes the server communications.
     * @throws java.lang.InterruptedException
     */
    @After
    public void tearDown() throws InterruptedException {
        // Close the client connection.
        try {
            rpcClient.close();
            Thread.sleep(500);
        } catch (java.lang.NullPointerException ex) {
            LOGGER.log(Level.INFO, "RPCClient connection failed to close. This "
                    + "is likely because a RPCClient instance was " + "not created during this test.");
        }

        // Shutdown the server.
        try {
            rpcServer.stop();
            Thread.sleep(500);
        } catch (java.lang.NullPointerException ex) {
            LOGGER.log(Level.INFO, "RPCServer failed to shutdown. This may be "
                    + "because no server was started in this " + "test.");
        }
    }

    /**
     * Test of isServing method, of class RPCServer.
     */
    @Test
    public void testIsServing() throws InterruptedException {
        System.out.println("isServing");

        boolean expResult = true;
        boolean result = rpcServer.isServing();
        assertEquals(expResult, result);

    }

    /**
     * Test of createSimulation and deleteSimulation methods, of class
     * RemoteSimulationServiceHandler.
     */
    @Test
    public void testCreateAndDeleteSimulation() throws TException {
        System.out.println("testCreateSimulation");

        RemoteSimulationService.Client client = rpcClient.getClient();

        int origNumSims;
        origNumSims = manager.getIds().size();

        int newSimId;
        newSimId = client.createSimulation();

        // There should now be one additional simulation in the manager..
        assertEquals(origNumSims + 1, manager.getIds().size());

        // Increment the new simulation by one time step and verify that only
        // the new simulation state has changed.
        int newImageCount;
        int oldImageCount;
        client.getNextImage(newSimId);
        oldImageCount = client.getImageCount(sims[0].getId());
        newImageCount = client.getImageCount(newSimId);
        assertEquals(0, oldImageCount);
        assertEquals(1, newImageCount);

        // Delete the new simulation.
        client.deleteSimulation(newSimId);
        List<Integer> listOfSims = manager.getIds();
        assertEquals(origNumSims, listOfSims.size());
        assert (!listOfSims.contains(newSimId));

    }

    /**
     * Test of getControlSignal method, of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testGetControlSignal() throws InterruptedException, UnknownSimulationIdException, TException {
        System.out.println("testGetControlSignal");

        RemoteSimulationService.Client client = rpcClient.getClient();

        double expResult = sims[0].getControlSignal();
        double result = client.getControlSignal(sims[0].getId());
        assertEquals(expResult, result, 0.0);
    }

    /**
     * Test of toJsonMessages method, of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testToJsonMessages() throws UnknownSimulationIdException, TException {
        System.out.println("testToJsonMessages");

        RemoteSimulationService.Client client = rpcClient.getClient();
        JsonParser parser = new JsonParser();

        // Run the simulation for a few steps to generate some messages.
        int simId = sims[0].getId();
        for (int i = 0; i < 10; i++) {
            client.incrementTimeStep(simId);
        }

        // Extract the messages from the first simulation.
        String info = client.toJsonMessages(simId);
        System.out.println(info);

        // Ensure that all messages have a TYPE field that is registered in
        // MessageType.
        EnumSet<MessageType> set = EnumSet.allOf(MessageType.class);
        List<String> typeStrings = new ArrayList<>();
        for (MessageType type : set) {
            typeStrings.add(type.name());
        }

        String typeString;
        JsonArray json = parser.parse(info).getAsJsonArray();
        for (JsonElement e : json) {
            typeString = e.getAsJsonObject().get("type").getAsString();
            assert (typeStrings.contains(typeString));
        }

    }

    /**
     * Test of toJsonState and getCameraJsonName methods,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testToJsonStateCamera() throws UnknownSimulationIdException, TException {
        System.out.println("testToJsonStateCamera");

        RemoteSimulationService.Client client = rpcClient.getClient();
        JsonParser parser = new JsonParser();

        // Extract the fluorescence info from the first simulation.
        String info = client.toJsonState(sims[0].getId());
        String cameraName = client.getCameraJsonName(sims[0].getId());
        JsonObject json = parser.parse(info).getAsJsonObject();
        JsonObject jsonCamera;
        jsonCamera = json.get(cameraName).getAsJsonObject();
        assertEquals(2.2, jsonCamera.get("aduPerElectron").getAsDouble(), 0.0);
        assertEquals(100, jsonCamera.get("baseline").getAsInt());
        assertEquals(0.06, jsonCamera.get("darkCurrent").getAsDouble(), 0.0);
        assertEquals(0, jsonCamera.get("emGain").getAsDouble(), 0.0);
        assertEquals(32, jsonCamera.get("nPixelsX").getAsInt());
        assertEquals(32, jsonCamera.get("nPixelsY").getAsInt());
        assertEquals(6.45, jsonCamera.get("pixelSize").getAsDouble(), 0.0);
        assertEquals(0.8, jsonCamera.get("quantumEfficiency").getAsDouble(), 0.0);
        assertEquals(1.6, jsonCamera.get("readoutNoise").getAsDouble(), 0.0);
        assertEquals(0.05, jsonCamera.get("thermalNoise").getAsDouble(), 0.0);

        // Extract the fluorescence info from the second simulation.
        info = client.toJsonState(sims[1].getId());
        cameraName = client.getCameraJsonName(sims[1].getId());
        json = parser.parse(info).getAsJsonObject();
        jsonCamera = json.get(cameraName).getAsJsonObject();
        assertEquals(2.2, jsonCamera.get("aduPerElectron").getAsDouble(), 0.0);
        assertEquals(100, jsonCamera.get("baseline").getAsInt());
        assertEquals(0.06, jsonCamera.get("darkCurrent").getAsDouble(), 0.0);
        assertEquals(0, jsonCamera.get("emGain").getAsDouble(), 0.0);
        assertEquals(64, jsonCamera.get("nPixelsX").getAsInt());
        assertEquals(64, jsonCamera.get("nPixelsY").getAsInt());
        assertEquals(6.45, jsonCamera.get("pixelSize").getAsDouble(), 0.0);
        assertEquals(0.8, jsonCamera.get("quantumEfficiency").getAsDouble(), 0.0);
        assertEquals(1.6, jsonCamera.get("readoutNoise").getAsDouble(), 0.0);
        assertEquals(0.05, jsonCamera.get("thermalNoise").getAsDouble(), 0.0);
    }

    /**
     * Test of toJsonState and getFluorescenceJsonName methods,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testToJsonStateFluorescence() throws UnknownSimulationIdException, TException {
        System.out.println("testToJsonStateFluorescence");

        RemoteSimulationService.Client client = rpcClient.getClient();
        JsonParser parser = new JsonParser();

        // Extract the fluorescence info from the first simulation.
        String info = client.toJsonState(sims[0].getId());
        String fluorName = client.getFluorescenceJsonName(sims[0].getId());
        JsonObject json = parser.parse(info).getAsJsonObject();
        JsonArray fluorArray;
        fluorArray = json.get(fluorName).getAsJsonArray();
        int expResult = 49; // (num_pixels / grid_spacing - 1)^2
        assertEquals(expResult, fluorArray.size());

        // Extract the fluorescence info from the second simulation.
        info = client.toJsonState(sims[1].getId());
        fluorName = client.getFluorescenceJsonName(sims[1].getId());
        json = parser.parse(info).getAsJsonObject();
        fluorArray = json.get(fluorName).getAsJsonArray();

        expResult = 225; // (num_pixels / grid_spacing - 1)^2
        assertEquals(expResult, fluorArray.size());
    }

    /**
     * Test of toJsonState and getLaserJsonName methods,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testToJsonStateLaser() throws UnknownSimulationIdException, TException {
        System.out.println("testToJsonStateLaser");

        RemoteSimulationService.Client client = rpcClient.getClient();
        JsonParser parser = new JsonParser();

        // Extract the fluorescence info from the first simulation.
        String info = client.toJsonState(sims[0].getId());
        String laserName = client.getLaserJsonName(sims[0].getId());
        JsonObject json = parser.parse(info).getAsJsonObject();
        JsonObject jsonLaser;
        jsonLaser = json.get(laserName).getAsJsonObject();
        assertEquals(0.0, jsonLaser.get("currentPower").getAsDouble(), 0.0);

        // Extract the fluorescence info from the second simulation.
        info = client.toJsonState(sims[1].getId());
        laserName = client.getLaserJsonName(sims[1].getId());
        json = parser.parse(info).getAsJsonObject();
        jsonLaser = json.get(laserName).getAsJsonObject();
        assertEquals(0.0, jsonLaser.get("currentPower").getAsDouble(), 0.0);
    }

    /**
     * Test of toJsonState and getObjectiveJsonName methods,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testToJsonStateObjective() throws UnknownSimulationIdException, TException {
        System.out.println("testToJsonStateObjective");

        RemoteSimulationService.Client client = rpcClient.getClient();
        JsonParser parser = new JsonParser();

        // Extract the fluorescence info from the first simulation.
        String info = client.toJsonState(sims[0].getId());
        String objectiveName = client.getObjectiveJsonName(sims[0].getId());
        JsonObject json = parser.parse(info).getAsJsonObject();
        JsonObject jsonObjective;
        jsonObjective = json.get(objectiveName).getAsJsonObject();
        assertEquals(60, jsonObjective.get("magnification").getAsDouble(), 0.0);
        assertEquals(1.3, jsonObjective.get("numerical aperture").getAsDouble(), 0.0);

        // Extract the fluorescence info from the second simulation.
        info = client.toJsonState(sims[1].getId());
        objectiveName = client.getObjectiveJsonName(sims[1].getId());
        json = parser.parse(info).getAsJsonObject();
        jsonObjective = json.get(objectiveName).getAsJsonObject();
        assertEquals(60, jsonObjective.get("magnification").getAsDouble(), 0.0);
        assertEquals(1.3, jsonObjective.get("numerical aperture").getAsDouble(), 0.0);
    }

    /**
    * Test of toJsonState and getLaserJsonName methods,
    * of class RemoteSimulationServiceHandler.
    */
    @Test
    public void testToJsonStateStage() throws UnknownSimulationIdException, TException {
        System.out.println("testToJsonStateStage");

        RemoteSimulationService.Client client = rpcClient.getClient();
        JsonParser parser = new JsonParser();

        // Extract the fluorescence info from the first simulation.
        String info = client.toJsonState(sims[0].getId());
        String stageName = client.getStageJsonName(sims[0].getId());
        JsonObject json = parser.parse(info).getAsJsonObject();
        JsonObject jsonStage;
        jsonStage = json.get(stageName).getAsJsonObject();
        assertEquals(0.0, jsonStage.get("x").getAsDouble(), 0.0);
        assertEquals(0.0, jsonStage.get("y").getAsDouble(), 0.0);
        assertEquals(0.0, jsonStage.get("z").getAsDouble(), 0.0);

        // Extract the fluorescence info from the second simulation.
        info = client.toJsonState(sims[1].getId());
        stageName = client.getStageJsonName(sims[1].getId());
        json = parser.parse(info).getAsJsonObject();
        jsonStage = json.get(stageName).getAsJsonObject();
        assertEquals(0.0, jsonStage.get("x").getAsDouble(), 0.0);
        assertEquals(0.0, jsonStage.get("y").getAsDouble(), 0.0);
        assertEquals(0.0, jsonStage.get("z").getAsDouble(), 0.0);
    }

    /**
     * Test of getFovSize method, of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testGetFovSize() throws UnknownSimulationIdException, TException {
        System.out.println("testGetFovSize");

        RemoteSimulationService.Client client = rpcClient.getClient();
        // pixel size * num pixels / mag
        double expResult = 6.45 * 6.45 * 32 * 32 / 60 / 60;
        double result = client.getFovSize(sims[0].getId());
        assertEquals(expResult, result, 0.0);

        // pixel size * num pixels / mag
        expResult = 6.45 * 6.45 * 64 * 64 / 60 / 60; // pixel size * num pixels / mag
        result = client.getFovSize(sims[1].getId());
        assertEquals(expResult, result, 0.0);
    }

    /**
     * Test of getNextImage and getImageCount methods,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testGetNextImageAndImageCount() throws UnknownSimulationIdException, TException {
        System.out.println("testGetNextImageAndImageCount");

        RemoteSimulationService.Client client = rpcClient.getClient();
        int expResult = 0;
        int result = client.getImageCount(sims[0].getId());
        assertEquals(expResult, result);

        result = client.getImageCount(sims[1].getId());
        assertEquals(expResult, result);

        // Generate an image in each simulation
        client.getNextImage(sims[0].getId());
        client.getNextImage(sims[1].getId());

        expResult = 1;
        result = client.getImageCount(sims[0].getId());
        assertEquals(expResult, result);

        result = client.getImageCount(sims[1].getId());
        assertEquals(expResult, result);
    }

    /**
     * Test of getObjectSpacePixelSize method,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testGetObjectSpacePixelSize() throws UnknownSimulationIdException, TException {
        System.out.println("testGetObjectSpacePixelSize");

        RemoteSimulationService.Client client = rpcClient.getClient();
        // pixel size / mag
        double expResult = 6.45 / 60;
        double result = client.getObjectSpacePixelSize(sims[0].getId());
        assertEquals(expResult, result, 0.0);

        result = client.getObjectSpacePixelSize(sims[1].getId());
        assertEquals(expResult, result, 0.0);
    }

    /**
     * Test of getGetServerStatus method,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testGetServerStatus() throws UnknownSimulationIdException, TException {
        System.out.println("testGetServerStatus");

        RemoteSimulationService.Client client = rpcClient.getClient();
        String expResult = "SASS RPC server is running.";
        String result = client.getServerStatus();

        assert (expResult.equals(result));
    }

    /**
     * Test of getShortTrueSignalDescription and getTrueSignal methods,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testTrueSignal() throws UnknownSimulationIdException, TException {
        System.out.println("testTrueSignal");

        RemoteSimulationService.Client client = rpcClient.getClient();
        String result = client.getShortTrueSignalDescription(sims[0].getId());

        // The result can vary, so just make sure that it's not empty.
        assert (!result.equals(""));

        double result2 = client.getTrueSignal(sims[0].getId(), 0);
        assert (result2 >= 0);

        result2 = client.getTrueSignal(sims[1].getId(), 0);
        assert (result2 >= 0);
    }

    /**
     * Test of incrementTimeStep method,
     * of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testIncrementTimeStep() throws UnknownSimulationIdException, TException {
        System.out.println("testIncrementTimeStep");

        RemoteSimulationService.Client client = rpcClient.getClient();

        //Sim 0
        String before = client.toJsonState(sims[0].getId());
        client.incrementTimeStep(sims[0].getId());
        String after = client.toJsonState(sims[0].getId());
        assert (!after.equals(before));

        // Sim 1
        before = client.toJsonState(sims[1].getId());
        client.incrementTimeStep(sims[1].getId());
        after = client.toJsonState(sims[1].getId());
        assert (!after.equals(before));
    }

    /**
     * Test of setControlSignal method, of class RemoteSimulationServiceHandler.
     */
    @Test
    public void testSetControlSignal() throws InterruptedException, UnknownSimulationIdException, TException {
        System.out.println("testSetControlSignal");

        RemoteSimulationService.Client client = rpcClient.getClient();

        // Test sim[0]
        double expResult = 1.42;
        client.setControlSignal(sims[0].getId(), expResult);
        double result = sims[0].getControlSignal();
        assertEquals(expResult, result, 0.0);

        // Test the other simulation
        expResult = 0.0;
        result = client.getControlSignal(sims[1].getId());
        assertEquals(expResult, result, 0.0);

    }
}