---
name: quarkus-verification
description: "Bucle de verificación para proyectos Quarkus: build, análisis estático, pruebas con cobertura, escaneos de seguridad, compilación nativa y revisión de diff antes del lanzamiento o PR."
origin: ECC
---

# Bucle de Verificación Quarkus

Ejecutar antes de PRs, después de cambios importantes y antes del despliegue.

## Cuándo Activar

- Antes de abrir un pull request para un servicio Quarkus
- Después de refactorizaciones importantes o actualizaciones de dependencias
- Verificación previa al despliegue para staging o producción
- Ejecutar el pipeline completo de build → lint → test → escaneo de seguridad → compilación nativa
- Validar que la cobertura de pruebas cumpla los umbrales (80%+)
- Probar compatibilidad con imagen nativa

## Fase 1: Build

```bash
# Maven
mvn clean verify -DskipTests

# Gradle
./gradlew clean assemble -x test
```

Si el build falla, detener y corregir errores de compilación.

## Fase 2: Análisis Estático

### Checkstyle, PMD, SpotBugs (Maven)

```bash
mvn checkstyle:check pmd:check spotbugs:check
```

### SonarQube (si está configurado)

```bash
mvn sonar:sonar \
  -Dsonar.projectKey=my-quarkus-project \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.login=${SONAR_TOKEN}
```

### Problemas Comunes a Resolver

- Importaciones o variables sin usar
- Métodos complejos (alta complejidad ciclomática)
- Posibles desreferencias de puntero nulo
- Problemas de seguridad detectados por SpotBugs

## Fase 3: Pruebas + Cobertura

```bash
# Ejecutar todas las pruebas
mvn clean test

# Generar reporte de cobertura
mvn jacoco:report

# Exigir umbral de cobertura (80%)
mvn jacoco:check

# O con Gradle
./gradlew test jacocoTestReport jacocoTestCoverageVerification
```

### Categorías de Prueba

#### Pruebas Unitarias

```java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
  @Mock UserRepository userRepository;
  @InjectMocks UserService userService;

  @Test
  void createUser_validInput_returnsUser() {
    var dto = new CreateUserDto("Alice", "alice@example.com");

    doNothing().when(userRepository).persist(any(User.class));

    User result = userService.create(dto);

    assertThat(result.name).isEqualTo("Alice");
    verify(userRepository).persist(any(User.class));
  }
}
```

#### Pruebas de Integración

```java
@QuarkusTest
@QuarkusTestResource(PostgresTestResource.class)
class UserRepositoryIntegrationTest {

  @Inject
  UserRepository userRepository;

  @Test
  @Transactional
  void findByEmail_existingUser_returnsUser() {
    User user = new User();
    user.name = "Alice";
    user.email = "alice@example.com";
    userRepository.persist(user);

    Optional<User> found = userRepository.findByEmail("alice@example.com");

    assertThat(found).isPresent();
    assertThat(found.get().name).isEqualTo("Alice");
  }
}
```

#### Pruebas de API

```java
@QuarkusTest
class UserResourceTest {

  @Test
  void createUser_validInput_returns201() {
    given()
        .contentType(ContentType.JSON)
        .body("""
            {"name": "Alice", "email": "alice@example.com"}
            """)
        .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);
  }
}
```

### Reporte de Cobertura

Verificar `target/site/jacoco/index.html` para cobertura detallada:
- Cobertura de líneas total (objetivo: 80%+)
- Cobertura de ramas (objetivo: 70%+)
- Identificar rutas críticas sin cobertura

## Fase 4: Escaneo de Seguridad

### Vulnerabilidades de Dependencias (Maven)

```bash
mvn org.owasp:dependency-check-maven:check
```

Revisar `target/dependency-check-report.html` para CVEs.

### Auditoría de Seguridad Quarkus

```bash
mvn quarkus:audit
mvn quarkus:list-extensions
```

### OWASP ZAP (Pruebas de Seguridad de API)

```bash
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \
  -t http://localhost:8080/q/openapi \
  -f openapi
```

### Verificaciones de Seguridad Comunes

- [ ] Todos los secretos en variables de entorno (no en código)
- [ ] Validación de entrada en todos los endpoints
- [ ] Autenticación/autorización configurada
- [ ] CORS correctamente configurado
- [ ] Cabeceras de seguridad establecidas
- [ ] Contraseñas hasheadas con BCrypt
- [ ] Protección contra inyección SQL (consultas parametrizadas)
- [ ] Limitación de velocidad en endpoints públicos

## Fase 5: Compilación Nativa

Probar compatibilidad de imagen nativa GraalVM:

```bash
# Construir ejecutable nativo
mvn package -Dnative

# O con contenedor
mvn package -Dnative -Dquarkus.native.container-build=true

# Probar ejecutable nativo
./target/*-runner

# Ejecutar smoke tests básicos
curl http://localhost:8080/q/health/live
curl http://localhost:8080/q/health/ready
```

### Solución de Problemas de Imagen Nativa

Problemas comunes:
- **Reflexión**: Agregar config de reflexión para clases dinámicas
- **Recursos**: Incluir recursos con `quarkus.native.resources.includes`
- **JNI**: Registrar clases JNI si se usan bibliotecas nativas

Ejemplo de configuración de reflexión:
```java
@RegisterForReflection(targets = {MyDynamicClass.class})
public class ReflectionConfiguration {}
```

## Fase 6: Pruebas de Rendimiento

### Prueba de Carga con K6

```javascript
// 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,
  });
}
```

```bash
k6 run load-test.js
```

## Fase 7: Health Checks

```bash
# Liveness
curl http://localhost:8080/q/health/live

# Readiness
curl http://localhost:8080/q/health/ready

# Todos los health checks
curl http://localhost:8080/q/health

# Métricas (si están habilitadas)
curl http://localhost:8080/q/metrics
```

## Fase 8: Build de Imagen de Contenedor

```bash
# Construir imagen de contenedor
mvn package -Dquarkus.container-image.build=true

# Escaneo de seguridad del contenedor
trivy image myorg/my-quarkus-app:1.0.0
grype myorg/my-quarkus-app:1.0.0
```

## Fase 9: Validación de Configuración

```bash
mvn quarkus:info
```

### Verificaciones por Entorno

- [ ] URLs de base de datos configuradas por entorno
- [ ] Secretos externalizados (Vault, variables de entorno)
- [ ] Niveles de logging apropiados
- [ ] Orígenes CORS configurados correctamente
- [ ] Limitación de velocidad configurada
- [ ] Monitoreo/trazado habilitado

## Fase 10: Revisión de Documentación

- [ ] Docs OpenAPI/Swagger actualizadas (`/q/swagger-ui`)
- [ ] README tiene instrucciones de configuración
- [ ] Cambios de API documentados
- [ ] Guía de migración para cambios disruptivos

Generar especificación OpenAPI:
```bash
curl http://localhost:8080/q/openapi -o openapi.json
```

## Lista de Verificación

### Calidad del Código
- [ ] El build pasa sin advertencias
- [ ] Análisis estático limpio (sin problemas altos/medios)
- [ ] El código sigue las convenciones del equipo
- [ ] Sin código comentado ni TODOs en el PR

### Pruebas
- [ ] Todas las pruebas pasan
- [ ] Cobertura de código ≥ 80%
- [ ] Pruebas de integración con base de datos real
- [ ] Pruebas de seguridad pasan
- [ ] Rendimiento dentro de límites aceptables

### Seguridad
- [ ] Sin vulnerabilidades en dependencias
- [ ] Autenticación/autorización probada
- [ ] Validación de entrada completa
- [ ] Secretos no en código fuente
- [ ] Cabeceras de seguridad configuradas

### Despliegue
- [ ] Compilación nativa exitosa
- [ ] Imagen de contenedor construida
- [ ] Health checks responden correctamente
- [ ] Configuración válida para el entorno objetivo

## Script de Verificación Automatizado

```bash
#!/bin/bash
set -e

echo "=== Fase 1: Build ==="
mvn clean verify -DskipTests

echo "=== Fase 2: Análisis Estático ==="
mvn checkstyle:check pmd:check spotbugs:check

echo "=== Fase 3: Pruebas + Cobertura ==="
mvn test jacoco:report jacoco:check

echo "=== Fase 4: Escaneo de Seguridad ==="
mvn org.owasp:dependency-check-maven:check

echo "=== Fase 5: Compilación Nativa ==="
mvn package -Dnative -Dquarkus.native.container-build=true

echo "=== Todas las Fases Completadas ==="
echo "Revisar reportes:"
echo "  - Cobertura: target/site/jacoco/index.html"
echo "  - Seguridad: target/dependency-check-report.html"
```

## Buenas Prácticas

- Ejecutar el bucle de verificación antes de cada PR
- Automatizar en el pipeline CI/CD
- Corregir problemas inmediatamente; no acumular deuda técnica
- Mantener cobertura por encima del 80%
- Actualizar dependencias regularmente
- Probar compilación nativa periódicamente
- Monitorear tendencias de rendimiento
- Documentar cambios disruptivos
