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

yasith pushed a commit to branch feat/grpc-armeria-migration
in repository https://gitbox.apache.org/repos/asf/airavata.git

commit 8ff089aa6e1aaedea51fe5e36215201870a76f0d
Author: yasithdev <[email protected]>
AuthorDate: Wed Apr 1 14:35:43 2026 -0400

    test: add unit tests for SharingHelper, AirvataFileService, 
CredentialStoreServerHandler
---
 .../compute/service/ResourceServiceTest.java       | 460 +++++++++++++++++++++
 .../handler/CredentialStoreServerHandlerTest.java  | 299 ++++++++++++++
 .../service/ResourceSharingServiceTest.java        | 197 +++++++++
 .../sharing/service/SharingHelperTest.java         | 193 +++++++++
 .../storage/service/AirvataFileServiceTest.java    | 199 +++++++++
 5 files changed, 1348 insertions(+)

diff --git 
a/airavata-api/compute-service/src/test/java/org/apache/airavata/compute/service/ResourceServiceTest.java
 
b/airavata-api/compute-service/src/test/java/org/apache/airavata/compute/service/ResourceServiceTest.java
index 21802fa799..6819f7763d 100644
--- 
a/airavata-api/compute-service/src/test/java/org/apache/airavata/compute/service/ResourceServiceTest.java
+++ 
b/airavata-api/compute-service/src/test/java/org/apache/airavata/compute/service/ResourceServiceTest.java
@@ -26,9 +26,14 @@ import java.util.Map;
 import org.apache.airavata.execution.handler.RegistryServerHandler;
 import org.apache.airavata.execution.service.ServiceException;
 import org.apache.airavata.model.appcatalog.computeresource.proto.*;
+import 
org.apache.airavata.model.appcatalog.gatewayprofile.proto.GatewayResourceProfile;
+import 
org.apache.airavata.model.appcatalog.groupresourceprofile.proto.GroupComputeResourcePreference;
 import 
org.apache.airavata.model.appcatalog.storageresource.proto.StorageResourceDescription;
 import org.apache.airavata.model.data.movement.proto.DMType;
+import org.apache.airavata.model.data.movement.proto.GridFTPDataMovement;
+import org.apache.airavata.model.data.movement.proto.LOCALDataMovement;
 import org.apache.airavata.model.data.movement.proto.SCPDataMovement;
+import org.apache.airavata.model.data.movement.proto.UnicoreDataMovement;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -224,4 +229,459 @@ class ResourceServiceTest {
         assertTrue(result);
         verify(registryHandler).deleteBatchQueue("cr-001", "normal");
     }
