/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package project.latex.balloon;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.PropertyConfigurator;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import project.latex.balloon.consumer.DataModelConsumer;
import project.latex.balloon.sensor.SensorController;
import project.latex.balloon.sensor.SensorReadFailedException;
import project.latex.balloon.writer.DataWriter;
/**
*
* @author dgorst
*/
public class BalloonControllerTest {
private SensorController mockSensorController;
private SentenceIdGenerator mockSentenceIdGenerator;
private DataModelConsumer mockDataModelConsumer;
private ControllerRunner mockControllerRunner;
public BalloonControllerTest() {
}
@BeforeClass
public static void setUpClass() {
PropertyConfigurator.configure("logger.properties");
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
this.mockSensorController = mock(SensorController.class);
this.mockSentenceIdGenerator = mock(SentenceIdGenerator.class);
this.mockDataModelConsumer = mock(DataModelConsumer.class);
this.mockControllerRunner = mock(ControllerRunner.class);
}
private BalloonController createDefaultController() throws IOException {
List<SensorController> sensors = new ArrayList<>();
sensors.add(this.mockSensorController);
List<DataModelConsumer> dataModelConsumers = new ArrayList<>();
dataModelConsumers.add(this.mockDataModelConsumer);
List<DataWriter> dataWriters = new ArrayList<>();
BalloonController controller = new BalloonController();
controller.setSensors(sensors);
controller.setDataWriters(dataWriters);
controller.setDataModelConsumers(dataModelConsumers);
controller.setSentenceIdGenerator(mockSentenceIdGenerator);
controller.setTimeKey("time");
controller.setDateKey("date");
controller.setPayloadNameKey("payload_name");
controller.setSentenceIdKey("sentence_id");
controller.setControllerRunner(mockControllerRunner);
return controller;
}
@Test(expected = IllegalArgumentException.class)
public void testRunThrowsIfRunnerIsNull() throws IOException {
BalloonController controller = createDefaultController();
controller.setControllerRunner(null);
controller.run();
}
@Test(expected = IllegalArgumentException.class)
public void testRunThrowsIfNoTimeDataKeyIsSpecified() throws IOException {
BalloonController controller = createDefaultController();
controller.setTimeKey(null);
when(mockControllerRunner.shouldKeepRunning()).thenReturn(true, false);
controller.run();
}
@Test(expected = IllegalArgumentException.class)
public void testRunThrowsIfNoPayloadNameKeyIsSpecified() throws IOException {
BalloonController controller = createDefaultController();
controller.setPayloadNameKey(null);
when(mockControllerRunner.shouldKeepRunning()).thenReturn(true, false);
controller.run();
}
@Test(expected = IllegalArgumentException.class)
public void testRunThrowsIfNoSentenceIdKeyIsSpecified() throws IOException {
BalloonController controller = createDefaultController();
controller.setSentenceIdKey(null);
when(mockControllerRunner.shouldKeepRunning()).thenReturn(true, false);
controller.run();
}
@Test
public void testRunSucceedsIfValidPropertiesArePassed() throws IOException, SensorReadFailedException {
BalloonController controller = createDefaultController();
when(mockControllerRunner.shouldKeepRunning()).thenReturn(true, false);
when(mockControllerRunner.getCurrentRunLoop()).thenReturn(ControllerRunLoop.SensorDataRunLoop);
Map<String, Object> mockSensorData = new HashMap<>();
mockSensorData.put("altitude", 0.1234);
when(mockSensorController.getCurrentData()).thenReturn(mockSensorData);
when(mockSentenceIdGenerator.generateId()).thenReturn("2");
controller.run();
Map<String, Object> expectedData = new HashMap<>();
expectedData.put("payload_name", "$$latex");
expectedData.put("sentence_id", "2");
expectedData.put("altitude", 0.1234);
verify(mockControllerRunner).controllerFinishedRunLoop(argThat(fieldsEqualTo(expectedData)));
}
// Custom argument matcher to verify our model data, without caring about the time, which we won't know exactly
private ArgumentMatcher<Map> fieldsEqualTo(final Map<String, Object> expected) {
return new ArgumentMatcher<Map>() {
@Override
public boolean matches(Object argument) {
Map<String, Object> actual = (Map<String, Object>) argument;
Double actualAltitude = (Double) actual.get("altitude");
Double expectedAltitude = (Double) expected.get("altitude");
double altitudeDiff = Math.abs(actualAltitude - expectedAltitude);
return (actual.get("payload_name").equals(expected.get("payload_name"))
&& actual.get("sentence_id").equals(expected.get("sentence_id"))
&& altitudeDiff <= 0.000001);
}
};
}
@Test
public void testThatDataModelConsumerIsCalledAfterModelIsPopulated() throws IOException, SensorReadFailedException {
BalloonController controller = createDefaultController();
when(mockControllerRunner.shouldKeepRunning()).thenReturn(true, false);
when(mockControllerRunner.getCurrentRunLoop()).thenReturn(ControllerRunLoop.SensorDataRunLoop);
Map<String, Object> mockSensorData = new HashMap<>();
mockSensorData.put("altitude", 0.1234);
when(mockSensorController.getCurrentData()).thenReturn(mockSensorData);
when(mockSentenceIdGenerator.generateId()).thenReturn("2");
controller.run();
verify(mockDataModelConsumer).consumeDataModel(anyMap());
}
}