feat(server-impl): refactoring resources JAX-RS, corrections AuditService/SyncService/UserService, ajout entites Sync et scripts Docker

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
lionsdev
2026-02-18 03:27:55 +00:00
parent bf1e9e16d8
commit bbab8ca7ec
56 changed files with 2916 additions and 4696 deletions

View File

@@ -1,37 +1,35 @@
package dev.lions.user.manager.client;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Response;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.admin.client.token.TokenManager;
import org.keycloak.representations.info.ServerInfoRepresentation;
import org.keycloak.admin.client.resource.ServerInfoResource;
import org.mockito.InjectMocks;
import org.mockito.MockedStatic;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import jakarta.ws.rs.NotFoundException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
/**
* Tests complets pour KeycloakAdminClientImpl pour atteindre 100% de couverture
* Couvre init(), getAllRealms(), reconnect(), et tous les cas limites
* Tests complets pour KeycloakAdminClientImpl
*/
@ExtendWith(MockitoExtension.class)
class KeycloakAdminClientImplCompleteTest {
@Mock
Keycloak mockKeycloak;
@InjectMocks
KeycloakAdminClientImpl client;
@@ -43,315 +41,123 @@ class KeycloakAdminClientImplCompleteTest {
@BeforeEach
void setUp() throws Exception {
// Set all config fields to null/empty for testing
setField("serverUrl", "");
setField("serverUrl", "http://localhost:8180");
setField("adminRealm", "master");
setField("adminClientId", "admin-cli");
setField("adminUsername", "admin");
setField("adminPassword", "");
setField("connectionPoolSize", 10);
setField("timeoutSeconds", 30);
setField("keycloak", null);
}
@Test
void testInit_WithServerUrl() throws Exception {
setField("serverUrl", "http://localhost:8080");
setField("adminRealm", "master");
setField("adminClientId", "admin-cli");
setField("adminUsername", "admin");
setField("adminPassword", "password");
// Mock KeycloakBuilder to avoid actual connection
// This will likely throw an exception, but that's ok - we test the exception path
try {
java.lang.reflect.Method initMethod = KeycloakAdminClientImpl.class.getDeclaredMethod("init");
initMethod.setAccessible(true);
initMethod.invoke(client);
} catch (Exception e) {
// Expected - KeycloakBuilder will fail without actual Keycloak server
}
// The init method will set keycloak to null on exception
Field keycloakField = KeycloakAdminClientImpl.class.getDeclaredField("keycloak");
keycloakField.setAccessible(true);
Keycloak result = (Keycloak) keycloakField.get(client);
// Result will be null due to exception, which is the expected behavior
// This test covers the exception path in init()
void testGetInstance() {
Keycloak result = client.getInstance();
assertSame(mockKeycloak, result);
}
@Test
void testInit_WithException() throws Exception {
setField("serverUrl", "http://localhost:8080");
setField("adminRealm", "master");
setField("adminClientId", "admin-cli");
setField("adminUsername", "admin");
setField("adminPassword", "password");
void testGetRealm_Success() {
RealmResource mockRealmResource = mock(RealmResource.class);
when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);
// Call init via reflection - will throw exception without actual Keycloak
// This test covers the exception handling path in init()
try {
java.lang.reflect.Method initMethod = KeycloakAdminClientImpl.class.getDeclaredMethod("init");
initMethod.setAccessible(true);
initMethod.invoke(client);
} catch (Exception e) {
// Expected - KeycloakBuilder may fail
}
// Verify keycloak is null after exception
Field keycloakField = KeycloakAdminClientImpl.class.getDeclaredField("keycloak");
keycloakField.setAccessible(true);
Keycloak result = (Keycloak) keycloakField.get(client);
// Result may be null due to exception, which is the expected behavior
// This test covers the exception handling path in init()
RealmResource result = client.getRealm("test-realm");
assertSame(mockRealmResource, result);
}
@Test
void testInit_WithNullServerUrl() throws Exception {
setField("serverUrl", null);
void testGetRealm_Exception() {
when(mockKeycloak.realm("bad-realm")).thenThrow(new RuntimeException("Connection error"));
// Call init via reflection
java.lang.reflect.Method initMethod = KeycloakAdminClientImpl.class.getDeclaredMethod("init");
initMethod.setAccessible(true);
initMethod.invoke(client);
// Verify keycloak is null
Field keycloakField = KeycloakAdminClientImpl.class.getDeclaredField("keycloak");
keycloakField.setAccessible(true);
Keycloak result = (Keycloak) keycloakField.get(client);
assertNull(result);
assertThrows(RuntimeException.class, () -> client.getRealm("bad-realm"));
}
@Test
void testInit_WithEmptyServerUrl() throws Exception {
setField("serverUrl", "");
void testGetUsers() {
RealmResource mockRealmResource = mock(RealmResource.class);
UsersResource mockUsersResource = mock(UsersResource.class);
when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);
when(mockRealmResource.users()).thenReturn(mockUsersResource);
// Call init via reflection
java.lang.reflect.Method initMethod = KeycloakAdminClientImpl.class.getDeclaredMethod("init");
initMethod.setAccessible(true);
initMethod.invoke(client);
// Verify keycloak is null
Field keycloakField = KeycloakAdminClientImpl.class.getDeclaredField("keycloak");
keycloakField.setAccessible(true);
Keycloak result = (Keycloak) keycloakField.get(client);
assertNull(result);
UsersResource result = client.getUsers("test-realm");
assertSame(mockUsersResource, result);
}
@Test
void testReconnect() throws Exception {
Keycloak mockKeycloak = mock(Keycloak.class);
setField("keycloak", mockKeycloak);
setField("serverUrl", "");
void testGetRoles() {
RealmResource mockRealmResource = mock(RealmResource.class);
RolesResource mockRolesResource = mock(RolesResource.class);
when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);
when(mockRealmResource.roles()).thenReturn(mockRolesResource);
// reconnect calls close() then init()
client.reconnect();
// Verify close was called
verify(mockKeycloak).close();
// Verify keycloak is null after close
Field keycloakField = KeycloakAdminClientImpl.class.getDeclaredField("keycloak");
keycloakField.setAccessible(true);
Keycloak result = (Keycloak) keycloakField.get(client);
assertNull(result);
RolesResource result = client.getRoles("test-realm");
assertSame(mockRolesResource, result);
}
@Test
void testGetAllRealms_Success() throws Exception {
Keycloak mockKeycloak = mock(Keycloak.class);
TokenManager mockTokenManager = mock(TokenManager.class);
setField("keycloak", mockKeycloak);
setField("serverUrl", "http://localhost:8080");
void testIsConnected_True() {
ServerInfoResource mockServerInfoResource = mock(ServerInfoResource.class);
when(mockKeycloak.serverInfo()).thenReturn(mockServerInfoResource);
when(mockServerInfoResource.getInfo()).thenReturn(mock(ServerInfoRepresentation.class));
when(mockKeycloak.tokenManager()).thenReturn(mockTokenManager);
when(mockTokenManager.getAccessTokenString()).thenReturn("test-token");
// Mock ClientBuilder
try (MockedStatic<ClientBuilder> mockedClientBuilder = mockStatic(ClientBuilder.class)) {
Client mockClient = mock(Client.class);
WebTarget mockWebTarget = mock(WebTarget.class);
Invocation.Builder mockBuilder = mock(Invocation.Builder.class);
Response mockResponse = mock(Response.class);
mockedClientBuilder.when(ClientBuilder::newClient).thenReturn(mockClient);
when(mockClient.target("http://localhost:8080/admin/realms")).thenReturn(mockWebTarget);
when(mockWebTarget.request(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)).thenReturn(mockBuilder);
when(mockBuilder.header(anyString(), anyString())).thenReturn(mockBuilder);
// Mock response with realm data
Map<String, Object> realm1 = new HashMap<>();
realm1.put("realm", "realm1");
Map<String, Object> realm2 = new HashMap<>();
realm2.put("realm", "realm2");
List<Map<String, Object>> realmsJson = new ArrayList<>();
realmsJson.add(realm1);
realmsJson.add(realm2);
when(mockBuilder.get(List.class)).thenReturn(realmsJson);
List<String> result = client.getAllRealms();
assertNotNull(result);
assertEquals(2, result.size());
assertTrue(result.contains("realm1"));
assertTrue(result.contains("realm2"));
verify(mockClient).close();
}
assertTrue(client.isConnected());
}
@Test
void testGetAllRealms_WithNullRealmsJson() throws Exception {
Keycloak mockKeycloak = mock(Keycloak.class);
TokenManager mockTokenManager = mock(TokenManager.class);
setField("keycloak", mockKeycloak);
setField("serverUrl", "http://localhost:8080");
void testIsConnected_False() {
when(mockKeycloak.serverInfo()).thenThrow(new RuntimeException("Connection refused"));
when(mockKeycloak.tokenManager()).thenReturn(mockTokenManager);
when(mockTokenManager.getAccessTokenString()).thenReturn("test-token");
try (MockedStatic<ClientBuilder> mockedClientBuilder = mockStatic(ClientBuilder.class)) {
Client mockClient = mock(Client.class);
WebTarget mockWebTarget = mock(WebTarget.class);
Invocation.Builder mockBuilder = mock(Invocation.Builder.class);
mockedClientBuilder.when(ClientBuilder::newClient).thenReturn(mockClient);
when(mockClient.target("http://localhost:8080/admin/realms")).thenReturn(mockWebTarget);
when(mockWebTarget.request(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)).thenReturn(mockBuilder);
when(mockBuilder.header(anyString(), anyString())).thenReturn(mockBuilder);
when(mockBuilder.get(List.class)).thenReturn(null);
List<String> result = client.getAllRealms();
assertNotNull(result);
assertTrue(result.isEmpty());
verify(mockClient).close();
}
assertFalse(client.isConnected());
}
@Test
void testGetAllRealms_WithEmptyRealmName() throws Exception {
Keycloak mockKeycloak = mock(Keycloak.class);
TokenManager mockTokenManager = mock(TokenManager.class);
setField("keycloak", mockKeycloak);
setField("serverUrl", "http://localhost:8080");
void testRealmExists_True() {
RealmResource mockRealmResource = mock(RealmResource.class);
RolesResource mockRolesResource = mock(RolesResource.class);
when(mockKeycloak.realm("test-realm")).thenReturn(mockRealmResource);
when(mockRealmResource.roles()).thenReturn(mockRolesResource);
when(mockRolesResource.list()).thenReturn(List.of());
when(mockKeycloak.tokenManager()).thenReturn(mockTokenManager);
when(mockTokenManager.getAccessTokenString()).thenReturn("test-token");
try (MockedStatic<ClientBuilder> mockedClientBuilder = mockStatic(ClientBuilder.class)) {
Client mockClient = mock(Client.class);
WebTarget mockWebTarget = mock(WebTarget.class);
Invocation.Builder mockBuilder = mock(Invocation.Builder.class);
mockedClientBuilder.when(ClientBuilder::newClient).thenReturn(mockClient);
when(mockClient.target("http://localhost:8080/admin/realms")).thenReturn(mockWebTarget);
when(mockWebTarget.request(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)).thenReturn(mockBuilder);
when(mockBuilder.header(anyString(), anyString())).thenReturn(mockBuilder);
// Mock response with empty realm name
Map<String, Object> realm1 = new HashMap<>();
realm1.put("realm", "");
Map<String, Object> realm2 = new HashMap<>();
realm2.put("realm", "realm2");
List<Map<String, Object>> realmsJson = new ArrayList<>();
realmsJson.add(realm1);
realmsJson.add(realm2);
when(mockBuilder.get(List.class)).thenReturn(realmsJson);
List<String> result = client.getAllRealms();
assertNotNull(result);
assertEquals(1, result.size()); // Empty realm name should be filtered out
assertTrue(result.contains("realm2"));
verify(mockClient).close();
}
assertTrue(client.realmExists("test-realm"));
}
@Test
void testGetAllRealms_WithNullRealmName() throws Exception {
Keycloak mockKeycloak = mock(Keycloak.class);
TokenManager mockTokenManager = mock(TokenManager.class);
setField("keycloak", mockKeycloak);
setField("serverUrl", "http://localhost:8080");
void testRealmExists_NotFound() {
RealmResource mockRealmResource = mock(RealmResource.class);
RolesResource mockRolesResource = mock(RolesResource.class);
when(mockKeycloak.realm("missing")).thenReturn(mockRealmResource);
when(mockRealmResource.roles()).thenReturn(mockRolesResource);
when(mockRolesResource.list()).thenThrow(new NotFoundException("Not found"));
when(mockKeycloak.tokenManager()).thenReturn(mockTokenManager);
when(mockTokenManager.getAccessTokenString()).thenReturn("test-token");
try (MockedStatic<ClientBuilder> mockedClientBuilder = mockStatic(ClientBuilder.class)) {
Client mockClient = mock(Client.class);
WebTarget mockWebTarget = mock(WebTarget.class);
Invocation.Builder mockBuilder = mock(Invocation.Builder.class);
mockedClientBuilder.when(ClientBuilder::newClient).thenReturn(mockClient);
when(mockClient.target("http://localhost:8080/admin/realms")).thenReturn(mockWebTarget);
when(mockWebTarget.request(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)).thenReturn(mockBuilder);
when(mockBuilder.header(anyString(), anyString())).thenReturn(mockBuilder);
// Mock response with null realm name
Map<String, Object> realm1 = new HashMap<>();
realm1.put("realm", null);
Map<String, Object> realm2 = new HashMap<>();
realm2.put("realm", "realm2");
List<Map<String, Object>> realmsJson = new ArrayList<>();
realmsJson.add(realm1);
realmsJson.add(realm2);
when(mockBuilder.get(List.class)).thenReturn(realmsJson);
List<String> result = client.getAllRealms();
assertNotNull(result);
assertEquals(1, result.size()); // Null realm name should be filtered out
assertTrue(result.contains("realm2"));
verify(mockClient).close();
}
assertFalse(client.realmExists("missing"));
}
@Test
void testGetAllRealms_WithException() throws Exception {
Keycloak mockKeycloak = mock(Keycloak.class);
TokenManager mockTokenManager = mock(TokenManager.class);
setField("keycloak", mockKeycloak);
setField("serverUrl", "http://localhost:8080");
void testRealmExists_OtherException() {
when(mockKeycloak.realm("error-realm")).thenThrow(new RuntimeException("Other error"));
when(mockKeycloak.tokenManager()).thenReturn(mockTokenManager);
when(mockTokenManager.getAccessTokenString()).thenThrow(new RuntimeException("Error"));
List<String> result = client.getAllRealms();
assertNotNull(result);
assertTrue(result.isEmpty()); // Should return empty list on exception
assertTrue(client.realmExists("error-realm"));
}
@Test
void testGetAllRealms_WithExceptionInClient() throws Exception {
Keycloak mockKeycloak = mock(Keycloak.class);
TokenManager mockTokenManager = mock(TokenManager.class);
setField("keycloak", mockKeycloak);
setField("serverUrl", "http://localhost:8080");
void testGetAllRealms_TokenError() {
// When token retrieval fails, getAllRealms should throw
when(mockKeycloak.tokenManager()).thenThrow(new RuntimeException("Token error"));
when(mockKeycloak.tokenManager()).thenReturn(mockTokenManager);
when(mockTokenManager.getAccessTokenString()).thenReturn("test-token");
assertThrows(RuntimeException.class, () -> client.getAllRealms());
}
try (MockedStatic<ClientBuilder> mockedClientBuilder = mockStatic(ClientBuilder.class)) {
Client mockClient = mock(Client.class);
WebTarget mockWebTarget = mock(WebTarget.class);
Invocation.Builder mockBuilder = mock(Invocation.Builder.class);
@Test
void testGetAllRealms_NullTokenManager() {
when(mockKeycloak.tokenManager()).thenReturn(null);
mockedClientBuilder.when(ClientBuilder::newClient).thenReturn(mockClient);
when(mockClient.target("http://localhost:8080/admin/realms")).thenReturn(mockWebTarget);
when(mockWebTarget.request(jakarta.ws.rs.core.MediaType.APPLICATION_JSON)).thenReturn(mockBuilder);
when(mockBuilder.header(anyString(), anyString())).thenReturn(mockBuilder);
when(mockBuilder.get(List.class)).thenThrow(new RuntimeException("Connection error"));
assertThrows(RuntimeException.class, () -> client.getAllRealms());
}
List<String> result = client.getAllRealms();
@Test
void testClose() {
assertDoesNotThrow(() -> client.close());
}
assertNotNull(result);
assertTrue(result.isEmpty()); // Should return empty list on exception
verify(mockClient).close(); // Should still close client in finally block
}
@Test
void testReconnect() {
assertDoesNotThrow(() -> client.reconnect());
}
}

View File

@@ -40,18 +40,20 @@ class KeycloakAdminClientImplTest {
@Mock
ServerInfoResource serverInfoResource;
@BeforeEach
void setUp() throws Exception {
// Inject the mock keycloak instance
setField(client, "keycloak", keycloak);
}
private void setField(Object target, String fieldName, Object value) throws Exception {
Field field = target.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(target, value);
}
@BeforeEach
void setUp() throws Exception {
setField(client, "serverUrl", "http://localhost:8180");
setField(client, "adminRealm", "master");
setField(client, "adminClientId", "admin-cli");
setField(client, "adminUsername", "admin");
}
@Test
void testGetInstance() {
Keycloak result = client.getInstance();
@@ -59,18 +61,6 @@ class KeycloakAdminClientImplTest {
assertEquals(keycloak, result);
}
@Test
void testGetInstanceReInitWhenNull() throws Exception {
// Set keycloak to null
setField(client, "keycloak", null);
// Should attempt to reinitialize (will fail without config, but that's ok)
// The method should return null since init() will fail without proper config
Keycloak result = client.getInstance();
// Since config values are null, keycloak will still be null
assertNull(result);
}
@Test
void testGetRealm() {
when(keycloak.realm("test-realm")).thenReturn(realmResource);
@@ -125,13 +115,6 @@ class KeycloakAdminClientImplTest {
assertFalse(client.isConnected());
}
@Test
void testIsConnected_false_null() throws Exception {
setField(client, "keycloak", null);
assertFalse(client.isConnected());
}
@Test
void testRealmExists_true() {
when(keycloak.realm("test-realm")).thenReturn(realmResource);
@@ -156,22 +139,16 @@ class KeycloakAdminClientImplTest {
when(realmResource.roles()).thenReturn(rolesResource);
when(rolesResource.list()).thenThrow(new RuntimeException("Some other error"));
// Should return true assuming realm exists but has issues
assertTrue(client.realmExists("problem-realm"));
}
@Test
void testClose() {
client.close();
verify(keycloak).close();
assertDoesNotThrow(() -> client.close());
}
@Test
void testCloseWhenNull() throws Exception {
setField(client, "keycloak", null);
// Should not throw
client.close();
void testReconnect() {
assertDoesNotThrow(() -> client.reconnect());
}
}