Sync: code local unifié

Synchronisation du code source local (fait foi).

Signed-off-by: lions dev Team
This commit is contained in:
dahoud
2026-03-15 16:25:40 +00:00
parent e82dc356f3
commit 75a19988b0
730 changed files with 53599 additions and 13145 deletions

View File

@@ -0,0 +1,206 @@
package dev.lions.unionflow.server.integration;
import dev.lions.unionflow.server.entity.Cotisation;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.CotisationRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
/**
* Tests d'intégration End-to-End pour le workflow des cotisations
*
* Scénario testé :
* 1. Création d'une organisation et d'un membre (prérequis)
* 2. Création d'une cotisation
* 3. Enregistrement d'un paiement
* 4. Consultation de l'historique
* 5. Statistiques de cotisations
*
* @author UnionFlow Team
* @version 3.0
* @since 2026-01-04
*/
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class CotisationWorkflowIntegrationTest {
private static final String BASE_PATH = "/api/cotisations";
@Inject
CotisationRepository cotisationRepository;
@Inject
MembreRepository membreRepository;
@Inject
OrganisationRepository organisationRepository;
private UUID organisationId;
private UUID membreId;
private UUID cotisationId;
@BeforeAll
@Transactional
void setupTestData() {
// Créer organisation
Organisation org = Organisation.builder()
.nom("Organisation Test E2E Cotisations")
.typeOrganisation("ASSOCIATION")
.statut("ACTIVE")
.email("org-cotisation-e2e-" + System.currentTimeMillis() + "@test.com")
.build();
org.setDateCreation(LocalDateTime.now());
org.setActif(true);
organisationRepository.persist(org);
organisationId = org.getId();
// Créer membre
Membre membre = Membre.builder()
.numeroMembre("UF-" + System.currentTimeMillis())
.nom("Test")
.prenom("Cotisation")
.email("membre-cot-e2e-" + System.currentTimeMillis() + "@test.com")
.telephone("+221701234567")
.dateNaissance(LocalDate.of(1990, 1, 1))
.build();
membre.setDateCreation(LocalDateTime.now());
membre.setActif(true);
membreRepository.persist(membre);
membreId = membre.getId();
}
@Test
@Order(1)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Cotisation-01: Créer une cotisation pour le membre")
void test01_CreerCotisation() {
String cotisationJson = String.format("""
{
"numeroReference": "COT-E2E-%d",
"membreId": "%s",
"organisationId": "%s",
"typeCotisation": "MENSUELLE",
"libelle": "Cotisation Mensuelle E2E",
"montantDu": 5000.00,
"codeDevise": "XOF",
"mois": %d,
"annee": %d,
"dateEcheance": "%s",
"statut": "EN_ATTENTE"
}
""",
System.currentTimeMillis(),
membreId.toString(),
organisationId.toString(),
LocalDate.now().getMonthValue(),
LocalDate.now().getYear(),
LocalDate.now().plusDays(30).toString());
String idStr = given()
.contentType(ContentType.JSON)
.body(cotisationJson)
.when()
.post(BASE_PATH)
.then()
.statusCode(201)
.body("montantDu", equalTo(5000.0f))
.body("statut", equalTo("EN_ATTENTE"))
.body("id", notNullValue())
.extract()
.path("id");
cotisationId = UUID.fromString(idStr);
}
@Test
@Order(2)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Cotisation-02: Enregistrer un paiement")
void test02_EnregistrerPaiement() {
String paiementJson = String.format("""
{
"montantPaye": 5000.00,
"datePaiement": "%s",
"modePaiement": "ESPECES",
"reference": "PAY-E2E-%d"
}
""",
LocalDate.now().toString(),
System.currentTimeMillis());
given()
.contentType(ContentType.JSON)
.pathParam("id", cotisationId)
.body(paiementJson)
.when()
.put(BASE_PATH + "/{id}/payer")
.then()
.statusCode(200)
.body("statut", equalTo("PAYEE"))
.body("montantPaye", equalTo(5000.0f));
}
@Test
@Order(3)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Cotisation-03: Consulter l'historique du membre")
void test03_ConsulterHistorique() {
given()
.pathParam("membreId", membreId)
.when()
.get(BASE_PATH + "/membre/{membreId}")
.then()
.statusCode(200)
.body("$", hasSize(greaterThanOrEqualTo(1)))
.body("[0].id", equalTo(cotisationId.toString()))
.body("[0].statut", equalTo("PAYEE"));
}
@Test
@Order(4)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Cotisation-04: Obtenir les statistiques")
void test04_StatistiquesCotisations() {
given()
.queryParam("annee", LocalDate.now().getYear())
.when()
.get(BASE_PATH + "/statistiques")
.then()
.statusCode(200)
.body("totalCotisations", greaterThanOrEqualTo(1))
.body("totalMontant", greaterThanOrEqualTo(5000.0f));
}
@AfterAll
@Transactional
void cleanup() {
if (cotisationId != null) {
cotisationRepository.findByIdOptional(cotisationId)
.ifPresent(cot -> cotisationRepository.delete(cot));
}
if (membreId != null) {
membreRepository.findByIdOptional(membreId)
.ifPresent(membre -> membreRepository.delete(membre));
}
if (organisationId != null) {
organisationRepository.findByIdOptional(organisationId)
.ifPresent(org -> organisationRepository.delete(org));
}
}
}

