Boucle de Vérification Quarkus
À exécuter avant les PR, après des changements majeurs et avant le déploiement.
Quand l'activer
- Avant d'ouvrir une pull request pour un service Quarkus
- Après un refactoring majeur ou des mises à jour de dépendances
- Vérification pré-déploiement pour la recette ou la production
- Exécution du pipeline complet : build → lint → test → scan de sécurité → compilation native
- Validation du seuil de couverture de tests (80%+)
- Test de compatibilité native
Phase 1 : Construction
# Maven
mvn clean verify -DskipTests
# Gradle
./gradlew clean assemble -x test
Si la construction échoue, arrêtez-vous et corrigez les erreurs de compilation.
Phase 2 : Analyse Statique
Checkstyle, PMD, SpotBugs (Maven)
mvn checkstyle:check pmd:check spotbugs:check
SonarQube (si configuré)
mvn sonar:sonar \
-Dsonar.projectKey=my-quarkus-project \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.login=${SONAR_TOKEN}
Problèmes courants à traiter
- Imports ou variables inutilisés
- Méthodes complexes (forte complexité cyclomatique)
- Déréférencements potentiels de pointeurs nuls
- Problèmes de sécurité signalés par SpotBugs
Phase 3 : Tests + Couverture
# Exécute tous les tests
mvn clean test
# Génère le rapport de couverture
mvn jacoco:report
# Applique le seuil de couverture (80%)
mvn jacoco:check
# Ou avec Gradle
./gradlew test jacocoTestReport jacocoTestCoverageVerification
Catégories de Tests
Tests Unitaires
Testez la logique métier avec des dépendances mockées :
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock UserRepository userRepository;
@InjectMocks UserService userService;
@Test
void createUser_validInput_returnsUser() {
var dto = new CreateUserDto("Alice", "[email protected]");
// Persist() de Panache est void — utiliser doNothing + verify
doNothing().when(userRepository).persist(any(User.class));
User result = userService.create(dto);
assertThat(result.name).isEqualTo("Alice");
verify(userRepository).persist(any(User.class));
}
}
Tests d'Intégration
Testez avec une vraie base de données (Testcontainers) :
@QuarkusTest
@QuarkusTestResource(PostgresTestResource.class)
class UserRepositoryIntegrationTest {
@Inject
UserRepository userRepository;
@Test
@Transactional
void findByEmail_existingUser_returnsUser() {
User user = new User();
user.name = "Alice";
user.email = "[email protected]";
userRepository.persist(user);
Optional<User> found = userRepository.findByEmail("[email protected]");
assertThat(found).isPresent();
assertThat(found.get().name).isEqualTo("Alice");
}
}
Tests d'API
Testez les points de terminaison REST avec REST Assured :
@QuarkusTest
class UserResourceTest {
@Test
void createUser_validInput_returns201() {
given()
.contentType(ContentType.JSON)
.body("""
{"name": "Alice", "email": "[email protected]"}
""")
.when().post("/api/users")
.then()
.statusCode(201)
.body("name", equalTo("Alice"));
}
@Test
void createUser_invalidEmail_returns400() {
given()
.contentType(ContentType.JSON)
.body("""
{"name": "Alice", "email": "invalid"}
""")
.when().post("/api/users")
.then()
.statusCode(400);
}
}
Rapport de Couverture
Consultez target/site/jacoco/index.html pour les détails de couverture :
- Couverture de ligne globale (cible : 80%+)
- Couverture de branches (cible : 70%+)
- Identifiez les chemins critiques non couverts
Phase 4 : Scan de Sécurité
Vulnérabilités des Dépendances (Maven)
mvn org.owasp:dependency-check-maven:check
Consultez target/dependency-check-report.html pour les CVE.
Audit de Sécurité Quarkus
# Vérifie les extensions vulnérables
mvn quarkus:audit
# Liste toutes les extensions
mvn quarkus:list-extensions
OWASP ZAP (Tests de Sécurité API)
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \
-t http://localhost:8080/q/openapi \
-f openapi
Vérifications de Sécurité Courantes
- Tous les secrets dans des variables d'environnement (pas dans le code)
- Validation des entrées sur tous les points de terminaison
- Authentification/autorisation configurée
- CORS correctement configuré
- En-têtes de sécurité configurés
- Mots de passe hachés avec BCrypt
- Protection contre l'injection SQL (requêtes paramétrées)
- Limitation de débit sur les points de terminaison publics
Phase 5 : Compilation Native
Testez la compatibilité avec l'image native GraalVM :
# Construit l'exécutable natif
mvn package -Dnative
# Ou avec conteneur
mvn package -Dnative -Dquarkus.native.container-build=true
# Teste l'exécutable natif
./target/*-runner
# Exécute des tests de fumée de base
curl http://localhost:8080/q/health/live
curl http://localhost:8080/q/health/ready
Dépannage de l'Image Native
Problèmes courants :
- Réflexion : Ajoutez la configuration de réflexion pour les classes dynamiques
- Ressources : Incluez les ressources avec
quarkus.native.resources.includes - JNI : Enregistrez les classes JNI si vous utilisez des bibliothèques natives
Exemple de configuration de réflexion :
@RegisterForReflection(targets = {MyDynamicClass.class})
public class ReflectionConfiguration {}
Phase 6 : Tests de Performance
Tests de Charge avec K6
// load-test.js
import http from 'k6/http';
import { check } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 50 },
{ duration: '1m', target: 100 },
{ duration: '30s', target: 0 },
],
};
export default function () {
const res = http.get('http://localhost:8080/api/markets');
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
});
}
Exécution :
k6 run load-test.js
Métriques à Surveiller
- Temps de réponse (p50, p95, p99)
- Débit (requêtes/seconde)
- Taux d'erreur
- Utilisation mémoire
- Utilisation CPU
Phase 7 : Health Checks
# Liveness
curl http://localhost:8080/q/health/live
# Readiness
curl http://localhost:8080/q/health/ready
# Tous les health checks
curl http://localhost:8080/q/health
# Métriques (si activées)
curl http://localhost:8080/q/metrics
Réponses attendues :
{
"status": "UP",
"checks": [
{
"name": "Connexion base de données",
"status": "UP"
}
]
}
Phase 8 : Construction de l'Image Conteneur
# Construit l'image conteneur
mvn package -Dquarkus.container-image.build=true
# Ou avec un registre spécifique
mvn package \
-Dquarkus.container-image.build=true \
-Dquarkus.container-image.registry=docker.io \
-Dquarkus.container-image.group=myorg \
-Dquarkus.container-image.tag=1.0.0
# Teste le conteneur
docker run -p 8080:8080 myorg/my-quarkus-app:1.0.0
Scan de Sécurité du Conteneur
# Trivy
trivy image myorg/my-quarkus-app:1.0.0
# Grype
grype myorg/my-quarkus-app:1.0.0
Phase 9 : Validation de la Configuration
# Vérifie toutes les propriétés de configuration
mvn quarkus:info
# Liste toutes les sources de configuration
curl http://localhost:8080/q/dev/io.quarkus.quarkus-vertx-http/config
Vérifications Spécifiques à l'Environnement
- URLs de base de données configurées par environnement
- Secrets externalisés (Vault, variables d'environnement)
- Niveaux de journalisation appropriés
- Origines CORS définies correctement
- Limitation de débit configurée
- Monitoring/traçage activé
Phase 10 : Revue de la Documentation
- Documentation OpenAPI/Swagger à jour (
/q/swagger-ui) - README contient les instructions d'installation
- Changements d'API documentés
- Guide de migration pour les changements cassants
- Propriétés de configuration documentées
Générer la spécification OpenAPI :
curl http://localhost:8080/q/openapi -o openapi.json
Checklist de Vérification
Qualité du Code
- Construction réussie sans avertissements
- Analyse statique propre (aucun problème haut/moyen)
- Code suit les conventions de l'équipe
- Pas de code commenté ou de TODOs dans la PR
Tests
- Tous les tests passent
- Couverture de code ≥ 80%
- Tests d'intégration avec vraie base de données
- Tests de sécurité réussis
- Performance dans les limites acceptables
Sécurité
- Aucune vulnérabilité de dépendance
- Authentification/autorisation testée
- Validation des entrées complète
- Secrets absents du code source
- En-têtes de sécurité configurés
Déploiement
- Compilation native réussie
- Image conteneur construite
- Health checks répondent correctement
- Configuration valide pour l'environnement cible
Image Native
- Exécutable natif construit
- Tests natifs réussis
- Temps de démarrage < 100ms
- Empreinte mémoire acceptable
Script de Vérification Automatisé
#!/bin/bash
set -e
echo "=== Phase 1 : Construction ==="
mvn clean verify -DskipTests
echo "=== Phase 2 : Analyse Statique ==="
mvn checkstyle:check pmd:check spotbugs:check
echo "=== Phase 3 : Tests + Couverture ==="
mvn test jacoco:report jacoco:check
echo "=== Phase 4 : Scan de Sécurité ==="
mvn org.owasp:dependency-check-maven:check
echo "=== Phase 5 : Compilation Native ==="
mvn package -Dnative -Dquarkus.native.container-build=true
echo "=== Toutes les Phases Terminées ==="
echo "Consultez les rapports :"
echo " - Couverture : target/site/jacoco/index.html"
echo " - Sécurité : target/dependency-check-report.html"
echo " - Native : target/*-runner"
Intégration CI/CD
Exemple GitHub Actions
name: Vérification
on: [push, pull_request]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Configurer JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
- name: Mise en cache des packages Maven
uses: actions/cache@v6
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
- name: Construction
run: mvn clean verify -DskipTests
- name: Tests avec Couverture
run: mvn test jacoco:report jacoco:check
- name: Scan de Sécurité
run: mvn org.owasp:dependency-check-maven:check
- name: Téléverser la Couverture
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: target/site/jacoco/jacoco.xml
Bonnes Pratiques
- Exécutez la boucle de vérification avant chaque PR
- Automatisez dans le pipeline CI/CD
- Corrigez les problèmes immédiatement ; n'accumulez pas de dette
- Maintenez la couverture au-dessus de 80%
- Mettez à jour les dépendances régulièrement
- Testez la compilation native périodiquement
- Surveillez les tendances de performance
- Documentez les changements cassants
- Examinez les résultats des scans de sécurité
- Validez la configuration pour chaque environnement