diff --git a/pages/docs/adding.md b/pages/docs/adding.md index ffbeda297edb3b458229fcad5006a6e95f39ad76..f777e324ad762b549b18474a7d0e88aa3ab466a1 100644 --- a/pages/docs/adding.md +++ b/pages/docs/adding.md @@ -125,6 +125,6 @@ RagConnect itself does not introduce dependencies. However, depending on the selected protocols (see [compiler options](using#compiler-options)), additional dependencies are required. | Protocol | Dependency (Gradle format) | Remarks | -|-|-|-| +|---|---|---| | `mqtt` | `group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'` | Mqtt is selected by default, so this dependency therefore is required "by default". Might work with other versions as well. | -| `rest` | `group: 'com.sparkjava', name: 'spark-core', version: '2.9.2'` | Might work with other versions as well. For debugging, it is beneficial to include an implementation for [SLF4J](http://www.slf4j.org/). | +| `rest` | `group: 'com.sparkjava', name: 'spark-core', version: '2.9.3'` | Might work with newer versions as well. For debugging, it is beneficial to include an implementation for [SLF4J](http://www.slf4j.org/). | diff --git a/ragconnect.base/build.gradle b/ragconnect.base/build.gradle index 671556c463b40a4224cc70df5ad1db0340858ee5..c1ee98d52184b358a411a17a359f75a4fa601e8e 100644 --- a/ragconnect.base/build.gradle +++ b/ragconnect.base/build.gradle @@ -108,6 +108,14 @@ task relast(type: JavaExec) { './src/gen/jastadd/RagConnectResolverStubs.jrag') } +clean { + delete "src/gen/jastadd/Coverage.jrag" + delete "src/gen/jastadd/RagConnect.ast" + delete "src/gen/jastadd/RagConnect.jadd" + delete "src/gen/jastadd/RagConnectRefResolver.jadd" + delete "src/gen/jastadd/RagConnectResolverStubs.jrag" +} + jastadd { configureModuleBuild() modules { diff --git a/ragconnect.base/src/main/jastadd/Errors.jrag b/ragconnect.base/src/main/jastadd/Errors.jrag index 1aa3666c2b19bf446667f1a763bfb4824aa44f25..770e506cc5c0145a0ba9979d57a1086a399ed39e 100644 --- a/ragconnect.base/src/main/jastadd/Errors.jrag +++ b/ragconnect.base/src/main/jastadd/Errors.jrag @@ -1,7 +1,3 @@ -import java.util.Set; -import java.util.TreeSet; -import java.util.LinkedList; - aspect Errors { coll Set<ErrorMessage> RagConnect.errors() [new TreeSet<ErrorMessage>()] diff --git a/ragconnect.base/src/main/jastadd/Imports.jadd b/ragconnect.base/src/main/jastadd/Imports.jadd new file mode 100644 index 0000000000000000000000000000000000000000..27fc9a5cfc5bbcbd2772fe35548bda22ab888e01 --- /dev/null +++ b/ragconnect.base/src/main/jastadd/Imports.jadd @@ -0,0 +1,5 @@ +import java.util.*; + +aspect Imports { + // empty +} diff --git a/ragconnect.base/src/main/jastadd/Navigation.jrag b/ragconnect.base/src/main/jastadd/Navigation.jrag index d3890f7d22a195127e7688435f9168aa64a37eac..437f65196c2dc3b8c4f5a112a23e80608084a063 100644 --- a/ragconnect.base/src/main/jastadd/Navigation.jrag +++ b/ragconnect.base/src/main/jastadd/Navigation.jrag @@ -1,6 +1,3 @@ -import java.util.List; -import java.util.ArrayList; - aspect RagConnectNavigation { // --- program --- diff --git a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd index 7e4bde916d565d16bdef34598d638d2080f2f5fa..b58b9670abd0abb26db113c3fee6f98033e3f4f7 100644 --- a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd +++ b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd @@ -64,7 +64,7 @@ aspect AttributesForMustache { syn boolean MEndpointDefinition.isTypeEndpointDefinition() = endpointDef().isTypeEndpointDefinition(); syn String MEndpointDefinition.disconnectMethod() { - // if both (send and receive) are defined for the token, ensure methods with different names + // if both (send and receive) are defined for an endpoint, ensure methods with different names String extra; if (endpointDef().isTokenEndpointDefinition()) { extra = endpointDef().asTokenEndpointDefinition().lookupTokenEndpointDefinitions(token()).size() > 1 ? uniqueSuffix() : ""; @@ -114,6 +114,8 @@ aspect AttributesForMustache { } return preemptiveExpectedValue() + " != null ? " + preemptiveExpectedValue() + ".equals(" + lastResult() + ") : " + lastResult() + " == null"; } + syn String MEndpointDefinition.sender() = null; // only for M*SendDefinitions + syn String MEndpointDefinition.lastValue() = sender() + ".lastValue"; // only for M*SendDefinitions // --- MTokenEndpointDefinition --- eq MTokenEndpointDefinition.getterMethod() = "get" + tokenName(); @@ -151,8 +153,7 @@ aspect AttributesForMustache { eq MTokenSendDefinition.updateMethod() = "_update_" + tokenName(); eq MTokenSendDefinition.writeMethod() = "_writeLastValue_" + tokenName(); - syn String MTokenSendDefinition.sender() = "_sender_" + tokenName(); - syn String MTokenSendDefinition.lastValue() = "_lastValue" + tokenName(); + eq MTokenSendDefinition.sender() = "_sender_" + tokenName(); syn String MTokenSendDefinition.tokenResetMethod() = getterMethod() + "_reset"; syn boolean MTokenSendDefinition.shouldSendValue() = endpointDef().asTokenEndpointDefinition().shouldSendValue(); @@ -164,7 +165,7 @@ aspect AttributesForMustache { eq MTypeReceiveDefinition.updateMethod() = null; eq MTypeReceiveDefinition.writeMethod() = null; - syn String MTypeReceiveDefinition.resolveInListAttributeName() = "resolve" + entityName() + "InList"; + syn String MTypeReceiveDefinition.resolveInListMethodName() = "_ragconnect_resolve" + entityName() + "InList"; syn String MTypeReceiveDefinition.idTokenName() = endpointDef().idTokenName(); // MTypeSendDefinition @@ -175,8 +176,7 @@ aspect AttributesForMustache { eq MTypeSendDefinition.updateMethod() = "_update_" + typeName(); eq MTypeSendDefinition.writeMethod() = "_writeLastValue_" + typeName(); - syn String MTypeSendDefinition.sender() = "_sender_" + typeName(); - syn String MTypeSendDefinition.lastValue() = "_lastValue" + typeName(); + eq MTypeSendDefinition.sender() = "_sender_" + typeName(); syn String MTypeSendDefinition.tokenResetMethod() = getterMethod() + "_reset"; syn boolean MTypeSendDefinition.shouldSendValue() = endpointDef().asTypeEndpointDefinition().shouldSendValue(); diff --git a/ragconnect.base/src/main/resources/MqttHandler.jadd b/ragconnect.base/src/main/resources/MqttHandler.jadd index a8f065e818c32874703d7f2775c589492fb6e8ee..d859d38d819c17df941d4b0179fbeec28df6f83f 100644 --- a/ragconnect.base/src/main/resources/MqttHandler.jadd +++ b/ragconnect.base/src/main/resources/MqttHandler.jadd @@ -1,10 +1,7 @@ -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer;aspect MqttHandler { +aspect MqttHandler { public class MqttServerHandler { private final java.util.Map<String, MqttHandler> handlers = new java.util.HashMap<>(); - private final java.util.Map<ConnectToken, java.util.function.BiConsumer<String, byte[]>> tokensForRemoval = new java.util.HashMap<>(); + private final java.util.Map<RagConnectToken, java.util.function.BiConsumer<String, byte[]>> tokensForRemoval = new java.util.HashMap<>(); private long time; private java.util.concurrent.TimeUnit unit; private String name; @@ -39,14 +36,12 @@ public class MqttServerHandler { return handler; } - public ConnectToken newConnection(java.net.URI uri, java.util.function.BiConsumer<String, byte[]> callback) throws java.io.IOException { - ConnectToken connectToken = new ConnectToken(uri); - resolveHandler(uri).newConnection(extractTopic(uri), callback); + public boolean newConnection(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) throws java.io.IOException { tokensForRemoval.put(connectToken, callback); - return connectToken; + return resolveHandler(connectToken.uri).newConnection(extractTopic(connectToken.uri), callback); } - public boolean disconnect(ConnectToken connectToken) throws java.io.IOException { + public boolean disconnect(RagConnectToken connectToken) throws java.io.IOException { MqttHandler handler = resolveHandler(connectToken.uri); return handler != null ? handler.disconnect(extractTopic(connectToken.uri), tokensForRemoval.get(connectToken)) : false; } @@ -89,6 +84,10 @@ public class MqttServerHandler { * @author rschoene - Initial contribution */ public class MqttHandler { + private class PatternCallbackListPair { + java.util.regex.Pattern pattern; + java.util.List<java.util.function.BiConsumer<String, byte[]>> callbacks; + } private static final int DEFAULT_PORT = 1883; private final org.apache.logging.log4j.Logger logger; @@ -100,11 +99,12 @@ public class MqttHandler { private org.fusesource.mqtt.client.CallbackConnection connection; /** Whether we are connected yet */ private final java.util.concurrent.CountDownLatch readyLatch; + private final java.util.concurrent.locks.Lock astLock; private boolean sendWelcomeMessage = true; private org.fusesource.mqtt.client.QoS qos; /** Dispatch knowledge */ private final java.util.Map<String, java.util.List<java.util.function.BiConsumer<String, byte[]>>> normalCallbacks; - private final java.util.Map<java.util.regex.Pattern, java.util.List<java.util.function.BiConsumer<String, byte[]>>> wildcardCallbacks; + private final java.util.List<PatternCallbackListPair> wildcardCallbacks; public MqttHandler() { this("RagConnect"); @@ -114,9 +114,10 @@ public class MqttHandler { this.name = java.util.Objects.requireNonNull(name, "Name must be set"); this.logger = org.apache.logging.log4j.LogManager.getLogger(MqttHandler.class); this.normalCallbacks = new java.util.HashMap<>(); - this.wildcardCallbacks = new java.util.HashMap<>(); + this.wildcardCallbacks = new java.util.ArrayList<>(); this.readyLatch = new java.util.concurrent.CountDownLatch(1); this.qos = org.fusesource.mqtt.client.QoS.AT_LEAST_ONCE; + this.astLock = new java.util.concurrent.locks.ReentrantLock(); } public MqttHandler dontSendWelcomeMessage() { @@ -179,9 +180,12 @@ public class MqttHandler { byte[] message = body.toByteArray(); for (java.util.function.BiConsumer<String, byte[]> callback : callbackList) { try { + astLock.lock(); callback.accept(topicString, message); } catch (Exception e) { logger.catching(e); + } finally { + astLock.unlock(); } } } @@ -240,13 +244,13 @@ public class MqttHandler { private java.util.List<java.util.function.BiConsumer<String, byte[]>> callbacksFor(String topicString) { java.util.List<java.util.function.BiConsumer<String, byte[]>> result = new java.util.ArrayList<>(); - List<BiConsumer<String, byte[]>> normalCallbackList = normalCallbacks.get(topicString); + java.util.List<java.util.function.BiConsumer<String, byte[]>> normalCallbackList = normalCallbacks.get(topicString); if (normalCallbackList != null) { result.addAll(normalCallbackList); } - wildcardCallbacks.forEach((topicPattern, callback) -> { - if (topicPattern.matcher(topicString).matches()) { - result.addAll(callback); + wildcardCallbacks.forEach(pair -> { + if (pair.pattern.matcher(topicString).matches()) { + result.addAll(pair.callbacks); } }); return result; @@ -295,25 +299,34 @@ public class MqttHandler { logger.debug("new connection for {}", topic); final boolean needSubscribe; if (isWildcardTopic(topic)) { - String regexForTopic = topic.replace("*", "[^/]*").replace("#", ".*"); - java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(regexForTopic); - wildcardCallbacks.computeIfAbsent(pattern, p -> new java.util.ArrayList<>()) - .add(callback); - needSubscribe = true; + String regex = regexForWildcardTopic(topic); + PatternCallbackListPair pairToAddTo = null; + for (PatternCallbackListPair pair : wildcardCallbacks) { + if (pair.pattern.pattern().equals(regex)) { + pairToAddTo = pair; + break; + } + } + if (pairToAddTo == null) { + pairToAddTo = new PatternCallbackListPair(); + pairToAddTo.pattern = java.util.regex.Pattern.compile(regex); + pairToAddTo.callbacks = new java.util.ArrayList<>(); + wildcardCallbacks.add(pairToAddTo); + } + needSubscribe = pairToAddTo.callbacks.isEmpty(); + pairToAddTo.callbacks.add(callback); } else { // normal topic java.util.List<java.util.function.BiConsumer<String, byte[]>> callbacksForTopic = normalCallbacks.get(topic); - if (callbacksForTopic == null || callbacksForTopic.isEmpty()) { + if (callbacksForTopic == null) { callbacksForTopic = new java.util.ArrayList<>(); normalCallbacks.put(topic, callbacksForTopic); - needSubscribe = true; - } else { - needSubscribe = false; } + needSubscribe = callbacksForTopic.isEmpty(); callbacksForTopic.add(callback); } if (needSubscribe) { // subscribe at broker - CountDownLatch operationFinished = new CountDownLatch(1); + java.util.concurrent.CountDownLatch operationFinished = new java.util.concurrent.CountDownLatch(1); java.util.concurrent.atomic.AtomicReference<Boolean> success = new java.util.concurrent.atomic.AtomicReference<>(true); org.fusesource.mqtt.client.Topic[] topicArray = { new org.fusesource.mqtt.client.Topic(topic, this.qos) }; connection.getDispatchQueue().execute(() -> { @@ -333,7 +346,7 @@ public class MqttHandler { }); }); try { - operationFinished.await(2, TimeUnit.SECONDS); + operationFinished.await(2, java.util.concurrent.TimeUnit.SECONDS); return success.get(); } catch (InterruptedException e) { return false; @@ -347,40 +360,49 @@ public class MqttHandler { return topic.contains("*") || topic.contains("#"); } + private String regexForWildcardTopic(String topic) { + return topic.replace("*", "[^/]*").replace("#", ".*"); + } + public boolean disconnect(String topic, java.util.function.BiConsumer<String, byte[]> callback) { boolean needUnsubscribe = false; java.util.concurrent.atomic.AtomicReference<Boolean> success = new java.util.concurrent.atomic.AtomicReference<>(true); - boolean foundTopicInCallbacks = false; + final String topicToUnsubscribe; // check if wildcard is to be removed if (isWildcardTopic(topic)) { - java.util.regex.Pattern wildcardPatternToRemove = null; - for (java.util.Map.Entry<java.util.regex.Pattern, java.util.List<java.util.function.BiConsumer<String, byte[]>>> entry : wildcardCallbacks.entrySet()) { - if (entry.getKey().pattern().equals(topic)) { - foundTopicInCallbacks = true; + boolean topicRegistered = false; + String topicRegex = regexForWildcardTopic(topic); + for (PatternCallbackListPair pair : wildcardCallbacks) { + if (pair.pattern.pattern().equals(topicRegex)) { + topicRegistered = true; // if still successful, update with whether callback could be removed - success.compareAndSet(true, (entry.getValue().remove(callback))); - if (entry.getValue().isEmpty()) { - wildcardPatternToRemove = entry.getKey(); + success.compareAndSet(true, pair.callbacks.remove(callback)); + // if no more callbacks left, unsubscribe and remove from list + if (pair.callbacks.isEmpty()) { needUnsubscribe = true; + wildcardCallbacks.remove(pair.pattern); } break; } } - ; - if (wildcardPatternToRemove != null) { - wildcardCallbacks.remove(wildcardPatternToRemove); - } + topicToUnsubscribe = topicRegistered ? topicRegex : null; } else if (normalCallbacks.containsKey(topic)) { - foundTopicInCallbacks = true; - // if still successful, update with whether callback could be removed + topicToUnsubscribe = topic; var normalCallbackList = normalCallbacks.get(topic); + // if still successful, update with whether callback could be removed success.compareAndSet(true, normalCallbackList.remove(callback)); - needUnsubscribe |= normalCallbackList.isEmpty(); + // if no more callbacks left, unsubscribe and remove from list + if (normalCallbackList.isEmpty()) { + needUnsubscribe = true; + normalCallbacks.remove(topic); + } + } else { + topicToUnsubscribe = null; } - if (!foundTopicInCallbacks) { + if (topicToUnsubscribe == null) { logger.warn("Disconnect for not connected topic '{}'", topic); return false; } @@ -389,7 +411,7 @@ public class MqttHandler { java.util.concurrent.CountDownLatch operationFinished = new java.util.concurrent.CountDownLatch(1); // no callbacks anymore for this topic, unsubscribe from mqtt connection.getDispatchQueue().execute(() -> { - org.fusesource.hawtbuf.UTF8Buffer topicBuffer = org.fusesource.hawtbuf.Buffer.utf8(topic); + org.fusesource.hawtbuf.UTF8Buffer topicBuffer = org.fusesource.hawtbuf.Buffer.utf8(topicToUnsubscribe); org.fusesource.hawtbuf.UTF8Buffer[] topicArray = new org.fusesource.hawtbuf.UTF8Buffer[]{topicBuffer}; connection.unsubscribe(topicArray, new org.fusesource.mqtt.client.Callback<>() { @Override @@ -462,19 +484,24 @@ public class MqttHandler { } public void publish(String topic, byte[] bytes, org.fusesource.mqtt.client.QoS qos, boolean retain) { - connection.getDispatchQueue().execute(() -> { - connection.publish(topic, bytes, qos, retain, new org.fusesource.mqtt.client.Callback<>() { - @Override - public void onSuccess(Void value) { - logger.debug("Published some bytes to {}", topic); - } + try { + astLock.lock(); + connection.getDispatchQueue().execute(() -> { + connection.publish(topic, bytes, qos, retain, new org.fusesource.mqtt.client.Callback<>() { + @Override + public void onSuccess(Void value) { + logger.debug("Published some bytes to {}", topic); + } - @Override - public void onFailure(Throwable value) { - logger.warn("Could not publish on topic '{}'", topic, value); - } + @Override + public void onFailure(Throwable value) { + logger.warn("Could not publish on topic '{}'", topic, value); + } + }); }); - }); + } finally { + astLock.unlock(); + } } } } diff --git a/ragconnect.base/src/main/resources/RestHandler.jadd b/ragconnect.base/src/main/resources/RestHandler.jadd index b69bf71b73ba9d4c5a9f1998ee2dd92ede77561d..9187afdab7a15c0bd7dc10679991505874c8af61 100644 --- a/ragconnect.base/src/main/resources/RestHandler.jadd +++ b/ragconnect.base/src/main/resources/RestHandler.jadd @@ -2,7 +2,7 @@ import java.util.concurrent.TimeUnit;aspect RestHandler { public class RestServerHandler { private static final int DEFAULT_PORT = 4567; private final java.util.Map<Integer, RestHandler> handlers = new java.util.HashMap<>(); - private final java.util.Map<ConnectToken, Object> tokensForRemoval = new java.util.HashMap<>(); + private final java.util.Map<RagConnectToken, Object> tokensForRemoval = new java.util.HashMap<>(); private String name; public RestServerHandler() { @@ -25,21 +25,19 @@ public class RestServerHandler { return handler; } - public ConnectToken newPUTConnection(java.net.URI uri, java.util.function.Consumer<String> callback) { - ConnectToken connectToken = new ConnectToken(uri); - resolveHandler(uri).newPUTConnection(uri.getPath(), callback); + public boolean newPUTConnection(RagConnectToken connectToken, java.util.function.Consumer<String> callback) { tokensForRemoval.put(connectToken, callback); - return connectToken; + resolveHandler(connectToken.uri).newPUTConnection(connectToken.uri.getPath(), callback); + return true; } - public ConnectToken newGETConnection(java.net.URI uri, SupplierWithException<String> supplier) { - ConnectToken connectToken = new ConnectToken(uri); - resolveHandler(uri).newGETConnection(uri.getPath(), supplier); + public boolean newGETConnection(RagConnectToken connectToken, SupplierWithException<String> supplier) { tokensForRemoval.put(connectToken, supplier); - return connectToken; + resolveHandler(connectToken.uri).newGETConnection(connectToken.uri.getPath(), supplier); + return true; } - public boolean disconnect(ConnectToken connectToken) { + public boolean disconnect(RagConnectToken connectToken) { RestHandler handler = resolveHandler(connectToken.uri); return handler != null ? handler.disconnect(connectToken.uri.getPath(), tokensForRemoval.get(connectToken)) : false; } @@ -127,9 +125,15 @@ public class RestHandler { } public boolean disconnect(String path, Object callbackOrSupplier) { - // only one will succeed (or false will be returned) - return callbacks.getOrDefault(path, java.util.Collections.emptyList()).remove(callbackOrSupplier) || - suppliers.remove(path, callbackOrSupplier); + if (callbacks.getOrDefault(path, java.util.Collections.emptyList()).remove(callbackOrSupplier)) { + return true; + } + if (suppliers.remove(path, callbackOrSupplier)) { + // unmap the route + return spark.Spark.unmap(path); + } + System.err.println("Disconnect for not connected path '" + path + "'!"); + return false; } private String makeError(spark.Response response, int statusCode, String message) { diff --git a/ragconnect.base/src/main/resources/handler.mustache b/ragconnect.base/src/main/resources/handler.mustache index 41e42387f69239f054b8ddaafa80680b13ca7591..fe8d9459a0d1b977f7416da85ba3fb1c4d3e6b8f 100644 --- a/ragconnect.base/src/main/resources/handler.mustache +++ b/ragconnect.base/src/main/resources/handler.mustache @@ -14,15 +14,74 @@ aspect RagConnectHandler { {{#InUse}}{{FieldName}}.close();{{/InUse}} {{/Handlers}} } - class ConnectToken { + class RagConnectToken { static java.util.concurrent.atomic.AtomicLong counter = new java.util.concurrent.atomic.AtomicLong(0); final long id; final java.net.URI uri; - public ConnectToken(java.net.URI uri) { + final String entityName; + public RagConnectToken(java.net.URI uri, String entityName) { this.id = counter.incrementAndGet(); this.uri = uri; + this.entityName = entityName; } + } + class RagConnectTokenMap { + java.util.Map<ASTNode, java.util.List<RagConnectToken>> connectTokensSend = new java.util.HashMap<>(); + java.util.Map<ASTNode, java.util.List<RagConnectToken>> connectTokensReceive = new java.util.HashMap<>(); + void add(ASTNode node, boolean isReceive, RagConnectToken token) { + java.util.Map<ASTNode, java.util.List<RagConnectToken>> mapOfTokens = (isReceive ? connectTokensReceive : connectTokensSend); + mapOfTokens.computeIfAbsent(node, n -> new java.util.ArrayList<>()).add(token); + } + java.util.List<RagConnectToken> removeAll(ASTNode node, boolean isReceive, java.net.URI uri, String entityName) { + java.util.List<RagConnectToken> listOfTokens = (isReceive ? connectTokensReceive : connectTokensSend).get(node); + if (listOfTokens == null) { + return java.util.Collections.emptyList(); + } + java.util.List<RagConnectToken> tokensToRemove = listOfTokens.stream() + .filter(token -> token.uri.equals(uri) && token.entityName.equals(entityName)) + .collect(java.util.stream.Collectors.toList()); + listOfTokens.removeAll(tokensToRemove); + return tokensToRemove; + } + } + static RagConnectTokenMap ASTNode.connectTokenMap = new RagConnectTokenMap(); + + interface RagConnectDisconnectHandlerMethod { + boolean call(RagConnectToken token) throws java.io.IOException; + } + class RagConnectPublisher { + java.util.List<Runnable> senders = new java.util.ArrayList<>(); + java.util.Map<RagConnectToken, Runnable> tokenToSender; + byte[] lastValue; + + void add(Runnable sender, RagConnectToken connectToken) { + if (tokenToSender == null) { + tokenToSender = new java.util.HashMap<>(); + } + senders.add(sender); + tokenToSender.put(connectToken, sender); + } + + boolean remove(RagConnectToken token) { + if (tokenToSender == null) { + System.err.println("Removing sender before first addition for " + token.entityName + " at " + token.uri); + return false; + } + Runnable sender = tokenToSender.remove(token); + if (sender == null) { + System.err.println("Could not find connected sender for " + token.entityName + " at " + token.uri); + return false; + } + boolean success = senders.remove(sender); + if (senders.isEmpty()) { + lastValue = null; + } + return success; + } + + void run() { + senders.forEach(Runnable::run); + } } - static java.util.Map<ASTNode, java.util.Map<java.net.URI, ConnectToken>> ASTNode.connectTokens = new java.util.HashMap<>(); } diff --git a/ragconnect.base/src/main/resources/ragconnect.mustache b/ragconnect.base/src/main/resources/ragconnect.mustache index c08529a22bfacc7ec5caa3e6e6569e51bc5182a1..dd509aa53b34e56f425777c16f5f9f3d34c2fc7a 100644 --- a/ragconnect.base/src/main/resources/ragconnect.mustache +++ b/ragconnect.base/src/main/resources/ragconnect.mustache @@ -58,12 +58,12 @@ aspect RagConnectObserver { class RagConnectObserver implements ASTState.Trace.Receiver { class RagConnectObserverEntry { - final ConnectToken connectToken; + final RagConnectToken connectToken; final ASTNode node; final String attributeString; final Runnable attributeCall; - RagConnectObserverEntry(ConnectToken connectToken, ASTNode node, String attributeString, Runnable attributeCall) { + RagConnectObserverEntry(RagConnectToken connectToken, ASTNode node, String attributeString, Runnable attributeCall) { this.connectToken = connectToken; this.node = node; this.attributeString = attributeString; @@ -99,13 +99,13 @@ aspect RagConnectObserver { node.trace().setReceiver(this); } - void add(ConnectToken connectToken, ASTNode node, String attributeString, Runnable attributeCall) { + void add(RagConnectToken connectToken, ASTNode node, String attributeString, Runnable attributeCall) { {{#loggingEnabledForIncremental}} System.out.println("** observer add: " + node + " on " + attributeString); {{/loggingEnabledForIncremental}} observedNodes.add(new RagConnectObserverEntry(connectToken, node, attributeString, attributeCall)); } - void remove(ConnectToken connectToken) { + void remove(RagConnectToken connectToken) { observedNodes.removeIf(entry -> entry.connectToken.equals(connectToken)); } @Override diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache index 4ae8a05c6f97e03f5522160a487f33a710186a2c..c29eff1372604f7e302deaeaebb3bb0b83d21827 100644 --- a/ragconnect.base/src/main/resources/receiveDefinition.mustache +++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache @@ -1,16 +1,6 @@ {{#typeIsList}} {{^UseList}} -/* first try with resolve to type -syn {{typeName}} {{parentTypeName}}.{{resolveInListAttributeName}}(String topic) { - for ({{typeName}} element : get{{entityName}}()) { - if (element.get{{idTokenName}}().equals(topic)) { - return element; - } - } - return null; -} -*/ -syn int {{parentTypeName}}.{{resolveInListAttributeName}}(String topic) { +private int {{parentTypeName}}.{{resolveInListMethodName}}(String topic) { for (int index = 0; index < getNum{{entityName}}(); index++) { if (get{{entityName}}(index).get{{idTokenName}}().equals(topic)) { return index; @@ -85,7 +75,7 @@ public boolean {{parentTypeName}}.{{connectMethod}}(String {{connectParameterNam System.out.println("[Receive] " + {{connectParameterName}} + " (" + topic + ") -> {{entityName}} = " + {{lastResult}}); {{/loggingEnabledForReads}} {{lastResult}}.set{{idTokenName}}(topic); - int resolvedIndex = {{resolveInListAttributeName}}(topic); + int resolvedIndex = {{resolveInListMethodName}}(topic); if (resolvedIndex == -1) { add{{entityName}}({{lastResult}}); } else { @@ -99,47 +89,56 @@ public boolean {{parentTypeName}}.{{connectMethod}}(String {{connectParameterNam private boolean {{parentTypeName}}.{{internalConnectMethod}}(String {{connectParameterName}}, java.util.function.BiConsumer<String, byte[]> consumer) throws java.io.IOException { {{>handleUri}} - ConnectToken connectToken; + RagConnectToken connectToken = new RagConnectToken(uri, "{{entityName}}"); + boolean success; switch (scheme) { {{#usesMqtt}} case "mqtt": - connectToken = {{mqttHandlerAttribute}}().newConnection(uri, consumer); - if (connectToken == null) { - return false; - } + success = {{mqttHandlerAttribute}}().newConnection(connectToken, consumer); break; {{/usesMqtt}} {{#usesRest}} case "rest": - connectToken = {{restHandlerAttribute}}().newPUTConnection(uri, input -> { + success = {{restHandlerAttribute}}().newPUTConnection(connectToken, input -> { // TODO wildcard-topic not supported yet consumer.accept("", input.getBytes()); }); - if (connectToken == null) { - return false; - } break; {{/usesRest}} default: System.err.println("Unknown protocol '" + scheme + "'."); - return false; + success = false; } - connectTokens.computeIfAbsent(this, astNode -> new java.util.HashMap<java.net.URI, ConnectToken>()) - .put(uri, connectToken); - return true; + if (success) { + connectTokenMap.add(this, true, connectToken); + } + return success; } public boolean {{parentTypeName}}.{{disconnectMethod}}(String {{connectParameterName}}) throws java.io.IOException { {{>handleUri}} + java.util.List<RagConnectToken> connectTokens = connectTokenMap.removeAll(this, true, uri, "{{entityName}}"); + if (connectTokens.isEmpty()) { + System.err.println("Disconnect called without connection for receiving " + this + ".{{entityName}} to '" + {{connectParameterName}} + "'!"); + return false; + } + RagConnectDisconnectHandlerMethod disconnectingMethod; switch (scheme) { {{#usesMqtt}} - case "mqtt": return {{mqttHandlerAttribute}}().disconnect(connectTokens.get(this).get(uri)); + case "mqtt": disconnectingMethod = {{mqttHandlerAttribute}}()::disconnect; + break; {{/usesMqtt}} {{#usesRest}} - case "rest": return {{restHandlerAttribute}}().disconnect(connectTokens.get(this).get(uri)); + case "rest": disconnectingMethod = {{restHandlerAttribute}}()::disconnect; + break; {{/usesRest}} default: - System.err.println("Unknown protocol '" + scheme + "'."); + System.err.println("Unknown protocol '" + scheme + "' in '" + {{connectParameterName}} + "' for disconnecting {{parentTypeName}}.{{entityName}}"); return false; } + boolean success = true; + for (RagConnectToken connectToken : connectTokens) { + success &= disconnectingMethod.call(connectToken); + } + return success; } diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 6fd97bf2cc7154cd0d053311f95166347cbccc6a..5cee6a483cda29519905918a505337db7779fce6 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -1,85 +1,83 @@ -private Runnable {{parentTypeName}}.{{sender}} = null; -private byte[] {{parentTypeName}}.{{lastValue}} = null; +private RagConnectPublisher {{parentTypeName}}.{{sender}} = new RagConnectPublisher(); public boolean {{parentTypeName}}.{{connectMethod}}(String {{connectParameterName}}, boolean writeCurrentValue) throws java.io.IOException { {{>handleUri}} - ConnectToken connectToken; - if (connectTokens.computeIfAbsent(this, astNode -> new java.util.HashMap<java.net.URI, ConnectToken>()) - .get(uri) != null) { - System.err.println("Already connected for " + uri + " on " + this + "!"); - return true; - } + RagConnectToken connectToken = new RagConnectToken(uri, "{{entityName}}"); + boolean success; switch (scheme) { {{#usesMqtt}} case "mqtt": final MqttHandler handler = {{mqttHandlerAttribute}}().resolveHandler(uri); final String topic = {{mqttHandlerAttribute}}().extractTopic(uri); - {{sender}} = () -> { + {{sender}}.add(() -> { {{#loggingEnabledForWrites}} System.out.println("[Send] {{entityName}} = " + {{getterMethod}}() + " -> " + {{connectParameterName}}); {{/loggingEnabledForWrites}} handler.publish(topic, {{lastValue}}); - }; + }, connectToken); {{updateMethod}}(); if (writeCurrentValue) { {{writeMethod}}(); } - connectToken = new ConnectToken(uri); + success = true; break; {{/usesMqtt}} {{#usesRest}} case "rest": - connectToken = {{restHandlerAttribute}}().newGETConnection(uri, () -> { + success = {{restHandlerAttribute}}().newGETConnection(connectToken, () -> { {{updateMethod}}(); return new String({{lastValue}}); }); - if (connectToken == null) { - return false; - } break; {{/usesRest}} default: System.err.println("Unknown protocol '" + scheme + "'."); - return false; + success = false; } - connectTokens.computeIfAbsent(this, astNode -> new java.util.HashMap<java.net.URI, ConnectToken>()) - .put(uri, connectToken); - {{#incrementalOptionActive}} - _ragConnectObserver().add(connectToken, this, "{{getterMethod}}", () -> { - if (this.{{updateMethod}}()) { - this.{{writeMethod}}(); - } - }); - {{/incrementalOptionActive}} - return true; + if (success) { + connectTokenMap.add(this, false, connectToken); + {{#incrementalOptionActive}} + _ragConnectObserver().add(connectToken, this, "{{getterMethod}}", () -> { + if (this.{{updateMethod}}()) { + this.{{writeMethod}}(); + } + }); + {{/incrementalOptionActive}} + } + return success; } public boolean {{parentTypeName}}.{{disconnectMethod}}(String {{connectParameterName}}) throws java.io.IOException { {{>handleUri}} - ConnectToken connectToken = connectTokens.get(this).remove(uri); - if (connectToken == null) { - System.err.println("Disconnect without connect for " + uri + " on " + this + "!"); + java.util.List<RagConnectToken> connectTokens = connectTokenMap.removeAll(this, false, uri, "{{entityName}}"); + if (connectTokens.isEmpty()) { + System.err.println("Disconnect called without connection for sending " + this + ".{{entityName}} to '" + {{connectParameterName}} + "'!"); + return false; } {{#incrementalOptionActive}} - _ragConnectObserver().remove(connectToken); + connectTokens.forEach(token -> _ragConnectObserver().remove(token)); {{/incrementalOptionActive}} + RagConnectDisconnectHandlerMethod disconnectingMethod; switch (scheme) { {{#usesMqtt}} case "mqtt": - {{sender}} = null; - {{lastValue}} = null; + disconnectingMethod = {{sender}}::remove; break; {{/usesMqtt}} {{#usesRest}} case "rest": - {{restHandlerAttribute}}().disconnect(connectToken); + disconnectingMethod = {{restHandlerAttribute}}()::disconnect; break; {{/usesRest}} default: - System.err.println("Unknown protocol '" + scheme + "'."); + System.err.println("Unknown protocol '" + scheme + "' in '" + {{connectParameterName}} + "' for disconnecting {{parentTypeName}}.{{entityName}}"); return false; } - return true; + boolean success = true; + for (RagConnectToken connectToken : connectTokens) { + success &= disconnectingMethod.call(connectToken); + } + return success; } protected boolean {{parentTypeName}}.{{updateMethod}}() { diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 61470f5292531d0ec7ca5d3691a3b248bcff1588..ee6da58c40c1bb690258d3958ac53a6ec44ac362 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -51,7 +51,7 @@ dependencies { testImplementation group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15' // rest and client - testImplementation group: 'com.sparkjava', name: 'spark-core', version: '2.9.2' + testImplementation group: 'com.sparkjava', name: 'spark-core', version: '2.9.3' testImplementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.11.2' testImplementation group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.31' testImplementation group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.31' @@ -550,15 +550,21 @@ task compileSingleListVariantIncremental(type: RagConnectTest, dependsOn: ':ragc } } -//task cleanCurrentManualTest(type: Delete) { +task cleanCurrentManualTest(type: Delete) { // delete "src/test/02-after-ragconnect/singleListVariant" // delete "src/test/03-after-relast/singleListVariant" // delete "src/test/java-gen/singleListVariant/ast" -//} -//task cleanCurrentIncrementalTest(type: Delete) { + delete "src/test/02-after-ragconnect/singleList" + delete "src/test/03-after-relast/singleList" + delete "src/test/java-gen/singleList/ast" +} +task cleanCurrentIncrementalTest(type: Delete) { // delete "src/test/02-after-ragconnect/singleListVariantInc" // delete "src/test/03-after-relast/singleListVariantInc" // delete "src/test/java-gen/singleListVariantInc/ast" -//} -//compileSingleListVariantManual.dependsOn cleanCurrentManualTest -//compileSingleListVariantIncremental.dependsOn cleanCurrentIncrementalTest + delete "src/test/02-after-ragconnect/singleListInc" + delete "src/test/03-after-relast/singleListInc" + delete "src/test/java-gen/singleListInc/ast" +} +compileSingleListManual.dependsOn cleanCurrentManualTest +compileSingleListIncremental.dependsOn cleanCurrentIncrementalTest diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java index 330c950b8114cb1364ea30a86cd76c7dc81eb4a2..db48fdf9a525e242bed1c39f7adf54260668a08a 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java @@ -55,7 +55,7 @@ public abstract class AbstractMqttTest { * Actual test code for communication when sending initial value. * @throws InterruptedException because of TestUtils.waitForMqtt() */ - protected abstract void communicateSendInitialValue() throws InterruptedException; + protected abstract void communicateSendInitialValue() throws IOException, InterruptedException; @Tag("mqtt") @Test @@ -70,7 +70,7 @@ public abstract class AbstractMqttTest { * Actual test code for communication without sending any value upon connecting. * @throws InterruptedException because of TestUtils.waitForMqtt() */ - protected abstract void communicateOnlyUpdatedValue() throws InterruptedException; + protected abstract void communicateOnlyUpdatedValue() throws IOException, InterruptedException; /** * Create the model, and set required default values. diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java index 580c4fc81a2952f0042eb273ffcb9be35b0a3df5..132317701c73cfa9a06fa136b985393c065823ba 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/IncrementalDependencyTest.java @@ -9,8 +9,7 @@ import java.io.IOException; import java.util.concurrent.TimeUnit; import static org.jastadd.ragconnect.tests.TestUtils.mqttUri; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /** * Testcase "Incremental Dependency". @@ -80,7 +79,7 @@ public class IncrementalDependencyTest extends AbstractMqttTest { } @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws InterruptedException, IOException { // check initial value TestUtils.waitForMqtt(); checkData(1, "aStart", @@ -104,10 +103,34 @@ public class IncrementalDependencyTest extends AbstractMqttTest { checkData(3, "a201", "b201Postfix", "b201Postfix"); + + // send and check new value (b1 should not change) + assertTrue(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1))); + sendData("301"); + checkData(4, "a301", + 3, "b201Postfix", + 4, "b301Postfix"); + + // disconnecting again should yield false + assertFalse(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1))); + + // send and check new value (b1 and b2 should not change) + assertTrue(b2.disconnectOutputOnB(mqttUri(TOPIC_OUT_B2))); + sendData("401"); + checkData(5, "a401", + 3, "b201Postfix", + 4, "b301Postfix"); + + // send and check new value (nothing should not change) + assertTrue(model.disconnectOutputOnA(mqttUri(TOPIC_OUT_A))); + sendData("501"); + checkData(5, "a401", + 3, "b201Postfix", + 4, "b301Postfix"); } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException { // check initial value TestUtils.waitForMqtt(); checkData(0, null, @@ -132,6 +155,29 @@ public class IncrementalDependencyTest extends AbstractMqttTest { "b202Postfix", "b202Postfix"); + // send and check new value (b1 should not change) + assertTrue(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1))); + sendData("302"); + checkData(3, "a302", + 2, "b202Postfix", + 3, "b302Postfix"); + + // disconnecting again should yield false + assertFalse(b1.disconnectOutputOnB(mqttUri(TOPIC_OUT_B1))); + + // send and check new value (b1 and b2 should not change) + assertTrue(b2.disconnectOutputOnB(mqttUri(TOPIC_OUT_B2))); + sendData("402"); + checkData(4, "a402", + 2, "b202Postfix", + 3, "b302Postfix"); + + // send and check new value (nothing should not change) + assertTrue(model.disconnectOutputOnA(mqttUri(TOPIC_OUT_A))); + sendData("502"); + checkData(4, "a402", + 2, "b202Postfix", + 3, "b302Postfix"); } @Override @@ -151,9 +197,17 @@ public class IncrementalDependencyTest extends AbstractMqttTest { private void checkData(int expectedNumberOfValues, String expectedLastAValue, String expectedLastB1Value, String expectedLastB2Value) { - dataA.assertEqualData(expectedNumberOfValues, expectedLastAValue); - dataB1.assertEqualData(expectedNumberOfValues, expectedLastB1Value); - dataB2.assertEqualData(expectedNumberOfValues, expectedLastB2Value); + checkData(expectedNumberOfValues, expectedLastAValue, + expectedNumberOfValues, expectedLastB1Value, + expectedNumberOfValues, expectedLastB2Value); + } + + private void checkData(int expectedNumberOfAValues, String expectedLastAValue, + int expectedNumberOfB1Values, String expectedLastB1Value, + int expectedNumberOfB2Values, String expectedLastB2Value) { + dataA.assertEqualData(expectedNumberOfAValues, expectedLastAValue); + dataB1.assertEqualData(expectedNumberOfB1Values, expectedLastB1Value); + dataB2.assertEqualData(expectedNumberOfB2Values, expectedLastB2Value); } private static class ReceiverData { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java index ce79190fe184f5b777366c25e9eff07cc8fc3576..bb557f6f88783c00f3bb2115758223bae0dc6f9c 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java @@ -14,8 +14,12 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import static java.lang.Math.abs; +import static java.util.Collections.addAll; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.util.Lists.newArrayList; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -136,6 +140,25 @@ public class TestUtils { TimeUnit.MILLISECONDS.sleep(1500); } + public static class IntList { + private final List<Integer> integers = newArrayList(); + public IntList(Integer... values) { + addAll(integers, values); + } + + public List<Integer> toList() { + return integers; + } + + public List<Integer> toAbsList() { + return integers.stream().map(Math::abs).collect(Collectors.toList()); + } + + public static IntList list(Integer... values) { + return new IntList(values); + } + } + @SuppressWarnings({"unused", "rawtypes"}) public static class DefaultMappings { static class ReadNode extends defaultOnlyRead.ast.ASTNode { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TokenValueSendTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TokenValueSendTest.java index 6d99149688b33d8401037fb358f736c2509b0921..da4d70308afd1efc12e10d4dbfa1a84c04852628 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TokenValueSendTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TokenValueSendTest.java @@ -6,8 +6,7 @@ import java.io.IOException; import java.util.concurrent.TimeUnit; import static org.jastadd.ragconnect.tests.TestUtils.mqttUri; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; /** * Test case "tokenValueSend". @@ -15,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @author rschoene - Initial contribution */ public class TokenValueSendTest extends AbstractMqttTest { + // TODO split into incremental and manual test private static final String TOPIC_SEND_ONE = "one/value/out"; @@ -96,9 +96,8 @@ public class TokenValueSendTest extends AbstractMqttTest { } @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws InterruptedException, IOException { // check initial value - TestUtils.waitForMqtt(); checkData(1, "Start-Post", 1, "Start-Post", 1, "Start-Post", @@ -106,9 +105,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // send new value sendData("200", "300"); - - // check new value - TestUtils.waitForMqtt(); checkData(1, "Start-Post", 2, "Pre-200-Post", 2, "Pre-300-Post", @@ -116,9 +112,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // set new value setData("101", "201", "301"); - - // check new value - TestUtils.waitForMqtt(); checkData(2, "101-Post", 3, "201-Post", 3, "301-Post", @@ -126,9 +119,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // send the same values (will not be sent again) setData("101", "201", "301"); - - // check new value - TestUtils.waitForMqtt(); checkData(2, "101-Post", 3, "201-Post", 3, "301-Post", @@ -136,9 +126,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // send values with prefixes imitating receiving setData("102", "Pre-202", "Pre-302"); - - // check new value - TestUtils.waitForMqtt(); checkData(3, "102-Post", 4, "Pre-202-Post", 4, "Pre-302-Post", @@ -146,19 +133,49 @@ public class TokenValueSendTest extends AbstractMqttTest { // send the same values (will not be sent again, because previously prefixed) sendData("202", "302"); - - // check new value - TestUtils.waitForMqtt(); checkData(3, "102-Post", 4, "Pre-202-Post", 4, "Pre-302-Post", 4, "Pre-302-T-Post"); + + // new values for two and three, but two will not send updated value + assertTrue(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO))); + sendData("203", "303"); + checkData(3, "102-Post", + 4, "Pre-202-Post", + 5, "Pre-303-Post", + 5, "Pre-303-T-Post"); + assertEquals("Pre-203", two.getValue()); + + // can not disconnect again, and also not for different topic + assertFalse(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO))); + assertFalse(two.disconnectSendValue(mqttUri(TOPIC_RECEIVE_TWO))); + + // new values for two and three, but two will neither receive nor send updated value + assertTrue(two.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_TWO))); + sendData("204", "304"); + checkData(3, "102-Post", + 4, "Pre-202-Post", + 6, "Pre-304-Post", + 6, "Pre-304-T-Post"); + assertEquals("Pre-203", two.getValue()); + + // new values for three, but it will not receive updated value, and, thus, not send it either + assertTrue(three.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_THREE_VALUE))); + sendData("204", "305"); + checkData(3, "102-Post", + 4, "Pre-202-Post", + 6, "Pre-304-Post", + 6, "Pre-304-T-Post"); + assertEquals("Pre-203", two.getValue()); + + // disconnect send is possible + assertTrue(three.disconnectSendValue(mqttUri(TOPIC_SEND_THREE_VALUE))); } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException { // check initial value - TestUtils.waitForMqtt(); checkData(0, null, 0, null, 0, null, @@ -166,9 +183,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // send new value sendData("210", "310"); - - // check new value - TestUtils.waitForMqtt(); checkData(0, null, 1, "Pre-210-Post", 1, "Pre-310-Post", @@ -176,9 +190,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // set new value setData("111", "211", "311"); - - // check new value - TestUtils.waitForMqtt(); checkData(1, "111-Post", 2, "211-Post", 2, "311-Post", @@ -186,9 +197,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // send the same values (will not be sent again) setData("111", "211", "311"); - - // check new value - TestUtils.waitForMqtt(); checkData(1, "111-Post", 2, "211-Post", 2, "311-Post", @@ -196,9 +204,6 @@ public class TokenValueSendTest extends AbstractMqttTest { // send values with prefixes imitating receiving setData("112", "Pre-212", "Pre-312"); - - // check new value - TestUtils.waitForMqtt(); checkData(2, "112-Post", 3, "Pre-212-Post", 3, "Pre-312-Post", @@ -206,13 +211,44 @@ public class TokenValueSendTest extends AbstractMqttTest { // send the same values (will not be sent again, because previously prefixed) sendData("212", "312"); - - // check new value - TestUtils.waitForMqtt(); checkData(2, "112-Post", 3, "Pre-212-Post", 3, "Pre-312-Post", 3, "Pre-312-T-Post"); + + // new values for two and three, but two will not send updated value + assertTrue(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO))); + sendData("213", "313"); + checkData(2, "112-Post", + 3, "Pre-212-Post", + 4, "Pre-313-Post", + 4, "Pre-313-T-Post"); + assertEquals("Pre-213", two.getValue()); + + // can not disconnect again, and also not for different topic + assertFalse(two.disconnectSendValue(mqttUri(TOPIC_SEND_TWO))); + assertFalse(two.disconnectSendValue(mqttUri(TOPIC_RECEIVE_TWO))); + + // new values for two and three, but two will neither receive nor send updated value + assertTrue(two.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_TWO))); + sendData("214", "314"); + checkData(2, "112-Post", + 3, "Pre-212-Post", + 5, "Pre-314-Post", + 5, "Pre-314-T-Post"); + assertEquals("Pre-213", two.getValue()); + + // new values for three, but it will not receive updated value, and, thus, not send it either + assertTrue(three.disconnectReceiveValue(mqttUri(TOPIC_RECEIVE_THREE_VALUE))); + sendData("214", "315"); + checkData(2, "112-Post", + 3, "Pre-212-Post", + 5, "Pre-314-Post", + 5, "Pre-314-T-Post"); + assertEquals("Pre-213", two.getValue()); + + // disconnect send is possible + assertTrue(three.disconnectSendValue(mqttUri(TOPIC_SEND_THREE_VALUE))); } @Override @@ -240,7 +276,8 @@ public class TokenValueSendTest extends AbstractMqttTest { int numberOfTwoValues, String lastTwoStringValue, int numberOfThreeValues, String lastThreeStringValue, int numberOfOtherValues, String lastOtherStringValue - ) { + ) throws InterruptedException { + TestUtils.waitForMqtt(); dataOne.assertEqualData(numberOfOneValues, lastOneStringValue); dataTwo.assertEqualData(numberOfTwoValues, lastTwoStringValue); dataThree.assertEqualData(numberOfThreeValues, lastThreeStringValue); diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java index 7ab46f7616a1cf90737c2e0b3ff752f553d38292..ded2990b5e997a18ff834379258689c359e4a465 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/ViaTest.java @@ -43,6 +43,8 @@ public class ViaTest extends AbstractMqttTest { private static final String REST_SERVER_BASE_URL = "http://localhost:" + REST_PORT + "/"; + private static final String NOT_MAPPED = "<html><body><h2>404 Not found</h2></body></html>"; + private MqttHandler handler; private A model; private ReceiverData dataMqtt2Mqtt; @@ -121,9 +123,8 @@ public class ViaTest extends AbstractMqttTest { } @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws InterruptedException, IOException { // check initial value - TestUtils.waitForMqtt(); checkData(1, "100-M2M-ToMqtt", "200-R2R-ToRest", "300-M2R-ToRest", @@ -135,7 +136,6 @@ public class ViaTest extends AbstractMqttTest { sendDataForBoth("501", true); // check new value - TestUtils.waitForMqtt(); checkData(2, "FromMqtt-101-M2M-ToMqtt", "FromRest-201-R2R-ToRest", "FromMqtt-301-M2R-ToRest", @@ -147,7 +147,6 @@ public class ViaTest extends AbstractMqttTest { sendDataForBoth("502", false); // check this value - TestUtils.waitForMqtt(); checkData(2, "FromMqtt-101-M2M-ToMqtt", "FromRest-201-R2R-ToRest", "FromMqtt-301-M2R-ToRest", @@ -159,7 +158,6 @@ public class ViaTest extends AbstractMqttTest { sendDataForBoth("502", true); // check this value - TestUtils.waitForMqtt(); checkData(2, "FromMqtt-101-M2M-ToMqtt", "FromRest-201-R2R-ToRest", "FromMqtt-301-M2R-ToRest", @@ -171,7 +169,6 @@ public class ViaTest extends AbstractMqttTest { sendData("102", "202", "302", "402"); // check this value - TestUtils.waitForMqtt(); checkData(3, "FromMqtt-102-M2M-ToMqtt", "FromRest-202-R2R-ToRest", "FromMqtt-302-M2R-ToRest", @@ -183,19 +180,57 @@ public class ViaTest extends AbstractMqttTest { sendData("102", "202", "302", "402"); // check this value - TestUtils.waitForMqtt(); checkData(3, "FromMqtt-102-M2M-ToMqtt", "FromRest-202-R2R-ToRest", "FromMqtt-302-M2R-ToRest", 3, "FromRest-402-R2M-ToMqtt", 3, "502-B2M-ToMqtt", "502-B2R-ToRest"); + + // send 503 over mqtt while disconnected should not change anything + assertTrue(model.disconnectBoth2BothInput(mqttUri(TOPIC_BOTH_MQTT_RECEIVE))); + sendDataForBoth("503", true); + checkData(3, "FromMqtt-102-M2M-ToMqtt", + "FromRest-202-R2R-ToRest", + "FromMqtt-302-M2R-ToRest", + 3, "FromRest-402-R2M-ToMqtt", + 3, "502-B2M-ToMqtt", + "502-B2R-ToRest"); + + // send 504 over rest while still connected should update + sendDataForBoth("504", false); + checkData(3, "FromMqtt-102-M2M-ToMqtt", + "FromRest-202-R2R-ToRest", + "FromMqtt-302-M2R-ToRest", + 3, "FromRest-402-R2M-ToMqtt", + 4, "504-B2M-ToMqtt", + "504-B2R-ToRest"); + + // send 505 over rest while also disconnected should not change anything + assertTrue(model.disconnectBoth2BothInput(restUri(PATH_BOTH_REST_RECEIVE, REST_PORT))); + sendDataForBoth("505", false); + checkData(3, "FromMqtt-102-M2M-ToMqtt", + "FromRest-202-R2R-ToRest", + "FromMqtt-302-M2R-ToRest", + 3, "FromRest-402-R2M-ToMqtt", + 4, "504-B2M-ToMqtt", + "504-B2R-ToRest"); + + // send new values. value over rest while sender disconnected does not provide a value anymore + assertTrue(model.disconnectRest2RestOutput(restUri(PATH_REST_2_REST_SEND, REST_PORT))); + assertTrue(model.disconnectMqtt2RestOutput(restUri(PATH_MQTT_2_REST_SEND, REST_PORT))); + sendData("103", "203", "303", "403"); + checkData(4, "FromMqtt-103-M2M-ToMqtt", + NOT_MAPPED, + NOT_MAPPED, + 4, "FromRest-403-R2M-ToMqtt", + 4, "504-B2M-ToMqtt", + "504-B2R-ToRest"); } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException { // check initial value - TestUtils.waitForMqtt(); checkData(0, null, "200-R2R-ToRest", "300-M2R-ToRest", @@ -205,9 +240,6 @@ public class ViaTest extends AbstractMqttTest { sendData("111", "211", "311", "411"); sendDataForBoth("511", true); - - // check new value - TestUtils.waitForMqtt(); checkData(1, "FromMqtt-111-M2M-ToMqtt", "FromRest-211-R2R-ToRest", "FromMqtt-311-M2R-ToRest", @@ -217,9 +249,6 @@ public class ViaTest extends AbstractMqttTest { // send value only for bothInput via REST sendDataForBoth("512", false); - - // check this value - TestUtils.waitForMqtt(); checkData(1, "FromMqtt-111-M2M-ToMqtt", "FromRest-211-R2R-ToRest", "FromMqtt-311-M2R-ToRest", @@ -229,9 +258,6 @@ public class ViaTest extends AbstractMqttTest { // send same value only for bothInput via MQTT sendDataForBoth("512", true); - - // check this value - TestUtils.waitForMqtt(); checkData(1, "FromMqtt-111-M2M-ToMqtt", "FromRest-211-R2R-ToRest", "FromMqtt-311-M2R-ToRest", @@ -241,9 +267,6 @@ public class ViaTest extends AbstractMqttTest { // send values for other things sendData("112", "212", "312", "412"); - - // check this value - TestUtils.waitForMqtt(); checkData(2, "FromMqtt-112-M2M-ToMqtt", "FromRest-212-R2R-ToRest", "FromMqtt-312-M2R-ToRest", @@ -253,15 +276,52 @@ public class ViaTest extends AbstractMqttTest { // send same values again for other things sendData("112", "212", "312", "412"); + checkData(2, "FromMqtt-112-M2M-ToMqtt", + "FromRest-212-R2R-ToRest", + "FromMqtt-312-M2R-ToRest", + 2, "FromRest-412-R2M-ToMqtt", + 2, "512-B2M-ToMqtt", + "512-B2R-ToRest"); - // check this value - TestUtils.waitForMqtt(); + // send 503 over mqtt while disconnected should not change anything + assertTrue(model.disconnectBoth2BothInput(mqttUri(TOPIC_BOTH_MQTT_RECEIVE))); + sendDataForBoth("513", true); checkData(2, "FromMqtt-112-M2M-ToMqtt", "FromRest-212-R2R-ToRest", "FromMqtt-312-M2R-ToRest", 2, "FromRest-412-R2M-ToMqtt", 2, "512-B2M-ToMqtt", "512-B2R-ToRest"); + + // send 514 over rest while still connected should update + sendDataForBoth("514", false); + checkData(2, "FromMqtt-112-M2M-ToMqtt", + "FromRest-212-R2R-ToRest", + "FromMqtt-312-M2R-ToRest", + 2, "FromRest-412-R2M-ToMqtt", + 3, "514-B2M-ToMqtt", + "514-B2R-ToRest"); + + // send 515 over rest while also disconnected should not change anything + assertTrue(model.disconnectBoth2BothInput(restUri(PATH_BOTH_REST_RECEIVE, REST_PORT))); + sendDataForBoth("515", false); + checkData(2, "FromMqtt-112-M2M-ToMqtt", + "FromRest-212-R2R-ToRest", + "FromMqtt-312-M2R-ToRest", + 2, "FromRest-412-R2M-ToMqtt", + 3, "514-B2M-ToMqtt", + "514-B2R-ToRest"); + + // send new values. value over rest while sender disconnected does not provide a value anymore + assertTrue(model.disconnectRest2RestOutput(restUri(PATH_REST_2_REST_SEND, REST_PORT))); + assertTrue(model.disconnectMqtt2RestOutput(restUri(PATH_MQTT_2_REST_SEND, REST_PORT))); + sendData("113", "213", "313", "413"); + checkData(3, "FromMqtt-113-M2M-ToMqtt", + NOT_MAPPED, + NOT_MAPPED, + 3, "FromRest-413-R2M-ToMqtt", + 3, "514-B2M-ToMqtt", + "514-B2R-ToRest"); } @Override @@ -289,7 +349,8 @@ public class ViaTest extends AbstractMqttTest { } } - private void checkData(int numberOfMqtt2MqttValues, String mqtt2MqttValue, String rest2RestValue, String mqtt2RestValue, int numberOfRest2MqttValues, String rest2MqttValue, int numberOfBoth2MqttValues, String both2MqttValue, String both2RestValue) { + private void checkData(int numberOfMqtt2MqttValues, String mqtt2MqttValue, String rest2RestValue, String mqtt2RestValue, int numberOfRest2MqttValues, String rest2MqttValue, int numberOfBoth2MqttValues, String both2MqttValue, String both2RestValue) throws InterruptedException { + TestUtils.waitForMqtt(); dataMqtt2Mqtt.assertEqualData(numberOfMqtt2MqttValues, mqtt2MqttValue); dataRest2Mqtt.assertEqualData(numberOfRest2MqttValues, rest2MqttValue); dataBoth2Mqtt.assertEqualData(numberOfBoth2MqttValues, both2MqttValue); diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java index 18a6e59bcc07ffc5c61006c671d15b8c55a8d501..5e26ba01360aaad05681c6ee3c045be0a6ca835d 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/AbstractListTest.java @@ -2,6 +2,7 @@ package org.jastadd.ragconnect.tests.list; import org.jastadd.ragconnect.tests.AbstractMqttTest; import org.jastadd.ragconnect.tests.TestUtils; +import org.jastadd.ragconnect.tests.TestUtils.IntList; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -10,9 +11,7 @@ import java.nio.file.Paths; import java.util.List; import java.util.function.Function; -import static java.util.Collections.addAll; -import static org.assertj.core.util.Lists.newArrayList; -import static org.jastadd.ragconnect.tests.list.AbstractListTest.IntList.list; +import static org.jastadd.ragconnect.tests.TestUtils.IntList.list; import static org.jastadd.ragconnect.tests.TestUtils.testJaddContainReferenceToJackson; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -77,7 +76,7 @@ public abstract class AbstractListTest extends AbstractMqttTest { } @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws InterruptedException, IOException { checkTree(1, list(), list(0), list(), list(0)); setInput(1); @@ -91,10 +90,18 @@ public abstract class AbstractListTest extends AbstractMqttTest { setInput(3); checkTree(4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(0, 1, 2, 3)); + + disconnectReceive(); + setInput(4); + checkTree(5, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(0, 1, 2, 3)); + + disconnectSend(); + setInput(5); + checkTree(5, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(0, 1, 2, 3)); } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException { checkTree(0, list(), list(), list(), list()); setInput(1); @@ -108,8 +115,20 @@ public abstract class AbstractListTest extends AbstractMqttTest { setInput(3); checkTree(3, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(1, 2, 3)); + + disconnectReceive(); + setInput(4); + checkTree(4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(1, 2, 3)); + + disconnectSend(); + setInput(5); + checkTree(4, list(1, 2, 3), list(3), list(1, 1, 2, 1, 2, 3), list(1, 2, 3)); } + protected abstract void disconnectReceive() throws IOException; + + protected abstract void disconnectSend() throws IOException; + protected abstract void setInput(int input); private void checkTree(int expectedTransmissions, IntList normalA, IntList fromSingleA, IntList withAddA, IntList withAddFromSingleA) throws InterruptedException { @@ -161,19 +180,4 @@ public abstract class AbstractListTest extends AbstractMqttTest { int numberOfElements = 0; } - protected static class IntList { - private final List<Integer> integers = newArrayList(); - public IntList(Integer... values) { - addAll(integers, values); - } - - public List<Integer> toList() { - return integers; - } - - public static IntList list(Integer... values) { - return new IntList(values); - } - } - } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListIncrementalTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListIncrementalTest.java index e5fbae01e28d2c31eed1511c7ff9a0712cd5e3c4..ac8b9415523c2a1e9121b5647e1d886fd2efba09 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListIncrementalTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListIncrementalTest.java @@ -62,16 +62,6 @@ public class ListIncrementalTest extends AbstractListTest { assertTrue(senderRoot.connectSingleAList(mqttUri(TOPIC_SINGLE_A), writeCurrentValue)); } - @Override - protected void closeConnections() { - if (handler != null) { - handler.close(); - } - if (model != null) { - model.ragconnectCloseConnections(); - } - } - @Override protected void setInput(int input) { senderRoot.setInput(input); @@ -82,4 +72,29 @@ public class ListIncrementalTest extends AbstractListTest { assertEquals(1, senderRoot.getNumSingleA(), "size of single NTA"); assertEquals(input, senderRoot.getSingleA(0).getID(), "ID value of single A"); } + + @Override + protected void disconnectReceive() throws IOException { + ReceiverRoot receiverRootWithLocalType = (ReceiverRoot) receiverRoot; + assertTrue(receiverRootWithLocalType.disconnectAList(mqttUri(TOPIC_A))); + assertTrue(receiverRootWithLocalType.disconnectFromSingleAList(mqttUri(TOPIC_SINGLE_A))); + assertTrue(receiverRootWithLocalType.disconnectWithAddFromAList(mqttUri(TOPIC_A))); + assertTrue(receiverRootWithLocalType.disconnectWithAddFromSingleAList(mqttUri(TOPIC_SINGLE_A))); + } + + @Override + protected void disconnectSend() throws IOException { + assertTrue(senderRoot.disconnectAList(mqttUri(TOPIC_A))); + assertTrue(senderRoot.disconnectSingleAList(mqttUri(TOPIC_SINGLE_A))); + } + + @Override + protected void closeConnections() { + if (handler != null) { + handler.close(); + } + if (model != null) { + model.ragconnectCloseConnections(); + } + } } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListManualTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListManualTest.java index f3e6eee5c93ea62e6edf939a1e6f5f3ef5419463..978359f772ba91187cae829ea0952807e1892ce2 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListManualTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/list/ListManualTest.java @@ -72,6 +72,21 @@ public class ListManualTest extends AbstractListTest { assertEquals(1, senderRoot.getNumSingleA(), "size of single NTA"); } + @Override + protected void disconnectReceive() throws IOException { + ReceiverRoot receiverRootWithLocalType = (ReceiverRoot) receiverRoot; + assertTrue(receiverRootWithLocalType.disconnectAList(mqttUri(TOPIC_A))); + assertTrue(receiverRootWithLocalType.disconnectFromSingleAList(mqttUri(TOPIC_SINGLE_A))); + assertTrue(receiverRootWithLocalType.disconnectWithAddFromAList(mqttUri(TOPIC_A))); + assertTrue(receiverRootWithLocalType.disconnectWithAddFromSingleAList(mqttUri(TOPIC_SINGLE_A))); + } + + @Override + protected void disconnectSend() throws IOException { + assertTrue(senderRoot.disconnectAList(mqttUri(TOPIC_A))); + assertTrue(senderRoot.disconnectSingleAList(mqttUri(TOPIC_SINGLE_A))); + } + @Override protected void closeConnections() { if (handler != null) { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java index 3c2779f8d4188c0f1fff7f8773d27401e94dd597..ff1e655370b85e3c75a69d7b5b4cab0a44fb8329 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/AbstractSingleListTest.java @@ -2,6 +2,7 @@ package org.jastadd.ragconnect.tests.singleList; import org.jastadd.ragconnect.tests.AbstractMqttTest; import org.jastadd.ragconnect.tests.TestUtils; +import org.jastadd.ragconnect.tests.TestUtils.IntList; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import singleList.ast.MqttHandler; @@ -16,11 +17,9 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Function; -import static java.util.Collections.addAll; -import static org.assertj.core.util.Lists.newArrayList; +import static org.jastadd.ragconnect.tests.TestUtils.IntList.list; import static org.jastadd.ragconnect.tests.TestUtils.mqttUri; import static org.jastadd.ragconnect.tests.TestUtils.testJaddContainReferenceToJackson; -import static org.jastadd.ragconnect.tests.singleList.AbstractSingleListTest.IntList.list; import static org.junit.jupiter.api.Assertions.*; /** @@ -52,6 +51,11 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest { @SuppressWarnings("unused") boolean connectUsingWildcardA(String mqttUri, int index) throws IOException; boolean connectWithAddA(String mqttUri) throws IOException; boolean connectUsingWildcardWithAddA(String mqttUri) throws IOException; + + boolean disconnectA(String mqttUri) throws IOException; + boolean disconnectUsingWildcardA(String mqttUri) throws IOException; + boolean disconnectWithAddA(String mqttUri) throws IOException; + boolean disconnectUsingWildcardWithAddA(String mqttUri) throws IOException; } @SuppressWarnings("UnusedReturnValue") public interface TestWrapperSenderRoot { @@ -61,6 +65,12 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest { boolean connectA4(String mqttUri, boolean writeCurrentValue) throws IOException; boolean connectInOutput(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean disconnectA1(String mqttUri) throws IOException; + boolean disconnectA2(String mqttUri) throws IOException; + boolean disconnectA3(String mqttUri) throws IOException; + boolean disconnectA4(String mqttUri) throws IOException; + boolean disconnectInOutput(String mqttUri) throws IOException; + TestWrapperSenderRoot setInput1(int input); TestWrapperSenderRoot setInput2(int input); TestWrapperSenderRoot setInput3(int input); @@ -170,7 +180,7 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest { abstract protected void setupReceiverAndConnectPart() throws IOException; @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws InterruptedException, IOException { checkTree(5, list(1, 2, 3, 4, 0), list(4, 3, 2, 1, 0), // normal: (normal / wildcard) list(4, 3, 2, 1, 0), list(4, 3, 2, 1, 0)); // withAdd: (normal / wildcard) @@ -198,10 +208,22 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest { setInput(3, 4); checkTree(9, list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard) list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard) + + // A2 will be send, but not received + disconnectReceive(); + setInput(2, 5); + checkTree(10, list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard) + list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard) + + // A2 will not be send + disconnectSend(); + setInput(2, 7); + checkTree(10, list(3, 2, 7, 4, 5), list(4, 7, 2, 3, 5), // normal: (normal / wildcard) + list(4, 3, 2, 1, 0, 2, 3, 5, 7), list(4, 3, 2, 1, 0, 2, 3, 5, 7)); // withAdd: (normal / wildcard) } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException { checkTree(0, list(0, 0, 0, 0, 0), list(), // normal list(), list()); // withAdd @@ -229,6 +251,44 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest { setInput(3, 4); checkTree(4, list(3, 0, 7, 0, 5), list(3,5,7), // normal list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd + + // A2 will be send, but not received + disconnectReceive(); + setInput(2, 5); + checkTree(5, list(3, 0, 7, 0, 5), list(3,5,7), // normal + list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd + + // A2 will not be send + disconnectSend(); + setInput(2, 7); + checkTree(5, list(3, 0, 7, 0, 5), list(3,5,7), // normal + list(2, 3, 5, 7), list(2, 3, 5, 7)); // withAdd + } + + protected void disconnectReceive() throws IOException { + assertTrue(receiverRoot.disconnectA(mqttUri(TOPIC_A_1))); + assertTrue(receiverRoot.disconnectA(mqttUri(TOPIC_A_2))); + assertTrue(receiverRoot.disconnectA(mqttUri(TOPIC_A_3))); + assertTrue(receiverRoot.disconnectA(mqttUri(TOPIC_A_4))); + assertTrue(receiverRoot.disconnectA(mqttUri(TOPIC_A_5_INOUT))); + + assertTrue(receiverRoot.disconnectWithAddA(mqttUri(TOPIC_A_1))); + assertTrue(receiverRoot.disconnectWithAddA(mqttUri(TOPIC_A_2))); + assertTrue(receiverRoot.disconnectWithAddA(mqttUri(TOPIC_A_3))); + assertTrue(receiverRoot.disconnectWithAddA(mqttUri(TOPIC_A_4))); + assertTrue(receiverRoot.disconnectWithAddA(mqttUri(TOPIC_A_5_INOUT))); + + // receive: wildcard subscription + assertTrue(receiverRoot.disconnectUsingWildcardA(mqttUri(TOPIC_A_WILDCARD))); + assertTrue(receiverRoot.disconnectUsingWildcardWithAddA(mqttUri(TOPIC_A_WILDCARD))); + } + + protected void disconnectSend() throws IOException { + assertTrue(senderRoot.disconnectA4(mqttUri(TOPIC_A_4))); + assertTrue(senderRoot.disconnectA3(mqttUri(TOPIC_A_3))); + assertTrue(senderRoot.disconnectA2(mqttUri(TOPIC_A_2))); + assertTrue(senderRoot.disconnectA1(mqttUri(TOPIC_A_1))); + assertTrue(senderRoot.disconnectInOutput(mqttUri(TOPIC_A_5_INOUT))); } protected void setInput(int index, int input) { @@ -279,19 +339,4 @@ public abstract class AbstractSingleListTest extends AbstractMqttTest { int numberOfElements = 0; } - protected static class IntList { - private final List<Integer> integers = newArrayList(); - public IntList(Integer... values) { - addAll(integers, values); - } - - public List<Integer> toList() { - return integers; - } - - public static IntList list(Integer... values) { - return new IntList(values); - } - } - } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListIncrementalTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListIncrementalTest.java index 7a946e44499f71dc0dfb92271ca1fc414275597b..54bbf675b2ad4c594a5c001cfaca7342248fbfbc 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListIncrementalTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListIncrementalTest.java @@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Test case "list incremental". + * Test case "single list incremental". * * @author rschoene - Initial contribution */ diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListManualTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListManualTest.java index c2896f633bc299159f0ab74913c3a9c0456d8370..9a8bf0a0d36d5a2f6e370bb7563453f00e0b5600 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListManualTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleList/SingleListManualTest.java @@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Test case "list manual". + * Test case "single list manual". * * @author rschoene - Initial contribution */ diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java index 465ad8ac024d595f29a87757c776db6c88e72fe4..d4d5f8397b9d8478435c2c8431dd6069800e5a36 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java @@ -1,7 +1,9 @@ package org.jastadd.ragconnect.tests.singleListVariant; +import org.assertj.core.api.Assertions; import org.jastadd.ragconnect.tests.AbstractMqttTest; import org.jastadd.ragconnect.tests.TestUtils; +import org.jastadd.ragconnect.tests.TestUtils.IntList; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -11,16 +13,14 @@ import java.util.List; import java.util.function.BiConsumer; import static java.lang.Math.abs; -import static java.util.Collections.addAll; -import static org.assertj.core.util.Lists.newArrayList; +import static org.jastadd.ragconnect.tests.TestUtils.IntList.list; import static org.jastadd.ragconnect.tests.TestUtils.mqttUri; import static org.jastadd.ragconnect.tests.TestUtils.testJaddContainReferenceToJackson; -import static org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.IntList.list; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Base class for test cases "singleList manual" and "singleList incremental". + * Base class for test cases "singleList variant manual" and "singleList variant incremental". * * @author rschoene - Initial contribution */ @@ -52,38 +52,67 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { TestWrapperJastAddList<? extends TestWrapperT_OneOfEach> getOneOfEachWithAddList(); TestWrapperJastAddList<? extends TestWrapperT_Abstract> getAbstractWithAddList(); - boolean connectT_Empty(String mqttUri) throws IOException; - boolean connectT_Token(String mqttUri) throws IOException; - boolean connectT_OneChild(String mqttUri) throws IOException; - boolean connectT_OneOpt(String mqttUri) throws IOException; - boolean connectT_OneList(String mqttUri) throws IOException; - boolean connectT_TwoChildren(String mqttUri) throws IOException; - boolean connectT_OneOfEach(String mqttUri) throws IOException; - boolean connectT_Abstract(String mqttUri) throws IOException; - - boolean connectMyEmpty(String mqttUri) throws IOException; - - boolean connectEmptyWithAdd(String mqttUri) throws IOException; - boolean connectTokenWithAdd(String mqttUri) throws IOException; - boolean connectOneChildWithAdd(String mqttUri) throws IOException; - boolean connectOneOptWithAdd(String mqttUri) throws IOException; - boolean connectOneListWithAdd(String mqttUri) throws IOException; - boolean connectTwoChildrenWithAdd(String mqttUri) throws IOException; - boolean connectOneOfEachWithAdd(String mqttUri) throws IOException; - boolean connectAbstractWithAdd(String mqttUri) throws IOException; + boolean connectT_Empty(String uriString) throws IOException; + boolean connectT_Token(String uriString) throws IOException; + boolean connectT_OneChild(String uriString) throws IOException; + boolean connectT_OneOpt(String uriString) throws IOException; + boolean connectT_OneList(String uriString) throws IOException; + boolean connectT_TwoChildren(String uriString) throws IOException; + boolean connectT_OneOfEach(String uriString) throws IOException; + boolean connectT_Abstract(String uriString) throws IOException; + + boolean connectMyEmpty(String uriString) throws IOException; + + boolean connectEmptyWithAdd(String uriString) throws IOException; + boolean connectTokenWithAdd(String uriString) throws IOException; + boolean connectOneChildWithAdd(String uriString) throws IOException; + boolean connectOneOptWithAdd(String uriString) throws IOException; + boolean connectOneListWithAdd(String uriString) throws IOException; + boolean connectTwoChildrenWithAdd(String uriString) throws IOException; + boolean connectOneOfEachWithAdd(String uriString) throws IOException; + boolean connectAbstractWithAdd(String uriString) throws IOException; + + boolean disconnectT_Empty(String uriString) throws IOException; + boolean disconnectT_Token(String uriString) throws IOException; + boolean disconnectT_OneChild(String uriString) throws IOException; + boolean disconnectT_OneOpt(String uriString) throws IOException; + boolean disconnectT_OneList(String uriString) throws IOException; + boolean disconnectT_TwoChildren(String uriString) throws IOException; + boolean disconnectT_OneOfEach(String uriString) throws IOException; + boolean disconnectT_Abstract(String uriString) throws IOException; + + boolean disconnectMyEmpty(String uriString) throws IOException; + + boolean disconnectEmptyWithAdd(String uriString) throws IOException; + boolean disconnectTokenWithAdd(String uriString) throws IOException; + boolean disconnectOneChildWithAdd(String uriString) throws IOException; + boolean disconnectOneOptWithAdd(String uriString) throws IOException; + boolean disconnectOneListWithAdd(String uriString) throws IOException; + boolean disconnectTwoChildrenWithAdd(String uriString) throws IOException; + boolean disconnectOneOfEachWithAdd(String uriString) throws IOException; + boolean disconnectAbstractWithAdd(String uriString) throws IOException; } - @SuppressWarnings("UnusedReturnValue") public interface TestWrapperSenderRoot { - boolean connectT_Empty(String mqttUri, boolean writeCurrentValue) throws IOException; - boolean connectT_Token(String mqttUri, boolean writeCurrentValue) throws IOException; - boolean connectT_OneChild(String mqttUri, boolean writeCurrentValue) throws IOException; - boolean connectT_OneOpt(String mqttUri, boolean writeCurrentValue) throws IOException; - boolean connectT_OneList(String mqttUri, boolean writeCurrentValue) throws IOException; - boolean connectT_TwoChildren(String mqttUri, boolean writeCurrentValue) throws IOException; - boolean connectT_OneOfEach(String mqttUri, boolean writeCurrentValue) throws IOException; - boolean connectT_Abstract(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_Empty(String uriString, boolean writeCurrentValue) throws IOException; + boolean connectT_Token(String uriString, boolean writeCurrentValue) throws IOException; + boolean connectT_OneChild(String uriString, boolean writeCurrentValue) throws IOException; + boolean connectT_OneOpt(String uriString, boolean writeCurrentValue) throws IOException; + boolean connectT_OneList(String uriString, boolean writeCurrentValue) throws IOException; + boolean connectT_TwoChildren(String uriString, boolean writeCurrentValue) throws IOException; + boolean connectT_OneOfEach(String uriString, boolean writeCurrentValue) throws IOException; + boolean connectT_Abstract(String uriString, boolean writeCurrentValue) throws IOException; + + boolean disconnectT_Empty(String uriString) throws IOException; + boolean disconnectT_Token(String uriString) throws IOException; + boolean disconnectT_OneChild(String uriString) throws IOException; + boolean disconnectT_OneOpt(String uriString) throws IOException; + boolean disconnectT_OneList(String uriString) throws IOException; + boolean disconnectT_TwoChildren(String uriString) throws IOException; + boolean disconnectT_OneOfEach(String uriString) throws IOException; + boolean disconnectT_Abstract(String uriString) throws IOException; TestWrapperSenderRoot setInput(int input); + @SuppressWarnings("UnusedReturnValue") TestWrapperSenderRoot setShouldSetOptAndList(boolean shouldSetOptAndList); TestWrapperT_Empty getT_Empty(); TestWrapperT_OneOpt getT_OneOpt(); @@ -198,7 +227,7 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { abstract protected void setupReceiverAndConnectPart() throws IOException; @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws IOException, InterruptedException { // transmissions: 8 * 1 = 8 checkTree(8, list(-0), list(0), list(-0)); @@ -225,10 +254,20 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { setInput(5); // transmissions: 27 + 8 = 35 checkTree(35, list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5)); + + disconnectReceive(); + setInput(6); // does not affect receive + // transmissions: 35 + 8 = 43 + checkTree(43, list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5)); + + disconnectSend(); + setInput(7); // not sent + // transmissions: 43 + checkTree(43, list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5)); } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws IOException, InterruptedException { // transmissions: 0 checkTree(0, list(), list(), list()); @@ -255,6 +294,53 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { setInput(5); // transmissions: 19 + 8 = 27 checkTree(27, list(5), list(1, 2, 5), list(-1, 1, 2, 5)); + + disconnectReceive(); + setInput(6); // does not affect receive + // transmissions: 27 + 8 = 35 + checkTree(35, list(5), list(1, 2, 5), list(-1, 1, 2, 5)); + + disconnectSend(); + setInput(7); // not sent + // transmissions: 35 + checkTree(35, list(5), list(1, 2, 5), list(-1, 1, 2, 5)); + } + + private void disconnectReceive() throws IOException { + // receive: unnamed + assertTrue(receiverRoot.disconnectT_Empty(mqttUri(TOPIC_T_Empty))); + assertTrue(receiverRoot.disconnectT_Token(mqttUri(TOPIC_T_Token))); + assertTrue(receiverRoot.disconnectT_OneChild(mqttUri(TOPIC_T_OneChild))); + assertTrue(receiverRoot.disconnectT_OneOpt(mqttUri(TOPIC_T_OneOpt))); + assertTrue(receiverRoot.disconnectT_OneList(mqttUri(TOPIC_T_OneList))); + assertTrue(receiverRoot.disconnectT_TwoChildren(mqttUri(TOPIC_T_TwoChildren))); + assertTrue(receiverRoot.disconnectT_OneOfEach(mqttUri(TOPIC_T_OneOfEach))); + assertTrue(receiverRoot.disconnectT_Abstract(mqttUri(TOPIC_T_Abstract))); + + // receive: named + assertTrue(receiverRoot.disconnectMyEmpty(mqttUri(TOPIC_T_Empty))); + + // receive: with add + assertTrue(receiverRoot.disconnectEmptyWithAdd(mqttUri(TOPIC_T_Empty))); + assertTrue(receiverRoot.disconnectTokenWithAdd(mqttUri(TOPIC_T_Token))); + assertTrue(receiverRoot.disconnectOneChildWithAdd(mqttUri(TOPIC_T_OneChild))); + assertTrue(receiverRoot.disconnectOneOptWithAdd(mqttUri(TOPIC_T_OneOpt))); + assertTrue(receiverRoot.disconnectOneListWithAdd(mqttUri(TOPIC_T_OneList))); + assertTrue(receiverRoot.disconnectTwoChildrenWithAdd(mqttUri(TOPIC_T_TwoChildren))); + assertTrue(receiverRoot.disconnectOneOfEachWithAdd(mqttUri(TOPIC_T_OneOfEach))); + assertTrue(receiverRoot.disconnectAbstractWithAdd(mqttUri(TOPIC_T_Abstract))); + } + + private void disconnectSend() throws IOException { + // send + assertTrue(senderRoot.disconnectT_Empty(mqttUri(TOPIC_T_Empty))); + assertTrue(senderRoot.disconnectT_Token(mqttUri(TOPIC_T_Token))); + assertTrue(senderRoot.disconnectT_OneChild(mqttUri(TOPIC_T_OneChild))); + assertTrue(senderRoot.disconnectT_OneOpt(mqttUri(TOPIC_T_OneOpt))); + assertTrue(senderRoot.disconnectT_OneList(mqttUri(TOPIC_T_OneList))); + assertTrue(senderRoot.disconnectT_TwoChildren(mqttUri(TOPIC_T_TwoChildren))); + assertTrue(senderRoot.disconnectT_OneOfEach(mqttUri(TOPIC_T_OneOfEach))); + assertTrue(senderRoot.disconnectT_Abstract(mqttUri(TOPIC_T_Abstract))); } protected void setInput(int input) { @@ -287,31 +373,31 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { assertEquals(expectedTransmissions, data.numberOfElements, "transmissions for any element"); // check unnamed - checkList(expectedList.toList(), receiverRoot.getT_EmptyList(), (e, n) -> {}); - checkList(expectedList.toList(), receiverRoot.getT_TokenList(), + checkList(expectedList, receiverRoot.getT_EmptyList(), (e, n) -> {}); + checkList(expectedList, receiverRoot.getT_TokenList(), (e, n) -> assertEquals(Integer.toString(abs(e)), n.getValue())); - checkList(expectedList.toList(), receiverRoot.getT_OneChildList(), + checkList(expectedList, receiverRoot.getT_OneChildList(), (e, n) -> assertEquals(abs(e) + 1, n.getOther().getID())); - checkList(expectedList.toList(), receiverRoot.getT_OneOptList(), + checkList(expectedList, receiverRoot.getT_OneOptList(), (e, n) -> { assertEquals(e > 0, n.hasOther()); if (n.hasOther()) { assertEquals(abs(e) + 1, n.getOther().getID()); } }); - checkList(expectedList.toList(), receiverRoot.getT_OneListList(), + checkList(expectedList, receiverRoot.getT_OneListList(), (e, n) -> { assertEquals(e > 0 ? 1 : 0, n.getNumOther()); if (n.getNumOther() > 0) { assertEquals(abs(e) + 1, n.getOther(0).getID()); } }); - checkList(expectedList.toList(), receiverRoot.getT_TwoChildrenList(), + checkList(expectedList, receiverRoot.getT_TwoChildrenList(), (e, n) -> { assertEquals(abs(e) + 1, n.getLeft().getID()); assertEquals(abs(e) + 1, n.getRight().getID()); }); - checkList(expectedList.toList(), receiverRoot.getT_OneOfEachList(), + checkList(expectedList, receiverRoot.getT_OneOfEachList(), (e, n) -> { assertEquals(abs(e) + 1, n.getFirst().getID()); assertEquals(e > 0, n.hasSecond()); @@ -324,39 +410,39 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { } assertEquals(Integer.toString(abs(e)), n.getFourth()); }); - checkList(expectedList.toList(), receiverRoot.getT_AbstractList(), + checkList(expectedList, receiverRoot.getT_AbstractList(), (e, n) -> { assertEquals(Integer.toString(abs(e)), n.getValueAbstract()); assertEquals(Integer.toString(abs(e)), n.getValueSub()); }); // check named - checkList(expectedList.toList(), receiverRoot.getMyEmptyList(), (e, n) -> {}); + checkList(expectedList, receiverRoot.getMyEmptyList(), (e, n) -> {}); // check with add - checkList(expectedWithAddList.toList(), receiverRoot.getEmptyWithAddList(), (e, n) -> {}); - checkList(expectedWithAddList.toList(), receiverRoot.getTokenWithAddList(), + checkList(expectedWithAddList, receiverRoot.getEmptyWithAddList(), (e, n) -> {}); + checkList(expectedWithAddList, receiverRoot.getTokenWithAddList(), (e, n) -> assertEquals(Integer.toString(abs(e)), n.getValue())); - checkList(expectedWithAddList.toList(), receiverRoot.getOneChildWithAddList(), + checkList(expectedWithAddList, receiverRoot.getOneChildWithAddList(), (e, n) -> assertEquals(abs(e) + 1, n.getOther().getID())); - checkList(expectedWithAddListForOptAndList.toList(), receiverRoot.getOneOptWithAddList(), + checkList(expectedWithAddListForOptAndList, receiverRoot.getOneOptWithAddList(), (e, n) -> { if (n.hasOther()) { assertEquals(abs(e) + 1, n.getOther().getID()); } }); - checkList(expectedWithAddListForOptAndList.toList(), receiverRoot.getOneListWithAddList(), + checkList(expectedWithAddListForOptAndList, receiverRoot.getOneListWithAddList(), (e, n) -> { if (n.getNumOther() > 0) { assertEquals(abs(e) + 1, n.getOther(0).getID()); } }); - checkList(expectedWithAddList.toList(), receiverRoot.getTwoChildrenWithAddList(), + checkList(expectedWithAddList, receiverRoot.getTwoChildrenWithAddList(), (e, n) -> { assertEquals(abs(e) + 1, n.getLeft().getID()); assertEquals(abs(e) + 1, n.getRight().getID()); }); - checkList(expectedWithAddListForOptAndList.toList(), receiverRoot.getOneOfEachWithAddList(), + checkList(expectedWithAddListForOptAndList, receiverRoot.getOneOfEachWithAddList(), (e, n) -> { assertEquals(abs(e) + 1, n.getFirst().getID()); if (n.hasSecond()) { @@ -367,19 +453,19 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { } assertEquals(Integer.toString(abs(e)), n.getFourth()); }); - checkList(expectedWithAddList.toList(), receiverRoot.getAbstractWithAddList(), + checkList(expectedWithAddList, receiverRoot.getAbstractWithAddList(), (e, n) -> { assertEquals(Integer.toString(abs(e)), n.getValueAbstract()); assertEquals(Integer.toString(abs(e)), n.getValueSub()); }); } - private <T extends TestWrapperNameable> void checkList(List<Integer> expectedList, TestWrapperJastAddList<T> actualList, BiConsumer<Integer, T> additionalTest) { - assertEquals(expectedList.size(), actualList.getNumChild(), "same list size"); + private <T extends TestWrapperNameable> void checkList(IntList expectedList, TestWrapperJastAddList<T> actualList, BiConsumer<Integer, T> additionalTest) { + Assertions.assertThat(actualList).extracting("ID").containsExactlyElementsOf(expectedList.toAbsList()); + List<Integer> normalExpectedList = expectedList.toList(); int index = 0; for (T element : actualList) { - assertEquals(abs(expectedList.get(index)), element.getID(), "correct ID for A"); - additionalTest.accept(expectedList.get(index), element); + additionalTest.accept(normalExpectedList.get(index), element); index++; } } @@ -388,19 +474,4 @@ public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { int numberOfElements = 0; } - protected static class IntList { - private final List<Integer> integers = newArrayList(); - public IntList(Integer... values) { - addAll(integers, values); - } - - public List<Integer> toList() { - return integers; - } - - public static IntList list(Integer... values) { - return new IntList(values); - } - } - } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java index 9a55da378b93cc3bcc741d1904dc58b3d9ae96bd..174bea2923e2977c93a058dc1408113276e47382 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java @@ -11,7 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Test case "list incremental". + * Test case "singleList variant incremental". * * @author rschoene - Initial contribution */ diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java index c65a09ec65add4afd7fa5ca8a2809b28e0be4df2..6ae0e75b5d2d35375baf508ce7af8044158370bc 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java @@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Test case "list manual". + * Test case "singleList variant manual". * * @author rschoene - Initial contribution */ diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/AbstractTreeTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/AbstractTreeTest.java index ebcccfe9898e374a5dc8d5886d83f999fc0def36..22cc2c0c4334d86c96fdec48682b7a92842fbc9f 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/AbstractTreeTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/AbstractTreeTest.java @@ -24,6 +24,7 @@ public abstract class AbstractTreeTest extends AbstractMqttTest { public interface TestWrapperReceiverRoot { TestWrapperAlfa getAlfa(); boolean connectAlfa(String mqttUri) throws IOException; + boolean disconnectAlfa(String mqttUri) throws IOException; } public interface TestWrapperAlfa { TestWrapperBravo getBravo(int i); @@ -68,7 +69,7 @@ public abstract class AbstractTreeTest extends AbstractMqttTest { } @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws InterruptedException, IOException { checkTree(1, 0); setInput(1); @@ -79,10 +80,18 @@ public abstract class AbstractTreeTest extends AbstractMqttTest { setInput(2); checkTree(3, 2); + + disconnectReceive(); + setInput(1); + checkTree(4, 2); + + disconnectSend(); + setInput(2); + checkTree(4, 2); } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException { checkTree(0, null); setInput(1); @@ -93,8 +102,20 @@ public abstract class AbstractTreeTest extends AbstractMqttTest { setInput(2); checkTree(2, 2); + + disconnectReceive(); + setInput(1); + checkTree(3, 2); + + disconnectSend(); + setInput(2); + checkTree(3, 2); } + protected abstract void disconnectReceive() throws IOException; + + protected abstract void disconnectSend() throws IOException; + protected abstract void setInput(int input); protected void checkTree(int expectedCount, Integer expectedInput) throws InterruptedException { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeIncrementalTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeIncrementalTest.java index 6722e159ed064ee253dd79c01fbf3e009ebba874..96cbadc4fbfabed7685c6a5d4c0f0ff827c4f9b1 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeIncrementalTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeIncrementalTest.java @@ -60,6 +60,20 @@ public class TreeIncrementalTest extends AbstractTreeTest { assertTrue(senderRoot.connectAlfa(mqttUri(TOPIC_ALFA), writeCurrentValue)); } + protected void setInput(int input) { + senderRoot.setInput(input); + } + + @Override + protected void disconnectReceive() throws IOException { + assertTrue(receiverRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + } + + @Override + protected void disconnectSend() throws IOException { + assertTrue(senderRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + } + @Override protected void closeConnections() { if (handler != null) { @@ -69,8 +83,4 @@ public class TreeIncrementalTest extends AbstractTreeTest { model.ragconnectCloseConnections(); } } - - protected void setInput(int input) { - senderRoot.setInput(input); - } } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeManualTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeManualTest.java index d60e8fa0590bc60306997a8896856da99b0a7956..e557c9442be50d04d4b9d1bb2de7d003f749d4f0 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeManualTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/tree/TreeManualTest.java @@ -62,6 +62,20 @@ public class TreeManualTest extends AbstractTreeTest { assertTrue(senderRoot.connectAlfa(mqttUri(TOPIC_ALFA), writeCurrentValue)); } + protected void setInput(int input) { + senderRoot.setInput(input); + } + + @Override + protected void disconnectReceive() throws IOException { + assertTrue(receiverRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + } + + @Override + protected void disconnectSend() throws IOException { + assertTrue(senderRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + } + @Override protected void closeConnections() { if (handler != null) { @@ -71,8 +85,4 @@ public class TreeManualTest extends AbstractTreeTest { model.ragconnectCloseConnections(); } } - - protected void setInput(int input) { - senderRoot.setInput(input); - } } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/AbstractTreeAllowedTokensTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/AbstractTreeAllowedTokensTest.java index 12b2c99912ac7f2b4401aeefd76a3f91fce06f7b..7c29538a71609e73a82fe0e22ad6c8bd74582f8c 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/AbstractTreeAllowedTokensTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/AbstractTreeAllowedTokensTest.java @@ -36,6 +36,8 @@ public abstract class AbstractTreeAllowedTokensTest extends AbstractMqttTest { TestWrapperAlfa getAlfaPrimitive(); boolean connectAlfa(String mqttUri) throws IOException; boolean connectAlfaPrimitive(String mqttUri) throws IOException; + boolean disconnectAlfa(String mqttUri) throws IOException; + boolean disconnectAlfaPrimitive(String mqttUri) throws IOException; } public interface TestWrapperAlfa { boolean getBooleanValue(); @@ -51,7 +53,7 @@ public abstract class AbstractTreeAllowedTokensTest extends AbstractMqttTest { } @Override - protected void communicateSendInitialValue() throws InterruptedException { + protected void communicateSendInitialValue() throws InterruptedException, IOException { checkTree(1, false, 0, INSTANT_A, 0); checkPrimitiveTree(1, INSTANT_A); @@ -99,10 +101,22 @@ public abstract class AbstractTreeAllowedTokensTest extends AbstractMqttTest { sendInput3(5.1); checkTree(6, true, 4, INSTANT_B, 5.1); checkPrimitiveTree(2, INSTANT_B); + + // sendInput3(7) -> send, but not receive + disconnectReceive(); + sendInput3(7); + checkTree(7, true, 4, INSTANT_B, 5.1); + checkPrimitiveTree(2, INSTANT_B); + + // sendInput3(8) -> not sent + disconnectSend(); + sendInput3(8); + checkTree(7, true, 4, INSTANT_B, 5.1); + checkPrimitiveTree(2, INSTANT_B); } @Override - protected void communicateOnlyUpdatedValue() throws InterruptedException { + protected void communicateOnlyUpdatedValue() throws InterruptedException, IOException { checkTree(0, false, null, null, 0); checkPrimitiveTree(0, null); @@ -150,8 +164,24 @@ public abstract class AbstractTreeAllowedTokensTest extends AbstractMqttTest { sendInput3(15.1); checkTree(5, true, 14, INSTANT_C, 15.1); checkPrimitiveTree(1, INSTANT_C); + + // sendInput3(7) -> send, but not receive + disconnectReceive(); + sendInput3(7); + checkTree(6, true, 14, INSTANT_C, 15.1); + checkPrimitiveTree(1, INSTANT_C); + + // sendInput3(8) -> not sent + disconnectSend(); + sendInput3(8); + checkTree(6, true, 14, INSTANT_C, 15.1); + checkPrimitiveTree(1, INSTANT_C); } + protected abstract void disconnectReceive() throws IOException; + + protected abstract void disconnectSend() throws IOException; + protected void sendInput1WhenFalse(int value) { publisher.publish(TOPIC_INPUT1FALSE, TestUtils.DefaultMappings.IntToBytes(value)); } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensIncrementalTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensIncrementalTest.java index e848ca4059b962aa3431209e23de5ed9ccad4a24..851565047c4c8a95284d9b8d58e158863596467f 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensIncrementalTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensIncrementalTest.java @@ -71,6 +71,31 @@ public class TreeAllowedTokensIncrementalTest extends AbstractTreeAllowedTokensT assertTrue(senderRoot.connectAlfaPrimitive(mqttUri(TOPIC_ALFA_PRIMITIVE), writeCurrentValue)); } + protected void setFlag(boolean value) { + senderRoot.setFlag(value); + } + + @Override + protected void checkMyEnum(TestWrapperAlfa alfa, boolean expectedBooleanValue) { + assertEquals(expectedBooleanValue ? MyEnum.TRUE : MyEnum.FALSE, ((Alfa) alfa).getEnumValue()); + } + + @Override + protected void disconnectReceive() throws IOException { + assertTrue(receiverRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + assertTrue(receiverRoot.disconnectAlfaPrimitive(mqttUri(TOPIC_ALFA_PRIMITIVE))); + } + + @Override + protected void disconnectSend() throws IOException { + assertTrue(senderRoot.disconnectInput1WhenFlagIsFalse(mqttUri(TOPIC_INPUT1FALSE))); + assertTrue(senderRoot.disconnectInput1WhenFlagIsTrue(mqttUri(TOPIC_INPUT1TRUE))); + assertTrue(senderRoot.disconnectInput2(mqttUri(TOPIC_INPUT2))); + assertTrue(senderRoot.disconnectInput3(mqttUri(TOPIC_INPUT3))); + assertTrue(senderRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + assertTrue(senderRoot.disconnectAlfaPrimitive(mqttUri(TOPIC_ALFA_PRIMITIVE))); + } + @Override protected void closeConnections() { if (handler != null) { @@ -80,13 +105,4 @@ public class TreeAllowedTokensIncrementalTest extends AbstractTreeAllowedTokensT model.ragconnectCloseConnections(); } } - - protected void setFlag(boolean value) { - senderRoot.setFlag(value); - } - - @Override - protected void checkMyEnum(TestWrapperAlfa alfa, boolean expectedBooleanValue) { - assertEquals(expectedBooleanValue ? MyEnum.TRUE : MyEnum.FALSE, ((Alfa) alfa).getEnumValue()); - } } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensManualTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensManualTest.java index 3903834434d1b5031e1db5a68e6a6d5dbdef9a43..8563e0b04808f939cf1070f08c5666f9de2fef00 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensManualTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/treeAllowedTokens/TreeAllowedTokensManualTest.java @@ -73,6 +73,31 @@ public class TreeAllowedTokensManualTest extends AbstractTreeAllowedTokensTest { assertTrue(senderRoot.connectAlfaPrimitive(mqttUri(TOPIC_ALFA_PRIMITIVE), writeCurrentValue)); } + protected void setFlag(boolean value) { + senderRoot.setFlag(value); + } + + @Override + protected void checkMyEnum(TestWrapperAlfa alfa, boolean expectedBooleanValue) { + assertEquals(expectedBooleanValue ? MyEnum.TRUE : MyEnum.FALSE, ((Alfa) alfa).getEnumValue()); + } + + @Override + protected void disconnectReceive() throws IOException { + assertTrue(receiverRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + assertTrue(receiverRoot.disconnectAlfaPrimitive(mqttUri(TOPIC_ALFA_PRIMITIVE))); + } + + @Override + protected void disconnectSend() throws IOException { + assertTrue(senderRoot.disconnectInput1WhenFlagIsFalse(mqttUri(TOPIC_INPUT1FALSE))); + assertTrue(senderRoot.disconnectInput1WhenFlagIsTrue(mqttUri(TOPIC_INPUT1TRUE))); + assertTrue(senderRoot.disconnectInput2(mqttUri(TOPIC_INPUT2))); + assertTrue(senderRoot.disconnectInput3(mqttUri(TOPIC_INPUT3))); + assertTrue(senderRoot.disconnectAlfa(mqttUri(TOPIC_ALFA))); + assertTrue(senderRoot.disconnectAlfaPrimitive(mqttUri(TOPIC_ALFA_PRIMITIVE))); + } + @Override protected void closeConnections() { if (handler != null) { @@ -82,13 +107,4 @@ public class TreeAllowedTokensManualTest extends AbstractTreeAllowedTokensTest { model.ragconnectCloseConnections(); } } - - protected void setFlag(boolean value) { - senderRoot.setFlag(value); - } - - @Override - protected void checkMyEnum(TestWrapperAlfa alfa, boolean expectedBooleanValue) { - assertEquals(expectedBooleanValue ? MyEnum.TRUE : MyEnum.FALSE, ((Alfa) alfa).getEnumValue()); - } }