diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 87d2c9ca04f5e7383dc6efd5e7a33d87f2d9b8c6..401f721305affd0b14d18923027c42dd32c6edfb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,6 +42,8 @@ test: - ./gradlew --console=plain --no-daemon allTests artifacts: when: always + paths: + - "ragconnect.tests/test.log" reports: junit: "ragconnect.tests/build/test-results/**/TEST-*.xml" expire_in: 1 week @@ -94,9 +96,6 @@ ragdoc_view: - OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc - cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR - /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR - only: - - dev - - master artifacts: paths: - "pages/docs/ragdoc" diff --git a/pages/docs/changelog.md b/pages/docs/changelog.md index fe3b87a7249a5b554902ea7239b58f91ac55a500..1f41f95d1e11cb361d9d4e4b3675d20e09e575fe 100644 --- a/pages/docs/changelog.md +++ b/pages/docs/changelog.md @@ -1,5 +1,20 @@ # Changelog +## 1.0.0 (dev) + +### Changes + +- Allow connection endpoints for relations ([#37](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/37)) and attributes ([#38](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/38)) +- Allow send connection endpoints non-NTA nonterminals ([#36](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/36)) +- Allow context-free context endpoints ([#34](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/34)) +- Experimental support for Java handler ([#52](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/52)) +- Make specification language more concise ([#33](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/33)) + +### Development Changes + +- Make grammar(s) more concise ([#40](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/40)) +- Enhance documentation, adding a DSL description + ## 0.3.2 - Allow connection endpoints for list nonterminals ([#21](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/21)) diff --git a/pages/docs/compiler.md b/pages/docs/compiler.md index d60822b10956accb9313f4a1b677574996a2e198..80a9acbb5e82cf693560e8287c5db320515eb4ad 100644 --- a/pages/docs/compiler.md +++ b/pages/docs/compiler.md @@ -6,16 +6,16 @@ Additional options are as follows. | Name | Required (Default) | Description | |---|---|---| | `--rootNode` | Yes | Root node in the base grammar. | -| `--protocols` | No (`mqtt`) | Protocols to enable, currently available: `mqtt, rest`. | +| `--protocols` | No (`mqtt`) | Protocols to enable, currently available: `java` (experimental), `mqtt`, `rest`. | | `--printYaml` | No (false) | Print out YAML instead of generating files. | | `--verbose` | No (false) | Print more messages while compiling. | | `--logReads` | No (false) | Enable logging for every received message. | | `--logWrites` | No (false) | Enable logging for every sent message. | | `--logIncremental` | No (false) | Enable logging for observer in incremental dependency tracking. | | `--logTarget` | No (`console`) | Logging target to use, currently available: `console, slf4j`. | -| `--experimental-jastadd-329` | No (false) | Use trace events `INC_FLUSH_START` and `INC_FLUSH_END` ([JastAdd issue #329][jastadd-issue-329]), see [section about automatic dependency tracking](/using#dependency-tracking-automatically-derived). | -| `--incremental` | No (false) | Enables incremental dependency tracking (if `trace` is also set appropriately). | -| `--trace[=flush]` | No (false) | Enables incremental dependency tracking (if `incremental` is also set appropriately). | +| `--experimental-jastadd-329` | No (false) | Use tracing events `INC_FLUSH_START` and `INC_FLUSH_END` ([JastAdd issue #329][jastadd-issue-329]), see [section about automatic dependency tracking](/using#dependency-tracking-automatically-derived). | +| `--incremental` | No (false) | Enables incremental dependency tracking (if `tracing` is also set appropriately). | +| `--tracing[=flush]` | No (false) | Enables incremental dependency tracking (if `incremental` is also set appropriately). | | `--version` | No (false) | Print version info and exit (reused JastAdd option) | | `--o` | No (`.`) | Output directory (reused JastAdd option) | @@ -29,6 +29,16 @@ However, depending on the selected protocols and/or used features, additional de ## Communication protocol characteristics +### Java + +- Protocol identifier: `java` +- URI scheme: `java://<ignored-host>[:ignored-port]/<topic>` + - the value for host and port are always ignored, but are necessary to form a legal URI +- No required runtime dependencies +- Additional remarks: + - First leading slash not included in topic. + - Currently, the default mappings are applied, which requires a consumer to expect `byte[]` (instead of a more intuitive token or node value). This might change in future versions. + ### MQTT - Protocol identifier: `mqtt` @@ -59,15 +69,15 @@ However, depending on the selected protocols and/or used features, additional de ### Automatic dependency tracking -- Condition: When passing `--incremental` and `--trace=flush` to RagConnect +- Condition: When passing `--incremental` and `--tracing=flush` to RagConnect - Required runtime dependencies: _none_ - Required options for RelAST compiler: _none_ - Required options for JastAdd: - `--incremental` - - `--trace=flush` + - `--tracing=flush` - Remarks: - Other (additional) values passed to those two options must be equal (e.g., `--incremental=param` passed to RagConnect must be also passed to JastAdd) - - Other values besides `flush` can be added to `--trace` + - Other values besides `flush` can be added to `--tracing` - [Feature description](/using#dependency-tracking-automatically-derived) ### (Safer) Automatic dependency tracking diff --git a/pages/docs/dsl.md b/pages/docs/dsl.md index e8b6b2bb11c67168bafd33efa48b505248ea9b37..98ee13c4254027096b645268c693c401dadc6d10 100644 --- a/pages/docs/dsl.md +++ b/pages/docs/dsl.md @@ -21,19 +21,19 @@ A breakdown of the parts of that syntax: - The first word (`send` or `receive`) defines the kind of endpoint - sending or receiving, respectively. - The optional `indexed` applies only for list children and lets the endpoint act on elements of that list. This only works for receiving endpoints, and is further changed by `with add`. - - A lonely `indexed` assigns each incoming "topic" to an index in a list. - This can be useful if multiple instances of this endpoint are connected, or the communication protocol supports wildcard topics. - For the former case, the connect method with an explicit index can be used, whereas the "normal" connect method without the index acts as a method for "wildcard-connect". - - Combining `indexed with add`, incoming data is required to be an element of the list, and will be appended to the list. + - A lonely `indexed` assigns each incoming "topic" to an index in a list. + This can be useful if multiple instances of this endpoint are connected, or the communication protocol supports wildcard topics. + For the former case, the connect method with an explicit index can be used, whereas the "normal" connect method without the index acts as a method for "wildcard-connect". + - Combining `indexed with add`, incoming data is required to be an element of the list, and will be appended to the list. - The second optional keyword `with add` can also be used only for receiving endpoints targeting a list children. As described above, it can be combined with `indexed`. If used on its own, the incoming data is interpreted as a complete list and its elements will be appended to the current list. - The `<Non-Terminal>[.<Target>["(<AttributeType>)"]]` notation describes the actual affected node. - - If the target is omitted, all nodes of that non-terminal type can be connected, irrespective of their context. This is a context-free endpoint definition. - - The target can be any child on the right-hand side of a production rule, a role of a relation, or an attribute. - The brackets `(<AttributeType>)` after the target must be used in case of an attribute, and only then. - Here, the return type of the attribute has to be specified, as aspect files are not parsed by RagConnect. - Hence, RagConnect can not and will not verify the existence of the attribute, and the possible non-existence of an attribute will be found by the Java compiler. + - If the target is omitted, all nodes of that non-terminal type can be connected, irrespective of their context. This is a context-free endpoint definition. + - The target can be any child on the right-hand side of a production rule, a role of a relation, or an attribute. + The brackets `(<AttributeType>)` after the target must be used in case of an attribute, and only then. + Here, the return type of the attribute has to be specified, as aspect files are not parsed by RagConnect. + Hence, RagConnect can not and will not verify the existence of the attribute, and the possible non-existence of an attribute will be found by the Java compiler. - Optionally, an endpoint can use one or more [mappings](#mappings). They will be applied before sending, or after receiving a message. Mappings will always be applied in the order they are listed after `using`. @@ -49,7 +49,7 @@ Specifying such an endpoint has several consequences: **Example**: -```java +``` // grammar Root ::= A SingleA:A [OptA:A] ListA:A* ; A ::= <Value> ; @@ -60,13 +60,15 @@ receive Root.SingleA using MyMapping; // specialized endpoint ``` Implied, additional connect specifications: -```java + +``` receive Root.A; receive Root.OptA; receive indexed Root.ListA; ``` Application code: + ```java A a = root.getOptA(); // new method on A: diff --git a/pages/docs/using.md b/pages/docs/using.md index d4d2a30bea5b060e1ccd071b5b2b9e0730c41357..87d91925f1fdd176faa57f724193dd24a1f5accc 100644 --- a/pages/docs/using.md +++ b/pages/docs/using.md @@ -47,7 +47,7 @@ Otherwise, the deprecated manual dependencies must be used. ### Dependency tracking: Automatically derived -To automatically track dependencies, the two additional parameters `--incremental` and `--trace=flush` have to be provided to both RagConnect and (in the later stage) JastAdd. +To automatically track dependencies, the two additional parameters `--incremental` and `--tracing=flush` have to be provided to both RagConnect and (in the later stage) JastAdd. This will generate a different implementation of RagConnect relying on enabled incremental evaluation of JastAdd. The value for `incremental` has only been tested for `incremental=param`. The value for `trace` can include other values besides `flush`. diff --git a/ragconnect.base/src/main/jastadd/Handlers.jrag b/ragconnect.base/src/main/jastadd/Handlers.jrag index 57c7ccda67ae38524dc46de4f1db192cc345cb91..e64a8c5d0db5467f9a4b0d7451e8c38ab22a8bbf 100644 --- a/ragconnect.base/src/main/jastadd/Handlers.jrag +++ b/ragconnect.base/src/main/jastadd/Handlers.jrag @@ -1,4 +1,5 @@ aspect RagConnectHandlers { + syn Handler RagConnect.javaHandler() = resolveHandlerByName("java"); syn Handler RagConnect.mqttHandler() = resolveHandlerByName("mqtt"); syn Handler RagConnect.restHandler() = resolveHandlerByName("rest"); diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd index 69ff5d8932cd33a97e44b2fa3562b13cd52617f2..95f9b865b7217091537e954fa8ac98c292e45822 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.jadd +++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd @@ -15,6 +15,10 @@ aspect SharedMustache { syn boolean RagConnect.configExperimentalJastAdd329() = getConfiguration().getExperimentalJastAdd329(); + syn boolean RagConnect.configEvaluationCounter() = getConfiguration().getEvaluationCounter(); + + syn String RagConnect.evaluationCounterVariable() = internalRagConnectPrefix() + "evaluationCounter"; + syn String RagConnect.internalRagConnectPrefix() = "_ragconnect_"; syn String RagConnect.logDebug() = logStatement("debug"); @@ -99,6 +103,10 @@ aspect MustacheHandler { // === RagConnect === syn String RagConnect.closeMethodName() = "ragconnectCloseConnections"; + syn String RagConnect.evaluationCounterInnerClass() = internalRagConnectPrefix() + "Counter"; + + syn String RagConnect.evaluationCounterSummaryMethodName() = "ragconnectEvaluationCounterSummary"; + syn boolean RagConnect.hasRootTypeComponents() = !rootTypeComponents().isEmpty(); syn List<TypeComponent> RagConnect.rootTypeComponents() { @@ -118,6 +126,10 @@ aspect MustacheHandler { syn String Handler.fieldName() = ragconnect().internalRagConnectPrefix() + getUniqueName() + "Handler"; + syn String Handler.pushMethodName() = "ragconnect" + capitalize(getUniqueName()) + "Push"; + + syn String Handler.registerConsumerMethodName() = "ragconnect" + capitalize(getUniqueName()) + "RegisterConsumer"; + syn String Handler.setupWaitUntilReadyMethodName() = "ragconnectSetup" + capitalize(getUniqueName()) + "WaitUntilReady"; } diff --git a/ragconnect.base/src/main/jastadd/Mappings.jrag b/ragconnect.base/src/main/jastadd/Mappings.jrag index 9fd55aa4cad7eb22f75913f7942b547ca91ddec2..e92fc4fa27569ee353b0c16798e2ce3b7eb07a29 100644 --- a/ragconnect.base/src/main/jastadd/Mappings.jrag +++ b/ragconnect.base/src/main/jastadd/Mappings.jrag @@ -243,7 +243,7 @@ aspect Mappings { return getEndpointTarget().isTypeEndpointTarget() && typeIsList() && !getIndexBasedListAccess() ? ragconnect().defaultBytesToListMapping(typeDecl.getName()) : ragconnect().defaultBytesToTreeMapping(typeDecl.getName()); } catch (Exception ignore) { } - System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this); + System.err.println("Could not find suitable default receive mapping for " + targetTypeName() + " on " + this); return null; } } @@ -287,7 +287,7 @@ aspect Mappings { } catch (Exception ignore) { // exception should be logged to debug/fine } - System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this); + System.err.println("Could not find suitable default send mapping for " + targetTypeName() + " on " + this); return null; } } diff --git a/ragconnect.base/src/main/jastadd/RagConnect.relast b/ragconnect.base/src/main/jastadd/RagConnect.relast index cf12d73202b144240ed929ba499d99a8e797aa89..df50e3dab1dde22e38bca0588396de647b49c8cb 100644 --- a/ragconnect.base/src/main/jastadd/RagConnect.relast +++ b/ragconnect.base/src/main/jastadd/RagConnect.relast @@ -40,5 +40,6 @@ Configuration ::= <JastAddOpt:String> <IncrementalOptionActive:boolean> <CacheAllOptionActive:boolean> +<EvaluationCounter:boolean> <ExperimentalJastAdd329:boolean>; rel Configuration.RootNode -> TypeDecl ; diff --git a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java index 8d4ab2ce26452684112ecebc9885591f82124cb4..fdb52151104f2ba8d3eb18a7487f9102ffcd19df 100644 --- a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java +++ b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java @@ -31,10 +31,12 @@ public class Compiler extends AbstractCompiler { private BooleanOption optionLogIncremental; private ValueOption optionLogTarget; private BooleanOption optionExperimentalJastAdd329; + private BooleanOption optionEvaluationCounter; private static final String OPTION_LOGGING_TARGET_CONSOLE = "console"; private static final String OPTION_LOGGING_TARGET_SLF4J = "slf4j"; + private static final String OPTION_PROTOCOL_JAVA = "java"; private static final String OPTION_PROTOCOL_MQTT = "mqtt"; private static final String OPTION_PROTOCOL_REST = "rest"; @@ -179,6 +181,7 @@ public class Compiler extends AbstractCompiler { new ValueOption("protocols", "Protocols to enable") .acceptMultipleValues(true) .addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT") + .addAcceptedValue(OPTION_PROTOCOL_JAVA, "Enable Java (experimental)") .addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST") ); optionPrintYaml = addOption( @@ -204,6 +207,9 @@ public class Compiler extends AbstractCompiler { optionExperimentalJastAdd329 = addOption( new BooleanOption("experimental-jastadd-329", "Use trace events INC_FLUSH_START and INC_FLUSH_END (JastAdd issue #329).") .defaultValue(false)); + optionEvaluationCounter = addOption( + new BooleanOption("evaluationCounter", "Enable counters for evaluation.") + .defaultValue(false)); } private RagConnect parseProgram(Collection<String> files) throws CompilerException { @@ -299,15 +305,16 @@ public class Compiler extends AbstractCompiler { * Set all configuration values. * @param ragConnect the RagConnect instance to set configuration values */ - private void setConfiguration(RagConnect ragConnect) { + private void setConfiguration(RagConnect ragConnect) throws CompilerException { ragConnect.setConfiguration(new Configuration()); ragConnect.getConfiguration().setLoggingEnabledForReads(optionLogReads.value()); ragConnect.getConfiguration().setLoggingEnabledForWrites(optionLogWrites.value()); ragConnect.getConfiguration().setLoggingEnabledForIncremental(optionLogIncremental.value()); ragConnect.getConfiguration().setLoggingTarget(optionLogTarget.value()); ragConnect.getConfiguration().setExperimentalJastAdd329(optionExperimentalJastAdd329.value()); + ragConnect.getConfiguration().setEvaluationCounter(optionEvaluationCounter.value()); - // reuse "--incremental" and "--trace=flush" options of JastAdd + // reuse "--incremental" and "--tracing=flush" options of JastAdd boolean incrementalOptionActive = this.getConfiguration().incremental() && this.getConfiguration().traceFlush(); ragConnect.getConfiguration().setIncrementalOptionActive(incrementalOptionActive); if (isVerbose()) { @@ -326,11 +333,12 @@ public class Compiler extends AbstractCompiler { rootNode = ragConnect.getProgram().resolveTypeDecl(optionRootNode.value()); } catch (RuntimeException re) { // root node was not found - throw new RuntimeException("Could not resolve root node '" + optionRootNode.value() + "'!", re); + throw new CompilerException("Could not resolve root node '" + optionRootNode.value() + "'!", re); } ragConnect.getConfiguration().setRootNode(rootNode); // Handler ::= <ClassName> <UniqueName> <InUse:boolean>; + ragConnect.addHandler(new Handler("JavaHandler", "java", optionProtocols.hasValue(OPTION_PROTOCOL_JAVA))); ragConnect.addHandler(new Handler("MqttServerHandler", "mqtt", optionProtocols.hasValue(OPTION_PROTOCOL_MQTT))); ragConnect.addHandler(new Handler("RestServerHandler", "rest", optionProtocols.hasValue(OPTION_PROTOCOL_REST))); } diff --git a/ragconnect.base/src/main/resources/JavaHandler.mustache b/ragconnect.base/src/main/resources/JavaHandler.mustache new file mode 100644 index 0000000000000000000000000000000000000000..d8d907b2969b114517eaf9944428a6cefd9842fc --- /dev/null +++ b/ragconnect.base/src/main/resources/JavaHandler.mustache @@ -0,0 +1,82 @@ +/** + * Singleton class providing routing functionality for byte[] based message calls. + */ +public class JavaHandler { + public static JavaHandler JAVA_HANDLER_INSTANCE = null; + private java.util.Map<String, java.util.List<java.util.function.BiConsumer<String, byte[]>>> callbackList = new java.util.concurrent.ConcurrentHashMap<>(); + private final java.util.Map<RagConnectToken, java.util.function.BiConsumer<String, byte[]>> tokensForRemoval = new java.util.HashMap<>(); + private String name; + + private JavaHandler() { + this("RagConnect"); + } + + public JavaHandler(String name) { + this.name = name; + } + + private static String extractPath(java.net.URI uri) { + String path = uri.getPath(); + if (path.charAt(0) == '/') { + path = path.substring(1); + } + return path; + } + + RagConnectToken registerConsumer(String path, java.util.function.Consumer<byte[]> consumer) { + RagConnectToken token = new RagConnectToken(java.net.URI.create("internal://host/" + path), null); + registerCallback(token, (s, bytes) -> consumer.accept(bytes)); + return token; + } + + boolean registerCallback(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) { + String path = extractPath(connectToken.uri); + {{logInfo}}("[JAVA_HANDLER] Registering new callback for {{log_}}.", path); + + java.util.List<java.util.function.BiConsumer<String, byte[]>> registeredCallbacks = callbackList.get(path); + + if (registeredCallbacks == null) { + registeredCallbacks = java.util.Collections.synchronizedList(new java.util.ArrayList<>()); + callbackList.put(path, registeredCallbacks); + } + registeredCallbacks.add(callback); + tokensForRemoval.put(connectToken, callback); + + return true; + } + + boolean unregisterCallback(RagConnectToken connectToken) { + String path = extractPath(connectToken.uri); + java.util.function.BiConsumer<String, byte[]> callback = tokensForRemoval.get(connectToken); + {{logInfo}}("[JAVA_HANDLER] Unregistering callback with uuid: on path: {{log_}}", path); + + return callbackList.get(path).remove(callback); + } + + void close() { + } + + boolean push(String uriString, byte[] data) { + String path = extractPath(java.net.URI.create(uriString)); + {{logDebug}}("[JAVA_HANDLER] Pushing a message for {{log_}}.", path); + if (data == null) { + {{logDebug}}("[JAVA_HANDLER] data was null, aborting"); + return false; + } + String dataString = new String(data); + {{logDebug}}("[JAVA_HANDLER] Data: {{log_}}", dataString); + + java.util.List<java.util.function.BiConsumer<String, byte[]>> callbacks = callbackList.get(path); + + if (callbacks == null) { + {{logError}}("[JAVA_HANDLER] Could not publish message. No callback registered for path {{log_}}", path); + return false; + } + + for (java.util.function.BiConsumer<String, byte[]> callback : callbacks) { + callback.accept(path, data); + } + + return true; + } +} diff --git a/ragconnect.base/src/main/resources/handleUri.mustache b/ragconnect.base/src/main/resources/handleUri.mustache index 2312cd6983822c0e0b2987459047b7ca2a277fc2..efb4aacfbf1e003dcb540ba77bdaca68a8aed6cd 100644 --- a/ragconnect.base/src/main/resources/handleUri.mustache +++ b/ragconnect.base/src/main/resources/handleUri.mustache @@ -10,14 +10,14 @@ try { return false; } if (scheme == null || scheme.isBlank()) { - {{logError}}("Missing or empty scheme in " + uri); + {{logError}}("Missing or empty scheme in {{log_}}", uri); return false; } if (host == null || host.isBlank()) { - {{logError}}("Missing or empty host in " + uri); + {{logError}}("Missing or empty host in {{log_}}", uri); return false; } if (path == null || path.isBlank()) { - {{logError}}("Missing or empty path in " + uri); + {{logError}}("Missing or empty path in {{log_}}", uri); return false; } diff --git a/ragconnect.base/src/main/resources/handler.mustache b/ragconnect.base/src/main/resources/handler.mustache index 49194266f96e84a4c24bc0987b83647082132dc2..75bd14ce26638ceeee267251988a01b516de0970 100644 --- a/ragconnect.base/src/main/resources/handler.mustache +++ b/ragconnect.base/src/main/resources/handler.mustache @@ -19,18 +19,30 @@ aspect RagConnectHandler { {{/configIncrementalOptionActive}} } +{{#javaHandler}} + {{#InUse}} + public RagConnectToken {{rootNodeName}}.{{registerConsumerMethodName}}(String path, java.util.function.Consumer<byte[]> consumer) { + return {{fieldName}}.registerConsumer(path, consumer); + } + public boolean {{rootNodeName}}.{{pushMethodName}}(String uriString, byte[] data) { + return {{fieldName}}.push(uriString, data); + } + {{> JavaHandler}} + {{/InUse}} +{{/javaHandler}} + {{#mqttHandler}} {{#InUse}} public void {{rootNodeName}}.{{setupWaitUntilReadyMethodName}}(long time, java.util.concurrent.TimeUnit unit) { {{fieldName}}.setupWaitUntilReady(time, unit); } + {{> MqttHandler}} {{/InUse}} -{{> MqttHandler}} {{/mqttHandler}} {{#restHandler}} {{#InUse}} -{{> RestHandler}} + {{> RestHandler}} {{/InUse}} {{/restHandler}} diff --git a/ragconnect.base/src/main/resources/mappingApplication.mustache b/ragconnect.base/src/main/resources/mappingApplication.mustache index 482d54783782ada82cacd9ce75b81d30c1e21e68..efd17af4e8947232f44b93c3749d86b1e637dd46 100644 --- a/ragconnect.base/src/main/resources/mappingApplication.mustache +++ b/ragconnect.base/src/main/resources/mappingApplication.mustache @@ -1,6 +1,12 @@ +{{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementCall("{{parentTypeName}}", "{{entityName}}"); +{{/configEvaluationCounter}} {{#Send}} {{^PrimitiveType}} if ({{firstInputVarName}} == null) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementFirstNull("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } {{/PrimitiveType}} @@ -12,13 +18,22 @@ try { {{/innerMappingDefinitions}} } catch (RagConnectRejectMappingException e) { // do not print message in case of rejection + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementReject("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } catch (Exception e) { e.printStackTrace(); + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementException("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } {{^AlwaysApply}} if ({{{condition}}}) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementSkip("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } {{/AlwaysApply}} diff --git a/ragconnect.base/src/main/resources/mappingDefinition.mustache b/ragconnect.base/src/main/resources/mappingDefinition.mustache index 5be93e4bdc91ca2eaa54f364eb8e5f7c069da2a5..b6a035eb41b9d3f877b731293203de399399e6c0 100644 --- a/ragconnect.base/src/main/resources/mappingDefinition.mustache +++ b/ragconnect.base/src/main/resources/mappingDefinition.mustache @@ -1,3 +1,3 @@ -protected static {{{toType}}} ASTNode.{{methodName}}({{{fromType}}} {{FromVariableName}}) throws Exception { +protected {{{toType}}} ASTNode.{{methodName}}({{{fromType}}} {{FromVariableName}}) throws Exception { {{{Content}}} } diff --git a/ragconnect.base/src/main/resources/ragconnect.mustache b/ragconnect.base/src/main/resources/ragconnect.mustache index ac7b906067f5f9ecd4a2bf0c51a368797f55dfbc..7e054a4927b527e6d32a30e32a6bffa71d86b97f 100644 --- a/ragconnect.base/src/main/resources/ragconnect.mustache +++ b/ragconnect.base/src/main/resources/ragconnect.mustache @@ -285,3 +285,98 @@ aspect RagConnectObserver { } } {{/configIncrementalOptionActive}} + +aspect EvaluationCounter { + public String ASTNode.{{evaluationCounterSummaryMethodName}}() { + {{#configEvaluationCounter}} + return {{evaluationCounterVariable}}.summary(); + {{/configEvaluationCounter}} + {{^configEvaluationCounter}} + String message = "Option --evaluationCounter was not set. No Summary available"; + {{logWarn}}(message); + return message; + {{/configEvaluationCounter}} + } +{{#configEvaluationCounter}} + static EvaluationCounter ASTNode.{{evaluationCounterVariable}} = new EvaluationCounter(); + + public class EvaluationCounter { + private java.util.Map<String, java.util.Map<String, {{evaluationCounterInnerClass}}>> counters = new java.util.HashMap<>(); + private final java.util.function.Function<? super String, ? extends java.util.Map<String, {{evaluationCounterInnerClass}}>> parentAbsent = key -> { + return new java.util.HashMap<>(); + }; + private final java.util.function.Function<? super String, ? extends {{evaluationCounterInnerClass}}> entityAbsent = key -> { + return new {{evaluationCounterInnerClass}}(); + }; + + public void incrementReceive(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).receive += 1; + } + + public void incrementSend(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).send += 1; + } + + public void incrementCall(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).call += 1; + } + + public void incrementFirstNull(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).firstNull += 1; + } + + public void incrementSkip(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).skip += 1; + } + + public void incrementException(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).exception += 1; + } + + public void incrementReject(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).reject += 1; + } + + public String summary() { + StringBuilder sb = new StringBuilder(); + // header + sb.append("parentTypeName,entityName,receive,send,call,firstNull,skip,exception,reject").append("\n"); + // values + java.util.Set<String> sortedParentTypes = new java.util.TreeSet<>(counters.keySet()); + for (String parentType : sortedParentTypes) { + java.util.Set<String> sortedEntityNames = new java.util.TreeSet<>(counters.get(parentType).keySet()); + for (String entityName : sortedEntityNames) { + {{evaluationCounterInnerClass}} count = getCounter(parentType, entityName); + java.util.StringJoiner sj = new java.util.StringJoiner(",", "", "\n"); + sj.add(parentType) + .add(entityName) + .add(Integer.toString(count.receive)) + .add(Integer.toString(count.send)) + .add(Integer.toString(count.call)) + .add(Integer.toString(count.firstNull)) + .add(Integer.toString(count.skip)) + .add(Integer.toString(count.exception)) + .add(Integer.toString(count.reject)) + ; + sb.append(sj); + } + } + return sb.toString(); + } + + private {{evaluationCounterInnerClass}} getCounter(String parentTypeName, String entityName) { + return counters.computeIfAbsent(parentTypeName, parentAbsent).computeIfAbsent(entityName, entityAbsent); + } + } + + class {{evaluationCounterInnerClass}} { + int receive = 0; + int send = 0; + int call = 0; + int firstNull = 0; + int skip = 0; + int exception = 0; + int reject = 0; + } +{{/configEvaluationCounter}} +} diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache index cb4dc8dc718eba53b0cd6a3bce9b4f996cdd4675..81b0ecbbd96aa40155ec8f396549a4af2160b64e 100644 --- a/ragconnect.base/src/main/resources/receiveDefinition.mustache +++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache @@ -25,6 +25,9 @@ private int {{parentTypeName}}.{{resolveInListMethodName}}(String topic) { */ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParameterName}}{{#typeIsList}}{{#IndexBasedListAccess}}{{^WithAdd}}, int index{{/WithAdd}}{{/IndexBasedListAccess}}{{/typeIsList}}) throws java.io.IOException { java.util.function.BiConsumer<String, byte[]> consumer = (topic, message) -> { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementReceive("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{> mappingApplication}} {{#configLoggingEnabledForReads}} {{logDebug}}("[Receive] {{log_}} -> {{entityName}} = {{log_}}", {{connectParameterName}}, {{lastResult}}); @@ -70,6 +73,9 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete */ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParameterName}}) throws java.io.IOException { java.util.function.BiConsumer<String, byte[]> consumer = (topic, message) -> { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementReceive("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} int index = {{resolveInListMethodName}}(topic); {{> mappingApplication}} {{#configLoggingEnabledForReads}} @@ -93,6 +99,13 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec RagConnectToken connectToken = new RagConnectToken(uri, "{{entityName}}"); boolean success; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": + success = {{attributeName}}().registerCallback(connectToken, consumer); + break; + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": @@ -130,6 +143,12 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam } RagConnectDisconnectHandlerMethod disconnectingMethod; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": disconnectingMethod = {{attributeName}}()::unregisterCallback; + break; + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": disconnectingMethod = {{attributeName}}()::disconnect; diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 1e66fdedcc7620aefe31a89fcece47dbcf9708ac..abcbdffe2d4f7aaff5dfce8700cb11e72ec8d83d 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -5,6 +5,22 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete RagConnectToken connectToken = new RagConnectToken(uri, "{{entityName}}"); boolean success; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": + final JavaHandler handler = {{attributeName}}(); + + {{senderName}}.add(() -> { + handler.push(path, {{lastValueGetterCall}}); + }{{#IndexBasedListAccess}}, index{{/IndexBasedListAccess}}, connectToken); + {{updateMethodName}}(); + if (writeCurrentValue) { + {{writeMethodName}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}connectToken); + } + success = true; + break; + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": @@ -78,6 +94,13 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam {{/configIncrementalOptionActive}} RagConnectDisconnectHandlerMethod disconnectingMethod; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": + disconnectingMethod = {{senderName}}::remove; + break; + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": @@ -111,14 +134,25 @@ protected boolean {{parentTypeName}}.{{updateMethodName}}({{#IndexBasedListAcces {{> mappingApplication}} {{lastValueSetter}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}{{lastResult}}); // normally we would return true here. unless no connect method was called so far to initialize {{senderName}} yet + {{#configEvaluationCounter}} + if ({{senderName}} == null) { + {{evaluationCounterVariable}}.incrementSkip("{{parentTypeName}}", "{{entityName}}"); + } + {{/configEvaluationCounter}} return {{senderName}} != null; } protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}int index{{/IndexBasedListAccess}}) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementSend("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{senderName}}.run({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}}); } protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}int index, {{/IndexBasedListAccess}}RagConnectToken token) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementSend("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{senderName}}.run({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}token); } diff --git a/ragconnect.tests/.gitignore b/ragconnect.tests/.gitignore index 87b4cdd3d7c6a41502ca98703abeeb69a1d536fb..31993cebfe5fdbd5c2727c631ebfec8394963232 100644 --- a/ragconnect.tests/.gitignore +++ b/ragconnect.tests/.gitignore @@ -3,3 +3,4 @@ src/gen-res/ src/gen/ out/ *.class +test.log diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 18dd839d9f8ec04684cdc45d2e40d1dacbf83362..4da4ee9ea07110aa3e91cc18a71074f19155c079 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -70,6 +70,8 @@ dependencies { testImplementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' api group: 'com.google.protobuf', name: 'protobuf-java', version: '3.0.0' + + implementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: "1.0.2-68" } // --- Preprocessors --- @@ -649,9 +651,7 @@ task compileRelationIncremental(type: RagConnectTest) { inputFiles = [file('src/test/01-input/relation/Test.relast'), file('src/test/01-input/relation/Test.connect')] rootNode = 'Root' - logWrites = true - logIncremental = true - extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329']) + extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329', '--evaluationCounter']) } relast { useJastAddNames = true @@ -666,9 +666,31 @@ task compileRelationIncremental(type: RagConnectTest) { } } +// --- Test: java-incremental --- +task compileJavaIncremental(type: RagConnectTest) { + ragconnect { + outputDir = file('src/test/02-after-ragconnect/javaInc') + inputFiles = [file('src/test/01-input/java/Test.relast'), + file('src/test/01-input/java/Test.connect')] + rootNode = 'Root' + protocols = ['java'] + extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329', '--evaluationCounter']) + } + relast { + useJastAddNames = true + grammarName = 'src/test/03-after-relast/javaInc/javaInc' + serializer = 'jackson' + } + jastadd { + jastAddList = 'JastAddList' + packageName = 'javaInc.ast' + inputFiles = [file('src/test/01-input/java/Test.jadd')] + extraOptions = JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL + } +} + // --- Task order --- classes.dependsOn(':ragconnect.base:jar') -//compileAttributeIncremental.outputs.upToDateWhen { false } // --- Misc --- static ArrayList<String> defaultRagConnectOptionsAnd(ArrayList<String> options = []) { diff --git a/ragconnect.tests/src/test/01-input/java/README.md b/ragconnect.tests/src/test/01-input/java/README.md new file mode 100644 index 0000000000000000000000000000000000000000..272a8518ce52567f6528810d1c3225a163675be5 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/README.md @@ -0,0 +1,3 @@ +# Java + +Idea: Use receive and send definitions using the Java handler. diff --git a/ragconnect.tests/src/test/01-input/java/Test.connect b/ragconnect.tests/src/test/01-input/java/Test.connect new file mode 100644 index 0000000000000000000000000000000000000000..d516cfe5cda16dbd0c50a3f485d5477d704ecdba --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/Test.connect @@ -0,0 +1,26 @@ +send SenderRoot.SendToken ; +send SenderRoot.SendNode ; +send SenderRoot.SendManyNode ; +send SenderRoot.SendNTA ; + +AddSuffix maps A a to A {: + A result = new A(); + String changedValue = a.getValue() + "-post"; + result.setValue(changedValue); + result.setInner(new Inner(a.getInner().getInnerValue() + "-post")); + return result; +:} + +AddStringSuffix maps String s to String {: + return s + "post"; +:} + +AddPlusOne maps int i to int {: + return i + 1; +:} + +receive ReceiverRoot.SomeToken; +receive ReceiverRoot.SomeNode; +receive ReceiverRoot.SomeNodeWithMapping using AddSuffix; +receive ReceiverRoot.ManyNode; +receive ReceiverRoot.NTA; diff --git a/ragconnect.tests/src/test/01-input/java/Test.jadd b/ragconnect.tests/src/test/01-input/java/Test.jadd new file mode 100644 index 0000000000000000000000000000000000000000..0bb643ed9a95cf0ca83d312d7cb9717eaacc2436 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/Test.jadd @@ -0,0 +1,30 @@ +aspect Computation { + syn String SenderRoot.basic() = getInput(); + syn String SenderRoot.simple() = getInput() + "Post"; + syn A SenderRoot.getSendNTA() { + A result = new A(); + result.setValue(getInput()); + Inner inner = new Inner(); + inner.setInnerValue("1"); + result.setInner(inner); + return result; + } +} +aspect MakeCodeCompile { + +} +aspect MakeCodeWork { + +} +aspect NameResolution { + // overriding customID guarantees to produce the same JSON representation for equal lists + // otherwise, the value for id is different each time + @Override + protected String A.customID() { + return getClass().getSimpleName() + getValue(); + } + @Override + protected String Inner.customID() { + return getClass().getSimpleName() + getInnerValue(); + } +} diff --git a/ragconnect.tests/src/test/01-input/java/Test.relast b/ragconnect.tests/src/test/01-input/java/Test.relast new file mode 100644 index 0000000000000000000000000000000000000000..62a23c231f4f54a99fad7d104173c3128b64393d --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/Test.relast @@ -0,0 +1,10 @@ +Root ::= SenderRoot* ReceiverRoot; +SenderRoot ::= <Input> <SendToken> SendNode:A SendManyNode:A* /SendNTA:A/ ; +ReceiverRoot ::= + <SomeToken> + SomeNode:A + SomeNodeWithMapping:A + ManyNode:A* + NTA:A; +A ::= <Value> Inner ; +Inner ::= <InnerValue> ; 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 c537a1db389f34545e59fc9c45f3525ce421dd75..61fc420c7e984070983dbfc181feb3519f7f1aa1 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 @@ -14,14 +14,12 @@ import java.util.concurrent.TimeUnit; * @author rschoene - Initial contribution */ @Tag("mqtt") -public abstract class AbstractMqttTest { +public abstract class AbstractMqttTest extends RagConnectTest { private static boolean checkDone = false; protected static MqttHandler publisher; - protected Logger logger = LoggerFactory.getLogger(getClass()); - /** * if the initial/current value shall be sent upon connecting */ @@ -61,7 +59,6 @@ public abstract class AbstractMqttTest { public final void testCommunicateSendInitialValue() throws IOException, InterruptedException { this.writeCurrentValue = true; - logger.debug("Start testCommunicateSendInitialValue"); createModel(); setupReceiverAndConnect(); @@ -80,7 +77,6 @@ public abstract class AbstractMqttTest { public final void testCommunicateOnlyUpdatedValue() throws IOException, InterruptedException { this.writeCurrentValue = false; - logger.debug("Start testCommunicateOnlyUpdatedValue"); createModel(); setupReceiverAndConnect(); diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java index d774d91d91fefab6b86d0b0bdf2f2c8e4e72d729..9d4c730ad3fa8a27e8de22a10f80d4594ff3dbf9 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java @@ -22,9 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * * @author rschoene - Initial contribution */ -public class Errors { +public class Errors extends RagConnectTest { - private static final Logger logger = LoggerFactory.getLogger(Errors.class); private static final String ERROR_DIRECTORY = "errors/"; private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + ERROR_DIRECTORY; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0c33e9c65e346a45fd4458428a81a273a9cf8148 --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -0,0 +1,246 @@ +package org.jastadd.ragconnect.tests; + +import javaInc.ast.*; +import org.assertj.core.groups.Tuple; +import org.jastadd.ragconnect.tests.TestUtils.TestChecker; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.List; + +import static org.assertj.core.api.Assertions.tuple; +import static org.jastadd.ragconnect.tests.TestUtils.javaUri; +import static org.junit.jupiter.api.Assertions.*; + +/** + * Testing the Java handler. + * + * @author rschoene - Initial contribution + */ +public class JavaTest extends RagConnectTest { + + private static final String TOPIC_RECEIVE_TOKEN = "receiveToken"; + private static final String TOPIC_RECEIVE_NODE_PLAIN = "receiveNode/plain"; + private static final String TOPIC_RECEIVE_NODE_MAPPED = "receiveNode/mapped"; + private static final String TOPIC_RECEIVE_MANY = "receiveMany"; + private static final String TOPIC_RECEIVE_NTA = "receiveNTA"; + + private static final String TOPIC_SEND_TOKEN = "sendToken"; + private static final String TOPIC_SEND_NODE = "sendNode"; + private static final String TOPIC_SEND_MANY = "sendMany"; + private static final String TOPIC_SEND_NTA = "sendNTA"; + + private Root model; + private SenderRoot senderRoot; + private ReceiverRoot receiverRoot; + + private String lastValueToken; + private A lastValueNode; + private JastAddList<A> lastValueMany; + private A lastValueNTA; + private TestChecker checker; + + void createModel() { + model = new Root(); + senderRoot = new SenderRoot().setInput("1").setSendNode(createA("1")); + receiverRoot = new ReceiverRoot(); + model.addSenderRoot(senderRoot); + model.setReceiverRoot(receiverRoot); + } + + private static A createA(String value) { + return new A().setValue(value).setInner(new Inner("inner")); + } + + private void setupReceiverAndConnect(boolean writeCurrentValue) throws IOException { + // checker + checker = new TestChecker(); + checker.setActualString(TOPIC_SEND_TOKEN, () -> lastValueToken) + .setCheckForString(TOPIC_SEND_NODE, (name, expected) -> checkA(expected, lastValueNode, name)) + .setCheckForTuple(TOPIC_SEND_MANY, (name, expected) -> checkAList(expected, lastValueMany, name)) + .setCheckForString(TOPIC_SEND_NTA, (name, expected) -> checkA(expected, lastValueNTA, name)) + .setActualString(TOPIC_RECEIVE_TOKEN, () -> receiverRoot.getSomeToken()) + .setCheckForString(TOPIC_RECEIVE_NODE_PLAIN, (name, expected) -> + checkA(expected, receiverRoot.getSomeNode(), name)) + .setCheckForString(TOPIC_RECEIVE_NODE_MAPPED, (name, expected) -> + checkA(expected, receiverRoot.getSomeNodeWithMapping(), name)) + .setCheckForTuple(TOPIC_RECEIVE_MANY, (name, expected) -> + checkAList(expected, receiverRoot.getManyNodeList(), name)) + .setCheckForString(TOPIC_RECEIVE_NTA, (name, expected) -> + checkA(expected, receiverRoot.getNTA(), name)) + .put(TOPIC_RECEIVE_TOKEN, "") + .put(TOPIC_RECEIVE_MANY, tuple()) + .setActualNumberOfValues(() -> 0) + .disableManualWait(); + + // callbacks + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_TOKEN, bytes -> lastValueToken = new String(bytes)); + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_NODE, bytes -> lastValueNode = ExposingASTNode.INSTANCE.bytesToA(bytes)); + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_MANY, bytes -> lastValueMany = ExposingASTNode.INSTANCE.bytesToList(bytes)); + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_NTA, bytes -> lastValueNTA = ExposingASTNode.INSTANCE.bytesToA(bytes)); + + // receive + receiverRoot.connectSomeToken(javaUri(TOPIC_RECEIVE_TOKEN)); + receiverRoot.connectSomeNode(javaUri(TOPIC_RECEIVE_NODE_PLAIN)); + receiverRoot.connectSomeNodeWithMapping(javaUri(TOPIC_RECEIVE_NODE_MAPPED)); + receiverRoot.connectManyNodeList(javaUri(TOPIC_RECEIVE_MANY)); + receiverRoot.connectNTA(javaUri(TOPIC_RECEIVE_NTA)); + + // send + senderRoot.connectSendToken(javaUri(TOPIC_SEND_TOKEN), writeCurrentValue); + senderRoot.connectSendNode(javaUri(TOPIC_SEND_NODE), writeCurrentValue); + senderRoot.connectSendManyNodeList(javaUri(TOPIC_SEND_MANY), writeCurrentValue); + senderRoot.connectSendNTA(javaUri(TOPIC_SEND_NTA), writeCurrentValue); + } + + @Test + public void testCommunicateSendInitialValue() throws IOException { + createModel(); + setupReceiverAndConnect(true); + checker.put(TOPIC_SEND_TOKEN, "") + .put(TOPIC_SEND_NODE, "1") + .put(TOPIC_SEND_MANY, tuple()) + .put(TOPIC_SEND_NTA, "1|1") + ; + + communicateBoth(); + } + + @Test + public void testCommunicateOnlyUpdatedValue() throws IOException { + createModel(); + setupReceiverAndConnect(false); + + checker.put(TOPIC_SEND_TOKEN, (String) null) + .put(TOPIC_SEND_NODE, (String) null) + .put(TOPIC_SEND_MANY, (Tuple) null) + .put(TOPIC_SEND_NTA, (String) null) + ; + + communicateBoth(); + } + + private void communicateBoth() { + checker.check(); + + senderRoot.setInput("2"); + checker.put(TOPIC_SEND_NTA, "2|1").check(); + + senderRoot.getSendNode().setValue("3"); + checker.put(TOPIC_SEND_NODE, "3").check(); + + senderRoot.setSendToken("test-4"); + checker.put(TOPIC_SEND_TOKEN, "test-4").check(); + + senderRoot.addSendManyNode(createA("5")); + checker.put(TOPIC_SEND_MANY, tuple("5")).check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_TOKEN, ExposingASTNode.INSTANCE.stringToBytes("7")); + checker.put(TOPIC_RECEIVE_TOKEN, "7").check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_NODE_PLAIN, ExposingASTNode.INSTANCE.aToBytes(createA("8"))); + checker.put(TOPIC_RECEIVE_NODE_PLAIN, "8").check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_NODE_MAPPED, ExposingASTNode.INSTANCE.aToBytes(createA("9"))); + checker.put(TOPIC_RECEIVE_NODE_MAPPED, "9-post|inner-post").check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_MANY, ExposingASTNode.INSTANCE.listToBytes(new JastAddList<>(createA("10"), createA("11")))); + checker.put(TOPIC_RECEIVE_MANY, tuple("10", "11")).check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_NTA, ExposingASTNode.INSTANCE.aToBytes(createA("12"))); + checker.put(TOPIC_RECEIVE_NTA, "12").check(); + + System.out.println(model.ragconnectEvaluationCounterSummary()); + } + + private void checkA(String expectedValue, A actual, String alias) { + if (expectedValue == null) { + assertNull(actual, alias); + } else { + final String expectedValueInA, expectedInnerValue; + if (expectedValue.contains("|")) { + String[] tokens = expectedValue.split("\\|"); + expectedValueInA = tokens[0]; + expectedInnerValue = tokens[1]; + } else { + expectedValueInA = expectedValue; + expectedInnerValue = "inner"; + } + assertNotNull(actual, alias); + assertEquals(expectedValueInA, actual.getValue(), alias); + assertNotNull(actual.getInner(), alias + ".inner"); + assertEquals(expectedInnerValue, actual.getInner().getInnerValue(), alias + ".inner"); + } + } + + private void checkAList(Tuple expectedTuple, JastAddList<A> actual, String alias) { + if (expectedTuple == null) { + assertNull(actual, alias); + return; + } + List<Object> expected = expectedTuple.toList(); + assertEquals(expected.size(), actual.getNumChild(), alias + ".size"); + for (int i = 0, expectedSize = expected.size(); i < expectedSize; i++) { + String s = (String) expected.get(i); + checkA(s, actual.getChild(i), alias + "[" + i + "]"); + } + } + + @AfterEach + public void alwaysCloseConnections() { + logger.debug("Closing connections"); + if (model != null) { + model.ragconnectCloseConnections(); + } + } + + @SuppressWarnings({"rawtypes" , "unchecked"}) + static class ExposingASTNode extends ASTNode { + static ExposingASTNode INSTANCE = new ExposingASTNode(); + + public A bytesToA(byte[] bytes) { + try { + return _ragconnect__apply__TreeDefaultBytesToAMapping(bytes); + } catch (Exception e) { + return null; + } + } + + public JastAddList<A> bytesToList(byte[] input) { + try { + return _ragconnect__apply__TreeDefaultBytesToJastAddListAListMapping(input); + } catch (Exception e) { + return null; + } + } + + public byte[] aToBytes(A input) { + try { + return _ragconnect__apply__TreeDefaultAToBytesMapping(input); + } catch (Exception e) { + return null; + } + } + + public byte[] listToBytes(JastAddList<A> input) { + try { + return _ragconnect__apply__TreeDefaultJastAddListToBytesMapping(input); + } catch (Exception e) { + return null; + } + } + + public byte[] stringToBytes(String input) { + try { + return _ragconnect__apply__DefaultStringToBytesMapping(input); + } catch (Exception e) { + return null; + } + } + } + +} diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java index 091990a64a31c01a6f2c59b934cfe15b6fb76ece..be61201ef687a72bc252380166cf1abbf5b82eb4 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java @@ -20,7 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @author rschoene - Initial contribution */ @Tag("mqtt") -public class MqttHandlerTest { +public class MqttHandlerTest extends RagConnectTest { @Test public void defaultBehaviour() { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RagConnectTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RagConnectTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e2da1577980ad00b644f3f95c25d7e66ca11be79 --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RagConnectTest.java @@ -0,0 +1,26 @@ +package org.jastadd.ragconnect.tests; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base for all RagConnect tests. + * + * @author rschoene - Initial contribution + */ +public class RagConnectTest { + protected Logger logger = LoggerFactory.getLogger(getClass()); + + @BeforeEach + public void logStart(TestInfo testInfo) { + logger.info("Starting {}.{}", getClass().getSimpleName(), testInfo.getDisplayName()); + } + + @AfterEach + public void logEnd(TestInfo testInfo) { + logger.info("Finished {}.{}", getClass().getSimpleName(), testInfo.getDisplayName()); + } +} diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java index 67c82177d96fe34c6379b9d62537f785292827df..5f74942484f67dae810feb70e92d573ecebf9aba 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java @@ -17,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.*; * * @author rschoene - Initial contribution */ -public class RegressionTests { +public class RegressionTests extends RagConnectTest { private static final String REGRESSION_TEST_OUTPUT_DIRECTORY = "regression-test/"; 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 3457ce0c69123ebbc31853e69af5e84b5ddf827b..3fb3e225d1003fb92b576a3fa1bb345a6b0302d9 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 @@ -62,6 +62,10 @@ public class TestUtils { return "rest://localhost:" + port + "/" + path; } + public static String javaUri(String path) { + return "java://localhost/" + path; + } + public static int getMqttDefaultPort() { return 1883; } @@ -213,71 +217,117 @@ public class TestUtils { awaitMqtt().alias(name).until(actual, Predicate.isEqual(expected)); } } + static class ValuesToCompare<T> { + protected final Map<String, ActualAndExpected<T>> values = new HashMap<>(); + protected final TestChecker parent; + + ValuesToCompare(TestChecker parent) { + this.parent = parent; + } + + public TestChecker setActual(String name, Callable<T> actual) { + values.computeIfAbsent(name, ActualAndExpected::new).actual = actual; + return parent; + } + + public TestChecker setCheck(String name, BiConsumer<String, T> check) { + values.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; + return parent; + } + + public TestChecker put(String name, T expected) { + values.computeIfAbsent(name, ActualAndExpected::new).expected = expected; + return parent; + } + + ActualAndExpected<T> get(String name) { + return values.get(name); + } + + void forEach(BiConsumer<? super String, ? super ActualAndExpected<T>> action) { + values.forEach(action); + } + } + static class IntegerValuesToCompare extends ValuesToCompare<Integer> { + IntegerValuesToCompare(TestChecker parent) { + super(parent); + } + + public TestChecker incNumberOfValues() { + return addToNumberOfValues(1); + } + + public TestChecker addToNumberOfValues(int increment) { + // if there is at least one call to this, we do not need to manually wait in the next check() + parent.needManualWait = false; + Integer currentExpected = values.computeIfAbsent(NUMBER_OF_VALUES, ActualAndExpected::new).expected; + return put(NUMBER_OF_VALUES, currentExpected + increment); + } + + public TestChecker setActualNumberOfValues(Callable<Integer> actual) { + setActual(NUMBER_OF_VALUES, actual); + values.get(NUMBER_OF_VALUES).expected = 0; + return parent; + } + } private final static String NUMBER_OF_VALUES = "numberOfValues"; - private final Map<String, ActualAndExpected<String>> stringValues = new HashMap<>(); - private final Map<String, ActualAndExpected<Tuple>> tupleValues = new HashMap<>(); - private final Map<String, ActualAndExpected<Integer>> intValues = new HashMap<>(); + public final ValuesToCompare<String> stringValues = new ValuesToCompare<>(this); + public final ValuesToCompare<Tuple> tupleValues = new ValuesToCompare<>(this); + public final IntegerValuesToCompare intValues = new IntegerValuesToCompare(this); private boolean needManualWait = true; + private boolean useManualWait = true; public TestChecker incNumberOfValues() { - return addToNumberOfValues(1); + return intValues.incNumberOfValues(); } public TestChecker addToNumberOfValues(int increment) { - // if there is at least one call to this, we do not need to manually wait in the next check() - needManualWait = false; - Integer currentExpected = intValues.computeIfAbsent(NUMBER_OF_VALUES, ActualAndExpected::new).expected; - return put(NUMBER_OF_VALUES, currentExpected + increment); + return intValues.addToNumberOfValues(increment); } public TestChecker setActualNumberOfValues(Callable<Integer> actual) { - setActualInteger(NUMBER_OF_VALUES, actual); - intValues.get(NUMBER_OF_VALUES).expected = 0; - return this; + return intValues.setActualNumberOfValues(actual); } public TestChecker setActualString(String name, Callable<String> actual) { - stringValues.computeIfAbsent(name, ActualAndExpected::new).actual = actual; - return this; + return stringValues.setActual(name, actual); } public TestChecker setCheckForString(String name, BiConsumer<String, String> check) { - stringValues.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; - return this; + return stringValues.setCheck(name, check); } public TestChecker put(String name, String expected) { - stringValues.computeIfAbsent(name, ActualAndExpected::new).expected = expected; - return this; + return stringValues.put(name, expected); } public TestChecker setActualTuple(String name, Callable<Tuple> actual) { - tupleValues.computeIfAbsent(name, ActualAndExpected::new).actual = actual; - return this; + return tupleValues.setActual(name, actual); } public TestChecker setCheckForTuple(String name, BiConsumer<String, Tuple> check) { - tupleValues.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; - return this; + return tupleValues.setCheck(name, check); } public TestChecker put(String name, Tuple expected) { - tupleValues.computeIfAbsent(name, ActualAndExpected::new).expected = expected; - return this; + return tupleValues.put(name, expected); } public TestChecker setActualInteger(String name, Callable<Integer> actual) { - intValues.computeIfAbsent(name, ActualAndExpected::new).actual = actual; - return this; + return intValues.setActual(name, actual); } public TestChecker setCheckForInteger(String name, BiConsumer<String, Integer> check) { - intValues.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; - return this; + return intValues.setCheck(name, check); } public TestChecker put(String name, Integer expected) { - intValues.computeIfAbsent(name, ActualAndExpected::new).expected = expected; + return intValues.put(name, expected); + } + + public TestChecker disableManualWait() { + useManualWait = false; + needManualWait = false; return this; } @@ -298,7 +348,7 @@ public class TestUtils { aae.check(name); } }); - needManualWait = true; + needManualWait = useManualWait; } } @@ -324,56 +374,56 @@ public class TestUtils { @SuppressWarnings({"unused", "rawtypes"}) public static class DefaultMappings { static class ReadNode extends defaultOnlyRead.ast.ASTNode { - public static boolean DefaultBytesToBooleanMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToBooleanMapping(input); + public boolean DefaultBytesToBooleanMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToBooleanMapping(input); } - public static int DefaultBytesToIntMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToIntMapping(input); + public int DefaultBytesToIntMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToIntMapping(input); } - public static short DefaultBytesToShortMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToShortMapping(input); + public short DefaultBytesToShortMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToShortMapping(input); } - public static long DefaultBytesToLongMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToLongMapping(input); + public long DefaultBytesToLongMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToLongMapping(input); } - public static float DefaultBytesToFloatMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToFloatMapping(input); + public float DefaultBytesToFloatMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToFloatMapping(input); } - public static double DefaultBytesToDoubleMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToDoubleMapping(input); + public double DefaultBytesToDoubleMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToDoubleMapping(input); } - public static char DefaultBytesToCharMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToCharMapping(input); + public char DefaultBytesToCharMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToCharMapping(input); } - public static String DefaultBytesToStringMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToStringMapping(input); + public String DefaultBytesToStringMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToStringMapping(input); } } static class WriteNode extends defaultOnlyWrite.ast.ASTNode { - public static byte[] DefaultBooleanToBytesMapping(boolean input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultBooleanToBytesMapping(input); + public byte[] DefaultBooleanToBytesMapping(boolean input) throws Exception { + return _ragconnect__apply__DefaultBooleanToBytesMapping(input); } - public static byte[] DefaultIntToBytesMapping(int input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultIntToBytesMapping(input); + public byte[] DefaultIntToBytesMapping(int input) throws Exception { + return _ragconnect__apply__DefaultIntToBytesMapping(input); } - public static byte[] DefaultShortToBytesMapping(short input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultShortToBytesMapping(input); + public byte[] DefaultShortToBytesMapping(short input) throws Exception { + return _ragconnect__apply__DefaultShortToBytesMapping(input); } - public static byte[] DefaultLongToBytesMapping(long input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultLongToBytesMapping(input); + public byte[] DefaultLongToBytesMapping(long input) throws Exception { + return _ragconnect__apply__DefaultLongToBytesMapping(input); } - public static byte[] DefaultFloatToBytesMapping(float input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultFloatToBytesMapping(input); + public byte[] DefaultFloatToBytesMapping(float input) throws Exception { + return _ragconnect__apply__DefaultFloatToBytesMapping(input); } - public static byte[] DefaultDoubleToBytesMapping(double input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultDoubleToBytesMapping(input); + public byte[] DefaultDoubleToBytesMapping(double input) throws Exception { + return _ragconnect__apply__DefaultDoubleToBytesMapping(input); } - public static byte[] DefaultCharToBytesMapping(char input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultCharToBytesMapping(input); + public byte[] DefaultCharToBytesMapping(char input) throws Exception { + return _ragconnect__apply__DefaultCharToBytesMapping(input); } - public static byte[] DefaultStringToBytesMapping(String input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultStringToBytesMapping(input); + public byte[] DefaultStringToBytesMapping(String input) throws Exception { + return _ragconnect__apply__DefaultStringToBytesMapping(input); } } @FunctionalInterface @@ -381,9 +431,12 @@ public class TestUtils { void accept(JsonGenerator g, String fieldName) throws E; } + static ReadNode readNode = new ReadNode(); + static WriteNode writeNode = new WriteNode(); + public static boolean BytesToBool(byte[] input) { try { - return ReadNode.DefaultBytesToBooleanMapping(input); + return readNode.DefaultBytesToBooleanMapping(input); } catch (Exception e) { e.printStackTrace(); return false; @@ -391,7 +444,7 @@ public class TestUtils { } public static int BytesToInt(byte[] input) { try { - return ReadNode.DefaultBytesToIntMapping(input); + return readNode.DefaultBytesToIntMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -399,7 +452,7 @@ public class TestUtils { } public static short BytesToShort(byte[] input) { try { - return ReadNode.DefaultBytesToShortMapping(input); + return readNode.DefaultBytesToShortMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -407,7 +460,7 @@ public class TestUtils { } public static long BytesToLong(byte[] input) { try { - return ReadNode.DefaultBytesToLongMapping(input); + return readNode.DefaultBytesToLongMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -415,7 +468,7 @@ public class TestUtils { } public static float BytesToFloat(byte[] input) { try { - return ReadNode.DefaultBytesToFloatMapping(input); + return readNode.DefaultBytesToFloatMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -423,7 +476,7 @@ public class TestUtils { } public static double BytesToDouble(byte[] input) { try { - return ReadNode.DefaultBytesToDoubleMapping(input); + return readNode.DefaultBytesToDoubleMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -431,7 +484,7 @@ public class TestUtils { } public static char BytesToChar(byte[] input) { try { - return ReadNode.DefaultBytesToCharMapping(input); + return readNode.DefaultBytesToCharMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -439,7 +492,7 @@ public class TestUtils { } public static String BytesToString(byte[] input) { try { - return ReadNode.DefaultBytesToStringMapping(input); + return readNode.DefaultBytesToStringMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -447,7 +500,7 @@ public class TestUtils { } public static byte[] BoolToBytes(boolean input) { try { - return WriteNode.DefaultBooleanToBytesMapping(input); + return writeNode.DefaultBooleanToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -455,7 +508,7 @@ public class TestUtils { } public static byte[] IntToBytes(int input) { try { - return WriteNode.DefaultIntToBytesMapping(input); + return writeNode.DefaultIntToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -463,7 +516,7 @@ public class TestUtils { } public static byte[] ShortToBytes(short input) { try { - return WriteNode.DefaultShortToBytesMapping(input); + return writeNode.DefaultShortToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -471,7 +524,7 @@ public class TestUtils { } public static byte[] LongToBytes(long input) { try { - return WriteNode.DefaultLongToBytesMapping(input); + return writeNode.DefaultLongToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -479,7 +532,7 @@ public class TestUtils { } public static byte[] FloatToBytes(float input) { try { - return WriteNode.DefaultFloatToBytesMapping(input); + return writeNode.DefaultFloatToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -487,7 +540,7 @@ public class TestUtils { } public static byte[] DoubleToBytes(double input) { try { - return WriteNode.DefaultDoubleToBytesMapping(input); + return writeNode.DefaultDoubleToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -495,7 +548,7 @@ public class TestUtils { } public static byte[] CharToBytes(char input) { try { - return WriteNode.DefaultCharToBytesMapping(input); + return writeNode.DefaultCharToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -503,7 +556,7 @@ public class TestUtils { } public static byte[] StringToBytes(String input) { try { - return WriteNode.DefaultStringToBytesMapping(input); + return writeNode.DefaultStringToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java index b0840d6d2d6d35ed50f759d61198b2d25586d800..121843c724d075318e483aa0ac072a53c64998e0 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java @@ -21,9 +21,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * * @author rschoene - Initial contribution */ -public class Warnings { +public class Warnings extends RagConnectTest { - private static final Logger logger = LoggerFactory.getLogger(Warnings.class); private static final String WARNING_DIRECTORY = "warnings/"; private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + WARNING_DIRECTORY; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java index a88f97fefabd47159f91d268a96ffe67a3dcee7e..4ac0f55dc829a628c63c79409e69cf97f60985cf 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java @@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.*; * @author rschoene - Initial contribution */ @Tag("Incremental") -@Tag("New") public class RelationTest extends AbstractMqttTest { private static final String TOPIC_WILDCARD = "rel/#"; @@ -617,6 +616,7 @@ public class RelationTest extends AbstractMqttTest { biB(3).getInner().setInnerValue("inner-bi-b3"); checker.check(); + logger.debug(model.ragconnectEvaluationCounterSummary()); } private void assertNullOrA(String expectedValue, A actual, String alias) { diff --git a/ragconnect.tests/src/test/resources/log4j2.xml b/ragconnect.tests/src/test/resources/log4j2.xml index 653d6c357cef6a51c43a2fe9e54d4a3e86148abf..9a1b22ee0120043991dfcfc7ad9c41f6dd5b4f06 100644 --- a/ragconnect.tests/src/test/resources/log4j2.xml +++ b/ragconnect.tests/src/test/resources/log4j2.xml @@ -4,6 +4,9 @@ <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level [%t] %logger{20} - %msg%n}" disableAnsi="false"/> </Console> + <File name="TestLogs" fileName="test.log" append="false"> + <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level [%t] %logger{20} - %msg%n"/> + </File> </Appenders> <Loggers> <Root level="debug">