+
+    // --- Compute Resource (additional) ---
+
+    @Test
+    void getAllComputeResourceNames_returnsMap() throws Exception {
+        Map<String, String> names = Map.of("cr-001", "cluster.example.com");
+        when(registryHandler.getAllComputeResourceNames()).thenReturn(names);
+
+        Map<String, String> result = 
resourceService.getAllComputeResourceNames();
+
+        assertEquals(1, result.size());
+        assertEquals("cluster.example.com", result.get("cr-001"));
+    }
+
+    @Test
+    void getAllComputeResourceNames_wrapsException() throws Exception {
+        when(registryHandler.getAllComputeResourceNames()).thenThrow(new 
RuntimeException("DB error"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.getAllComputeResourceNames());
+    }
+
+    @Test
+    void updateComputeResource_returnsTrue() throws Exception {
+        ComputeResourceDescription desc = 
ComputeResourceDescription.getDefaultInstance();
+        when(registryHandler.updateComputeResource("cr-001", 
desc)).thenReturn(true);
+
+        boolean result = resourceService.updateComputeResource("cr-001", desc);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void updateComputeResource_wrapsException() throws Exception {
+        ComputeResourceDescription desc = 
ComputeResourceDescription.getDefaultInstance();
+        when(registryHandler.updateComputeResource("cr-001", 
desc)).thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.updateComputeResource("cr-001", desc));
+    }
+
+    @Test
+    void getComputeResource_wrapsException() throws Exception {
+        when(registryHandler.getComputeResource("cr-bad")).thenThrow(new 
RuntimeException("not found"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.getComputeResource("cr-bad"));
+    }
+
+    @Test
+    void deleteComputeResource_wrapsException() throws Exception {
+        when(registryHandler.deleteComputeResource("cr-bad")).thenThrow(new 
RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.deleteComputeResource("cr-bad"));
+    }
+
+    // --- Storage Resource (additional) ---
+
+    @Test
+    void registerStorageResource_returnsId() throws Exception {
+        StorageResourceDescription desc = 
StorageResourceDescription.newBuilder().setHostName("storage.example.com").build();
+        
when(registryHandler.registerStorageResource(desc)).thenReturn("sr-001");
+
+        String result = resourceService.registerStorageResource(desc);
+
+        assertEquals("sr-001", result);
+    }
+
+    @Test
+    void registerStorageResource_wrapsException() throws Exception {
+        StorageResourceDescription desc = 
StorageResourceDescription.getDefaultInstance();
+        when(registryHandler.registerStorageResource(desc)).thenThrow(new 
RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.registerStorageResource(desc));
+    }
+
+    @Test
+    void updateStorageResource_returnsTrue() throws Exception {
+        StorageResourceDescription desc = 
StorageResourceDescription.getDefaultInstance();
+        when(registryHandler.updateStorageResource("sr-001", 
desc)).thenReturn(true);
+
+        boolean result = resourceService.updateStorageResource("sr-001", desc);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void updateStorageResource_wrapsException() throws Exception {
+        StorageResourceDescription desc = 
StorageResourceDescription.getDefaultInstance();
+        when(registryHandler.updateStorageResource("sr-001", 
desc)).thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.updateStorageResource("sr-001", desc));
+    }
+
+    @Test
+    void deleteStorageResource_returnsTrue() throws Exception {
+        when(registryHandler.deleteStorageResource("sr-001")).thenReturn(true);
+
+        boolean result = resourceService.deleteStorageResource("sr-001");
+
+        assertTrue(result);
+    }
+
+    // --- Job Submission (additional) ---
+
+    @Test
+    void addLocalSubmissionDetails_returnsId() throws Exception {
+        LOCALSubmission submission = LOCALSubmission.getDefaultInstance();
+        when(registryHandler.addLocalSubmissionDetails("cr-001", 1, 
submission)).thenReturn("js-local-001");
+
+        String result = resourceService.addLocalSubmissionDetails("cr-001", 1, 
submission);
+
+        assertEquals("js-local-001", result);
+    }
+
+    @Test
+    void addLocalSubmissionDetails_wrapsException() throws Exception {
+        LOCALSubmission submission = LOCALSubmission.getDefaultInstance();
+        when(registryHandler.addLocalSubmissionDetails("cr-001", 1, 
submission)).thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.addLocalSubmissionDetails("cr-001", 1, submission));
+    }
+
+    @Test
+    void updateLocalSubmissionDetails_returnsTrue() throws Exception {
+        LOCALSubmission submission = LOCALSubmission.getDefaultInstance();
+        when(registryHandler.updateLocalSubmissionDetails("js-local-001", 
submission)).thenReturn(true);
+
+        boolean result = 
resourceService.updateLocalSubmissionDetails("js-local-001", submission);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void addSSHForkJobSubmissionDetails_returnsId() throws Exception {
+        SSHJobSubmission submission = SSHJobSubmission.getDefaultInstance();
+        when(registryHandler.addSSHForkJobSubmissionDetails("cr-001", 1, 
submission)).thenReturn("js-fork-001");
+
+        String result = 
resourceService.addSSHForkJobSubmissionDetails("cr-001", 1, submission);
+
+        assertEquals("js-fork-001", result);
+    }
+
+    @Test
+    void addSSHForkJobSubmissionDetails_wrapsException() throws Exception {
+        SSHJobSubmission submission = SSHJobSubmission.getDefaultInstance();
+        when(registryHandler.addSSHForkJobSubmissionDetails("cr-001", 1, 
submission)).thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.addSSHForkJobSubmissionDetails("cr-001", 1, submission));
+    }
+
+    @Test
+    void getSSHJobSubmission_returnsSubmission() throws Exception {
+        SSHJobSubmission submission = 
SSHJobSubmission.newBuilder().setJobSubmissionInterfaceId("js-ssh-001").build();
+        
when(registryHandler.getSSHJobSubmission("js-ssh-001")).thenReturn(submission);
+
+        SSHJobSubmission result = 
resourceService.getSSHJobSubmission("js-ssh-001");
+
+        assertNotNull(result);
+        assertEquals("js-ssh-001", result.getJobSubmissionInterfaceId());
+    }
+
+    @Test
+    void addCloudJobSubmissionDetails_returnsId() throws Exception {
+        CloudJobSubmission submission = 
CloudJobSubmission.getDefaultInstance();
+        when(registryHandler.addCloudJobSubmissionDetails("cr-001", 1, 
submission)).thenReturn("js-cloud-001");
+
+        String result = resourceService.addCloudJobSubmissionDetails("cr-001", 
1, submission);
+
+        assertEquals("js-cloud-001", result);
+    }
+
+    @Test
+    void getCloudJobSubmission_returnsSubmission() throws Exception {
+        CloudJobSubmission submission = 
CloudJobSubmission.newBuilder().setJobSubmissionInterfaceId("js-cloud-001").build();
+        
when(registryHandler.getCloudJobSubmission("js-cloud-001")).thenReturn(submission);
+
+        CloudJobSubmission result = 
resourceService.getCloudJobSubmission("js-cloud-001");
+
+        assertNotNull(result);
+        assertEquals("js-cloud-001", result.getJobSubmissionInterfaceId());
+    }
+
+    @Test
+    void addUNICOREJobSubmissionDetails_returnsId() throws Exception {
+        UnicoreJobSubmission submission = 
UnicoreJobSubmission.getDefaultInstance();
+        when(registryHandler.addUNICOREJobSubmissionDetails("cr-001", 1, 
submission)).thenReturn("js-unicore-001");
+
+        String result = 
resourceService.addUNICOREJobSubmissionDetails("cr-001", 1, submission);
+
+        assertEquals("js-unicore-001", result);
+    }
+
+    @Test
+    void getUnicoreJobSubmission_returnsSubmission() throws Exception {
+        UnicoreJobSubmission submission = 
UnicoreJobSubmission.newBuilder().setJobSubmissionInterfaceId("js-unicore-001").build();
+        
when(registryHandler.getUnicoreJobSubmission("js-unicore-001")).thenReturn(submission);
+
+        UnicoreJobSubmission result = 
resourceService.getUnicoreJobSubmission("js-unicore-001");
+
+        assertNotNull(result);
+        assertEquals("js-unicore-001", result.getJobSubmissionInterfaceId());
+    }
+
+    @Test
+    void updateSSHJobSubmissionDetails_returnsTrue() throws Exception {
+        SSHJobSubmission submission = SSHJobSubmission.getDefaultInstance();
+        when(registryHandler.updateSSHJobSubmissionDetails("js-001", 
submission)).thenReturn(true);
+
+        boolean result = 
resourceService.updateSSHJobSubmissionDetails("js-001", submission);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void updateCloudJobSubmissionDetails_returnsTrue() throws Exception {
+        CloudJobSubmission submission = 
CloudJobSubmission.getDefaultInstance();
+        when(registryHandler.updateCloudJobSubmissionDetails("js-001", 
submission)).thenReturn(true);
+
+        boolean result = 
resourceService.updateCloudJobSubmissionDetails("js-001", submission);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void updateUnicoreJobSubmissionDetails_returnsTrue() throws Exception {
+        UnicoreJobSubmission submission = 
UnicoreJobSubmission.getDefaultInstance();
+        when(registryHandler.updateUnicoreJobSubmissionDetails("js-001", 
submission)).thenReturn(true);
+
+        boolean result = 
resourceService.updateUnicoreJobSubmissionDetails("js-001", submission);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void deleteJobSubmissionInterface_wrapsException() throws Exception {
+        when(registryHandler.deleteJobSubmissionInterface("cr-001", 
"js-bad")).thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.deleteJobSubmissionInterface("cr-001", "js-bad"));
+    }
+
+    // --- Data Movement (additional) ---
+
+    @Test
+    void addLocalDataMovementDetails_returnsId() throws Exception {
+        LOCALDataMovement movement = LOCALDataMovement.getDefaultInstance();
+        when(registryHandler.addLocalDataMovementDetails("cr-001", 
DMType.COMPUTE_RESOURCE, 0, movement)).thenReturn("dm-local-001");
+
+        String result = resourceService.addLocalDataMovementDetails("cr-001", 
DMType.COMPUTE_RESOURCE, 0, movement);
+
+        assertEquals("dm-local-001", result);
+    }
+
+    @Test
+    void updateLocalDataMovementDetails_returnsTrue() throws Exception {
+        LOCALDataMovement movement = LOCALDataMovement.getDefaultInstance();
+        when(registryHandler.updateLocalDataMovementDetails("dm-001", 
movement)).thenReturn(true);
+
+        boolean result = 
resourceService.updateLocalDataMovementDetails("dm-001", movement);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void getLocalDataMovement_returnsMovement() throws Exception {
+        LOCALDataMovement movement = 
LOCALDataMovement.newBuilder().setDataMovementInterfaceId("dm-local-001").build();
+        
when(registryHandler.getLocalDataMovement("dm-local-001")).thenReturn(movement);
+
+        LOCALDataMovement result = 
resourceService.getLocalDataMovement("dm-local-001");
+
+        assertNotNull(result);
+        assertEquals("dm-local-001", result.getDataMovementInterfaceId());
+    }
+
+    @Test
+    void updateSCPDataMovementDetails_returnsTrue() throws Exception {
+        SCPDataMovement movement = SCPDataMovement.getDefaultInstance();
+        when(registryHandler.updateSCPDataMovementDetails("dm-001", 
movement)).thenReturn(true);
+
+        boolean result = 
resourceService.updateSCPDataMovementDetails("dm-001", movement);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void getSCPDataMovement_returnsMovement() throws Exception {
+        SCPDataMovement movement = 
SCPDataMovement.newBuilder().setDataMovementInterfaceId("dm-scp-001").build();
+        
when(registryHandler.getSCPDataMovement("dm-scp-001")).thenReturn(movement);
+
+        SCPDataMovement result = 
resourceService.getSCPDataMovement("dm-scp-001");
+
+        assertNotNull(result);
+        assertEquals("dm-scp-001", result.getDataMovementInterfaceId());
+    }
+
+    @Test
+    void addUnicoreDataMovementDetails_returnsId() throws Exception {
+        UnicoreDataMovement movement = 
UnicoreDataMovement.getDefaultInstance();
+        when(registryHandler.addUnicoreDataMovementDetails("cr-001", 
DMType.COMPUTE_RESOURCE, 0, movement)).thenReturn("dm-unicore-001");
+
+        String result = 
resourceService.addUnicoreDataMovementDetails("cr-001", 
DMType.COMPUTE_RESOURCE, 0, movement);
+
+        assertEquals("dm-unicore-001", result);
+    }
+
+    @Test
+    void updateUnicoreDataMovementDetails_returnsTrue() throws Exception {
+        UnicoreDataMovement movement = 
UnicoreDataMovement.getDefaultInstance();
+        when(registryHandler.updateUnicoreDataMovementDetails("dm-001", 
movement)).thenReturn(true);
+
+        boolean result = 
resourceService.updateUnicoreDataMovementDetails("dm-001", movement);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void getUnicoreDataMovement_returnsMovement() throws Exception {
+        UnicoreDataMovement movement = 
UnicoreDataMovement.newBuilder().setDataMovementInterfaceId("dm-unicore-001").build();
+        
when(registryHandler.getUnicoreDataMovement("dm-unicore-001")).thenReturn(movement);
+
+        UnicoreDataMovement result = 
resourceService.getUnicoreDataMovement("dm-unicore-001");
+
+        assertNotNull(result);
+        assertEquals("dm-unicore-001", result.getDataMovementInterfaceId());
+    }
+
+    @Test
+    void addGridFTPDataMovementDetails_returnsId() throws Exception {
+        GridFTPDataMovement movement = 
GridFTPDataMovement.getDefaultInstance();
+        when(registryHandler.addGridFTPDataMovementDetails("cr-001", 
DMType.COMPUTE_RESOURCE, 0, movement)).thenReturn("dm-gridftp-001");
+
+        String result = 
resourceService.addGridFTPDataMovementDetails("cr-001", 
DMType.COMPUTE_RESOURCE, 0, movement);
+
+        assertEquals("dm-gridftp-001", result);
+    }
+
+    @Test
+    void updateGridFTPDataMovementDetails_returnsTrue() throws Exception {
+        GridFTPDataMovement movement = 
GridFTPDataMovement.getDefaultInstance();
+        when(registryHandler.updateGridFTPDataMovementDetails("dm-001", 
movement)).thenReturn(true);
+
+        boolean result = 
resourceService.updateGridFTPDataMovementDetails("dm-001", movement);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void getGridFTPDataMovement_returnsMovement() throws Exception {
+        GridFTPDataMovement movement = 
GridFTPDataMovement.newBuilder().setDataMovementInterfaceId("dm-gridftp-001").build();
+        
when(registryHandler.getGridFTPDataMovement("dm-gridftp-001")).thenReturn(movement);
+
+        GridFTPDataMovement result = 
resourceService.getGridFTPDataMovement("dm-gridftp-001");
+
+        assertNotNull(result);
+        assertEquals("dm-gridftp-001", result.getDataMovementInterfaceId());
+    }
+
+    @Test
+    void deleteDataMovementInterface_wrapsException() throws Exception {
+        when(registryHandler.deleteDataMovementInterface("cr-001", "dm-bad", 
DMType.COMPUTE_RESOURCE))
+                .thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class,
+                () -> resourceService.deleteDataMovementInterface("cr-001", 
"dm-bad", DMType.COMPUTE_RESOURCE));
+    }
+
+    // --- Resource Job Manager (additional) ---
+
+    @Test
+    void updateResourceJobManager_returnsTrue() throws Exception {
+        ResourceJobManager manager = ResourceJobManager.getDefaultInstance();
+        when(registryHandler.updateResourceJobManager("rjm-001", 
manager)).thenReturn(true);
+
+        boolean result = resourceService.updateResourceJobManager("rjm-001", 
manager);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void getResourceJobManager_returnsManager() throws Exception {
+        ResourceJobManager manager = ResourceJobManager.newBuilder()
+                .setResourceJobManagerId("rjm-001")
+                .setResourceJobManagerType(ResourceJobManagerType.SLURM)
+                .build();
+        
when(registryHandler.getResourceJobManager("rjm-001")).thenReturn(manager);
+
+        ResourceJobManager result = 
resourceService.getResourceJobManager("rjm-001");
+
+        assertNotNull(result);
+        assertEquals("rjm-001", result.getResourceJobManagerId());
+        assertEquals(ResourceJobManagerType.SLURM, 
result.getResourceJobManagerType());
+    }
+
+    @Test
+    void registerResourceJobManager_wrapsException() throws Exception {
+        ResourceJobManager manager = ResourceJobManager.getDefaultInstance();
+        
when(registryHandler.registerResourceJobManager(manager)).thenThrow(new 
RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.registerResourceJobManager(manager));
+    }
+
+    @Test
+    void deleteResourceJobManager_wrapsException() throws Exception {
+        
when(registryHandler.deleteResourceJobManager("rjm-bad")).thenThrow(new 
RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.deleteResourceJobManager("rjm-bad"));
+    }
+
+    // --- Batch Queue (additional) ---
+
+    @Test
+    void deleteBatchQueue_wrapsException() throws Exception {
+        when(registryHandler.deleteBatchQueue("cr-001", 
"bad-queue")).thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.deleteBatchQueue("cr-001", "bad-queue"));
+    }
+
+    // --- ComputeResourceProvider SPI delegates ---
+
+    @Test
+    void getGatewayResourceProfile_returnsProfile() throws Exception {
+        GatewayResourceProfile profile = 
GatewayResourceProfile.newBuilder().setGatewayId("gw-001").build();
+        
when(registryHandler.getGatewayResourceProfile("gw-001")).thenReturn(profile);
+
+        GatewayResourceProfile result = 
resourceService.getGatewayResourceProfile("gw-001");
+
+        assertNotNull(result);
+        assertEquals("gw-001", result.getGatewayId());
+    }
+
+    @Test
+    void getGatewayResourceProfile_wrapsException() throws Exception {
+        
when(registryHandler.getGatewayResourceProfile("gw-bad")).thenThrow(new 
RuntimeException("fail"));
+
+        assertThrows(ServiceException.class, () -> 
resourceService.getGatewayResourceProfile("gw-bad"));
+    }
+
+    @Test
+    void getGroupComputeResourcePreference_returnsPreference() throws 
Exception {
+        GroupComputeResourcePreference pref = 
GroupComputeResourcePreference.newBuilder()
+                .setComputeResourceId("cr-001")
+                .build();
+        when(registryHandler.getGroupComputeResourcePreference("cr-001", 
"grp-001")).thenReturn(pref);
+
+        GroupComputeResourcePreference result = 
resourceService.getGroupComputeResourcePreference("cr-001", "grp-001");
+
+        assertNotNull(result);
+        assertEquals("cr-001", result.getComputeResourceId());
+    }
+
+    @Test
+    void getGroupComputeResourcePreference_wrapsException() throws Exception {
+        when(registryHandler.getGroupComputeResourcePreference("cr-bad", 
"grp-bad"))
+                .thenThrow(new RuntimeException("fail"));
+
+        assertThrows(ServiceException.class,
+                () -> 
resourceService.getGroupComputeResourcePreference("cr-bad", "grp-bad"));
+    }
 }
diff --git 
a/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/handler/CredentialStoreServerHandlerTest.java
 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/handler/CredentialStoreServerHandlerTest.java
new file mode 100644
index 0000000000..7f63624a43
--- /dev/null
+++ 
b/airavata-api/credential-service/src/test/java/org/apache/airavata/credential/handler/CredentialStoreServerHandlerTest.java
@@ -0,0 +1,299 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.credential.handler;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.apache.airavata.credential.model.Credential;
+import org.apache.airavata.credential.repository.CredentialReaderImpl;
+import org.apache.airavata.credential.repository.CredentialStoreException;
+import org.apache.airavata.credential.repository.SSHCredentialWriter;
+import org.apache.airavata.model.credential.store.proto.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class CredentialStoreServerHandlerTest {
+
+    @Mock
+    CredentialReaderImpl credentialReader;
+
+    @Mock
+    SSHCredentialWriter sshCredentialWriter;
+
+    CredentialStoreServerHandler handler;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        // Use Mockito to create a spy-like instance without invoking the real 
constructor
+        // (which requires DB connections), then inject mocked dependencies 
via reflection
+        handler = mock(CredentialStoreServerHandler.class, 
withSettings().defaultAnswer(CALLS_REAL_METHODS));
+        setField(handler, "credentialReader", credentialReader);
+        setField(handler, "sshCredentialWriter", sshCredentialWriter);
+    }
+
+    private void setField(Object target, String fieldName, Object value) 
throws Exception {
+        Field field = findField(target.getClass(), fieldName);
+        field.setAccessible(true);
+        field.set(target, value);
+    }
+
+    private Field findField(Class<?> clazz, String fieldName) throws 
NoSuchFieldException {
+        while (clazz != null) {
+            try {
+                return clazz.getDeclaredField(fieldName);
+            } catch (NoSuchFieldException e) {
+                clazz = clazz.getSuperclass();
+            }
+        }
+        throw new NoSuchFieldException(fieldName);
+    }
+
+    @Test
+    void getSSHCredential_returnsCredentialWhenFound() throws Exception {
+        org.apache.airavata.credential.model.SSHCredential modelCred = new 
org.apache.airavata.credential.model.SSHCredential();
+        modelCred.setPortalUserName("testUser");
+        modelCred.setGateway("gw1");
+        modelCred.setPublicKey("ssh-rsa AAAA".getBytes());
+        modelCred.setPrivateKey("-----BEGIN RSA PRIVATE KEY-----".getBytes());
+        modelCred.setPassphrase("passphrase123");
+        modelCred.setToken("token-1");
+        modelCred.setCertificateRequestedTime(new Date(1000000));
+        modelCred.setDescription("test key");
+
+        when(credentialReader.getCredential("gw1", 
"token-1")).thenReturn(modelCred);
+
+        SSHCredential result = handler.getSSHCredential("token-1", "gw1");
+
+        assertNotNull(result);
+        assertEquals("testUser", result.getUsername());
+        assertEquals("gw1", result.getGatewayId());
+        assertEquals("ssh-rsa AAAA", result.getPublicKey());
+        assertEquals("passphrase123", result.getPassphrase());
+        assertEquals("token-1", result.getToken());
+        assertEquals(1000000, result.getPersistedTime());
+        assertEquals("test key", result.getDescription());
+    }
+
+    @Test
+    void getSSHCredential_returnsNullWhenNotSSHCredential() throws Exception {
+        org.apache.airavata.credential.model.PasswordCredential modelCred =
+                new org.apache.airavata.credential.model.PasswordCredential();
+        modelCred.setToken("token-1");
+
+        when(credentialReader.getCredential("gw1", 
"token-1")).thenReturn(modelCred);
+
+        SSHCredential result = handler.getSSHCredential("token-1", "gw1");
+
+        assertNull(result);
+    }
+
+    @Test
+    void getSSHCredential_throwsOnReaderError() throws Exception {
+        when(credentialReader.getCredential("gw1", "token-1"))
+                .thenThrow(new CredentialStoreException("DB error"));
+
+        assertThrows(CredentialStoreException.class, () -> 
handler.getSSHCredential("token-1", "gw1"));
+    }
+
+    @Test
+    void getPasswordCredential_returnsCredentialWhenFound() throws Exception {
+        org.apache.airavata.credential.model.PasswordCredential modelCred =
+                new org.apache.airavata.credential.model.PasswordCredential();
+        modelCred.setGateway("gw1");
+        modelCred.setPortalUserName("portalUser");
+        modelCred.setUserName("loginUser");
+        modelCred.setPassword("secret");
+        modelCred.setToken("pwd-token-1");
+        modelCred.setCertificateRequestedTime(new Date(2000000));
+        modelCred.setDescription("pwd cred");
+
+        when(credentialReader.getCredential("gw1", 
"pwd-token-1")).thenReturn(modelCred);
+
+        PasswordCredential result = 
handler.getPasswordCredential("pwd-token-1", "gw1");
+
+        assertNotNull(result);
+        assertEquals("gw1", result.getGatewayId());
+        assertEquals("portalUser", result.getPortalUserName());
+        assertEquals("loginUser", result.getLoginUserName());
+        assertEquals("secret", result.getPassword());
+        assertEquals("pwd-token-1", result.getToken());
+    }
+
+    @Test
+    void getPasswordCredential_returnsNullWhenNotPasswordCredential() throws 
Exception {
+        org.apache.airavata.credential.model.SSHCredential modelCred =
+                new org.apache.airavata.credential.model.SSHCredential();
+        modelCred.setToken("token-1");
+
+        when(credentialReader.getCredential("gw1", 
"token-1")).thenReturn(modelCred);
+
+        PasswordCredential result = handler.getPasswordCredential("token-1", 
"gw1");
+
+        assertNull(result);
+    }
+
+    @Test
+    void addSSHCredential_writesAndReturnsToken() throws Exception {
+        SSHCredential sshCredential = SSHCredential.newBuilder()
+                .setGatewayId("gw1")
+                .setUsername("testUser")
+                .setPublicKey("ssh-rsa AAAA")
+                .setPrivateKey("-----BEGIN RSA-----")
+                .setDescription("my key")
+                .build();
+
+        String token = handler.addSSHCredential(sshCredential);
+
+        assertNotNull(token);
+        assertFalse(token.isEmpty());
+        
verify(sshCredentialWriter).writeCredentials(any(org.apache.airavata.credential.model.SSHCredential.class));
+    }
+
+    @Test
+    void addPasswordCredential_writesAndReturnsToken() throws Exception {
+        PasswordCredential pwdCredential = PasswordCredential.newBuilder()
+                .setGatewayId("gw1")
+                .setPortalUserName("portalUser")
+                .setLoginUserName("loginUser")
+                .setPassword("secret")
+                .setDescription("pwd cred")
+                .build();
+
+        String token = handler.addPasswordCredential(pwdCredential);
+
+        assertNotNull(token);
+        assertFalse(token.isEmpty());
+        
verify(sshCredentialWriter).writeCredentials(any(org.apache.airavata.credential.model.PasswordCredential.class));
+    }
+
+    @Test
+    void getAllCredentialSummaries_sshType_filtersCorrectly() throws Exception 
{
+        org.apache.airavata.credential.model.SSHCredential sshCred =
+                new org.apache.airavata.credential.model.SSHCredential();
+        sshCred.setPortalUserName("user1");
+        sshCred.setGateway("gw1");
+        sshCred.setPublicKey("ssh-rsa key".getBytes());
+        sshCred.setToken("ssh-token-1");
+        sshCred.setCertificateRequestedTime(new Date(1000000));
+
+        org.apache.airavata.credential.model.PasswordCredential pwdCred =
+                new org.apache.airavata.credential.model.PasswordCredential();
+        pwdCred.setPortalUserName("user2");
+        pwdCred.setGateway("gw1");
+        pwdCred.setToken("pwd-token-1");
+        pwdCred.setCertificateRequestedTime(new Date(2000000));
+
+        List<String> tokens = List.of("ssh-token-1", "pwd-token-1");
+        when(credentialReader.getAllAccessibleCredentialsPerGateway("gw1", 
tokens))
+                .thenReturn(List.of(sshCred, pwdCred));
+
+        List<CredentialSummary> result = 
handler.getAllCredentialSummaries(SummaryType.SSH, tokens, "gw1");
+
+        assertEquals(1, result.size());
+        assertEquals(SummaryType.SSH, result.get(0).getType());
+        assertEquals("ssh-token-1", result.get(0).getToken());
+    }
+
+    @Test
+    void getAllCredentialSummaries_passwdType_filtersCorrectly() throws 
Exception {
+        org.apache.airavata.credential.model.PasswordCredential pwdCred =
+                new org.apache.airavata.credential.model.PasswordCredential();
+        pwdCred.setPortalUserName("user1");
+        pwdCred.setGateway("gw1");
+        pwdCred.setToken("pwd-token-1");
+        pwdCred.setCertificateRequestedTime(new Date(1000000));
+
+        List<String> tokens = List.of("pwd-token-1");
+        when(credentialReader.getAllAccessibleCredentialsPerGateway("gw1", 
tokens))
+                .thenReturn(List.of(pwdCred));
+
+        List<CredentialSummary> result = 
handler.getAllCredentialSummaries(SummaryType.PASSWD, tokens, "gw1");
+
+        assertEquals(1, result.size());
+        assertEquals(SummaryType.PASSWD, result.get(0).getType());
+    }
+
+    @Test
+    void deleteSSHCredential_delegatesToReader() throws Exception {
+        handler.deleteSSHCredential("token-1", "gw1");
+
+        verify(credentialReader).removeCredentials("gw1", "token-1");
+    }
+
+    @Test
+    void deleteSSHCredential_throwsOnError() throws Exception {
+        doThrow(new CredentialStoreException("DB 
error")).when(credentialReader).removeCredentials("gw1", "token-1");
+
+        assertThrows(CredentialStoreException.class, () -> 
handler.deleteSSHCredential("token-1", "gw1"));
+    }
+
+    @Test
+    void getAllCredentialSummaryForGateway_sshType_returnsSSHOnly() throws 
Exception {
+        org.apache.airavata.credential.model.SSHCredential sshCred =
+                new org.apache.airavata.credential.model.SSHCredential();
+        sshCred.setPortalUserName("user1");
+        sshCred.setGateway("gw1");
+        sshCred.setPublicKey("ssh-rsa key".getBytes());
+        sshCred.setToken("ssh-token-1");
+        sshCred.setCertificateRequestedTime(new Date(1000000));
+
+        
when(credentialReader.getAllCredentialsPerGateway("gw1")).thenReturn(List.of(sshCred));
+
+        List<CredentialSummary> result = 
handler.getAllCredentialSummaryForGateway(SummaryType.SSH, "gw1");
+
+        assertEquals(1, result.size());
+        assertEquals("ssh-token-1", result.get(0).getToken());
+    }
+
+    @Test
+    void getAllCredentialSummaryForGateway_nonSSHType_returnsEmpty() throws 
Exception {
+        List<CredentialSummary> result = 
handler.getAllCredentialSummaryForGateway(SummaryType.PASSWD, "gw1");
+
+        assertTrue(result.isEmpty());
+    }
+
+    @Test
+    void getAllPWDCredentialsForGateway_returnsPwdTokensAndDescriptions() 
throws Exception {
+        org.apache.airavata.credential.model.PasswordCredential pwdCred =
+                new org.apache.airavata.credential.model.PasswordCredential();
+        pwdCred.setToken("pwd-token-1");
+        pwdCred.setDescription("my password");
+        pwdCred.setGateway("gw1");
+        pwdCred.setPortalUserName("user1");
+        pwdCred.setCertificateRequestedTime(new Date());
+
+        
when(credentialReader.getAllCredentialsPerGateway("gw1")).thenReturn(List.of(pwdCred));
+
+        Map<String, String> result = 
handler.getAllPWDCredentialsForGateway("gw1");
+
+        assertEquals(1, result.size());
+        assertEquals("my password", result.get("pwd-token-1"));
+    }
+}
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/sharing/service/ResourceSharingServiceTest.java
 
b/airavata-api/src/test/java/org/apache/airavata/sharing/service/ResourceSharingServiceTest.java
index db0007912f..025d3eb54d 100644
--- 
a/airavata-api/src/test/java/org/apache/airavata/sharing/service/ResourceSharingServiceTest.java
+++ 
b/airavata-api/src/test/java/org/apache/airavata/sharing/service/ResourceSharingServiceTest.java
@@ -29,7 +29,9 @@ import org.apache.airavata.execution.service.RequestContext;
 import org.apache.airavata.execution.service.ServiceAuthorizationException;
 import org.apache.airavata.model.group.proto.ResourcePermissionType;
 import org.apache.airavata.sharing.handler.SharingRegistryServerHandler;
+import org.apache.airavata.sharing.model.EntityEntity;
 import org.apache.airavata.sharing.model.UserEntity;
+import org.apache.airavata.sharing.model.UserGroupEntity;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -137,4 +139,199 @@ class ResourceSharingServiceTest {
                 .shareEntityWithGroups(
                         eq("testGateway"), eq("resource-1"), anyList(), 
eq("testGateway:WRITE"), eq(true));
     }
+
+    @Test
+    void shareResourceWithGroups_nonOwnerWithoutSharingPermissionRejected() 
throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(false);
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:MANAGE_SHARING"))
+                .thenReturn(false);
+
+        assertThrows(
+                ServiceAuthorizationException.class,
+                () -> resourceSharingService.shareResourceWithGroups(
+                        ctx, "resource-1", Map.of("group-1", 
ResourcePermissionType.READ)));
+    }
+
+    @Test
+    void shareResourceWithGroups_manageSharingUserCanShareRead() throws 
Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(false);
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:MANAGE_SHARING"))
+                .thenReturn(true);
+
+        boolean result = resourceSharingService.shareResourceWithGroups(
+                ctx, "resource-1", Map.of("group-1", 
ResourcePermissionType.READ));
+
+        assertTrue(result);
+        verify(sharingHandler)
+                .shareEntityWithGroups(
+                        eq("testGateway"), eq("resource-1"), anyList(), 
eq("testGateway:READ"), eq(true));
+    }
+
+    @Test
+    void revokeSharingOfResourceFromGroups_ownerCanRevoke() throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(true);
+        EntityEntity entity = new EntityEntity();
+        entity.setEntityTypeId("testGateway:OTHER");
+        when(sharingHandler.getEntity("testGateway", 
"resource-1")).thenReturn(entity);
+
+        boolean result = 
resourceSharingService.revokeSharingOfResourceFromGroups(
+                ctx, "resource-1", Map.of("group-1", 
ResourcePermissionType.WRITE));
+
+        assertTrue(result);
+        verify(sharingHandler)
+                .revokeEntitySharingFromUsers(
+                        eq("testGateway"), eq("resource-1"), anyList(), 
eq("testGateway:WRITE"));
+    }
+
+    @Test
+    void 
revokeSharingOfResourceFromGroups_nonOwnerWithoutSharingPermissionRejected() 
throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(false);
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:MANAGE_SHARING"))
+                .thenReturn(false);
+
+        assertThrows(
+                ServiceAuthorizationException.class,
+                () -> resourceSharingService.revokeSharingOfResourceFromGroups(
+                        ctx, "resource-1", Map.of("group-1", 
ResourcePermissionType.READ)));
+    }
+
+    @Test
+    void getAllDirectlyAccessibleUsers_returnsUserIds() throws Exception {
+        UserEntity user1 = new UserEntity();
+        user1.setUserId("user1@testGateway");
+        when(sharingHandler.getListOfDirectlySharedUsers("testGateway", 
"resource-1", "testGateway:WRITE"))
+                .thenReturn(List.of(user1));
+        UserEntity owner = new UserEntity();
+        owner.setUserId("owner@testGateway");
+        when(sharingHandler.getListOfDirectlySharedUsers("testGateway", 
"resource-1", "testGateway:OWNER"))
+                .thenReturn(List.of(owner));
+
+        List<String> result =
+                resourceSharingService.getAllDirectlyAccessibleUsers(ctx, 
"resource-1", ResourcePermissionType.WRITE);
+
+        assertEquals(2, result.size());
+        assertTrue(result.contains("user1@testGateway"));
+        assertTrue(result.contains("owner@testGateway"));
+    }
+
+    @Test
+    void getAllAccessibleGroups_returnsGroupIds() throws Exception {
+        UserGroupEntity group1 = new UserGroupEntity();
+        group1.setGroupId("group-1");
+        when(sharingHandler.getListOfSharedGroups("testGateway", "resource-1", 
"testGateway:READ"))
+                .thenReturn(List.of(group1));
+
+        List<String> result =
+                resourceSharingService.getAllAccessibleGroups(ctx, 
"resource-1", ResourcePermissionType.READ);
+
+        assertEquals(1, result.size());
+        assertTrue(result.contains("group-1"));
+    }
+
+    @Test
+    void getAllDirectlyAccessibleGroups_returnsGroupIds() throws Exception {
+        UserGroupEntity group1 = new UserGroupEntity();
+        group1.setGroupId("group-1");
+        when(sharingHandler.getListOfDirectlySharedGroups("testGateway", 
"resource-1", "testGateway:WRITE"))
+                .thenReturn(List.of(group1));
+
+        List<String> result =
+                resourceSharingService.getAllDirectlyAccessibleGroups(ctx, 
"resource-1", ResourcePermissionType.WRITE);
+
+        assertEquals(1, result.size());
+        assertTrue(result.contains("group-1"));
+    }
+
+    @Test
+    void userHasAccess_writePermission_trueWhenWriteAccess() throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(false);
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:WRITE"))
+                .thenReturn(true);
+
+        boolean result = resourceSharingService.userHasAccess(ctx, 
"resource-1", ResourcePermissionType.WRITE);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void userHasAccess_manageSharingPermission() throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(false);
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:MANAGE_SHARING"))
+                .thenReturn(true);
+
+        boolean result = resourceSharingService.userHasAccess(ctx, 
"resource-1", ResourcePermissionType.MANAGE_SHARING);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void userHasAccess_ownerImpliesAllPermissions() throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(true);
+
+        assertTrue(resourceSharingService.userHasAccess(ctx, "resource-1", 
ResourcePermissionType.OWNER));
+        assertTrue(resourceSharingService.userHasAccess(ctx, "resource-1", 
ResourcePermissionType.WRITE));
+        assertTrue(resourceSharingService.userHasAccess(ctx, "resource-1", 
ResourcePermissionType.READ));
+        assertTrue(resourceSharingService.userHasAccess(ctx, "resource-1", 
ResourcePermissionType.MANAGE_SHARING));
+    }
+
+    @Test
+    void shareResourceWithUsers_writePermission() throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(true);
+
+        boolean result = resourceSharingService.shareResourceWithUsers(
+                ctx, "resource-1", Map.of("otherUser", 
ResourcePermissionType.WRITE));
+
+        assertTrue(result);
+        verify(sharingHandler)
+                .shareEntityWithUsers(eq("testGateway"), eq("resource-1"), 
anyList(), eq("testGateway:WRITE"), eq(true));
+    }
+
+    @Test
+    void revokeSharingOfResourceFromUsers_readPermission() throws Exception {
+        when(sharingHandler.userHasAccess("testGateway", 
"testUser@testGateway", "resource-1", "testGateway:OWNER"))
+                .thenReturn(true);
+
+        boolean result = 
resourceSharingService.revokeSharingOfResourceFromUsers(
+                ctx, "resource-1", Map.of("otherUser", 
ResourcePermissionType.READ));
+
+        assertTrue(result);
+        verify(sharingHandler)
+                .revokeEntitySharingFromUsers(eq("testGateway"), 
eq("resource-1"), anyList(), eq("testGateway:READ"));
+    }
+
+    @Test
+    void getAllAccessibleUsers_ownerPermission_returnsOnlyOwners() throws 
Exception {
+        UserEntity owner = new UserEntity();
+        owner.setUserId("owner@testGateway");
+        when(sharingHandler.getListOfSharedUsers("testGateway", "resource-1", 
"testGateway:OWNER"))
+                .thenReturn(List.of(owner));
+
+        List<String> result =
+                resourceSharingService.getAllAccessibleUsers(ctx, 
"resource-1", ResourcePermissionType.OWNER);
+
+        assertEquals(1, result.size());
+        assertTrue(result.contains("owner@testGateway"));
+    }
+
+    @Test
+    void getAllAccessibleGroups_manageSharingPermission() throws Exception {
+        UserGroupEntity group1 = new UserGroupEntity();
+        group1.setGroupId("group-manage-1");
+        when(sharingHandler.getListOfSharedGroups("testGateway", "resource-1", 
"testGateway:MANAGE_SHARING"))
+                .thenReturn(List.of(group1));
+
+        List<String> result =
+                resourceSharingService.getAllAccessibleGroups(ctx, 
"resource-1", ResourcePermissionType.MANAGE_SHARING);
+
+        assertEquals(1, result.size());
+        assertTrue(result.contains("group-manage-1"));
+    }
 }
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/sharing/service/SharingHelperTest.java
 
