feat(lum): KeycloakRealmSetupService + rôles RBAC UnionFlow + Jacoco 100%

- Ajoute KeycloakRealmSetupService : auto-initialisation des rôles realm
  (admin, user_manager, user_viewer, role_manager...) et assignation du rôle
  user_manager au service account unionflow-server au démarrage (idempotent,
  retries, thread séparé pour ne pas bloquer le démarrage)
  → Corrige le 403 sur resetPassword / changement de mot de passe premier login

- UserResource : étend les @RolesAllowed avec ADMIN/SUPER_ADMIN/USER pour
  permettre aux appels inter-services unionflow-server d'accéder aux endpoints
  sans être bloqués par le RBAC LUM ; corrige sendVerificationEmail (retourne Response)

- application-dev.properties : service-accounts.user-manager-clients=unionflow-server
- application-prod.properties : client-id, credentials.secret, token.audience, auto-setup
- application-test.properties : H2 in-memory (plus besoin de Docker pour les tests)
- pom.xml : H2 scope test, Jacoco 100% enforcement (exclusions MapStruct/repos/setup),
  annotation processors MapStruct+Lombok explicites
- .gitignore + .env ajouté (.env exclu du commit)
- script/docker/.env.example : variables KEYCLOAK_ADMIN_USERNAME/PASSWORD documentées
This commit is contained in:
dahoud
2026-04-12 15:04:23 +00:00
parent 2ed890803c
commit 8ab1513bf5
35 changed files with 5594 additions and 19 deletions

View File

@@ -1,5 +1,6 @@
package dev.lions.user.manager.resource;
import dev.lions.user.manager.dto.importexport.ImportResultDTO;
import dev.lions.user.manager.dto.user.*;
import dev.lions.user.manager.service.UserService;
import jakarta.ws.rs.core.Response;
@@ -15,6 +16,7 @@ import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
@@ -164,9 +166,11 @@ class UserResourceTest {
void testSendVerificationEmail() {
doNothing().when(userService).sendVerificationEmail("1", REALM);
userResource.sendVerificationEmail("1", REALM);
Response response = userResource.sendVerificationEmail("1", REALM);
verify(userService).sendVerificationEmail("1", REALM);
assertNotNull(response);
assertEquals(202, response.getStatus());
}
@Test
@@ -189,4 +193,51 @@ class UserResourceTest {
assertEquals(1, result.size());
assertEquals("session-1", result.get(0));
}
@Test
void testCreateUser_IllegalArgumentException() {
UserDTO newUser = UserDTO.builder().username("existinguser").email("existing@test.com").build();
when(userService.createUser(any(), eq(REALM))).thenThrow(new IllegalArgumentException("Username exists"));
Response response = userResource.createUser(newUser, REALM);
assertEquals(409, response.getStatus());
}
@Test
void testCreateUser_RuntimeException() {
UserDTO newUser = UserDTO.builder().username("user").email("user@test.com").build();
when(userService.createUser(any(), eq(REALM))).thenThrow(new RuntimeException("Connection error"));
assertThrows(RuntimeException.class, () -> userResource.createUser(newUser, REALM));
}
@Test
void testExportUsersToCSV() {
String csvContent = "username,email,prenom,nom\ntest,test@test.com,Test,User";
when(userService.exportUsersToCSV(any())).thenReturn(csvContent);
Response response = userResource.exportUsersToCSV(REALM);
assertEquals(200, response.getStatus());
assertEquals(csvContent, response.getEntity());
}
@Test
void testImportUsersFromCSV() {
String csvContent = "username,email,prenom,nom\ntest,test@test.com,Test,User";
ImportResultDTO importResult = ImportResultDTO.builder()
.successCount(1)
.errorCount(0)
.totalLines(2)
.errors(Collections.emptyList())
.build();
when(userService.importUsersFromCSV(csvContent, REALM)).thenReturn(importResult);
ImportResultDTO result = userResource.importUsersFromCSV(REALM, csvContent);
assertNotNull(result);
assertEquals(1, result.getSuccessCount());
assertEquals(0, result.getErrorCount());
}
}