quarkus-verification
Verification loop for Quarkus projects: build, static analysis, tests with coverage, security scans, native compilation, and diff review before release or PR.
Quarkus Verification Loop
Run before PRs, after major changes, and pre-deploy.
When to Activate
- Before opening a pull request for a Quarkus service
- After major refactoring or dependency upgrades
- Pre-deployment verification for staging or production
- Running full build → lint → test → security scan → native compilation pipeline
- Validating test coverage meets thresholds (80%+)
- Testing native image compatibility
Phase 1: Build
# Mavenmvn clean verify -DskipTests
# Gradle./gradlew clean assemble -x testIf build fails, stop and fix compilation errors.
Phase 2: Static Analysis
Checkstyle, PMD, SpotBugs (Maven)
mvn checkstyle:check pmd:check spotbugs:checkSonarQube (if configured)
mvn sonar:sonar \ -Dsonar.projectKey=my-quarkus-project \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.login=${SONAR_TOKEN}Common Issues to Address
- Unused imports or variables
- Complex methods (high cyclomatic complexity)
- Potential null pointer dereferences
- Security issues flagged by SpotBugs
Phase 3: Tests + Coverage
# Run all testsmvn clean test
# Generate coverage reportmvn jacoco:report
# Enforce coverage threshold (80%)mvn jacoco:check
# Or with Gradle./gradlew test jacocoTestReport jacocoTestCoverageVerificationTest Categories
Unit Tests
Test service logic with mocked dependencies:
@ExtendWith(MockitoExtension.class)class UserServiceTest { @Mock UserRepository userRepository; @InjectMocks UserService userService;
@Test void createUser_validInput_returnsUser() { var dto = new CreateUserDto("Alice", "alice@example.com");
// Panache persist() is void — use 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)); }}Integration Tests
Test with real database (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 = "alice@example.com"; userRepository.persist(user);
Optional<User> found = userRepository.findByEmail("alice@example.com");
assertThat(found).isPresent(); assertThat(found.get().name).isEqualTo("Alice"); }}API Tests
Test REST endpoints with REST Assured:
@QuarkusTestclass 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); }}Coverage Report
Check target/site/jacoco/index.html for detailed coverage:
- Overall line coverage (target: 80%+)
- Branch coverage (target: 70%+)
- Identify uncovered critical paths
Phase 4: Security Scanning
Dependency Vulnerabilities (Maven)
mvn org.owasp:dependency-check-maven:checkReview target/dependency-check-report.html for CVEs.
Quarkus Security Audit
# Check vulnerable extensionsmvn quarkus:audit
# List all extensionsmvn quarkus:list-extensionsOWASP ZAP (API Security Testing)
docker run -t owasp/zap2docker-stable zap-api-scan.py \ -t http://localhost:8080/q/openapi \ -f openapiCommon Security Checks
- All secrets in environment variables (not in code)
- Input validation on all endpoints
- Authentication/authorization configured
- CORS properly configured
- Security headers set
- Passwords hashed with BCrypt
- SQL injection protection (parameterized queries)
- Rate limiting on public endpoints
Phase 5: Native Compilation
Test GraalVM native image compatibility:
# Build native executablemvn package -Dnative
# Or with containermvn package -Dnative -Dquarkus.native.container-build=true
# Test native executable./target/*-runner
# Run basic smoke testscurl http://localhost:8080/q/health/livecurl http://localhost:8080/q/health/readyNative Image Troubleshooting
Common issues:
- Reflection: Add reflection config for dynamic classes
- Resources: Include resources with
quarkus.native.resources.includes - JNI: Register JNI classes if using native libraries
Example reflection config:
@RegisterForReflection(targets = {MyDynamicClass.class})public class ReflectionConfiguration {}Phase 6: Performance Testing
Load Testing with K6
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, });}Run:
k6 run load-test.jsMetrics to Monitor
- Response time (p50, p95, p99)
- Throughput (requests/sec)
- Error rate
- Memory usage
- CPU usage
Phase 7: Health Checks
# Livenesscurl http://localhost:8080/q/health/live
# Readinesscurl http://localhost:8080/q/health/ready
# All health checkscurl http://localhost:8080/q/health
# Metrics (if enabled)curl http://localhost:8080/q/metricsExpected responses:
{ "status": "UP", "checks": [ { "name": "Database connection", "status": "UP" } ]}Phase 8: Container Image Build
# Build container imagemvn package -Dquarkus.container-image.build=true
# Or with specific registrymvn package \ -Dquarkus.container-image.build=true \ -Dquarkus.container-image.registry=docker.io \ -Dquarkus.container-image.group=myorg \ -Dquarkus.container-image.tag=1.0.0
# Test containerdocker run -p 8080:8080 myorg/my-quarkus-app:1.0.0Container Security Scan
# Trivytrivy image myorg/my-quarkus-app:1.0.0
# Grypegrype myorg/my-quarkus-app:1.0.0Phase 9: Configuration Validation
# Check all configuration propertiesmvn quarkus:info
# List all config sourcescurl http://localhost:8080/q/dev/io.quarkus.quarkus-vertx-http/configEnvironment-Specific Checks
- Database URLs configured per environment
- Secrets externalized (Vault, env vars)
- Logging levels appropriate
- CORS origins set correctly
- Rate limiting configured
- Monitoring/tracing enabled
Phase 10: Documentation Review
- OpenAPI/Swagger docs up to date (
/q/swagger-ui) - README has setup instructions
- API changes documented
- Migration guide for breaking changes
- Configuration properties documented
Generate OpenAPI spec:
curl http://localhost:8080/q/openapi -o openapi.jsonVerification Checklist
Code Quality
- Build passes without warnings
- Static analysis clean (no high/medium issues)
- Code follows team conventions
- No commented-out code or TODOs in PR
Testing
- All tests pass
- Code coverage ≥ 80%
- Integration tests with real database
- Security tests pass
- Performance within acceptable limits
Security
- No dependency vulnerabilities
- Authentication/authorization tested
- Input validation complete
- Secrets not in source code
- Security headers configured
Deployment
- Native compilation successful
- Container image builds
- Health checks respond correctly
- Configuration valid for target environment
Native Image
- Native executable builds
- Native tests pass
- Startup time < 100ms
- Memory footprint acceptable
Automated Verification Script
#!/bin/bashset -e
echo "=== Phase 1: Build ==="mvn clean verify -DskipTests
echo "=== Phase 2: Static Analysis ==="mvn checkstyle:check pmd:check spotbugs:check
echo "=== Phase 3: Tests + Coverage ==="mvn test jacoco:report jacoco:check
echo "=== Phase 4: Security Scan ==="mvn org.owasp:dependency-check-maven:check
echo "=== Phase 5: Native Compilation ==="mvn package -Dnative -Dquarkus.native.container-build=true
echo "=== All Phases Complete ==="echo "Review reports:"echo " - Coverage: target/site/jacoco/index.html"echo " - Security: target/dependency-check-report.html"echo " - Native: target/*-runner"CI/CD Integration
GitHub Actions Example
name: Verification
on: [push, pull_request]
jobs: verify: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Set up JDK 21 uses: actions/setup-java@v3 with: java-version: '21' distribution: 'temurin'
- name: Cache Maven packages uses: actions/cache@v3 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
- name: Build run: mvn clean verify -DskipTests
- name: Test with Coverage run: mvn test jacoco:report jacoco:check
- name: Security Scan run: mvn org.owasp:dependency-check-maven:check
- name: Upload Coverage uses: codecov/codecov-action@v3 with: files: target/site/jacoco/jacoco.xmlBest Practices
- Run verification loop before every PR
- Automate in CI/CD pipeline
- Fix issues immediately; don’t accumulate debt
- Keep coverage above 80%
- Update dependencies regularly
- Test native compilation periodically
- Monitor performance trends
- Document breaking changes
- Review security scan results
- Validate configuration for each environment