b/airavata-api/src/test/java/org/apache/airavata/sharing/service/SharingHelperTest.java
new file mode 100644
index 0000000000..68fbab96a5
--- /dev/null
+++ 
b/airavata-api/src/test/java/org/apache/airavata/sharing/service/SharingHelperTest.java
@@ -0,0 +1,193 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.sharing.service;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Arrays;
+import org.apache.airavata.execution.handler.RegistryServerHandler;
+import org.apache.airavata.model.appcatalog.gatewaygroups.proto.GatewayGroups;
+import org.apache.airavata.model.group.proto.ResourcePermissionType;
+import org.apache.airavata.sharing.handler.SharingRegistryServerHandler;
+import org.apache.airavata.sharing.model.PermissionTypeEntity;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class SharingHelperTest {
+
+    @Mock
+    SharingRegistryServerHandler sharingHandler;
+
+    @Mock
+    RegistryServerHandler registryHandler;
+
+    @Test
+    void isSharingEnabled_returnsFalseWhenSettingsNotConfigured() {
+        // ServerSettings not configured in test context
+        assertFalse(SharingHelper.isSharingEnabled());
+    }
+
+    @Test
+    void userHasAccess_ownerPermission_returnsTrueWhenOwner() throws Exception 
{
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:OWNER"))
+                .thenReturn(true);
+
+        boolean result =
+                SharingHelper.userHasAccess(sharingHandler, "gw1", "alice", 
"entity1", ResourcePermissionType.OWNER);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void userHasAccess_ownerPermission_returnsFalseWhenNotOwner() throws 
Exception {
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:OWNER"))
+                .thenReturn(false);
+
+        boolean result =
+                SharingHelper.userHasAccess(sharingHandler, "gw1", "alice", 
"entity1", ResourcePermissionType.OWNER);
+
+        assertFalse(result);
+    }
+
+    @Test
+    void userHasAccess_readPermission_returnsTrueWhenOwner() throws Exception {
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:OWNER"))
+                .thenReturn(true);
+
+        boolean result =
+                SharingHelper.userHasAccess(sharingHandler, "gw1", "alice", 
"entity1", ResourcePermissionType.READ);
+
+        assertTrue(result);
+        // should not check READ permission when OWNER already grants access
+        verify(sharingHandler, never()).userHasAccess("gw1", "alice@gw1", 
"entity1", "gw1:READ");
+    }
+
+    @Test
+    void userHasAccess_readPermission_fallsBackToReadWhenNotOwner() throws 
Exception {
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:OWNER"))
+                .thenReturn(false);
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:READ"))
+                .thenReturn(true);
+
+        boolean result =
+                SharingHelper.userHasAccess(sharingHandler, "gw1", "alice", 
"entity1", ResourcePermissionType.READ);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void userHasAccess_readPermission_returnsFalseWhenNeitherOwnerNorReader() 
throws Exception {
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:OWNER"))
+                .thenReturn(false);
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:READ"))
+                .thenReturn(false);
+
+        boolean result =
+                SharingHelper.userHasAccess(sharingHandler, "gw1", "alice", 
"entity1", ResourcePermissionType.READ);
+
+        assertFalse(result);
+    }
+
+    @Test
+    void userHasAccess_qualifiedUserId_usedAsIs() throws Exception {
+        when(sharingHandler.userHasAccess("gw1", "alice@gw1", "entity1", 
"gw1:OWNER"))
+                .thenReturn(true);
+
+        boolean result = SharingHelper.userHasAccess(
+                sharingHandler, "gw1", "alice@gw1", "entity1", 
ResourcePermissionType.OWNER);
+
+        assertTrue(result);
+    }
+
+    @Test
+    void userHasAccess_throwsRuntimeExceptionOnFailure() throws Exception {
+        when(sharingHandler.userHasAccess(anyString(), anyString(), 
anyString(), anyString()))
+                .thenThrow(new RuntimeException("DB error"));
+
+        assertThrows(
+                RuntimeException.class,
+                () -> SharingHelper.userHasAccess(
+                        sharingHandler, "gw1", "alice", "entity1", 
ResourcePermissionType.OWNER));
+    }
+
+    @Test
+    void retrieveGatewayGroups_returnsExistingGroups() throws Exception {
+        GatewayGroups groups = GatewayGroups.newBuilder()
+                .setGatewayId("gw1")
+                .setAdminsGroupId("admins")
+                .build();
+        when(registryHandler.isGatewayGroupsExists("gw1")).thenReturn(true);
+        when(registryHandler.getGatewayGroups("gw1")).thenReturn(groups);
+
+        GatewayGroups result = 
SharingHelper.retrieveGatewayGroups(registryHandler, "gw1");
+
+        assertEquals("gw1", result.getGatewayId());
+        assertEquals("admins", result.getAdminsGroupId());
+    }
+
+    @Test
+    void createManageSharingPermissionTypeIfMissing_createsWhenNotExists() 
throws Exception {
+        when(sharingHandler.isPermissionExists("gw1", 
"gw1:MANAGE_SHARING")).thenReturn(false);
+
+        
SharingHelper.createManageSharingPermissionTypeIfMissing(sharingHandler, "gw1");
+
+        verify(sharingHandler).createPermissionType(argThat(pt -> 
pt.getPermissionTypeId().equals("gw1:MANAGE_SHARING")
+                && pt.getDomainId().equals("gw1")
+                && pt.getName().equals("MANAGE_SHARING")));
+    }
+
+    @Test
+    void createManageSharingPermissionTypeIfMissing_skipsWhenExists() throws 
Exception {
+        when(sharingHandler.isPermissionExists("gw1", 
"gw1:MANAGE_SHARING")).thenReturn(true);
+
+        
SharingHelper.createManageSharingPermissionTypeIfMissing(sharingHandler, "gw1");
+
+        verify(sharingHandler, never()).createPermissionType(any());
+    }
+
+    @Test
+    void shareEntityWithAdminGatewayGroups_sharesWithAdminAndReadOnlyGroups() 
throws Exception {
+        GatewayGroups groups = GatewayGroups.newBuilder()
+                .setGatewayId("gw1")
+                .setAdminsGroupId("admins")
+                .setReadOnlyAdminsGroupId("readOnlyAdmins")
+                .build();
+        when(registryHandler.isGatewayGroupsExists("gw1")).thenReturn(true);
+        when(registryHandler.getGatewayGroups("gw1")).thenReturn(groups);
+        when(sharingHandler.isPermissionExists("gw1", 
"gw1:MANAGE_SHARING")).thenReturn(true);
+
+        org.apache.airavata.sharing.model.EntityEntity entity = new 
org.apache.airavata.sharing.model.EntityEntity();
+        entity.setDomainId("gw1");
+        entity.setEntityId("entity1");
+
+        SharingHelper.shareEntityWithAdminGatewayGroups(sharingHandler, 
registryHandler, entity);
+
+        verify(sharingHandler)
+                .shareEntityWithGroups("gw1", "entity1", 
Arrays.asList("admins"), "gw1:MANAGE_SHARING", true);
+        verify(sharingHandler).shareEntityWithGroups("gw1", "entity1", 
Arrays.asList("admins"), "gw1:WRITE", true);
+        verify(sharingHandler)
+                .shareEntityWithGroups(
+                        "gw1", "entity1", Arrays.asList("admins", 
"readOnlyAdmins"), "gw1:READ", true);
+    }
+}
diff --git 
a/airavata-api/storage-service/src/test/java/org/apache/airavata/storage/service/AirvataFileServiceTest.java
 
b/airavata-api/storage-service/src/test/java/org/apache/airavata/storage/service/AirvataFileServiceTest.java
new file mode 100644
index 0000000000..33be634d89
--- /dev/null
+++ 
b/airavata-api/storage-service/src/test/java/org/apache/airavata/storage/service/AirvataFileServiceTest.java
@@ -0,0 +1,199 @@
+/**
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.apache.airavata.storage.service;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.List;
+import org.apache.airavata.compute.util.AgentAdaptor;
+import org.apache.airavata.execution.orchestrator.AdaptorSupport;
+import org.apache.airavata.execution.handler.RegistryServerHandler;
+import org.apache.airavata.storage.model.AiravataDirectory;
+import org.apache.airavata.storage.model.AiravataFile;
+import org.apache.airavata.storage.util.FileMetadata;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class AirvataFileServiceTest {
+
+    @Mock
+    AdaptorSupport adaptorSupport;
+
+    @Mock
+    RegistryServerHandler registryClient;
+
+    @Mock
+    AgentAdaptor agentAdaptor;
+
+    @InjectMocks
+    AirvataFileService fileService;
+
+    @Test
+    void getInfo_returnsFileMetadata() throws Exception {
+        FileMetadata metadata = new FileMetadata();
+        metadata.setName("test.txt");
+        metadata.setSize(1024);
+
+        try (MockedConstruction<ProcessDataManager> mocked = 
mockConstruction(ProcessDataManager.class, (mock, ctx) -> {
+            when(mock.getAgentAdaptor()).thenReturn(agentAdaptor);
+            when(mock.getBaseDir()).thenReturn("/home/user/");
+        })) {
+            
when(agentAdaptor.getFileMetadata("/home/user/subdir/test.txt")).thenReturn(metadata);
+
+            FileMetadata result = fileService.getInfo("proc-1", 
"subdir/test.txt");
+
+            assertEquals("test.txt", result.getName());
+            assertEquals(1024, result.getSize());
+        }
+    }
+
+    @Test
+    void listDir_returnsDirectoryWithContents() throws Exception {
+        FileMetadata dirMeta = new FileMetadata();
+        dirMeta.setName("workdir");
+        dirMeta.setSize(4096);
+        dirMeta.setDirectory(true);
+
+        FileMetadata fileMeta = new FileMetadata();
+        fileMeta.setName("output.txt");
+        fileMeta.setSize(512);
+        fileMeta.setDirectory(false);
+
+        FileMetadata subDirMeta = new FileMetadata();
+        subDirMeta.setName("logs");
+        subDirMeta.setSize(4096);
+        subDirMeta.setDirectory(true);
+
+        try (MockedConstruction<ProcessDataManager> mocked = 
mockConstruction(ProcessDataManager.class, (mock, ctx) -> {
+            when(mock.getAgentAdaptor()).thenReturn(agentAdaptor);
+            when(mock.getBaseDir()).thenReturn("/home/user/");
+        })) {
+            
when(agentAdaptor.getFileMetadata("/home/user/workdir")).thenReturn(dirMeta);
+            
when(agentAdaptor.listDirectory("/home/user/workdir")).thenReturn(List.of("output.txt",
 "logs"));
+            
when(agentAdaptor.getFileMetadata("/home/user/workdir/output.txt")).thenReturn(fileMeta);
+            
when(agentAdaptor.getFileMetadata("/home/user/workdir/logs")).thenReturn(subDirMeta);
+
+            AiravataDirectory result = fileService.listDir("proc-1", 
"workdir");
+
+            assertEquals("workdir", result.getDirectoryName());
+            assertEquals(1, result.getInnerFiles().size());
+            assertEquals("output.txt", 
result.getInnerFiles().get(0).getFileName());
+            assertEquals(1, result.getInnerDirectories().size());
+            assertEquals("logs", 
result.getInnerDirectories().get(0).getDirectoryName());
+        }
+    }
+
+    @Test
+    void listDir_throwsWhenPathIsNotDirectory() throws Exception {
+        FileMetadata fileMeta = new FileMetadata();
+        fileMeta.setName("file.txt");
+        fileMeta.setDirectory(false);
+
+        try (MockedConstruction<ProcessDataManager> mocked = 
mockConstruction(ProcessDataManager.class, (mock, ctx) -> {
+            when(mock.getAgentAdaptor()).thenReturn(agentAdaptor);
+            when(mock.getBaseDir()).thenReturn("/home/user/");
+        })) {
+            
when(agentAdaptor.getFileMetadata("/home/user/file.txt")).thenReturn(fileMeta);
+
+            assertThrows(Exception.class, () -> fileService.listDir("proc-1", 
"file.txt"));
+        }
+    }
+
+    @Test
+    void listFile_returnsFileInfo() throws Exception {
+        FileMetadata fileMeta = new FileMetadata();
+        fileMeta.setName("data.csv");
+        fileMeta.setSize(2048);
+        fileMeta.setDirectory(false);
+
+        try (MockedConstruction<ProcessDataManager> mocked = 
mockConstruction(ProcessDataManager.class, (mock, ctx) -> {
+            when(mock.getAgentAdaptor()).thenReturn(agentAdaptor);
+            when(mock.getBaseDir()).thenReturn("/home/user/");
+        })) {
+            
when(agentAdaptor.getFileMetadata("/home/user/data.csv")).thenReturn(fileMeta);
+
+            AiravataFile result = fileService.listFile("proc-1", "data.csv");
+
+            assertEquals("data.csv", result.getFileName());
+            assertEquals(2048, result.getFileSize());
+        }
+    }
+
+    @Test
+    void uploadFile_delegatesToAdaptor() throws Exception {
+        byte[] content = "hello world".getBytes();
+        InputStream inputStream = new ByteArrayInputStream(content);
+
+        try (MockedConstruction<ProcessDataManager> mocked = 
mockConstruction(ProcessDataManager.class, (mock, ctx) -> {
+            when(mock.getAgentAdaptor()).thenReturn(agentAdaptor);
+            when(mock.getBaseDir()).thenReturn("/home/user/");
+        })) {
+            fileService.uploadFile("proc-1", "output/test.txt", inputStream, 
"test.txt", content.length);
+
+            verify(agentAdaptor).createDirectory("/home/user/output", true);
+            verify(agentAdaptor).uploadFile(any(InputStream.class), 
any(FileMetadata.class), eq("/home/user/output/test.txt"));
+        }
+    }
+
+    @Test
+    void downloadFile_returnsPathWhenFileExists() throws Exception {
+        try (MockedConstruction<ProcessDataManager> mocked = 
mockConstruction(ProcessDataManager.class, (mock, ctx) -> {
+            when(mock.getAgentAdaptor()).thenReturn(agentAdaptor);
+            when(mock.getBaseDir()).thenReturn("/home/user/");
+        })) {
+            
when(agentAdaptor.doesFileExist("/home/user/result.txt")).thenReturn(true);
+            doAnswer(invocation -> {
+                // Simulate download by creating the temp file content
+                String localPath = invocation.getArgument(1);
+                java.nio.file.Files.writeString(Path.of(localPath), "file 
content");
+                return null;
+            }).when(agentAdaptor).downloadFile(eq("/home/user/result.txt"), 
anyString());
+
+            Path result = fileService.downloadFile("proc-1", "result.txt");
+
+            assertNotNull(result);
+            assertTrue(result.toFile().exists());
+            // cleanup
+            result.toFile().delete();
+        }
+    }
+
+    @Test
+    void downloadFile_throwsWhenFileDoesNotExist() throws Exception {
+        try (MockedConstruction<ProcessDataManager> mocked = 
mockConstruction(ProcessDataManager.class, (mock, ctx) -> {
+            when(mock.getAgentAdaptor()).thenReturn(agentAdaptor);
+            when(mock.getBaseDir()).thenReturn("/home/user/");
+        })) {
+            
when(agentAdaptor.doesFileExist("/home/user/missing.txt")).thenReturn(false);
+
+            assertThrows(Exception.class, () -> 
fileService.downloadFile("proc-1", "missing.txt"));
+        }
+    }
+}

Reply via email to