View File

@@ -0,0 +1,205 @@
package dev.lions.unionflow.server.integration;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.EvenementRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
/**
* Tests d'intégration End-to-End pour le workflow des événements
*
* Scénario testé :
* 1. Création d'une organisation (prérequis)
* 2. Création d'un événement
* 3. Consultation des détails
* 4. Modification de l'événement
* 5. Liste des événements à venir
* 6. Annulation de l'événement
*
* @author UnionFlow Team
* @version 3.0
* @since 2026-01-04
*/
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class EvenementWorkflowIntegrationTest {
private static final String BASE_PATH = "/api/evenements";
@Inject
EvenementRepository evenementRepository;
@Inject
OrganisationRepository organisationRepository;
private UUID organisationId;
private UUID evenementId;
@BeforeAll
@Transactional
void setupOrganisation() {
Organisation org = Organisation.builder()
.nom("Organisation Test E2E Événements")
.typeOrganisation("ASSOCIATION")
.statut("ACTIVE")
.email("org-event-e2e-" + System.currentTimeMillis() + "@test.com")
.build();
org.setDateCreation(LocalDateTime.now());
org.setActif(true);
organisationRepository.persist(org);
organisationId = org.getId();
}
@Test
@Order(1)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Event-01: Créer un nouvel événement")
void test01_CreerEvenement() {
LocalDate dateDebut = LocalDate.now().plusDays(7);
String eventJson = String.format("""
{
"titre": "Événement E2E Test",
"description": "Description événement test end-to-end",
"dateDebut": "%sT10:00:00",
"lieu": "Dakar, Sénégal",
"typeEvenement": "FORMATION",
"statut": "PLANIFIE",
"capaciteMax": 50,
"prix": 5000.00,
"organisation": { "id": "%s", "version": 0 },
"inscriptionRequise": true,
"visiblePublic": true,
"actif": true
}
""",
dateDebut.toString(),
organisationId.toString());
String idStr = given()
.contentType(ContentType.JSON)
.body(eventJson)
.when()
.post(BASE_PATH)
.then()
.statusCode(201)
.body("titre", equalTo("Événement E2E Test"))
.body("statut", equalTo("PLANIFIE"))
.body("id", notNullValue())
.extract()
.path("id");
evenementId = UUID.fromString(idStr);
}
@Test
@Order(2)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Event-02: Consulter les détails de l'événement")
void test02_ConsulterEvenement() {
given()
.pathParam("id", evenementId)
.when()
.get(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.body("id", equalTo(evenementId.toString()))
.body("titre", equalTo("Événement E2E Test"));
}
@Test
@Order(3)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Event-03: Modifier l'événement")
void test03_ModifierEvenement() {
LocalDate dateDebut = LocalDate.now().plusDays(14);
String updateJson = String.format("""
{
"titre": "Événement E2E Test Modifié",
"description": "Description modifiée",
"dateDebut": "%sT14:00:00",
"lieu": "Abidjan, Côte d'Ivoire",
"typeEvenement": "FORMATION",
"statut": "CONFIRME",
"capaciteMax": 75,
"prix": 7500.00,
"organisation": { "id": "%s", "version": 0 },
"inscriptionRequise": true,
"visiblePublic": true,
"actif": true
}
""",
dateDebut.toString(),
organisationId.toString());
given()
.contentType(ContentType.JSON)
.pathParam("id", evenementId)
.body(updateJson)
.when()
.put(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.body("titre", equalTo("Événement E2E Test Modifié"))
.body("statut", equalTo("CONFIRME"))
.body("capaciteMax", equalTo(75));
}
@Test
@Order(4)
@TestSecurity(user = "membre@unionflow.com", roles = { "MEMBRE" })
@DisplayName("E2E-Event-04: Lister tous les événements")
void test04_ListerEvenements() {
given()
.queryParam("page", 0)
.queryParam("size", 10)
.when()
.get(BASE_PATH)
.then()
.statusCode(200)
.body("data", notNullValue())
.body("data", hasSize(greaterThanOrEqualTo(1)));
}
@Test
@Order(5)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Event-05: Supprimer l'événement")
void test05_SupprimerEvenement() {
given()
.pathParam("id", evenementId)
.when()
.delete(BASE_PATH + "/{id}")
.then()
.statusCode(204);
// Éviter la tentative de suppression dans cleanup
}
@AfterAll
@Transactional
void cleanup() {
// Supprimer tous les événements de l'organisation de test d'abord
if (organisationId != null) {
evenementRepository.getEntityManager()
.createQuery("DELETE FROM Evenement e WHERE e.organisation.id = :orgId")
.setParameter("orgId", organisationId)
.executeUpdate();
organisationRepository.findByIdOptional(organisationId)
.ifPresent(org -> organisationRepository.delete(org));
}
}
}

View File

@@ -0,0 +1,217 @@
package dev.lions.unionflow.server.integration;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import dev.lions.unionflow.server.service.MembreKeycloakSyncService;
import org.junit.jupiter.api.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
/**
* Tests d'intégration End-to-End pour le workflow complet d'un membre
*
* Scénario testé :
* 1. Création d'une organisation (prérequis)
* 2. Inscription d'un nouveau membre
* 3. Consultation du profil
* 4. Modification des informations
* 5. Recherche du membre
* 6. Suspension du membre
*
* @author UnionFlow Team
* @version 3.0
* @since 2026-01-04
*/
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MembreWorkflowIntegrationTest {
private static final String BASE_PATH = "/api/membres";
private static final String ORG_PATH = "/api/organisations";
@Inject
MembreRepository membreRepository;
@Inject
OrganisationRepository organisationRepository;
@InjectMock
MembreKeycloakSyncService keycloakSyncService;
private UUID organisationId;
private UUID membreId;
private String membreEmail;
@BeforeAll
@Transactional
void setupOrganisation() {
// Créer l'organisation de test
Organisation org = Organisation.builder()
.nom("Organisation Test E2E Membre")
.typeOrganisation("ASSOCIATION")
.statut("ACTIVE")
.email("org-membre-e2e-" + System.currentTimeMillis() + "@test.com")
.build();
org.setDateCreation(LocalDateTime.now());
org.setActif(true);
organisationRepository.persist(org);
organisationId = org.getId();
}
@Test
@Order(1)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Membre-01: Inscrire un nouveau membre")
void test01_InscrireMembre() {
membreEmail = "membre-e2e-" + System.currentTimeMillis() + "@test.com";
String membreJson = String.format("""
{
"numeroMembre": "UF-E2E-%d",
"nom": "Test",
"prenom": "Membre",
"email": "%s",
"telephone": "+221701234567",
"dateNaissance": "%s",
"dateAdhesion": "%s",
"associationId": "%s"
}
""",
System.currentTimeMillis(),
membreEmail,
LocalDate.of(1990, 1, 1).toString(),
LocalDate.now().toString(),
organisationId.toString());
String idStr = given()
.contentType(ContentType.JSON)
.body(membreJson)
.when()
.post(BASE_PATH)
.then()
.statusCode(201)
.contentType(ContentType.JSON)
.body("nom", equalTo("Test"))
.body("prenom", equalTo("Membre"))
.body("email", equalTo(membreEmail))
.body("id", notNullValue())
.extract()
.path("id");
membreId = UUID.fromString(idStr);
}
@Test
@Order(2)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Membre-02: Consulter le profil du membre")
void test02_ConsulterMembre() {
given()
.pathParam("id", membreId)
.when()
.get(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.body("id", equalTo(membreId.toString()))
.body("nom", equalTo("Test"))
.body("email", equalTo(membreEmail));
}
@Test
@Order(3)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Membre-03: Modifier les informations du membre")
void test03_ModifierMembre() {
String updateJson = String.format("""
{
"numeroMembre": "UF-E2E-%d",
"nom": "Test Modifié",
"prenom": "Membre Modifié",
"email": "%s",
"telephone": "+221709876543",
"dateNaissance": "%s",
"dateAdhesion": "%s",
"associationId": "%s"
}
""",
System.currentTimeMillis(),
membreEmail,
LocalDate.of(1990, 1, 1).toString(),
LocalDate.now().toString(),
organisationId.toString());
given()
.contentType(ContentType.JSON)
.pathParam("id", membreId)
.body(updateJson)
.when()
.put(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.body("nom", equalTo("Test Modifié"))
.body("prenom", equalTo("Membre Modifié"));
}
@Test
@Order(4)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Membre-04: Lister tous les membres (vérifier présence)")
void test04_ListerMembres() {
given()
.queryParam("page", 0)
.queryParam("size", 100)
.when()
.get(BASE_PATH)
.then()
.statusCode(200)
.body("data", hasSize(greaterThan(0)));
}
@Test
@Order(5)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-Membre-05: Supprimer le membre")
void test05_SupprimerMembre() {
given()
.pathParam("id", membreId)
.when()
.delete(BASE_PATH + "/{id}")
.then()
.statusCode(204);
// Vérifier qu'il est supprimé
given()
.pathParam("id", membreId)
.when()
.get(BASE_PATH + "/{id}")
.then()
.statusCode(404);
}
@AfterAll
@Transactional
void cleanup() {
if (membreId != null) {
membreRepository.findByIdOptional(membreId)
.ifPresent(membre -> membreRepository.delete(membre));
}
if (organisationId != null) {
organisationRepository.findByIdOptional(organisationId)
.ifPresent(org -> organisationRepository.delete(org));
}
}
}

View File

@@ -0,0 +1,205 @@
package dev.lions.unionflow.server.integration;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.restassured.http.ContentType;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.*;
import java.util.UUID;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests d'intégration End-to-End pour le workflow complet d'une organisation
*
* Scénario testé :
* 1. Création d'une nouvelle organisation
* 2. Consultation des détails
* 3. Modification des informations
* 4. Suspension
* 5. Réactivation
*
* @author UnionFlow Team
* @version 3.0
* @since 2026-01-04
*/
@QuarkusTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class OrganisationWorkflowIntegrationTest {
private static final String BASE_PATH = "/api/organisations";
@Inject
OrganisationRepository organisationRepository;
private UUID organisationId;
private String organisationEmail;
@Test
@Order(1)
@TestSecurity(user = "superadmin@unionflow.com", roles = { "SUPER_ADMIN" })
@DisplayName("E2E-01: Créer une nouvelle organisation")
void test01_CreerOrganisation() {
organisationEmail = "org-e2e-" + System.currentTimeMillis() + "@test.com";
String orgJson = String.format("""
{
"nom": "Organisation E2E Test",
"typeOrganisation": "ASSOCIATION",
"statut": "ACTIVE",
"email": "%s",
"telephone": "+221701234567",
"adresse": "123 Rue Test, Dakar",
"ville": "Dakar",
"pays": "Sénégal"
}
""", organisationEmail);
String idStr = given()
.contentType(ContentType.JSON)
.body(orgJson)
.when()
.post(BASE_PATH)
.then()
.statusCode(201)
.contentType(ContentType.JSON)
.body("nom", equalTo("Organisation E2E Test"))
.body("statut", equalTo("ACTIVE"))
.body("id", notNullValue())
.extract()
.path("id");
organisationId = UUID.fromString(idStr);
assertNotNull(organisationId, "L'ID de l'organisation doit être retourné");
}
@Test
@Order(2)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-02: Consulter les détails de l'organisation")
void test02_ConsulterOrganisation() {
given()
.pathParam("id", organisationId)
.when()
.get(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("id", equalTo(organisationId.toString()))
.body("nom", equalTo("Organisation E2E Test"))
.body("email", equalTo(organisationEmail));
}
@Test
@Order(3)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-03: Modifier l'organisation")
void test03_ModifierOrganisation() {
String updateJson = String.format("""
{
"nom": "Organisation E2E Test Modifiée",
"typeOrganisation": "ASSOCIATION",
"statut": "ACTIVE",
"email": "%s",
"telephone": "+221709876543",
"adresse": "456 Avenue Nouvelle, Dakar"
}
""", organisationEmail);
given()
.contentType(ContentType.JSON)
.pathParam("id", organisationId)
.body(updateJson)
.when()
.put(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.body("nom", equalTo("Organisation E2E Test Modifiée"))
.body("telephone", equalTo("+221709876543"));
}
@Test
@Order(4)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-04: Changer le statut à SUSPENDU")
void test04_SuspendreOrganisation() {
String updateJson = String.format("""
{
"nom": "Organisation E2E Test Modifiée",
"typeOrganisation": "ASSOCIATION",
"statut": "SUSPENDUE",
"email": "%s",
"telephone": "+221709876543"
}
""", organisationEmail);
given()
.contentType(ContentType.JSON)
.pathParam("id", organisationId)
.body(updateJson)
.when()
.put(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.body("statut", equalTo("SUSPENDUE"));
}
@Test
@Order(5)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-05: Réactiver en changeant le statut")
void test05_ReactiverOrganisation() {
String updateJson = String.format("""
{
"nom": "Organisation E2E Test Modifiée",
"typeOrganisation": "ASSOCIATION",
"statut": "ACTIVE",
"email": "%s",
"telephone": "+221709876543"
}
""", organisationEmail);
given()
.contentType(ContentType.JSON)
.pathParam("id", organisationId)
.body(updateJson)
.when()
.put(BASE_PATH + "/{id}")
.then()
.statusCode(200)
.body("statut", equalTo("ACTIVE"));
}
@Test
@Order(6)
@TestSecurity(user = "admin@unionflow.com", roles = { "ADMIN" })
@DisplayName("E2E-06: Lister toutes les organisations (pagination)")
void test06_ListerOrganisations() {
given()
.queryParam("page", 0)
.queryParam("size", 10)
.when()
.get(BASE_PATH)
.then()
.statusCode(200)
.body("data", notNullValue())
.body("data", hasSize(greaterThan(0)))
.body("total", greaterThan(0));
}
@AfterAll
@Transactional
void cleanup() {
if (organisationId != null) {
organisationRepository.findByIdOptional(organisationId)
.ifPresent(org -> organisationRepository.delete(org));
}
}
}