Skip to content

Conversation

@DImuthuUpe
Copy link
Contributor

No description provided.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds test cases to support experiment cleanup functionality. The changes introduce SFTP directory deletion capabilities and test infrastructure to verify the functionality.

  • Added new test class SFTPDeleteDirTest.java with test cases for deleting empty and non-empty directories via SFTP
  • Implemented recursive directory deletion functionality in SSHJAgentAdaptor
  • Renamed field from cleanupStrategy to cleanUpStrategy in ExperimentEntity for consistency
  • Removed jmockit test configuration from root pom.xml and added Apache SSHD test dependency

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pom.xml Removed jmockit agent configuration from maven-surefire-plugin
airavata-api/pom.xml Added Apache SSHD SFTP test dependency (version 2.12.1)
airavata-api/src/test/java/org/apache/airavata/helix/SFTPDeleteDirTest.java New test class for SFTP directory deletion with embedded SSH server setup
airavata-api/src/main/java/org/apache/airavata/registry/core/entities/expcatalog/ExperimentEntity.java Renamed cleanupStrategy field and getter/setter methods to cleanUpStrategy
airavata-api/src/main/java/org/apache/airavata/helix/adaptor/SSHJAgentAdaptor.java Added recursive directory deletion implementation (contains duplicate method definition)
Comments suppressed due to low confidence (1)

airavata-api/src/main/java/org/apache/airavata/helix/adaptor/SSHJAgentAdaptor.java:350

  • Duplicate method definition detected. The deleteDirectory method is defined twice (lines 299-323 and 326-350). The first implementation supports recursive deletion using deleteDirectoryRecursively, while the second one only calls rmdir which won't work for non-empty directories. The second definition will override the first, breaking the recursive deletion functionality that the tests expect.
    @Override
    public void deleteDirectory(String path) throws AgentException {
        if (path == null || path.trim().isEmpty()) {
            throw new AgentException("Directory path cannot be null or empty");
        }
        SFTPClientWrapper sftpClient = null;
        try {
            sftpClient = sshjClient.newSFTPClientWrapper();
            deleteDirectoryRecursively(sftpClient, path);
        } catch (Exception e) {
            if (e instanceof ConnectionException) {
                Optional.ofNullable(sftpClient).ifPresent(ft -> ft.setErrored(true));
            }
            logger.error("Error while deleting directory {}", path, e);
            throw new AgentException(e);

        } finally {
            Optional.ofNullable(sftpClient).ifPresent(client -> {
                try {
                    client.close();
                } catch (IOException e) {
                    // Ignore
                }
            });
        }
    }

    @Override
    public void deleteDirectory(String path) throws AgentException {
        if (path == null || path.trim().isEmpty()) {
            throw new AgentException("Directory path cannot be null or empty");
        }
        SFTPClientWrapper sftpClient = null;
        try {
            sftpClient = sshjClient.newSFTPClientWrapper();
            sftpClient.rmdir(path);
        } catch (Exception e) {
            if (e instanceof ConnectionException) {
                Optional.ofNullable(sftpClient).ifPresent(ft -> ft.setErrored(true));
            }
            logger.error("Error while deleting directory {}", path, e);
            throw new AgentException(e);

        } finally {
            Optional.ofNullable(sftpClient).ifPresent(client -> {
                try {
                    client.close();
                } catch (IOException e) {
                    // Ignore
                }
            });
        }
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

sftpClient.rmdir(path);
} else {
for (RemoteResourceInfo r : ls) {
deleteDirectoryRecursively(sftpClient, path + "/" + r.getName());
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path concatenation issue: Using string concatenation with "/" to build paths (e.g., path + "/" + r.getName()) may cause issues on Windows systems or when dealing with paths that already end with a separator. Consider using proper path handling utilities or checking if the path already ends with a separator before concatenating.

Copilot uses AI. Check for mistakes.
if (ls == null || ls.isEmpty()) {
sftpClient.rmdir(path);
} else {
for (RemoteResourceInfo r : ls) {
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing filter for special directory entries. The ls command typically returns "." and ".." entries in directory listings. The recursive delete function doesn't filter these out, which could cause issues or inefficiency. Consider filtering out these entries before processing: for (RemoteResourceInfo r : ls) { if (".".equals(r.getName()) || "..".equals(r.getName())) continue; ... }

Suggested change
for (RemoteResourceInfo r : ls) {
for (RemoteResourceInfo r : ls) {
if (".".equals(r.getName()) || "..".equals(r.getName())) {
continue;
}

Copilot uses AI. Check for mistakes.
@Column(name = "CLEANUP_STRATEGY")
@Enumerated(EnumType.STRING)
public ExperimentCleanupStrategy cleanupStrategy;
public ExperimentCleanupStrategy cleanUpStrategy;
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Inconsistent naming: The field name has been changed from cleanupStrategy to cleanUpStrategy. While "cleanup" is often written as one word in technical contexts, this change should be consistent with the column name "CLEANUP_STRATEGY" (which uses the single-word form). Consider whether this naming inconsistency between the Java field and database column is intentional.

Suggested change
public ExperimentCleanupStrategy cleanUpStrategy;
public ExperimentCleanupStrategy cleanupStrategy;

Copilot uses AI. Check for mistakes.
Comment on lines 136 to 157
@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("/");
System.out.printf("Before: %s\n", itemsBefore);
System.out.printf("After: %s\n", itemsAfter);

}
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing assertions in test method. The test deleteNonEmptyDir verifies that a non-empty directory can be deleted but doesn't include any assertions to validate the expected behavior. The test should verify that 'dir1' is actually removed and no longer appears in itemsAfter.

Copilot uses AI. Check for mistakes.
Comment on lines +148 to +149
SSHJAgentAdaptor adaptor = new SSHJAgentAdaptor();
adaptor.init("testuser", "localhost", sftpPort, publicKey, privateKey, passphrase);
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource leak: The SSHJAgentAdaptor instance is created but never properly closed. The adaptor has a destroy() method that should be called to clean up SSH connections. Consider adding adaptor.destroy() in a finally block or use a try-with-resources pattern if the class implements AutoCloseable.

Copilot uses AI. Check for mistakes.
Comment on lines +164 to +165
SSHJAgentAdaptor adaptor = new SSHJAgentAdaptor();
adaptor.init("testuser", "localhost", sftpPort, publicKey, privateKey, passphrase);
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resource leak: The SSHJAgentAdaptor instance is created but never properly closed. The adaptor has a destroy() method that should be called to clean up SSH connections. Consider adding adaptor.destroy() in a finally block or use a try-with-resources pattern if the class implements AutoCloseable.

Copilot uses AI. Check for mistakes.
@DImuthuUpe DImuthuUpe merged commit 2b3c211 into master Dec 17, 2025
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants