Commit bf364bb6 authored by René Schöne's avatar René Schöne
Browse files

Fixed issue #22

- Added TestUtils.waitForMqtt
parent fe3ebc47
Pipeline #6988 passed with stages
in 4 minutes and 37 seconds
...@@ -146,16 +146,23 @@ aspect AspectGeneration { ...@@ -146,16 +146,23 @@ aspect AspectGeneration {
sb.append(ind(indent + 1)).append(preemptiveReturnStatement()).append("\n"); sb.append(ind(indent + 1)).append(preemptiveReturnStatement()).append("\n");
sb.append(ind(indent)).append("}\n"); sb.append(ind(indent)).append("}\n");
if (!getAlwaysApply()) { if (!getAlwaysApply()) {
sb.append(ind(indent)).append("if (").append(preemptiveExpectedValue()); MappingDefinition lastMapping = effectiveMappings().get(effectiveMappings().size() - 1);
if (getToken().isPrimitiveType()) { sb.append(ind(indent)).append("if (");
sb.append(" == ").append(inputVariableName); if (lastMapping.getToType().isArray()) {
} else if (effectiveMappings().get(effectiveMappings().size() - 1).isDefaultMappingDefinition()) { sb.append("java.util.Arrays.equals(").append(preemptiveExpectedValue())
sb.append(" != null && ").append(preemptiveExpectedValue()).append(".equals(") .append(", ").append(inputVariableName).append(")");
.append(inputVariableName).append(")");
} else { } else {
sb.append(" != null ? ").append(preemptiveExpectedValue()).append(".equals(") sb.append(preemptiveExpectedValue());
.append(inputVariableName).append(")").append(" : ") if (getToken().isPrimitiveType() && lastMapping.getToType().isPrimitiveType()) {
.append(inputVariableName).append(" == null"); sb.append(" == ").append(inputVariableName);
} else if (lastMapping.isDefaultMappingDefinition()) {
sb.append(" != null && ").append(preemptiveExpectedValue()).append(".equals(")
.append(inputVariableName).append(")");
} else {
sb.append(" != null ? ").append(preemptiveExpectedValue()).append(".equals(")
.append(inputVariableName).append(")").append(" : ")
.append(inputVariableName).append(" == null");
}
} }
sb.append(") { ").append(preemptiveReturnStatement()).append(" }\n"); sb.append(") { ").append(preemptiveReturnStatement()).append(" }\n");
} }
......
...@@ -151,6 +151,12 @@ aspect Mappings { ...@@ -151,6 +151,12 @@ aspect Mappings {
default: return false; default: return false;
} }
} }
syn boolean MappingDefinitionType.isPrimitiveType() = false;
eq JavaMappingDefinitionType.isPrimitiveType() = getType().isPrimitiveType();
// --- isArray ---
syn boolean MappingDefinitionType.isArray() = false;
eq JavaArrayMappingDefinitionType.isArray() = true;
// --- suitableDefaultMapping --- // --- suitableDefaultMapping ---
syn DefaultMappingDefinition UpdateDefinition.suitableDefaultMapping(); syn DefaultMappingDefinition UpdateDefinition.suitableDefaultMapping();
......
...@@ -4,7 +4,7 @@ ZoneModel ::= <Size:IntPosition> SafetyZone:Zone* ; ...@@ -4,7 +4,7 @@ ZoneModel ::= <Size:IntPosition> SafetyZone:Zone* ;
Zone ::= Coordinate* ; Zone ::= Coordinate* ;
RobotArm ::= Joint* EndEffector <AttributeTestSource:int> /<AppropriateSpeed:double>/ ; RobotArm ::= Joint* EndEffector /<AppropriateSpeed:double>/ ;
Joint ::= <Name:String> <CurrentPosition:IntPosition> ; Joint ::= <Name:String> <CurrentPosition:IntPosition> ;
......
...@@ -5,7 +5,6 @@ write RobotArm.AppropriateSpeed using CreateSpeedMessage, SerializeRobotConfig ; ...@@ -5,7 +5,6 @@ write RobotArm.AppropriateSpeed using CreateSpeedMessage, SerializeRobotConfig ;
// --- dependency definitions --- // --- dependency definitions ---
RobotArm.AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ; RobotArm.AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ;
RobotArm.AppropriateSpeed canDependOn RobotArm.AttributeTestSource as dependency2 ;
// --- mapping definitions --- // --- mapping definitions ---
ParseLinkState maps byte[] bytes to panda.Linkstate.PandaLinkState {: ParseLinkState maps byte[] bytes to panda.Linkstate.PandaLinkState {:
...@@ -18,8 +17,7 @@ SerializeRobotConfig maps config.Robotconfig.RobotConfig rc to byte[] {: ...@@ -18,8 +17,7 @@ SerializeRobotConfig maps config.Robotconfig.RobotConfig rc to byte[] {:
LinkStateToIntPosition maps panda.Linkstate.PandaLinkState pls to IntPosition {: LinkStateToIntPosition maps panda.Linkstate.PandaLinkState pls to IntPosition {:
panda.Linkstate.PandaLinkState.Position p = pls.getPos(); panda.Linkstate.PandaLinkState.Position p = pls.getPos();
{ int i = 0; } return IntPosition.of((int) (10 * p.getPositionX()), (int) (10 * p.getPositionY()), (int) (10 * p.getPositionZ()));
return IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ());
:} :}
CreateSpeedMessage maps double speed to config.Robotconfig.RobotConfig {: CreateSpeedMessage maps double speed to config.Robotconfig.RobotConfig {:
......
...@@ -106,7 +106,7 @@ public class DefaultOnlyReadTest extends AbstractMqttTest { ...@@ -106,7 +106,7 @@ public class DefaultOnlyReadTest extends AbstractMqttTest {
sender.publish(TOPIC_BOXED_DOUBLE, ByteBuffer.allocate(8).putDouble(expectedDoubleValue).array()); sender.publish(TOPIC_BOXED_DOUBLE, ByteBuffer.allocate(8).putDouble(expectedDoubleValue).array());
sender.publish(TOPIC_BOXED_CHARACTER, ByteBuffer.allocate(2).putChar(expectedCharValue).array()); sender.publish(TOPIC_BOXED_CHARACTER, ByteBuffer.allocate(2).putChar(expectedCharValue).array());
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
assertEquals(expectedIntValue, integers.getIntValue()); assertEquals(expectedIntValue, integers.getIntValue());
assertEquals(expectedShortValue, integers.getShortValue()); assertEquals(expectedShortValue, integers.getShortValue());
......
...@@ -67,21 +67,21 @@ public class DefaultOnlyWriteTest extends AbstractMqttTest { ...@@ -67,21 +67,21 @@ public class DefaultOnlyWriteTest extends AbstractMqttTest {
setupReceiverAndConnect(true); setupReceiverAndConnect(true);
// check initial value // check initial value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(1, 1, 1.1, 'a', "ab"); checkData(1, 1, 1.1, 'a', "ab");
// set new value // set new value
setData("2", "2.2", "cd"); setData("2", "2.2", "cd");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(2, 2, 2.2, 'c', "cd"); checkData(2, 2, 2.2, 'c', "cd");
// set new value // set new value
setData("3", "3.2", "ee"); setData("3", "3.2", "ee");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(3, 3, 3.2, 'e', "ee"); checkData(3, 3, 3.2, 'e', "ee");
} }
...@@ -92,21 +92,21 @@ public class DefaultOnlyWriteTest extends AbstractMqttTest { ...@@ -92,21 +92,21 @@ public class DefaultOnlyWriteTest extends AbstractMqttTest {
setupReceiverAndConnect(false); setupReceiverAndConnect(false);
// check initial value (will be default values) // check initial value (will be default values)
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(0, null, null, null, null); checkData(0, null, null, null, null);
// set new value // set new value
setData("2", "2.2", "cd"); setData("2", "2.2", "cd");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(1, 2, 2.2, 'c', "cd"); checkData(1, 2, 2.2, 'c', "cd");
// set new value // set new value
setData("3", "3.2", "ee"); setData("3", "3.2", "ee");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(2, 3, 3.2, 'e', "ee"); checkData(2, 3, 3.2, 'e', "ee");
} }
......
...@@ -5,10 +5,9 @@ import config.Robotconfig.RobotConfig; ...@@ -5,10 +5,9 @@ import config.Robotconfig.RobotConfig;
import example.ast.*; import example.ast.*;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import panda.Linkstate;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
...@@ -22,16 +21,19 @@ public class ExampleTest extends AbstractMqttTest { ...@@ -22,16 +21,19 @@ public class ExampleTest extends AbstractMqttTest {
private static final String TOPIC_CONFIG = "robot/config"; private static final String TOPIC_CONFIG = "robot/config";
private static final String TOPIC_JOINT1 = "robot/arm/joint1"; private static final String TOPIC_JOINT1 = "robot/arm/joint1";
private static final String TOPIC_JOINT2 = "robot/arm/joint2";
private Model model; private Model model;
private RobotArm robotArm; private RobotArm robotArm;
private Joint joint1; private Joint joint1;
private MqttUpdater receiver; private Joint joint2;
private MqttUpdater handler;
private ReceiverData data;
@AfterEach @AfterEach
public void closeConnections() { public void closeConnections() {
if (receiver != null) { if (handler != null) {
receiver.close(); handler.close();
} }
if (model != null) { if (model != null) {
model.MqttCloseConnections(); model.MqttCloseConnections();
...@@ -44,49 +46,116 @@ public class ExampleTest extends AbstractMqttTest { ...@@ -44,49 +46,116 @@ public class ExampleTest extends AbstractMqttTest {
} }
@Test @Test
public void communicate() throws IOException, InterruptedException { public void communicateSendInitialValue() throws IOException, InterruptedException {
createModel(); createModel();
List<RobotConfig> receivedConfigs = new ArrayList<>(); setupReceiverAndConnect(true);
createListener(receivedConfigs);
model.MqttSetHost(TestUtils.getMqttHost());
assertTrue(model.MqttWaitUntilReady(2, TimeUnit.SECONDS));
// joint is currently within the safety zone, so speed should be low // joint is currently within the safety zone, so speed should be low
robotArm.connectAppropriateSpeed(TOPIC_CONFIG, true); TestUtils.waitForMqtt();
joint1.connectCurrentPosition(TOPIC_JOINT1); assertEquals(1, data.numberOfConfigs);
assertFalse(data.failedLastConversion);
assertEquals(robotArm.speedLow(), data.lastConfig.getSpeed(), TestUtils.DELTA);
// change position of the first joint out of the safety zone, second still in
sendData(TOPIC_JOINT1, 0.2f, 0.2f, 0.2f);
// still in safety zone, so no update should have been sent
TestUtils.waitForMqtt();
assertEquals(makePosition(2, 2, 2), joint1.getCurrentPosition());
assertEquals(1, data.numberOfConfigs);
assertFalse(data.failedLastConversion);
assertEquals(robotArm.speedLow(), data.lastConfig.getSpeed(), TestUtils.DELTA);
// change position of second joint also out of the safety zone, now speed must be high
sendData(TOPIC_JOINT2, 0.3f, 0.4f, 0.5f);
TestUtils.waitForMqtt();
assertEquals(makePosition(3, 4, 5), joint2.getCurrentPosition());
assertEquals(2, data.numberOfConfigs);
assertFalse(data.failedLastConversion);
assertEquals(robotArm.speedHigh(), data.lastConfig.getSpeed(), TestUtils.DELTA);
// change position of second joint, still out of the safety zone, no update should be sent
sendData(TOPIC_JOINT2, 1.3f, 2.4f, 3.5f);
TestUtils.waitForMqtt();
assertEquals(makePosition(13, 24, 35), joint2.getCurrentPosition());
assertEquals(2, data.numberOfConfigs);
}
@Test
public void communicateOnlyUpdatedValue() throws IOException, InterruptedException {
createModel();
setupReceiverAndConnect(false);
// now change the position of the joint out of the safety zone // no value should have been sent
joint1.setCurrentPosition(makePosition(2, 2, 2)); TestUtils.waitForMqtt();
assertEquals(0, data.numberOfConfigs);
// and wait for MQTT to send/receive messages // change position of the first joint out of the safety zone, second still in
TimeUnit.SECONDS.sleep(2); sendData(TOPIC_JOINT1, 0.2f, 0.2f, 0.2f);
// there should be two configs received by now (the initial one, and the updated) // still in safety zone, first update should have been sent
assertEquals(2, receivedConfigs.size()); TestUtils.waitForMqtt();
RobotConfig actualInitialConfig = receivedConfigs.get(0); assertEquals(makePosition(2, 2, 2), joint1.getCurrentPosition());
assertEquals(robotArm.speedLow(), actualInitialConfig.getSpeed(), TestUtils.DELTA); assertEquals(0, data.numberOfConfigs);
RobotConfig actualUpdatedConfig = receivedConfigs.get(1); // change position of second joint also out of the safety zone, now speed must be high
assertEquals(robotArm.speedHigh(), actualUpdatedConfig.getSpeed(), TestUtils.DELTA); sendData(TOPIC_JOINT2, 0.3f, 0.4f, 0.5f);
TestUtils.waitForMqtt();
assertEquals(makePosition(3, 4, 5), joint2.getCurrentPosition());
assertEquals(1, data.numberOfConfigs);
assertFalse(data.failedLastConversion);
assertEquals(robotArm.speedHigh(), data.lastConfig.getSpeed(), TestUtils.DELTA);
// change position of second joint, still out of the safety zone, no update should be sent
sendData(TOPIC_JOINT2, 1.3f, 2.4f, 3.5f);
TestUtils.waitForMqtt();
assertEquals(makePosition(13, 24, 35), joint2.getCurrentPosition());
assertEquals(1, data.numberOfConfigs);
} }
private void createListener(List<RobotConfig> receivedConfigs) { private void sendData(String topic, float x, float y, float z) {
receiver = new MqttUpdater("receiver"); handler.publish(topic, Linkstate.PandaLinkState.newBuilder()
try { .setPos(Linkstate.PandaLinkState.Position.newBuilder()
receiver.setHost(TestUtils.getMqttHost(), TestUtils.getMqttDefaultPort()); .setPositionX(x)
} catch (IOException e) { .setPositionY(y)
fail("Could not set host: " + e.getMessage()); .setPositionZ(z)
} .build())
assertTrue(receiver.waitUntilReady(2, TimeUnit.SECONDS)); .build()
receiver.newConnection(TOPIC_CONFIG, bytes -> { .toByteArray()
);
}
private void setupReceiverAndConnect(boolean writeCurrentValue) throws IOException {
model.MqttSetHost(TestUtils.getMqttHost());
assertTrue(model.MqttWaitUntilReady(2, TimeUnit.SECONDS));
handler = new MqttUpdater().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost());
assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS));
// add dependencies
robotArm.addDependency1(joint1);
robotArm.addDependency1(joint2);
robotArm.addDependency1(robotArm.getEndEffector());
data = new ReceiverData();
handler.newConnection(TOPIC_CONFIG, bytes -> {
data.numberOfConfigs += 1;
try { try {
RobotConfig config = RobotConfig.parseFrom(bytes); data.lastConfig = RobotConfig.parseFrom(bytes);
receivedConfigs.add(config); data.failedLastConversion = false;
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {
fail("Received bad config: " + e.getMessage()); data.failedLastConversion = true;
} }
}); });
robotArm.connectAppropriateSpeed(TOPIC_CONFIG, writeCurrentValue);
joint1.connectCurrentPosition(TOPIC_JOINT1);
joint2.connectCurrentPosition(TOPIC_JOINT2);
} }
private void createModel() { private void createModel() {
...@@ -95,41 +164,44 @@ public class ExampleTest extends AbstractMqttTest { ...@@ -95,41 +164,44 @@ public class ExampleTest extends AbstractMqttTest {
ZoneModel zoneModel = new ZoneModel(); ZoneModel zoneModel = new ZoneModel();
zoneModel.setSize(makePosition(1, 1, 1)); zoneModel.setSize(makePosition(1, 1, 1));
IntPosition myPosition = makePosition(0, 0, 0); IntPosition firstPosition = makePosition(0, 0, 0);
Coordinate myCoordinate = new Coordinate(myPosition); IntPosition secondPosition = makePosition(-1, 0, 0);
Coordinate leftPosition = new Coordinate(makePosition(-1, 0, 0)); IntPosition thirdPosition = makePosition(1, 0, 0);
Coordinate rightPosition = new Coordinate(makePosition(1, 0, 0));
Zone safetyZone = new Zone(); Zone safetyZone = new Zone();
safetyZone.addCoordinate(myCoordinate); safetyZone.addCoordinate(new Coordinate(firstPosition));
safetyZone.addCoordinate(leftPosition); safetyZone.addCoordinate(new Coordinate(secondPosition));
safetyZone.addCoordinate(rightPosition); safetyZone.addCoordinate(new Coordinate(thirdPosition));
zoneModel.addSafetyZone(safetyZone); zoneModel.addSafetyZone(safetyZone);
model.setZoneModel(zoneModel); model.setZoneModel(zoneModel);
robotArm = new RobotArm(); robotArm = new RobotArm();
robotArm.setAttributeTestSource(1); // set initial value, no trigger
joint1 = new Joint(); joint1 = new Joint();
joint1.setName("joint1"); joint1.setName("joint1");
joint1.setCurrentPosition(myPosition); joint1.setCurrentPosition(firstPosition);
joint2 = new Joint();
joint2.setName("joint2");
joint2.setCurrentPosition(secondPosition);
EndEffector endEffector = new EndEffector(); EndEffector endEffector = new EndEffector();
endEffector.setName("gripper"); endEffector.setName("gripper");
endEffector.setCurrentPosition(makePosition(2, 2, 3)); endEffector.setCurrentPosition(makePosition(2, 2, 3));
robotArm.addJoint(joint1); robotArm.addJoint(joint1);
robotArm.addJoint(joint2);
robotArm.setEndEffector(endEffector); robotArm.setEndEffector(endEffector);
model.setRobotArm(robotArm); model.setRobotArm(robotArm);
// add dependencies
robotArm.addDependency1(joint1);
robotArm.addDependency1(endEffector);
robotArm.addDependency2(robotArm);
} }
private static IntPosition makePosition(int x, int y, int z) { private static IntPosition makePosition(int x, int y, int z) {
return IntPosition.of(x, y, z); return IntPosition.of(x, y, z);
} }
private static class ReceiverData {
RobotConfig lastConfig;
boolean failedLastConversion = true;
int numberOfConfigs = 0;
}
} }
...@@ -59,28 +59,28 @@ public class Read1Write2Test extends AbstractMqttTest { ...@@ -59,28 +59,28 @@ public class Read1Write2Test extends AbstractMqttTest {
setupReceiverAndConnect(true); setupReceiverAndConnect(true);
// check initial value // check initial value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(1, Integer.parseInt(INITIAL_VALUE), prefixed(INITIAL_VALUE), 1, Integer.parseInt(INITIAL_VALUE), prefixed(INITIAL_VALUE)); checkData(1, Integer.parseInt(INITIAL_VALUE), prefixed(INITIAL_VALUE), 1, Integer.parseInt(INITIAL_VALUE), prefixed(INITIAL_VALUE));
// set new value // set new value
sendData("2", "3"); sendData("2", "3");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(2, 2, prefixed("2"), 2, 3, prefixed("3")); checkData(2, 2, prefixed("2"), 2, 3, prefixed("3"));
// set new value // set new value
sendData("4", "4"); sendData("4", "4");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(3, 4, prefixed("4"), 3, 4, prefixed("4")); checkData(3, 4, prefixed("4"), 3, 4, prefixed("4"));
// set new value only for same // set new value only for same
setDataOnlySame("77"); setDataOnlySame("77");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(4, 77, prefixed("77"), 3, 4, prefixed("4")); checkData(4, 77, prefixed("77"), 3, 4, prefixed("4"));
} }
...@@ -94,28 +94,28 @@ public class Read1Write2Test extends AbstractMqttTest { ...@@ -94,28 +94,28 @@ public class Read1Write2Test extends AbstractMqttTest {
setupReceiverAndConnect(false); setupReceiverAndConnect(false);
// check initial value // check initial value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(0, null, null, 0, null, null); checkData(0, null, null, 0, null, null);
// set new value // set new value
sendData("2", "3"); sendData("2", "3");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(1, 2, prefixed("2"), 1, 3, prefixed("3")); checkData(1, 2, prefixed("2"), 1, 3, prefixed("3"));
// set new value // set new value
sendData("4", "4"); sendData("4", "4");
// check new value // check new value
TimeUnit.SECONDS.sleep(2); TestUtils.waitForMqtt();
checkData(2, 4, prefixed("4"), 2, 4, prefixed("4")); checkData(2, 4, prefixed("4"), 2, 4, prefixed("4"));
// set new value only for same // set new value only for same
setDataOnlySame("77"); setDataOnlySame("77");