-
Notifications
You must be signed in to change notification settings - Fork 4
Opencmw-cpp interoperability fixes and testing #239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| Process cppOpencmw = new ProcessBuilder("../CompatibilityTest", "serialise", "--value", value + "", "--array-size", arraySize + "").start(); | ||
|
|
||
| final TestData testData = new TestData(); | ||
| testData.booleanValue = value % 2 == 0; |
Check warning
Code scanning / CodeQL
Useless comparison test Warning test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 13 days ago
In general, to fix a “useless comparison test” where a condition is always true or false, remove or simplify the condition so that the code expresses the constant outcome directly. If the condition is meant to vary, adjust the surrounding logic so that the compared values are not constant.
Here, value is always 42, so value % 2 == 0 is always true. The test constructs a fixed TestData instance; no later logic depends on computing the parity dynamically. The minimal behaviour‑preserving change is to set testData.booleanValue directly to true. This removes the redundant comparison and keeps the actual runtime value identical.
Concretely, in client/src/test/java/io/opencmw/client/OpenCmwCppInteropTest.java, within testSerialiserCompatibility, replace line 60:
testData.booleanValue = value % 2 == 0;with:
testData.booleanValue = true;No additional imports, methods, or definitions are required.
-
Copy modified line R60
| @@ -57,7 +57,7 @@ | ||
| Process cppOpencmw = new ProcessBuilder("../CompatibilityTest", "serialise", "--value", value + "", "--array-size", arraySize + "").start(); | ||
|
|
||
| final TestData testData = new TestData(); | ||
| testData.booleanValue = value % 2 == 0; | ||
| testData.booleanValue = true; | ||
| testData.int8Value = value; | ||
| testData.int16Value = value; | ||
| testData.int32Value = value; |
| IoClassSerialiser serialiser = new IoClassSerialiser(buffer, BinarySerialiser.class); | ||
| buffer.reset(); // '0' writing at start of buffer | ||
| serialiser.serialiseObject(testData); | ||
| String opencmwJavaString = new String(buffer.elements(), 0, buffer.position(), Charset.defaultCharset()); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 13 days ago
In general, the right fix for an unread local variable is to either remove the declaration entirely or, if it was supposed to be used, add the missing usage. Here the string construction has no side effects and there is no active use, so the safest and simplest fix is to delete the variable declaration line.
Specifically, in client/src/test/java/io/opencmw/client/OpenCmwCppInteropTest.java, within testSerialiserCompatibility, remove the line that declares and initializes opencmwJavaString. The surrounding logic remains unchanged: we still serialise into buffer, then write buffer.elements() directly to java.hex, then proceed with the C++ process output. No new methods or imports are required.
| @@ -81,7 +81,6 @@ | ||
| IoClassSerialiser serialiser = new IoClassSerialiser(buffer, BinarySerialiser.class); | ||
| buffer.reset(); // '0' writing at start of buffer | ||
| serialiser.serialiseObject(testData); | ||
| String opencmwJavaString = new String(buffer.elements(), 0, buffer.position(), Charset.defaultCharset()); | ||
| Files.write(new File("java.hex").toPath(), buffer.elements()); | ||
|
|
||
| cppOpencmw.waitFor(); |
| event.throwables.forEach((Throwable e) -> System.err.println(e.getMessage())); | ||
| } else { | ||
| if (event.payload.getType() == TestData.class) { | ||
| System.out.println(event.payload.get(TestData.class)); |
Check notice
Code scanning / CodeQL
Use of default toString() Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 13 days ago
In general, to fix this kind of issue you define a domain-specific toString() method on the relevant class (here, TestData) so that when the object is printed or logged, a human-readable and informative representation is produced instead of the default Object.toString().
Given the constraints (we can only edit the shown test file), the best we can do without changing behavior elsewhere is to avoid relying on TestData’s default toString() at this call site. Since we cannot modify TestData itself (no definition is shown) and we must not introduce assumptions about its internal structure, the safest change is to wrap the printed value in a descriptive message that does not depend on TestData.toString() for meaning. However, that would still implicitly invoke toString() and keep the warning alive.
A more robust and standards-compliant solution in this constrained context is to stop implicitly converting the TestData instance to a string at all. Instead, log a generic description that does not print the instance directly. For example, replace:
System.out.println(event.payload.get(TestData.class));with something like:
TestData data = event.payload.get(TestData.class);
System.out.println("Received TestData instance of type: " + data.getClass().getName());This no longer uses TestData.toString(). It still confirms that an update was received and avoids assumptions about TestData’s fields. Because we cannot assume any methods on TestData beyond those of Object, using getClass().getName() is safe.
Concretely, in client/src/test/java/io/opencmw/client/OpenCmwCppInteropTest.java, inside the eventStore.register lambda in testSubscriptionWithListener, change the line that prints event.payload.get(TestData.class) to first assign the value to a variable and then print a message that uses only methods from Object/Class. No new imports or additional methods are needed.
-
Copy modified lines R115-R116
| @@ -112,7 +112,8 @@ | ||
| event.throwables.forEach((Throwable e) -> System.err.println(e.getMessage())); | ||
| } else { | ||
| if (event.payload.getType() == TestData.class) { | ||
| System.out.println(event.payload.get(TestData.class)); | ||
| TestData data = event.payload.get(TestData.class); | ||
| System.out.println("Received TestData instance of type: " + data.getClass().getName()); | ||
| } else { | ||
| System.err.println("unexpected payload type" + event.payload.getType().getSimpleName()); | ||
| } |
| Assumptions.assumeTrue(new File("../CompatibilityTest").exists()); // skip if the test binary is not available | ||
| int port = brokerAddress.getPort(); | ||
| int portMds = brokerPubAddress.getPort(); | ||
| Process cppOpencmw = new ProcessBuilder("../CompatibilityTest", "serve", "--port", port + "", "--port-mds", portMds + "").inheritIO().start(); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 13 days ago
In general, to fix an unread local variable you either (1) remove the variable declaration and keep only the side-effectful expression, or (2) start using the variable meaningfully (for example, for cleanup). Here, the process object is important for resource management, as evidenced by the other test that calls cppOpencmw.destroy();. The best fix without changing observable behavior is to ensure we still start the process, and additionally to use the Process instance to clean up the child process at the end of the test. This both eliminates the “unread variable” and improves resource handling.
Concretely, in client/src/test/java/io/opencmw/client/OpenCmwCppInteropTest.java, inside the testGetRequest method:
- Keep the declaration
Process cppOpencmw = ...start();so we still start the external CompatibilityTest server and have a handle to it. - Add a
try/finallystructure around the body of the test so thatcppOpencmw.destroy();(and possiblydestroyForcibly()as a fallback) is called in thefinallyblock. - Move the existing logic (eventStore.start(), dataSourcePublisher.start(), request/response, and stop calls) into the
tryblock.
No new imports are required since Process is part of java.lang. The only changes are within the shown method: wrapping existing logic in a try/finally and adding cppOpencmw.destroy(); so that the variable is now read/used.
-
Copy modified lines R171-R174 -
Copy modified lines R176-R185 -
Copy modified lines R187-R188 -
Copy modified line R190 -
Copy modified lines R192-R198
| @@ -168,28 +168,34 @@ | ||
| int port = brokerAddress.getPort(); | ||
| int portMds = brokerPubAddress.getPort(); | ||
| Process cppOpencmw = new ProcessBuilder("../CompatibilityTest", "serve", "--port", port + "", "--port-mds", portMds + "").inheritIO().start(); | ||
| eventStore.start(); | ||
| dataSourcePublisher.start(); | ||
| LockSupport.parkNanos(Duration.ofMillis(200).toNanos()); | ||
| try { | ||
| eventStore.start(); | ||
| dataSourcePublisher.start(); | ||
| LockSupport.parkNanos(Duration.ofMillis(200).toNanos()); | ||
|
|
||
| // get request | ||
| final URI requestURI = URI.create(brokerAddress + "/testProperty?contentType=application/octet-stream&contextA=test&contextB=asdf"); | ||
| LOGGER.atInfo().addArgument(requestURI).log("requesting GET from endpoint: {}"); | ||
| final Future<TestData> future; | ||
| try (final DataSourcePublisher.Client client = dataSourcePublisher.getClient()) { | ||
| future = client.get(requestURI, null, TestData.class); // uri_without_query oder serviceName + resolver, requestContext, type | ||
| } catch (Exception e) { | ||
| System.err.println(e.getMessage()); | ||
| throw e; | ||
| } | ||
| // get request | ||
| final URI requestURI = URI.create(brokerAddress + "/testProperty?contentType=application/octet-stream&contextA=test&contextB=asdf"); | ||
| LOGGER.atInfo().addArgument(requestURI).log("requesting GET from endpoint: {}"); | ||
| final Future<TestData> future; | ||
| try (final DataSourcePublisher.Client client = dataSourcePublisher.getClient()) { | ||
| future = client.get(requestURI, null, TestData.class); // uri_without_query oder serviceName + resolver, requestContext, type | ||
| } catch (Exception e) { | ||
| System.err.println(e.getMessage()); | ||
| throw e; | ||
| } | ||
|
|
||
| // assert result | ||
| final TestData result = future.get(1000, TimeUnit.MILLISECONDS); | ||
| // assert result | ||
| final TestData result = future.get(1000, TimeUnit.MILLISECONDS); | ||
|
|
||
| System.out.println(result.doubleValue); | ||
| System.out.println(result.doubleValue); | ||
|
|
||
| eventStore.stop(); | ||
| dataSourcePublisher.stop(); | ||
| eventStore.stop(); | ||
| dataSourcePublisher.stop(); | ||
| } finally { | ||
| if (cppOpencmw != null) { | ||
| cppOpencmw.destroy(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Test |
| Assumptions.assumeTrue(new File("../CompatibilityTest").exists()); // skip if the test binary is not available | ||
| int port = brokerAddress.getPort(); | ||
| int portMds = brokerPubAddress.getPort(); | ||
| Process cppOpencmw = new ProcessBuilder("../CompatibilityTest", "serve", "--port", port + "", "--port-mds", portMds + "").inheritIO().start(); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 13 days ago
In general, to fix an unread local variable you either (a) remove the variable entirely while preserving any side-effecting expression, or (b) start using the variable meaningfully. Here, the test only needs to start the external compatibility server; it does not use the Process object. The simplest, behavior-preserving fix is to drop the Process cppOpencmw declaration and just invoke new ProcessBuilder(...).start(); as a standalone statement.
Concretely, in client/src/test/java/io/opencmw/client/OpenCmwCppInteropTest.java, inside testGetRequestWithAnnotations, change line 200 from a variable declaration Process cppOpencmw = new ProcessBuilder(...).start(); to just new ProcessBuilder(...).inheritIO().start();. This keeps all existing behavior (starting the process with inherited IO) and removes the unread variable. No new imports, methods, or other definitions are required.
-
Copy modified line R200
| @@ -197,7 +197,7 @@ | ||
| Assumptions.assumeTrue(new File("../CompatibilityTest").exists()); // skip if the test binary is not available | ||
| int port = brokerAddress.getPort(); | ||
| int portMds = brokerPubAddress.getPort(); | ||
| Process cppOpencmw = new ProcessBuilder("../CompatibilityTest", "serve", "--port", port + "", "--port-mds", portMds + "").inheritIO().start(); | ||
| new ProcessBuilder("../CompatibilityTest", "serve", "--port", port + "", "--port-mds", portMds + "").inheritIO().start(); | ||
| eventStore.start(); | ||
| dataSourcePublisher.start(); | ||
| LockSupport.parkNanos(Duration.ofMillis(200).toNanos()); |
|
|
||
| public void setFieldGroups(final List<String> fieldGroups) { | ||
| this.fieldGroups = fieldGroups; | ||
| public byte getFieldModifier() { |
Check notice
Code scanning / CodeQL
Missing Override annotation Note
FieldDescription.getFieldModifier
Opencmw-java and opencmw-cpp used different metadata entries for the field descriptions. While opencmw-cpp serialised [description(string), unit(string), modifier(byte/enum)], opencmw-java used [description(string), unit(string), direction(string), groups(string[])]. This lead to failures in deserialising c++ serialised field medatadata. These changes make opencmw-java use the same format as c++. Signed-off-by: Alexander Krimm <A.Krimm@gsi.de>
Signed-off-by: Alexander Krimm <A.Krimm@gsi.de>
To run the tests locally, copy the Compatibility test executable from opencmw-cpp to the repository root. The CI will fetch it from the artifact of opencmw-cpp. If it is not available, the tests will be skipped. Signed-off-by: Alexander Krimm <A.Krimm@gsi.de>
b59e823 to
ca0c7f5
Compare
follow up of #223 and companion PR to fair-acc/opencmw-cpp#389
missing functionality: