Cycle de vérification Quarkus
À exécuter avant les PR, après des modifications majeures et avant le déploiement.
Quand l'activer
- Avant d'ouvrir une pull request pour un service Quarkus
- Après un remaniement important ou une mise à jour de dépendances
- Vérification pré-déploiement pour les environnements de staging ou de production
- Exécution du pipeline complet : construction → lint → test → scan de sécurité → compilation native
- Validation que la couverture de tests atteint les seuils (80 %+)
- Test de compatibilité avec les images natives
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 à résoudre
- Imports ou variables inutilisés
- Méthodes complexes (forte complexité cyclomatique)
- Dé-référencements potentiels de pointeur nul
- Problèmes de sécurité signalés par SpotBugs
Phase 3 : Tests + Couverture
# Exécuter tous les tests
mvn clean test
# Générer le rapport de couverture
mvn jacoco:report
# Appliquer 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]");
// Panache persist() 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 base de données réelle (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 endpoints 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 globale des lignes (objectif : 80 %+)
- Couverture des branches (objectif : 70 %+)
- Identifier 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érifier les extensions vulnérables
mvn quarkus:audit
# Lister toutes les extensions
mvn quarkus:list-extensions
OWASP ZAP (Tests de sécurité d'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 endpoints
- Authentification/autorisation configurée
- CORS correctement configuré
- En-têtes de sécurité définis
- Mots de passe hachés avec BCrypt
- Protection contre les injections SQL (requêtes paramétrées)
- Limitation de débit sur les endpoints publics
Phase 5 : Compilation native
Testez la compatibilité avec les images natives GraalVM :
# Construire l'exécutable natif
mvn package -Dnative
# Ou avec conteneur
mvn package -Dnative -Dquarkus.native.container-build=true
# Tester l'exécutable natif
./target/*-runner
# Exécuter les tests de base
curl http://localhost:8080/q/health/live
curl http://localhost:8080/q/health/ready
Résolution des problèmes d'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écutez :
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 : Vérifications de santé
# Liveness
curl http://localhost:8080/q/health/live
# Readiness
curl http://localhost:8080/q/health/ready
# Toutes les vérifications de santé
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 à la base de données",
"status": "UP"
}
]
}
Phase 8 : Construction d'image conteneur
# Construire 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
# Tester le conteneur
docker run -p 8080:8080 myorg/my-quarkus-app:1.0.0
Scan de sécurité des conteneurs
# Trivy
trivy image myorg/my-quarkus-app:1.0.0
# Grype
grype myorg/my-quarkus-app:1.0.0
Phase 9 : Validation de configuration
# Vérifier toutes les propriétés de configuration
mvn quarkus:info
# Lister 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 correctement définies
- Limitation de débit configurée
- Monitoring/traçage activé
Phase 10 : Revue de documentation
- Documentation OpenAPI/Swagger à jour (
/q/swagger-ui) - README avec instructions d'installation
- Modifications d'API documentées
- 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
Liste de vérification
Qualité du code
- Construction réussie sans avertissements
- Analyse statique propre (aucun problème haut/moyen)
- Code respecte les conventions de l'équipe
- Pas de code commenté ni de TODO dans la PR
Tests
- Tous les tests passent
- Couverture de code ≥ 80 %
- Tests d'intégration avec base de données réelle
- Tests de sécurité réussis
- Performances 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
- Vérifications de santé répondent correctement
- Configuration valide pour l'environnement cible
Image native
- Exécutable natif construit
- Tests natifs réussis
- Temps de démarrage < 100 ms
- 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: Mettre en cache les paquets 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écharger la couverture
uses: codecov/codecov-action@v7
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: target/site/jacoco/jacoco.xml
Bonnes pratiques
- Exécutez le cycle 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