From 2a281c3ea3e3734f6c079f43d5048c58315824f2 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Thu, 3 Feb 2022 10:36:37 +0100 Subject: [PATCH] working on attributes as endpoint target - change syntax in connect file, avoid colon - begin with AttributeTest - discovered error when endpoint is connected twice --- .../src/main/jastadd/Analysis.jrag | 16 +- .../src/main/jastadd/Intermediate.jadd | 22 ++- .../src/main/jastadd/Intermediate.relast | 1 + .../src/main/jastadd/Navigation.jrag | 13 ++ .../src/main/jastadd/parser/RagConnect.parser | 2 +- .../src/main/jastadd/scanner/Keywords.flex | 4 +- .../src/main/resources/handler.mustache | 8 + .../main/resources/sendDefinition.mustache | 8 +- ragconnect.tests/build.gradle | 1 + .../src/test/01-input/attribute/Test.connect | 12 +- .../src/test/01-input/attribute/Test.relast | 2 +- .../ragconnect/tests/AttributeTest.java | 148 +++++++++++++++++- 12 files changed, 215 insertions(+), 22 deletions(-) diff --git a/ragconnect.base/src/main/jastadd/Analysis.jrag b/ragconnect.base/src/main/jastadd/Analysis.jrag index b48146f..b5fb2ce 100644 --- a/ragconnect.base/src/main/jastadd/Analysis.jrag +++ b/ragconnect.base/src/main/jastadd/Analysis.jrag @@ -2,6 +2,19 @@ aspect Analysis { // --- isAlreadyDefined --- syn boolean EndpointDefinition.isAlreadyDefined() = getEndpointTarget().isAlreadyDefined(); syn boolean EndpointTarget.isAlreadyDefined(); + eq AttributeEndpointTarget.isAlreadyDefined() { + // define lookup here, as not used elsewhere + int numberOfSameDefs = 0; + for (EndpointTarget target : ragconnect().givenEndpointTargetList()) { + if (target.isAttributeEndpointTarget()) { + AttributeEndpointTarget other = target.asAttributeEndpointTarget(); + if (other.getParentTypeDecl().equals(this.getParentTypeDecl()) && other.getName().equals(this.getName())) { + numberOfSameDefs += 1; + } + } + } + return numberOfSameDefs > 1; + } eq TokenEndpointTarget.isAlreadyDefined() { return lookupTokenEndpointDefinitions(getToken()).stream() .filter(containingEndpointDefinition()::matchesType) @@ -63,8 +76,9 @@ aspect Analysis { } } + // TODO rename entityIsNormalAttribute to actual meaning syn boolean EndpointTarget.entityIsNormalAttribute(); - // TODO AttributeEndpointTarget.entityIsNormalAttribute + eq AttributeEndpointTarget.entityIsNormalAttribute() = true; eq TokenEndpointTarget.entityIsNormalAttribute() = !getToken().getNTA(); eq TypeEndpointTarget.entityIsNormalAttribute() = !getType().getNTA(); eq ContextFreeTypeEndpointTarget.entityIsNormalAttribute() = false; diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd index b215f18..e26b797 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.jadd +++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd @@ -168,6 +168,11 @@ aspect MustacheMappingApplicationAndDefinition { syn String MEndpointDefinition.preemptiveReturn(); syn String MEndpointDefinition.firstInputVarName(); + // TODO check MAttributeSendDefinition + eq MAttributeSendDefinition.firstInputVarName() = getterMethodCall(); + eq MAttributeSendDefinition.preemptiveExpectedValue() = lastValueGetterCall(); + eq MAttributeSendDefinition.preemptiveReturn() = "return false;"; + eq MTokenReceiveDefinition.firstInputVarName() = "message"; eq MTokenReceiveDefinition.preemptiveExpectedValue() = getterMethodCall(); eq MTokenReceiveDefinition.preemptiveReturn() = "return;"; @@ -323,7 +328,7 @@ aspect MustacheRagConnect { aspect MustacheReceiveAndSendAndHandleUri { // === EndpointDefinition === - syn String EndpointDefinition.connectMethodName() = "connect" + entityName(); + syn String EndpointDefinition.connectMethodName() = "connect" + capitalize(entityName()); syn String EndpointDefinition.connectParameterName() = "uriString"; @@ -348,7 +353,7 @@ aspect MustacheReceiveAndSendAndHandleUri { } else { extra = ""; } - return "disconnect" + extra + entityName(); + return "disconnect" + extra + capitalize(entityName()); } syn String EndpointDefinition.entityName() = getEndpointTarget().entityName(); @@ -371,7 +376,7 @@ aspect MustacheReceiveAndSendAndHandleUri { syn String EndpointTarget.parentTypeName(); syn String EndpointTarget.entityName(); - // TODO AttributeEndpointTarget.getterName + eq AttributeEndpointTarget.getterMethodName() = getName(); eq AttributeEndpointTarget.parentTypeName() = getParentTypeDecl().getName(); eq AttributeEndpointTarget.entityName() = getName(); @@ -463,9 +468,14 @@ aspect MustacheSendDefinition { syn String EndpointTarget.senderName() = ragconnect().internalRagConnectPrefix() + "_sender_" + entityName(); eq ContextFreeTypeEndpointTarget.senderName() = null; + // TOOO both updateMethodName and writeMethodName could be defined for MEndpointDefinition using getEndpointDefinition().enitityName() syn String MEndpointDefinition.updateMethodName(); syn String MEndpointDefinition.writeMethodName(); + // TODO check MAttributeSendDefinition. maybe name-clash possible if there is an attribute with same name as a child + eq MAttributeSendDefinition.updateMethodName() = ragconnect().internalRagConnectPrefix() + "_update_" + getEndpointDefinition().entityName(); + eq MAttributeSendDefinition.writeMethodName() = ragconnect().internalRagConnectPrefix() + "_writeLastValue_" + getEndpointDefinition().entityName(); + eq MTokenReceiveDefinition.updateMethodName() = null; eq MTokenReceiveDefinition.writeMethodName() = null; @@ -582,6 +592,12 @@ aspect AttributesForMustache { return result; } abstract MEndpointDefinition EndpointTarget.createMEndpointDefinition(boolean isSend); + MEndpointDefinition AttributeEndpointTarget.createMEndpointDefinition(boolean isSend) { + if (!isSend) { + throw new IllegalArgumentException("AttributeEndpointTarget can only be sent!"); + } + return new MAttributeSendDefinition(); + } MEndpointDefinition TokenEndpointTarget.createMEndpointDefinition(boolean isSend) { return isSend ? new MTokenSendDefinition() : new MTokenReceiveDefinition(); } diff --git a/ragconnect.base/src/main/jastadd/Intermediate.relast b/ragconnect.base/src/main/jastadd/Intermediate.relast index 7909750..486158a 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.relast +++ b/ragconnect.base/src/main/jastadd/Intermediate.relast @@ -1,6 +1,7 @@ abstract MEndpointDefinition ::= InnerMappingDefinition:MInnerMappingDefinition*; rel MEndpointDefinition.EndpointDefinition -> EndpointDefinition; +MAttributeSendDefinition : MEndpointDefinition; abstract MTokenEndpointDefinition : MEndpointDefinition; MTokenReceiveDefinition : MTokenEndpointDefinition; MTokenSendDefinition : MTokenEndpointDefinition; diff --git a/ragconnect.base/src/main/jastadd/Navigation.jrag b/ragconnect.base/src/main/jastadd/Navigation.jrag index 260ed55..cb89e31 100644 --- a/ragconnect.base/src/main/jastadd/Navigation.jrag +++ b/ragconnect.base/src/main/jastadd/Navigation.jrag @@ -25,6 +25,12 @@ aspect NewStuff { syn boolean EndpointTarget.isUntypedEndpointTarget() = false; eq UntypedEndpointTarget.isUntypedEndpointTarget() = true; + /** Tests if EndpointTarget is a AttributeEndpointTarget. + * @return 'true' if this is a AttributeEndpointTarget, otherwise 'false' + */ + syn boolean EndpointTarget.isAttributeEndpointTarget() = false; + eq AttributeEndpointTarget.isAttributeEndpointTarget() = true; + /** casts a EndpointTarget into a TokenEndpointTarget if possible. * @return 'this' cast to a TokenEndpointTarget or 'null' */ @@ -52,6 +58,13 @@ aspect NewStuff { syn UntypedEndpointTarget EndpointTarget.asUntypedEndpointTarget(); eq EndpointTarget.asUntypedEndpointTarget() = null; eq UntypedEndpointTarget.asUntypedEndpointTarget() = this; + + /** casts a EndpointTarget into a AttributeEndpointTarget if possible. + * @return 'this' cast to a AttributeEndpointTarget or 'null' + */ + syn AttributeEndpointTarget EndpointTarget.asAttributeEndpointTarget(); + eq EndpointTarget.asAttributeEndpointTarget() = null; + eq AttributeEndpointTarget.asAttributeEndpointTarget() = this; } aspect RagConnectNavigation { diff --git a/ragconnect.base/src/main/jastadd/parser/RagConnect.parser b/ragconnect.base/src/main/jastadd/parser/RagConnect.parser index dcd55d2..f822bf0 100644 --- a/ragconnect.base/src/main/jastadd/parser/RagConnect.parser +++ b/ragconnect.base/src/main/jastadd/parser/RagConnect.parser @@ -63,7 +63,7 @@ EndpointDefinition endpoint_definition_type EndpointTarget endpoint_target = ID.type_name DOT ID.child_name {: return new UntypedEndpointTarget(type_name, child_name, false); :} - | ID.type_name DOT ID.child_name BRACKETS COLON ID.attribute_type_name + | ID.type_name DOT ID.child_name BRACKET_LEFT ID.attribute_type_name BRACKET_RIGHT {: return new UntypedEndpointTarget(type_name, child_name + ":" + attribute_type_name, true); :} | ID.type_name {: return new UntypedEndpointTarget(type_name, "", false); :} ; diff --git a/ragconnect.base/src/main/jastadd/scanner/Keywords.flex b/ragconnect.base/src/main/jastadd/scanner/Keywords.flex index ffa057b..cda59f5 100644 --- a/ragconnect.base/src/main/jastadd/scanner/Keywords.flex +++ b/ragconnect.base/src/main/jastadd/scanner/Keywords.flex @@ -8,5 +8,5 @@ "with" { return sym(Terminals.WITH); } "indexed" { return sym(Terminals.INDEXED); } "add" { return sym(Terminals.ADD); } -"()" { return sym(Terminals.BRACKETS); } -":" { return sym(Terminals.COLON); } +"(" { return sym(Terminals.BRACKET_LEFT); } +")" { return sym(Terminals.BRACKET_RIGHT); } diff --git a/ragconnect.base/src/main/resources/handler.mustache b/ragconnect.base/src/main/resources/handler.mustache index a7ef597..0d36873 100644 --- a/ragconnect.base/src/main/resources/handler.mustache +++ b/ragconnect.base/src/main/resources/handler.mustache @@ -110,6 +110,10 @@ aspect RagConnectHandler { senders.forEach(Runnable::run); } + void run(RagConnectToken token) { + tokenToSender.get(token).run(); + } + byte[] getLastValue() { return lastValue; } @@ -150,6 +154,10 @@ aspect RagConnectHandler { java.util.Optional.ofNullable(publishers.get(index)).ifPresent(RagConnectPublisher::run); } + void run(int index, RagConnectToken token) { + java.util.Optional.ofNullable(publishers.get(index)).ifPresent(publisher -> publisher.run(token)); + } + byte[] getLastValue(int index) { RagConnectPublisher publisher = publishers.get(index); if (publisher == null) { diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 293b37c..499116e 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -18,7 +18,7 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete }{{#IndexBasedListAccess}}, index{{/IndexBasedListAccess}}, connectToken); {{updateMethodName}}({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}}); if (writeCurrentValue) { - {{writeMethodName}}({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}}); + {{writeMethodName}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}connectToken); } success = true; break; @@ -49,7 +49,7 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete {{#IndexBasedListAccess}}index,{{/IndexBasedListAccess}} () -> { if (this.{{updateMethodName}}({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}})) { - this.{{writeMethodName}}({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}}); + this.{{writeMethodName}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}connectToken); } } ); @@ -106,8 +106,8 @@ protected boolean {{parentTypeName}}.{{updateMethodName}}({{#IndexBasedListAcces return {{senderName}} != null; } -protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}int index{{/IndexBasedListAccess}}) { - {{senderName}}.run({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}}); +protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}int index, {{/IndexBasedListAccess}}RagConnectToken token) { + {{senderName}}.run({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}token); } {{#needForwardingNTA}} diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index b545b19..f57f477 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -50,6 +50,7 @@ dependencies { testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.4.0' testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.12.1' testImplementation group: 'org.awaitility', name: 'awaitility', version: '4.1.1' + testImplementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: '0.3.5' // jackson (for serialization of types) implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.12.1' diff --git a/ragconnect.tests/src/test/01-input/attribute/Test.connect b/ragconnect.tests/src/test/01-input/attribute/Test.connect index 3e6a66e..03688a9 100644 --- a/ragconnect.tests/src/test/01-input/attribute/Test.connect +++ b/ragconnect.tests/src/test/01-input/attribute/Test.connect @@ -1,14 +1,14 @@ -send SenderRoot.basic():String ; -send SenderRoot.simple():String ; -send SenderRoot.transformed():int ; -send SenderRoot.toReferenceType():A ; -send SenderRoot.toNTA():A ; +send SenderRoot.basic(String) ; +send SenderRoot.simple(String) ; +send SenderRoot.transformed(int) ; +send SenderRoot.toReferenceType(A) ; +send SenderRoot.toNTA(A) ; AddSuffix maps A a to A {: A result = new A(); String changedValue = a.getValue() + "post"; result.setValue(changedValue); - result.setInner(new Inner("inner" + changedValue)); + result.setInner(new Inner("inner" + a.getInner().getInnerValue())); return result; :} diff --git a/ragconnect.tests/src/test/01-input/attribute/Test.relast b/ragconnect.tests/src/test/01-input/attribute/Test.relast index d7edb5c..7afc9b7 100644 --- a/ragconnect.tests/src/test/01-input/attribute/Test.relast +++ b/ragconnect.tests/src/test/01-input/attribute/Test.relast @@ -1,4 +1,4 @@ -Root ::= SenderRoot ReceiverRoot; +Root ::= SenderRoot* ReceiverRoot; SenderRoot ::= <Input> ; ReceiverRoot ::= <FromBasic> diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java index 6b87744..ed6ef0c 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AttributeTest.java @@ -1,9 +1,22 @@ package org.jastadd.ragconnect.tests; -import attribute.ast.*; +import attributeInc.ast.*; +import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper; import org.junit.jupiter.api.Tag; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; + +import static java.util.function.Predicate.isEqual; +import static org.awaitility.Awaitility.await; +import static org.jastadd.ragconnect.tests.TestUtils.mqttUri; +import static org.jastadd.ragconnect.tests.TestUtils.waitForMqtt; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Test case "attribute". @@ -13,27 +26,150 @@ import java.io.IOException; @Tag("Incremental") @Tag("New") public class AttributeTest extends AbstractMqttTest { - Root model; - MqttHandler handler; + + private static final String TOPIC_WILDCARD = "attr/#"; + private static final String TOPIC_BASIC = "attr/string/basic"; + private static final String TOPIC_SIMPLE_NO_MAPPING = "attr/string/simple/plain"; + private static final String TOPIC_SIMPLE_WITH_MAPPING = "attr/string/simple/mapped"; + private static final String TOPIC_TRANSFORMED_NO_MAPPING = "attr/int/transformed/plain"; + private static final String TOPIC_TRANSFORMED_WITH_MAPPING = "attr/int/transformed/mapped"; + private static final String TOPIC_REFERENCE_TYPE_NO_MAPPING = "attr/a/ref/plain"; + private static final String TOPIC_REFERENCE_TYPE_WITH_MAPPING = "attr/a/ref/mapped"; + private static final String TOPIC_NTA_NO_MAPPING = "attr/a/nta/plain"; + private static final String TOPIC_NTA_WITH_MAPPING = "attr/a/nta/mapped"; + + private static final String INITIAL_STRING = "initial"; + + private MqttHandler handler; + private ReceiverData data; + + private Root model; + private SenderRoot senderString; + private SenderRoot senderInt; + private SenderRoot senderA; + private ReceiverRoot receiverRoot; @Override protected void createModel() { - + model = new Root(); + // model.trace().setReceiver(TestUtils::logEvent); + senderString = new SenderRoot().setInput(INITIAL_STRING); + senderInt = new SenderRoot().setInput(INITIAL_STRING); + senderA = new SenderRoot().setInput(INITIAL_STRING); + receiverRoot = new ReceiverRoot(); + model.addSenderRoot(senderString); + model.addSenderRoot(senderInt); + model.addSenderRoot(senderA); + model.setReceiverRoot(receiverRoot); } @Override protected void setupReceiverAndConnect() throws IOException, InterruptedException { + model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS); + handler = new MqttHandler().setHost(TestUtils.getMqttHost()).dontSendWelcomeMessage(); + assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS)); + + data = new ReceiverData(); + assertTrue(handler.newConnection(TOPIC_WILDCARD, bytes -> data.numberOfValues += 1)); + + // connect receive + assertTrue(receiverRoot.connectFromBasic(mqttUri(TOPIC_BASIC))); + assertTrue(receiverRoot.connectFromSimpleNoMapping(mqttUri(TOPIC_SIMPLE_NO_MAPPING))); + assertTrue(receiverRoot.connectFromSimpleWithMapping(mqttUri(TOPIC_SIMPLE_WITH_MAPPING))); + assertTrue(receiverRoot.connectFromTransformedNoMapping(mqttUri(TOPIC_TRANSFORMED_NO_MAPPING))); + assertTrue(receiverRoot.connectFromTransformedWithMapping(mqttUri(TOPIC_TRANSFORMED_WITH_MAPPING))); + assertTrue(receiverRoot.connectFromReferenceTypeNoMapping(mqttUri(TOPIC_REFERENCE_TYPE_NO_MAPPING))); + assertTrue(receiverRoot.connectFromReferenceTypeWithMapping(mqttUri(TOPIC_REFERENCE_TYPE_WITH_MAPPING))); + assertTrue(receiverRoot.connectFromNTANoMapping(mqttUri(TOPIC_NTA_NO_MAPPING))); + assertTrue(receiverRoot.connectFromNTAWithMapping(mqttUri(TOPIC_NTA_WITH_MAPPING))); + // connect send, and wait to receive (if writeCurrentValue is set) + assertTrue(senderString.connectBasic(mqttUri(TOPIC_BASIC), isWriteCurrentValue())); + assertTrue(senderString.connectSimple(mqttUri(TOPIC_SIMPLE_NO_MAPPING), isWriteCurrentValue())); + assertTrue(senderString.connectSimple(mqttUri(TOPIC_SIMPLE_WITH_MAPPING), isWriteCurrentValue())); + + assertTrue(senderInt.connectTransformed(mqttUri(TOPIC_TRANSFORMED_NO_MAPPING), isWriteCurrentValue())); + assertTrue(senderInt.connectTransformed(mqttUri(TOPIC_TRANSFORMED_WITH_MAPPING), isWriteCurrentValue())); + + assertTrue(senderA.connectToReferenceType(mqttUri(TOPIC_REFERENCE_TYPE_NO_MAPPING), isWriteCurrentValue())); + assertTrue(senderA.connectToReferenceType(mqttUri(TOPIC_REFERENCE_TYPE_WITH_MAPPING), isWriteCurrentValue())); + assertTrue(senderA.connectToNTA(mqttUri(TOPIC_NTA_NO_MAPPING), isWriteCurrentValue())); + assertTrue(senderA.connectToNTA(mqttUri(TOPIC_NTA_WITH_MAPPING), isWriteCurrentValue())); + + waitForValue(senderString.basic(), receiverRoot::getFromBasic); + waitForValue(senderString.simple(), receiverRoot::getFromSimpleNoMapping); + waitForNonNull(receiverRoot::getFromReferenceTypeNoMapping); + waitForNonNull(receiverRoot::getFromNTANoMapping); + } + + private <T> void waitForValue(T expectedValue, Callable<T> callable) { + if (isWriteCurrentValue()) { + await().until(callable, isEqual(expectedValue)); + } + } + + private <T> void waitForNonNull(Callable<T> callable) { + if (isWriteCurrentValue()) { + await().until(callable, Predicate.not(isEqual(null))); + } } @Override protected void communicateSendInitialValue() throws IOException, InterruptedException { + // basic, simple <-- senderString + // transformed <-- senderInt + // ref-type, nta <-- senderA + check(9, INITIAL_STRING, INITIAL_STRING + "Post", INITIAL_STRING, INITIAL_STRING, INITIAL_STRING); + senderString.setInput("test-01"); + check(12, "test-01", "test-01Post", INITIAL_STRING, INITIAL_STRING, INITIAL_STRING); } @Override protected void communicateOnlyUpdatedValue() throws IOException, InterruptedException { + waitForMqtt(); + } + + private void check(int numberOfValues, String basic, String simple, String transformed, + String refType, String nta) { + awaitEquals(numberOfValues, () -> data.numberOfValues, "numberOfValues"); + + try { + Path tempFile = Files.createTempFile("receiverRoot", "yml"); + Dumper.read(receiverRoot).dumpAsYaml(tempFile, false); + String content = Files.readString(tempFile); + logger.debug("receiverRoot\n" + content); + } catch (IOException e) { + e.printStackTrace(); + } + + awaitEquals(basic, receiverRoot::getFromBasic, "basic"); + + awaitEquals(simple, receiverRoot::getFromSimpleNoMapping, "simple"); + awaitEquals(simple + "post", receiverRoot::getFromSimpleWithMapping, "simple mapped"); + + int transformedLength = transformed.length(); + awaitEquals(transformedLength, receiverRoot::getFromTransformedNoMapping, "transformed"); + awaitEquals(transformedLength + 1, receiverRoot::getFromTransformedWithMapping, "transformed mapped"); + checkA(refType, "1", + receiverRoot.getFromReferenceTypeNoMapping(), "ref-type"); + checkA(refType + "post", "inner1", + receiverRoot.getFromReferenceTypeWithMapping(), "ref-type mapped"); + + checkA(nta, "2", + receiverRoot.getFromNTANoMapping(), "nta"); + checkA(nta + "post", "inner2", + receiverRoot.getFromNTAWithMapping(), "nta mapped"); + } + + private void checkA(String expectedValue, String expectedInner, A actual, String message) { + awaitEquals(expectedValue, actual::getValue, message + " value"); + awaitEquals(expectedInner, actual.getInner()::getInnerValue, message + " inner"); + } + + private <T> void awaitEquals(T expected, Callable<T> actual, String alias) { + await(alias).atMost(1500, TimeUnit.MILLISECONDS).until(actual, isEqual(expected)); } @Override @@ -45,4 +181,8 @@ public class AttributeTest extends AbstractMqttTest { model.ragconnectCloseConnections(); } } + + private static class ReceiverData { + int numberOfValues = 0; + } } -- GitLab