File size: 12,032 Bytes
d6afd6c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
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<CloudConnectionDTO> 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<CloudConnectionDTO> 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());
    }
}