Copilot commented on code in PR #930:
URL: https://github.com/apache/mina-sshd/pull/930#discussion_r4274837436


##########
sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java:
##########
@@ -249,6 +249,40 @@ public Result process(ConnectionService connectionService, 
String request, boole
         }
     }
 
+    // see GH-929
+    @Test
+    void testPerSessionHeartbeatConfiguration() throws Exception {
+        CoreModuleProperties.IDLE_TIMEOUT.set(sshd, Duration.ofSeconds(30));
+        List<RequestHandler<ConnectionService>> globalHandlers = 
sshd.getGlobalRequestHandlers();
+        sshd.setGlobalRequestHandlers(Collections.singletonList(new 
AbstractConnectionServiceRequestHandler() {
+            @Override
+            public Result process(ConnectionService connectionService, String 
request, boolean wantReply, Buffer buffer)
+                    throws Exception {
+                // Never reply;
+                return Result.Replied;
+            }

Review Comment:
   `Result.Replied` indicates the request has been replied to, but this handler 
does not actually send any reply. This contradicts the intent (“Never reply”) 
and can invalidate the test by not truly exercising the “no reply” heartbeat 
path. Return the appropriate status for “handled but no reply sent” (or 
explicitly send no response when `wantReply` is true), consistent with the 
request-handler contract in this codebase.



##########
sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java:
##########
@@ -47,9 +47,9 @@
 public class ClientConnectionService
         extends AbstractConnectionService
         implements ClientSessionHolder {
-    protected final String heartbeatRequest;
-    protected final Duration heartbeatInterval;
-    protected final int heartbeatMaxNoReply;
+    protected String heartbeatRequest;
+    protected Duration heartbeatInterval;
+    protected int heartbeatMaxNoReply;

Review Comment:
   These fields were changed from `final` to mutable and are written in 
`startHeartBeat()`, but may be read from other threads (e.g., scheduled 
heartbeat task) without a guaranteed happens-before relationship. This can 
cause stale reads or inconsistent combinations of values. Consider making them 
`volatile`, or ensuring all reads/writes occur under the same synchronization, 
or copying refreshed values into local finals that are captured/used by the 
scheduled runnable.



##########
sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java:
##########
@@ -249,6 +249,40 @@ public Result process(ConnectionService connectionService, 
String request, boole
         }
     }
 
+    // see GH-929
+    @Test
+    void testPerSessionHeartbeatConfiguration() throws Exception {
+        CoreModuleProperties.IDLE_TIMEOUT.set(sshd, Duration.ofSeconds(30));
+        List<RequestHandler<ConnectionService>> globalHandlers = 
sshd.getGlobalRequestHandlers();
+        sshd.setGlobalRequestHandlers(Collections.singletonList(new 
AbstractConnectionServiceRequestHandler() {
+            @Override
+            public Result process(ConnectionService connectionService, String 
request, boolean wantReply, Buffer buffer)
+                    throws Exception {
+                // Never reply;
+                return Result.Replied;
+            }
+        }));
+        Duration heartbeat = Duration.ofMillis(500L);
+        try (ClientSession session = client.connect(getCurrentTestName(), 
TEST_LOCALHOST, port).verify(CONNECT_TIMEOUT)
+                .getSession()) {
+            CoreModuleProperties.HEARTBEAT_INTERVAL.set(session, heartbeat);
+            CoreModuleProperties.HEARTBEAT_NO_REPLY_MAX.set(session, 1);
+            session.addPasswordIdentity(getCurrentTestName());
+            session.auth().verify(AUTH_TIMEOUT);
+
+            try (ClientChannel channel = 
session.createChannel(Channel.CHANNEL_SHELL)) {

Review Comment:
   The channel is created but never opened. Waiting for `CLOSED` on a channel 
that was never opened can lead to false positives/negatives (depending on 
initial channel state and implementation details) and makes the timing 
assertion less meaningful. Open the channel (e.g., 
`channel.open().verify(...)`) before waiting for closure so the test reliably 
validates heartbeat-driven disconnect behavior.



##########
sshd-core/src/main/java/org/apache/sshd/client/session/ClientConnectionService.java:
##########
@@ -122,6 +122,9 @@ public void start() {
 
     @Override
     protected synchronized ScheduledFuture<?> startHeartBeat() {
+        heartbeatRequest = 
CoreModuleProperties.HEARTBEAT_REQUEST.getRequired(this);
+        heartbeatInterval = 
CoreModuleProperties.HEARTBEAT_INTERVAL.getRequired(this);
+        heartbeatMaxNoReply = configureMaxNoReply();

Review Comment:
   These fields were changed from `final` to mutable and are written in 
`startHeartBeat()`, but may be read from other threads (e.g., scheduled 
heartbeat task) without a guaranteed happens-before relationship. This can 
cause stale reads or inconsistent combinations of values. Consider making them 
`volatile`, or ensuring all reads/writes occur under the same synchronization, 
or copying refreshed values into local finals that are captured/used by the 
scheduled runnable.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to