This is an automated email from the ASF dual-hosted git repository.

dimuthuupe pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata.git


The following commit(s) were added to refs/heads/master by this push:
     new 2b3c211bb4 Experiment cleanup support test cases (#583)
2b3c211bb4 is described below

commit 2b3c211bb43df98cbc18045356d072dcd7e8efe9
Author: Dimuthu Wannipurage <[email protected]>
AuthorDate: Wed Dec 17 11:03:57 2025 -0500

    Experiment cleanup support test cases (#583)
    
    * Adding support to clean up experiment working directory on cluster
    
    * Adding commented delete dir functionality
    
    * escaped the directory path, generated python thrift stubs, and updated 
the java styles
    
    * Adding test cases to validate the delete directory functionality
    
    * Fixed merge conflict and added missing assertions
    
    * Minor refactoring
    
    Co-authored-by: Copilot <[email protected]>
    
    ---------
    
    Co-authored-by: lahiruj <[email protected]>
    Co-authored-by: Copilot <[email protected]>
---
 airavata-api/pom.xml                               |   8 +
 .../airavata/helix/adaptor/SSHJAgentAdaptor.java   |  20 ++-
 .../core/entities/expcatalog/ExperimentEntity.java |  10 +-
 .../apache/airavata/helix/SFTPDeleteDirTest.java   | 177 +++++++++++++++++++++
 pom.xml                                            |   3 -
 5 files changed, 209 insertions(+), 9 deletions(-)

diff --git a/airavata-api/pom.xml b/airavata-api/pom.xml
index b64be1d8aa..14fe1543ad 100644
--- a/airavata-api/pom.xml
+++ b/airavata-api/pom.xml
@@ -346,6 +346,14 @@ under the License.
         </exclusion>
       </exclusions>
     </dependency>
+
+    <dependency>
+      <groupId>org.apache.sshd</groupId>
+      <artifactId>sshd-sftp</artifactId>
+      <version>2.12.1</version>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
 
   <build>
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/helix/adaptor/SSHJAgentAdaptor.java
 
b/airavata-api/src/main/java/org/apache/airavata/helix/adaptor/SSHJAgentAdaptor.java
index 495f9476d4..67161d073c 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/helix/adaptor/SSHJAgentAdaptor.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/helix/adaptor/SSHJAgentAdaptor.java
@@ -277,6 +277,24 @@ public class SSHJAgentAdaptor implements AgentAdaptor {
         }
     }
 
+
+    private void deleteDirectoryRecursively(SFTPClientWrapper sftpClient, 
String path) throws IOException {
+        FileAttributes lstat = sftpClient.lstat(path);
+        if (lstat.getMode().getType() == Type.DIRECTORY) {
+            List<RemoteResourceInfo> ls = sftpClient.ls(path);
+            if (ls == null || ls.isEmpty()) {
+                sftpClient.rmdir(path);
+            } else {
+                for (RemoteResourceInfo r : ls) {
+                    deleteDirectoryRecursively(sftpClient, path + "/" + 
r.getName());
+                }
+                sftpClient.rmdir(path);
+            }
+        } else {
+            sftpClient.rm(path);
+        }
+    }
+
     @Override
     public void deleteDirectory(String path) throws AgentException {
         if (path == null || path.trim().isEmpty()) {
@@ -285,7 +303,7 @@ public class SSHJAgentAdaptor implements AgentAdaptor {
         SFTPClientWrapper sftpClient = null;
         try {
             sftpClient = sshjClient.newSFTPClientWrapper();
-            sftpClient.rmdir(path);
+            deleteDirectoryRecursively(sftpClient, path);
         } catch (Exception e) {
             if (e instanceof ConnectionException) {
                 Optional.ofNullable(sftpClient).ifPresent(ft -> 
ft.setErrored(true));
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/core/entities/expcatalog/ExperimentEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/core/entities/expcatalog/ExperimentEntity.java
index 0a208ecf8c..8055dde100 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/core/entities/expcatalog/ExperimentEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/core/entities/expcatalog/ExperimentEntity.java
@@ -50,7 +50,7 @@ public class ExperimentEntity implements Serializable {
 
     @Column(name = "CLEANUP_STRATEGY")
     @Enumerated(EnumType.STRING)
-    public ExperimentCleanupStrategy cleanupStrategy;
+    public ExperimentCleanupStrategy cleanUpStrategy;
 
     @Column(name = "USER_NAME")
     public String userName;
@@ -269,12 +269,12 @@ public class ExperimentEntity implements Serializable {
         this.experimentStatus = experimentStatus;
     }
 
-    public ExperimentCleanupStrategy getCleanupStrategy() {
-        return cleanupStrategy;
+    public ExperimentCleanupStrategy getCleanUpStrategy() {
+        return cleanUpStrategy;
     }
 
-    public void setCleanupStrategy(ExperimentCleanupStrategy cleanupStrategy) {
-        this.cleanupStrategy = cleanupStrategy;
+    public void setCleanUpStrategy(ExperimentCleanupStrategy cleanUpStrategy) {
+        this.cleanUpStrategy = cleanUpStrategy;
     }
 
     public List<ProcessEntity> getProcesses() {
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/helix/SFTPDeleteDirTest.java 
b/airavata-api/src/test/java/org/apache/airavata/helix/SFTPDeleteDirTest.java
new file mode 100644
index 0000000000..a1de29ecc9
--- /dev/null
+++ 
b/airavata-api/src/test/java/org/apache/airavata/helix/SFTPDeleteDirTest.java
@@ -0,0 +1,177 @@
+package org.apache.airavata.helix;
+
+import org.apache.airavata.helix.adaptor.SSHJAgentAdaptor;
+import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.config.keys.AuthorizedKeysAuthenticator;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.sftp.server.SftpSubsystemFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+
+public class SFTPDeleteDirTest {
+
+    private SshServer sshd;
+    private int port;
+    private Path sftpRootDir;
+    private int sftpPort = 52122;
+
+    private String privateKey = "-----BEGIN OPENSSH PRIVATE KEY-----\n" +
+            
"b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCHHZONdz\n" +
+            
"yrWLbnw4nyEw3BAAAAGAAAAAEAAAGXAAAAB3NzaC1yc2EAAAADAQABAAABgQCxhKaGaUlU\n" +
+            
"Znlr6OtFQ7hjVceZsWLBaIWB5NUwp45IoWLm7Hnor+Y8J/SwLBgdUSsjxkMUQMMbJdY/rP\n" +
+            
"Gwc8aW0K1JMjSNhv03dBxvXHdY+NSd24WjSezD89l6v78lGhVQ5g3rI4eTFsfPy2WSxZw1\n" +
+            
"Fo0UUDVzzBtLuvC9ZCWd3nsT8Ox4LnZWLHrrRxGX2eCotEEO6CT1+wmk4szIkeDDmX79Tb\n" +
+            
"KatcN2vv7H6WjsoGH1bhc1QwS2/hmOdBwqGfm+sE0BI3VgMJ1NVDQrnt0IXlMtLH9Feg1y\n" +
+            
"tdagCzaHulQ9lHn1wBzSARP/NqYzu2vNwpWSSJeafClHpA8yF/9FW9gOi4k+Oo949b+Xd1\n" +
+            
"NHqjt+7lnlsepm0IsgfJ9Gr/0sweYfUSsTfGZGMstSRMu8V+bD1BaVqXQKZ80XoCm0NMnR\n" +
+            
"Chm109wXtt5+0atDmIFiy1Byr8QjwjqsIap1j93R/8R3L3mhUmLruSl7IPKPhjShEIL253\n" +
+            
"GpoHiSENae9e0AAAWgEaos8m239pnUDpWU3N9VtUvg3XVh9WC1YwL9wg1rnl+uW3ygA4Xq\n" +
+            
"VvGUEc5Xx5AR3buKaYGI7+Tb4RAwQL8HkQS78mDtmSiNKJbxmUWkLIWERBe/OZGO/HYPSl\n" +
+            
"WS3nkXogcYy5Q/9Fy4U35Trg82yq/kaSjIneJAGLz0ShbQNgWBtnpzK8eHqceoMFYQsvZ+\n" +
+            
"eaK3JWTwQPgXinj2E37OU5N0y5ncZ8yQ5bKEbOBZ62uYdZFnIgQhz9oNVS8ShIVZtBC0h4\n" +
+            
"ytl45Tdsd4H8cy2RMzzvvLtsfnvA6EOzj5exSNrtsbjZMFvK7f1oatKkm71IknvieGr0nh\n" +
+            
"qvmR+qc15wwnmmFus9MFpqxsOKdPzkeSvBjhe9Oj5Qc9g9ecNHuSuS7MTRcx6UFmB9tvo+\n" +
+            
"iLW0uEzIguQSyaAo1VBNgbr+wz11TaB+rhi2krdUc59skS6/mrah7gJr0kGAJowLR+YGjN\n" +
+            
"/UTJpaEhMWkktuAznY56qs7AlHqKzcNq+258LpIOQJzN9/gw9IB2rz0PNnA+NqDCHttQLw\n" +
+            
"0dZe/oPHJQ6vI/5ykakSas5GJZOph5udSz05ndM5kRoMOGHhi8WeYA0vFBed3BH+lkZ59K\n" +
+            
"z+vjf4sGmOb0ptW95QA9ZeMN899QvuCYOgnuyCPguVL3SsRkQ9AXmOrLT4oPTSUOY3t7vv\n" +
+            
"GI5WN5ZN9zYtT21bOMqYi+cHlIhnaqz+GjRpEfGaqJFPLcj1tVznHbi+2HHCG0M+NTjw9G\n" +
+            
"JRjAjqOfkJZ0/7KmfBT7lGWNPPNgXtYPDdYRHHiIeDMLu4s2gBbqn8pmIdG14K4IqLl7uC\n" +
+            
"payMNJxmQ75oRFpv3Vtf31FlpnsT762iS0e7P0CwBxVZyjdCYet9IVjw6MJC62svnTDznn\n" +
+            
"0ZxPdz78acoXlBkH67zDH69LyPGZlZ9e7HeKrMbOTU5mnUfSiHc3mk8PYEuphnKXFd8Zzi\n" +
+            
"bc/SfaxLbf19MsuqlM+gqKR9hVqDn6Ri9JAmHJBgFNc5hdLSKucunNFFamCslCXRkB3TNl\n" +
+            
"pbPxSLMJ9UDTcrRnzgi5zyQxSe3K8tspqhXQ6ek5Z2sZ+zZuFzcKzgUcd8fpYxC9lZvJ1b\n" +
+            
"pS8OCuGUI6KHHmGJmNKBTbxvp0B4EjRIy3lDJDBMap/GN9GsgqscrvYPIfqlnVR7GXN+qj\n" +
+            
"MgOsue1jtVzG1SBAmBxcctEFLzBsr4k/fNNTXPt/mPKeO3w59zt1OSPyNx63NbNmo/uWO1\n" +
+            
"8P24MBcO5crhlYa5ptb6Fvi1/j6Yrg1NYDPutRopcZNemEFPkR4dqW5AhJwT8L8hqZmmhs\n" +
+            
"DH97qNiqkqyVmrRIygnVMdYqXsn/uV8yEb5mgRw8C6fJ7OZsvwsSfy052tBKJhj/63Ay/S\n" +
+            
"wJ+HxQ/8vthvEkXsaJWiQ2RwatZIoVpOhYEpKwSDuBHMKrnMiCow13+pAq9Gf/CbXUd/Ko\n" +
+            
"xNQ8RZ8lkreUDjJJhTXRRcpufJChL6zQj9bat6E9QBq4l1XjGDhAqgfvQT/1fDataZW3vW\n" +
+            
"skze0s7diqtYIWNlx2+4vGxL38pSCSqtOWjHS6Rbjf37ERKQMH57z4w3aEiahtBcgKTWBy\n" +
+            
"n4UD18TfLGd2i7jtENLxOcWBFzRxtIbFnKGiktLcp0XILs/lOhtRF+K2abiif26rDx++jI\n" +
+            
"4iQCet6ltdeQJLekjmNh4/9Y4hCf5yx9lKuGbzGeZPI66ClbY+R2l29ZXUNUxZmVKM4BDw\n" +
+            
"2LqMlVLcM1Nzg6ftQ09Dku1ApX/uKeOaf0I0DPaBwVD+iTGCeZWuOg5b1LZUuxxYT4ZB6F\n" +
+            
"hoZ8/1mt5gTzo4XdZCmJ7jCOqEc75JV2NEfcIwpy6TOZPVMMWFYT88OgkF86Vxx8GR0FQU\n" +
+            "CLSDGVZjFU7kv1eKpDJ0oETyGBELC1PPMpm90nxCkzCx7uQw\n" +
+            "-----END OPENSSH PRIVATE KEY-----\n";
+
+    private String publicKey = "ssh-rsa 
AAAAB3NzaC1yc2EAAAADAQABAAABgQCxhKaGaUlUZnlr6OtFQ7hjVceZsWLBaIWB5NUwp45IoWLm7Hnor+Y8J/SwLBgdUSsjxkMUQMMbJdY/rPGwc8aW0K1JMjSNhv03dBxvXHdY+NSd24WjSezD89l6v78lGhVQ5g3rI4eTFsfPy2WSxZw1Fo0UUDVzzBtLuvC9ZCWd3nsT8Ox4LnZWLHrrRxGX2eCotEEO6CT1+wmk4szIkeDDmX79TbKatcN2vv7H6WjsoGH1bhc1QwS2/hmOdBwqGfm+sE0BI3VgMJ1NVDQrnt0IXlMtLH9Feg1ytdagCzaHulQ9lHn1wBzSARP/NqYzu2vNwpWSSJeafClHpA8yF/9FW9gOi4k+Oo949b+Xd1NHqjt+7lnlsepm0IsgfJ9Gr/0sweYfUSsTfGZGMstSRMu8V+bD1BaVqXQKZ80X
 [...]
+    private String passphrase = "airavata";
+
+    @BeforeEach
+    void setUp() throws Exception {
+        sftpRootDir = Files.createTempDirectory("sftp-root-");
+        sftpRootDir.toFile().deleteOnExit();
+
+        Path authorizedKeysFile = Files.createTempFile("authorized_keys-", "");
+        Files.write(authorizedKeysFile, 
publicKey.getBytes(StandardCharsets.UTF_8));
+        authorizedKeysFile.toFile().deleteOnExit();
+
+        sshd = SshServer.setUpDefaultServer();
+        sshd.setHost("localhost");
+        sshd.setPort(sftpPort);
+
+        // Host key (for the server itself, unrelated to client auth)
+        sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
+
+        // SFTP subsystem
+        sshd.setSubsystemFactories(
+                Collections.singletonList(new 
SftpSubsystemFactory.Builder().build())
+        );
+
+        // Virtual root
+        sshd.setFileSystemFactory(new VirtualFileSystemFactory(sftpRootDir));
+
+        // *** AUTH CONFIG ***
+
+        // 1) Disable password auth (only key-based logins allowed)
+        sshd.setPasswordAuthenticator(null);
+
+        sshd.setPublickeyAuthenticator(new 
AuthorizedKeysAuthenticator(authorizedKeysFile));
+
+        sshd.start();
+        port = sshd.getPort();
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        if (sshd != null && !sshd.isClosed()) {
+            sshd.stop(true);
+        }
+    }
+
+    public void createFilesInDir(Path root) throws IOException {
+        Path dir1 = Files.createDirectory(root.resolve("dir1"));
+        dir1.toFile().deleteOnExit();
+        Path dir2 = Files.createDirectory(root.resolve("dir2"));
+        dir2.toFile().deleteOnExit();
+
+        Path file1 = Files.createFile(root.resolve("file1.txt"));
+        file1.toFile().deleteOnExit();
+        Path file2 = Files.createFile(root.resolve("file2.txt"));
+        file2.toFile().deleteOnExit();
+
+        Path file3 = Files.createFile(dir1.resolve("file3.txt"));
+        file3.toFile().deleteOnExit();
+        Path file4 = Files.createFile(dir1.resolve("file4.txt"));
+        file4.toFile().deleteOnExit();
+
+        Files.writeString(file1, "Hello from file1\n");
+        Files.writeString(file2, "Hello from file2\n");
+        Files.writeString(file3, "Hello from file3\n");
+        Files.writeString(file4, "Hello from file4\n");
+    }
+
+    @Test
+    public void deleteNonEmptyDir() throws Exception {
+        System.out.printf("Root dir: %s\n", sftpRootDir);
+
+        Path dir1 = Files.createDirectory(sftpRootDir.resolve("dir1"));
+        dir1.toFile().deleteOnExit();
+        Path dir2 = Files.createDirectory(sftpRootDir.resolve("dir2"));
+        dir2.toFile().deleteOnExit();
+
+        createFilesInDir(dir1);
+        createFilesInDir(dir2);
+
+        SSHJAgentAdaptor adaptor = new SSHJAgentAdaptor();
+        adaptor.init("testuser", "localhost", sftpPort, publicKey, privateKey, 
passphrase);
+
+        List<String> itemsBefore = adaptor.listDirectory("/");
+        adaptor.deleteDirectory("dir1");
+        List<String> itemsAfter = adaptor.listDirectory("/");
+
+        Assertions.assertTrue(itemsBefore.contains("dir1"));
+        Assertions.assertTrue(itemsBefore.contains("dir2"));
+
+        Assertions.assertFalse(itemsAfter.contains("dir1"));
+        Assertions.assertTrue(itemsAfter.contains("dir2"));
+
+    }
+
+    @Test
+    public void deleteEmptyDir() throws Exception {
+        Path dir1 = Files.createDirectory(sftpRootDir.resolve("dir1"));
+        dir1.toFile().deleteOnExit();
+
+        SSHJAgentAdaptor adaptor = new SSHJAgentAdaptor();
+        adaptor.init("testuser", "localhost", sftpPort, publicKey, privateKey, 
passphrase);
+        List<String> itemsBefore = adaptor.listDirectory("/");
+        adaptor.deleteDirectory("dir1");
+        List<String> itemsAfter = adaptor.listDirectory("/");
+
+        Assertions.assertTrue(itemsBefore.contains("dir1"));
+        Assertions.assertTrue(itemsAfter.isEmpty());
+    }
+}
diff --git a/pom.xml b/pom.xml
index d5cc2be601..8609f5f92e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -612,9 +612,6 @@ under the License.
                     <skipTests>${skipTests}</skipTests>
                     
<workingDirectory>${project.build.testOutputDirectory}</workingDirectory>
                     <useSystemClassLoader>false</useSystemClassLoader>
-                    <argLine>-Xmx1024m -XX:MaxPermSize=256m --add-opens 
java.base/java.lang=ALL-UNNAMED
-                        
-javaagent:${settings.localRepository}/org/jmockit/jmockit/1.50/jmockit-1.50.jar
-                    </argLine>
                     <reuseForks>false</reuseForks>
                     <excludes>
                         <exclude>**/IT.java</exclude>

Reply via email to