package com.dalab.adminservice.service.impl; import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; 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.junit.jupiter.MockitoExtension; import com.dalab.adminservice.dto.CloudConnectionDTO; import com.dalab.adminservice.dto.CloudConnectionTestResultDTO; import com.dalab.adminservice.exception.ConflictException; import com.dalab.adminservice.exception.NotFoundException; import com.dalab.adminservice.mapper.CloudConnectionMapper; import com.dalab.adminservice.model.CloudConnectionEntity; import com.dalab.adminservice.model.enums.CloudProviderType; import com.dalab.adminservice.repository.CloudConnectionRepository; import com.dalab.adminservice.service.IEncryptionService; @ExtendWith(MockitoExtension.class) class CloudConnectionServiceImplTest { @Mock private CloudConnectionRepository cloudConnectionRepository; @Mock private CloudConnectionMapper cloudConnectionMapper; @Mock private IEncryptionService encryptionService; @InjectMocks private CloudConnectionServiceImpl cloudConnectionService; private CloudConnectionEntity connectionEntity; private CloudConnectionDTO connectionDTO; private String connectionId = "test-conn-id"; private String sensitiveData = "supersecret"; private String encryptedData = "encryptedSuperSecret"; @BeforeEach void setUp() { connectionEntity = new CloudConnectionEntity(); connectionEntity.setId(connectionId); connectionEntity.setName("TestConnection"); connectionEntity.setProviderType(CloudProviderType.GCP); connectionEntity.setEncryptedCredentials(encryptedData); connectionEntity.setConnectionParameters(Map.of("projectId", "gcp-project")); connectionEntity.setEnabled(true); connectionDTO = CloudConnectionDTO.builder() .id(connectionId) .name("TestConnection") .providerType(CloudProviderType.GCP) .connectionParameters(Map.of("projectId", "gcp-project")) .sensitiveCredentials(sensitiveData) // DTO carries raw sensitive data for creation/update .enabled(true) .build(); } @Test void getAllCloudConnections_shouldReturnDtoList() { when(cloudConnectionRepository.findAll()).thenReturn(Collections.singletonList(connectionEntity)); when(cloudConnectionMapper.toDtoList(anyList())).thenReturn(Collections.singletonList(connectionDTO)); List result = cloudConnectionService.getAllCloudConnections(); assertThat(result).isNotNull().hasSize(1); assertThat(result.get(0).getName()).isEqualTo(connectionDTO.getName()); verify(cloudConnectionRepository).findAll(); } @Test void getCloudConnectionById_whenFound_shouldReturnDto() { when(cloudConnectionRepository.findById(connectionId)).thenReturn(Optional.of(connectionEntity)); when(cloudConnectionMapper.toDto(connectionEntity)).thenReturn(connectionDTO); Optional result = cloudConnectionService.getCloudConnectionById(connectionId); assertThat(result).isPresent(); assertThat(result.get().getName()).isEqualTo(connectionDTO.getName()); } @Test void createCloudConnection_shouldEncryptCredentialsAndSave() { when(cloudConnectionRepository.findByName(connectionDTO.getName())).thenReturn(Optional.empty()); when(cloudConnectionMapper.toEntity(connectionDTO)).thenReturn(connectionEntity); // Assume mapper creates entity without encrypted creds when(encryptionService.encrypt(sensitiveData)).thenReturn(encryptedData); when(cloudConnectionRepository.save(any(CloudConnectionEntity.class))).thenReturn(connectionEntity); when(cloudConnectionMapper.toDto(connectionEntity)).thenReturn(connectionDTO); // DTO returned should not have sensitive creds CloudConnectionDTO result = cloudConnectionService.createCloudConnection(connectionDTO); assertThat(result).isNotNull(); assertThat(result.getName()).isEqualTo(connectionDTO.getName()); verify(encryptionService).encrypt(sensitiveData); verify(cloudConnectionRepository).save(argThat(entity -> entity.getEncryptedCredentials().equals(encryptedData))); } @Test void createCloudConnection_withNullSensitiveCredentials_shouldNotEncrypt() { CloudConnectionDTO dtoWithNullCreds = CloudConnectionDTO.builder().name("NoCredsConn").sensitiveCredentials(null).build(); CloudConnectionEntity entityFromMapper = new CloudConnectionEntity(); entityFromMapper.setName("NoCredsConn"); when(cloudConnectionRepository.findByName("NoCredsConn")).thenReturn(Optional.empty()); when(cloudConnectionMapper.toEntity(dtoWithNullCreds)).thenReturn(entityFromMapper); when(cloudConnectionRepository.save(any(CloudConnectionEntity.class))).thenReturn(entityFromMapper); when(cloudConnectionMapper.toDto(entityFromMapper)).thenReturn(dtoWithNullCreds); cloudConnectionService.createCloudConnection(dtoWithNullCreds); verify(encryptionService, never()).encrypt(any()); verify(cloudConnectionRepository).save(argThat(entity -> entity.getEncryptedCredentials() == null)); } @Test void createCloudConnection_whenNameExists_shouldThrowConflictException() { when(cloudConnectionRepository.findByName(connectionDTO.getName())).thenReturn(Optional.of(new CloudConnectionEntity())); assertThrows(ConflictException.class, () -> cloudConnectionService.createCloudConnection(connectionDTO)); verify(cloudConnectionRepository, never()).save(any()); } @Test void updateCloudConnection_shouldUpdateAndEncryptIfCredentialsProvided() { CloudConnectionDTO updateDto = CloudConnectionDTO.builder() .name("UpdatedName") .sensitiveCredentials("newSecret") .build(); String newEncryptedSecret = "newEncryptedSecret"; when(cloudConnectionRepository.findById(connectionId)).thenReturn(Optional.of(connectionEntity)); when(encryptionService.encrypt("newSecret")).thenReturn(newEncryptedSecret); when(cloudConnectionRepository.save(any(CloudConnectionEntity.class))).thenReturn(connectionEntity); when(cloudConnectionMapper.toDto(connectionEntity)).thenReturn(CloudConnectionDTO.builder().name("UpdatedName").build()); doNothing().when(cloudConnectionMapper).updateEntityFromDto(updateDto, connectionEntity); CloudConnectionDTO result = cloudConnectionService.updateCloudConnection(connectionId, updateDto); assertThat(result.getName()).isEqualTo("UpdatedName"); verify(cloudConnectionMapper).updateEntityFromDto(updateDto, connectionEntity); verify(encryptionService).encrypt("newSecret"); verify(cloudConnectionRepository).save(argThat(entity -> entity.getEncryptedCredentials().equals(newEncryptedSecret))); } @Test void updateCloudConnection_whenNameChangedToExisting_shouldThrowConflict() { CloudConnectionDTO updateDto = CloudConnectionDTO.builder().name("ExistingOtherName").build(); CloudConnectionEntity otherEntity = new CloudConnectionEntity(); otherEntity.setId("other-id"); otherEntity.setName("ExistingOtherName"); when(cloudConnectionRepository.findById(connectionId)).thenReturn(Optional.of(connectionEntity)); when(cloudConnectionRepository.findByName("ExistingOtherName")).thenReturn(Optional.of(otherEntity)); assertThrows(ConflictException.class, () -> cloudConnectionService.updateCloudConnection(connectionId, updateDto)); verify(cloudConnectionRepository, never()).save(any()); } @Test void deleteCloudConnection_shouldDelete() { when(cloudConnectionRepository.existsById(connectionId)).thenReturn(true); doNothing().when(cloudConnectionRepository).deleteById(connectionId); cloudConnectionService.deleteCloudConnection(connectionId); verify(cloudConnectionRepository).deleteById(connectionId); } @Test void deleteCloudConnection_whenNotFound_shouldThrowNotFoundException() { when(cloudConnectionRepository.existsById(connectionId)).thenReturn(false); assertThrows(NotFoundException.class, () -> cloudConnectionService.deleteCloudConnection(connectionId)); } @Test void testCloudConnection_shouldDecryptAndReturnResult() { when(cloudConnectionRepository.findById(connectionId)).thenReturn(Optional.of(connectionEntity)); when(encryptionService.decrypt(encryptedData)).thenReturn(sensitiveData); // Assume save is called to update last test status when(cloudConnectionRepository.save(any(CloudConnectionEntity.class))).thenReturn(connectionEntity); CloudConnectionTestResultDTO result = cloudConnectionService.testCloudConnection(connectionId); assertThat(result.isSuccess()).isTrue(); // Simulated success assertThat(result.getMessage()).contains("Simulated connection test successful"); verify(encryptionService).decrypt(encryptedData); verify(cloudConnectionRepository).save(argThat(entity -> entity.getLastConnectionTestStatus().equals("SUCCESS") && entity.getLastConnectionTestAt() != null )); } @Test void testCloudConnection_whenNoCredentials_shouldFailTest() { connectionEntity.setEncryptedCredentials(null); when(cloudConnectionRepository.findById(connectionId)).thenReturn(Optional.of(connectionEntity)); when(encryptionService.decrypt(null)).thenReturn(null); // Service will call decrypt with null when(cloudConnectionRepository.save(any(CloudConnectionEntity.class))).thenReturn(connectionEntity); CloudConnectionTestResultDTO result = cloudConnectionService.testCloudConnection(connectionId); assertThat(result.isSuccess()).isFalse(); assertThat(result.getMessage()).contains("No credentials to test"); verify(encryptionService).decrypt(null); // Service does call decrypt, but with null verify(cloudConnectionRepository).save(argThat(entity -> entity.getLastConnectionTestStatus().equals("FAILED") )); } @Test void getDecryptedCredentials_shouldReturnDecryptedString() { when(cloudConnectionRepository.findById(connectionId)).thenReturn(Optional.of(connectionEntity)); when(encryptionService.decrypt(encryptedData)).thenReturn(sensitiveData); String result = cloudConnectionService.getDecryptedCredentials(connectionId); assertThat(result).isEqualTo(sensitiveData); verify(encryptionService).decrypt(encryptedData); } @Test void getDecryptedCredentials_whenEntityNotFound_shouldThrowNotFound() { when(cloudConnectionRepository.findById("unknown")).thenReturn(Optional.empty()); assertThrows(NotFoundException.class, () -> cloudConnectionService.getDecryptedCredentials("unknown")); } @Test void getDecryptedCredentials_whenNoEncryptedData_shouldReturnNull() { connectionEntity.setEncryptedCredentials(null); when(cloudConnectionRepository.findById(connectionId)).thenReturn(Optional.of(connectionEntity)); String result = cloudConnectionService.getDecryptedCredentials(connectionId); assertThat(result).isNull(); verify(encryptionService, never()).decrypt(any()); } }