mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-13 19:51:24 +08:00
fix: make plugin hooks run on Node 21+ and green the suite under modern Node (#2184)
ROOT CAUSE: hooks load plugin-hook-bootstrap.js via `node -e "...; process.argv.splice(1,0,s); require(s)"`. On Node 21+, require.main is `undefined` under --eval, so the `if (require.main === module)` guard was false and main() never ran — every plugin hook silently no-op'd (e.g. the MCP-health PreToolUse hook stopped blocking). CI (Node 18/20) hid this; it only surfaces on Node 21+. Fix: also run main() when require.main is undefined (the eval-bootstrap case), while staying dormant on real imports. Also clears pre-existing main debt the full local suite enforces: - catalog:sync — README/docs agent+skill counts drifted after recent merges - tests/ci/supply-chain-watch-workflow: update checkout SHA to the merged v6.0.3 (#2183) - markdownlint + check-unicode-safety --write across docs/skills Suite: 2683/2683 green under Node v25; lint + unicode clean. Co-authored-by: ECC Test <ecc@example.test>
This commit is contained in:
@@ -48,52 +48,52 @@ public class As2ProcessingService {
|
||||
public void processFile(Path filePath) throws Exception {
|
||||
LogContext logContext = CustomLog.getCurrentContext();
|
||||
try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
|
||||
|
||||
|
||||
String structureIdPartner = logContext.get(As2Constants.STRUCTURE_ID);
|
||||
|
||||
|
||||
// Koşullu akış mantığı
|
||||
boolean isChorusFlow = Boolean.parseBoolean(logContext.get(As2Constants.CHORUS_FLOW));
|
||||
log.info("Is CHORUS_FLOW message: {}", isChorusFlow);
|
||||
|
||||
|
||||
ValidationFlowConfig validationFlowConfig = isChorusFlow
|
||||
? ValidationFlowConfig.xsdOnly()
|
||||
: ValidationFlowConfig.allValidations();
|
||||
|
||||
|
||||
InvoiceValidationResult invoiceValidationResult = this.invoiceFlowValidator
|
||||
.validateFlowWithConfig(filePath, validationFlowConfig,
|
||||
.validateFlowWithConfig(filePath, validationFlowConfig,
|
||||
EInvoiceSyntaxFormat.UBL, logContext);
|
||||
|
||||
|
||||
FlowProfile flowProfile = isChorusFlow ?
|
||||
FlowProfile.EXTENDED_CTC_FR :
|
||||
this.invoiceFlowValidator.computeFlowProfile(invoiceValidationResult,
|
||||
this.invoiceFlowValidator.computeFlowProfile(invoiceValidationResult,
|
||||
invoiceValidationResult.getInvoiceDetails().invoiceFormat().getProfile());
|
||||
|
||||
|
||||
log.info("Invoice validation completed. Message is valid");
|
||||
|
||||
|
||||
// CompletableFuture async işlemi
|
||||
try(InputStream inputStream = Files.newInputStream(filePath)) {
|
||||
CompletableFuture<StoredDocumentInfo> documentInfoCompletableFuture =
|
||||
fileStorageService.uploadOriginalFile(inputStream,
|
||||
invoiceValidationResult.getSize(), logContext,
|
||||
CompletableFuture<StoredDocumentInfo> documentInfoCompletableFuture =
|
||||
fileStorageService.uploadOriginalFile(inputStream,
|
||||
invoiceValidationResult.getSize(), logContext,
|
||||
invoiceValidationResult.getInvoiceFormat());
|
||||
|
||||
|
||||
StoredDocumentInfo documentInfo = documentInfoCompletableFuture.join();
|
||||
log.info("File uploaded successfully: {}", documentInfo.getPath());
|
||||
|
||||
|
||||
if (StringUtils.isBlank(documentInfo.getPath())) {
|
||||
String errorMsg = "File path is empty after upload";
|
||||
log.error(errorMsg);
|
||||
this.eventService.createErrorEvent(documentInfo, "FILE_UPLOAD_FAILED", errorMsg);
|
||||
throw new As2ServerProcessingException(errorMsg);
|
||||
}
|
||||
|
||||
|
||||
this.eventService.createSuccessEvent(documentInfo, "PERSISTENCE_BLOB_EVENT_TYPE");
|
||||
|
||||
|
||||
String originalFileName = documentInfo.getOriginalFileName();
|
||||
BusinessRulesPayload payload = this.documentJobService.createDocumentAndJobEntities(
|
||||
documentInfo, originalFileName, structureIdPartner,
|
||||
documentInfo, originalFileName, structureIdPartner,
|
||||
flowProfile, invoiceValidationResult.getDocumentHash());
|
||||
|
||||
|
||||
// Async Camel yayınlama
|
||||
businessRulesPublisher.publishAsync(payload);
|
||||
this.eventService.createSuccessEvent(payload, "BUSINESS_RULES_MESSAGE_SENT");
|
||||
@@ -117,7 +117,7 @@ public class As2ProcessingService {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class ProcessingService {
|
||||
|
||||
|
||||
public void processDocument(Document doc) {
|
||||
LogContext logContext = CustomLog.getCurrentContext();
|
||||
try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
|
||||
@@ -125,12 +125,12 @@ public class ProcessingService {
|
||||
logContext.put("documentId", doc.getId().toString());
|
||||
logContext.put("documentType", doc.getType());
|
||||
logContext.put("userId", SecurityContext.getUserId());
|
||||
|
||||
|
||||
log.info("Starting document processing");
|
||||
|
||||
|
||||
// Bu kapsam içindeki tüm loglar bağlamı devralır
|
||||
processInternal(doc);
|
||||
|
||||
|
||||
log.info("Document processing completed");
|
||||
} catch (Exception e) {
|
||||
log.error("Document processing failed", e);
|
||||
@@ -150,7 +150,7 @@ public class ProcessingService {
|
||||
<includeMdc>true</includeMdc>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<logger name="com.example" level="INFO"/>
|
||||
<root level="WARN">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
@@ -167,7 +167,7 @@ public class ProcessingService {
|
||||
public class EventService {
|
||||
private final EventRepository eventRepository;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
|
||||
public void createSuccessEvent(Object payload, String eventType) {
|
||||
Objects.requireNonNull(payload, "Payload cannot be null");
|
||||
Event event = new Event();
|
||||
@@ -175,11 +175,11 @@ public class EventService {
|
||||
event.setStatus(EventStatus.SUCCESS);
|
||||
event.setPayload(serializePayload(payload));
|
||||
event.setTimestamp(Instant.now());
|
||||
|
||||
|
||||
eventRepository.persist(event);
|
||||
log.info("Success event created: {}", eventType);
|
||||
}
|
||||
|
||||
|
||||
public void createErrorEvent(Object payload, String eventType, String errorMessage) {
|
||||
Objects.requireNonNull(payload, "Payload cannot be null");
|
||||
if (errorMessage == null || errorMessage.isBlank()) {
|
||||
@@ -191,11 +191,11 @@ public class EventService {
|
||||
event.setErrorMessage(errorMessage);
|
||||
event.setPayload(serializePayload(payload));
|
||||
event.setTimestamp(Instant.now());
|
||||
|
||||
|
||||
eventRepository.persist(event);
|
||||
log.error("Error event created: {} - {}", eventType, errorMessage);
|
||||
}
|
||||
|
||||
|
||||
private String serializePayload(Object payload) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(payload);
|
||||
@@ -213,21 +213,21 @@ public class EventService {
|
||||
@RequiredArgsConstructor
|
||||
public class BusinessRulesPublisher {
|
||||
private final ProducerTemplate producerTemplate;
|
||||
|
||||
|
||||
@ConfigProperty(name = "camel.rabbitmq.queue.business-rules")
|
||||
String businessRulesQueue;
|
||||
|
||||
|
||||
public void publishAsync(BusinessRulesPayload payload) {
|
||||
producerTemplate.asyncSendBody(
|
||||
"direct:business-rules-publisher",
|
||||
"direct:business-rules-publisher",
|
||||
payload
|
||||
);
|
||||
log.info("Message published to business rules queue: {}", payload.getDocumentId());
|
||||
}
|
||||
|
||||
|
||||
public void publishSync(BusinessRulesPayload payload) {
|
||||
producerTemplate.sendBody(
|
||||
"direct:business-rules-publisher",
|
||||
"direct:business-rules-publisher",
|
||||
payload
|
||||
);
|
||||
}
|
||||
@@ -239,23 +239,23 @@ public class BusinessRulesPublisher {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class BusinessRulesRoute extends RouteBuilder {
|
||||
|
||||
|
||||
@ConfigProperty(name = "camel.rabbitmq.queue.business-rules")
|
||||
String businessRulesQueue;
|
||||
|
||||
|
||||
@ConfigProperty(name = "rabbitmq.host")
|
||||
String rabbitHost;
|
||||
|
||||
|
||||
@ConfigProperty(name = "rabbitmq.port")
|
||||
Integer rabbitPort;
|
||||
|
||||
|
||||
@Override
|
||||
public void configure() {
|
||||
from("direct:business-rules-publisher")
|
||||
.routeId("business-rules-publisher")
|
||||
.log("Publishing message to RabbitMQ: ${body}")
|
||||
.marshal().json(JsonLibrary.Jackson)
|
||||
.toF("spring-rabbitmq:%s?hostname=%s&portNumber=%d",
|
||||
.toF("spring-rabbitmq:%s?hostname=%s&portNumber=%d",
|
||||
businessRulesQueue, rabbitHost, rabbitPort);
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,7 @@ public class BusinessRulesRoute extends RouteBuilder {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class DocumentProcessingRoute extends RouteBuilder {
|
||||
|
||||
|
||||
@Override
|
||||
public void configure() {
|
||||
// Hata yönetimi
|
||||
@@ -274,7 +274,7 @@ public class DocumentProcessingRoute extends RouteBuilder {
|
||||
.handled(true)
|
||||
.to("direct:validation-error-handler")
|
||||
.log("Validation error: ${exception.message}");
|
||||
|
||||
|
||||
// Ana işleme route'u
|
||||
from("direct:process-document")
|
||||
.routeId("document-processing")
|
||||
@@ -289,7 +289,7 @@ public class DocumentProcessingRoute extends RouteBuilder {
|
||||
.otherwise()
|
||||
.to("direct:process-generic")
|
||||
.end();
|
||||
|
||||
|
||||
from("direct:validation-error-handler")
|
||||
.bean(EventService.class, "createErrorEvent")
|
||||
.log("Validation error handled");
|
||||
@@ -302,24 +302,24 @@ public class DocumentProcessingRoute extends RouteBuilder {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class FileMonitoringRoute extends RouteBuilder {
|
||||
|
||||
|
||||
@ConfigProperty(name = "file.input.directory")
|
||||
String inputDirectory;
|
||||
|
||||
|
||||
@ConfigProperty(name = "file.processed.directory")
|
||||
String processedDirectory;
|
||||
|
||||
|
||||
@ConfigProperty(name = "file.error.directory")
|
||||
String errorDirectory;
|
||||
|
||||
|
||||
@Override
|
||||
public void configure() {
|
||||
from("file:" + inputDirectory + "?move=" + processedDirectory +
|
||||
from("file:" + inputDirectory + "?move=" + processedDirectory +
|
||||
"&moveFailed=" + errorDirectory + "&delay=5000")
|
||||
.routeId("file-monitor")
|
||||
.log("Processing file: ${header.CamelFileName}")
|
||||
.to("direct:process-file");
|
||||
|
||||
|
||||
from("direct:process-file")
|
||||
.bean(As2ProcessingService.class, "processFile")
|
||||
.log("File processing completed");
|
||||
@@ -332,13 +332,13 @@ public class FileMonitoringRoute extends RouteBuilder {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class InvoiceRoute extends RouteBuilder {
|
||||
|
||||
|
||||
@Override
|
||||
public void configure() {
|
||||
from("direct:invoice-validation")
|
||||
.bean(InvoiceFlowValidator.class, "validateFlowWithConfig")
|
||||
.log("Validation result: ${body}");
|
||||
|
||||
|
||||
from("direct:persist-and-publish")
|
||||
.bean(DocumentJobService.class, "createDocumentAndJobEntities")
|
||||
.bean(BusinessRulesPublisher.class, "publishAsync")
|
||||
@@ -391,7 +391,7 @@ public class DocumentResource {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class DocumentRepository implements PanacheRepository<Document> {
|
||||
|
||||
|
||||
public List<Document> findByStatus(DocumentStatus status, int page, int size) {
|
||||
return find("status = ?1 order by createdAt desc", status)
|
||||
.page(page, size)
|
||||
@@ -401,7 +401,7 @@ public class DocumentRepository implements PanacheRepository<Document> {
|
||||
public Optional<Document> findByReferenceNumber(String referenceNumber) {
|
||||
return find("referenceNumber", referenceNumber).firstResultOptional();
|
||||
}
|
||||
|
||||
|
||||
public long countByStatusAndDate(DocumentStatus status, LocalDate date) {
|
||||
return count("status = ?1 and createdAt >= ?2", status, date.atStartOfDay());
|
||||
}
|
||||
@@ -424,11 +424,11 @@ public class DocumentService {
|
||||
document.setDescription(request.description());
|
||||
document.setStatus(DocumentStatus.PENDING);
|
||||
document.setCreatedAt(Instant.now());
|
||||
|
||||
|
||||
repo.persist(document);
|
||||
|
||||
|
||||
eventService.createSuccessEvent(document, "DOCUMENT_CREATED");
|
||||
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ public record CreateDocumentRequest(
|
||||
|
||||
public record DocumentResponse(Long id, String referenceNumber, DocumentStatus status) {
|
||||
public static DocumentResponse from(Document document) {
|
||||
return new DocumentResponse(document.getId(), document.getReferenceNumber(),
|
||||
return new DocumentResponse(document.getId(), document.getReferenceNumber(),
|
||||
document.getStatus());
|
||||
}
|
||||
}
|
||||
@@ -471,7 +471,7 @@ public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViol
|
||||
String message = exception.getConstraintViolations().stream()
|
||||
.map(cv -> cv.getPropertyPath() + ": " + cv.getMessage())
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
|
||||
return Response.status(Response.Status.BAD_REQUEST)
|
||||
.entity(Map.of("error", "validation_error", "message", message))
|
||||
.build();
|
||||
@@ -501,29 +501,29 @@ public class GenericExceptionMapper implements ExceptionMapper<Exception> {
|
||||
public class FileStorageService {
|
||||
private final S3Client s3Client;
|
||||
private final ExecutorService executorService;
|
||||
|
||||
|
||||
@ConfigProperty(name = "storage.bucket-name") String bucketName;
|
||||
|
||||
|
||||
public CompletableFuture<StoredDocumentInfo> uploadOriginalFile(
|
||||
InputStream inputStream,
|
||||
long size,
|
||||
InputStream inputStream,
|
||||
long size,
|
||||
LogContext logContext,
|
||||
InvoiceFormat format) {
|
||||
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
|
||||
String path = generateStoragePath(format);
|
||||
|
||||
|
||||
PutObjectRequest request = PutObjectRequest.builder()
|
||||
.bucket(bucketName)
|
||||
.key(path)
|
||||
.contentLength(size)
|
||||
.build();
|
||||
|
||||
|
||||
s3Client.putObject(request, RequestBody.fromInputStream(inputStream, size));
|
||||
|
||||
|
||||
log.info("File uploaded to S3: {}", path);
|
||||
|
||||
|
||||
return new StoredDocumentInfo(path, size, Instant.now());
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to upload file to S3", e);
|
||||
@@ -569,7 +569,7 @@ public class DocumentCacheService {
|
||||
hibernate-orm:
|
||||
database:
|
||||
generation: drop-and-create
|
||||
|
||||
|
||||
rabbitmq:
|
||||
host: localhost
|
||||
port: 5672
|
||||
@@ -595,7 +595,7 @@ public class DocumentCacheService {
|
||||
hibernate-orm:
|
||||
database:
|
||||
generation: validate
|
||||
|
||||
|
||||
rabbitmq:
|
||||
host: ${RABBITMQ_HOST}
|
||||
port: ${RABBITMQ_PORT}
|
||||
@@ -688,7 +688,7 @@ public class CamelHealthCheck implements HealthCheck {
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-config-yaml</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Camel Uzantıları -->
|
||||
<dependency>
|
||||
<groupId>org.apache.camel.quarkus</groupId>
|
||||
@@ -702,7 +702,7 @@ public class CamelHealthCheck implements HealthCheck {
|
||||
<groupId>org.apache.camel.quarkus</groupId>
|
||||
<artifactId>camel-quarkus-bean</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
@@ -710,7 +710,7 @@ public class CamelHealthCheck implements HealthCheck {
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Loglama -->
|
||||
<dependency>
|
||||
<groupId>io.quarkiverse.logging.logback</groupId>
|
||||
|
||||
@@ -38,7 +38,7 @@ başlıklarını açıkça yapılandırın, gizli bilgileri Vault veya ortam de
|
||||
@Path("/api/protected")
|
||||
@Authenticated
|
||||
public class ProtectedResource {
|
||||
|
||||
|
||||
@Inject
|
||||
JsonWebToken jwt;
|
||||
|
||||
@@ -75,20 +75,20 @@ quarkus.oidc.credentials.secret=${OIDC_SECRET}
|
||||
@Provider
|
||||
@Priority(Priorities.AUTHENTICATION)
|
||||
public class CustomAuthFilter implements ContainerRequestFilter {
|
||||
|
||||
|
||||
@Inject
|
||||
SecurityIdentity identity;
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) {
|
||||
String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
|
||||
// Başlık yoksa veya hatalıysa hemen reddet
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String token = authHeader.substring(7);
|
||||
if (!validateToken(token)) {
|
||||
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
|
||||
@@ -110,7 +110,7 @@ public class CustomAuthFilter implements ContainerRequestFilter {
|
||||
@Path("/api/admin")
|
||||
@RolesAllowed("ADMIN")
|
||||
public class AdminResource {
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/users")
|
||||
public List<UserDto> listUsers() {
|
||||
@@ -128,7 +128,7 @@ public class AdminResource {
|
||||
|
||||
@Path("/api/users")
|
||||
public class UserResource {
|
||||
|
||||
|
||||
@Inject
|
||||
SecurityIdentity securityIdentity;
|
||||
|
||||
@@ -137,7 +137,7 @@ public class UserResource {
|
||||
@RolesAllowed("USER")
|
||||
public Response getUser(@PathParam("id") Long id) {
|
||||
// Sahipliği kontrol et
|
||||
if (!securityIdentity.hasRole("ADMIN") &&
|
||||
if (!securityIdentity.hasRole("ADMIN") &&
|
||||
!isOwner(id, securityIdentity.getPrincipal().getName())) {
|
||||
return Response.status(Response.Status.FORBIDDEN).build();
|
||||
}
|
||||
@@ -155,7 +155,7 @@ public class UserResource {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class SecurityService {
|
||||
|
||||
|
||||
@Inject
|
||||
SecurityIdentity securityIdentity;
|
||||
|
||||
@@ -163,7 +163,7 @@ public class SecurityService {
|
||||
if (securityIdentity.isAnonymous()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (securityIdentity.hasRole("ADMIN")) {
|
||||
return true;
|
||||
}
|
||||
@@ -239,7 +239,7 @@ List<User> users = User.list("email = ?1 and active = ?2", email, true);
|
||||
Optional<User> user = User.find("username", username).firstResultOptional();
|
||||
|
||||
// İYİ: İsimlendirilmiş parametreler
|
||||
List<User> users = User.list("email = :email and age > :minAge",
|
||||
List<User> users = User.list("email = :email and age > :minAge",
|
||||
Parameters.with("email", email).and("minAge", 18));
|
||||
```
|
||||
|
||||
@@ -266,7 +266,7 @@ public class User extends PanacheEntity {
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class PasswordService {
|
||||
|
||||
|
||||
public String hash(String plainPassword) {
|
||||
return BcryptUtil.bcryptHash(plainPassword);
|
||||
}
|
||||
@@ -334,7 +334,7 @@ quarkus.vault.authentication.kubernetes.role=my-role
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class SecretService {
|
||||
|
||||
|
||||
@ConfigProperty(name = "api-key")
|
||||
String apiKey; // Vault'tan alınır
|
||||
|
||||
@@ -360,7 +360,7 @@ public class RateLimitFilter implements ContainerRequestFilter {
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) {
|
||||
String clientId = getClientIdentifier();
|
||||
RateLimiter limiter = limiters.computeIfAbsent(clientId,
|
||||
RateLimiter limiter = limiters.computeIfAbsent(clientId,
|
||||
k -> RateLimiter.create(100.0)); // Saniyede 100 istek
|
||||
|
||||
if (!limiter.tryAcquire()) {
|
||||
@@ -385,24 +385,24 @@ public class RateLimitFilter implements ContainerRequestFilter {
|
||||
```java
|
||||
@Provider
|
||||
public class SecurityHeadersFilter implements ContainerResponseFilter {
|
||||
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext request, ContainerResponseContext response) {
|
||||
MultivaluedMap<String, Object> headers = response.getHeaders();
|
||||
|
||||
|
||||
// Clickjacking'i önle
|
||||
headers.putSingle("X-Frame-Options", "DENY");
|
||||
|
||||
|
||||
// XSS koruması
|
||||
headers.putSingle("X-Content-Type-Options", "nosniff");
|
||||
headers.putSingle("X-XSS-Protection", "1; mode=block");
|
||||
|
||||
|
||||
// HSTS
|
||||
headers.putSingle("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
|
||||
|
||||
|
||||
// CSP — script-src için 'unsafe-inline' kullanmayın, XSS korumasını etkisiz kılar;
|
||||
// bunun yerine nonce veya hash kullanın
|
||||
headers.putSingle("Content-Security-Policy",
|
||||
headers.putSingle("Content-Security-Policy",
|
||||
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");
|
||||
}
|
||||
}
|
||||
@@ -419,11 +419,11 @@ public class AuditService {
|
||||
SecurityIdentity securityIdentity;
|
||||
|
||||
public void logAccess(String resource, String action) {
|
||||
String user = securityIdentity.isAnonymous()
|
||||
? "anonymous"
|
||||
String user = securityIdentity.isAnonymous()
|
||||
? "anonymous"
|
||||
: securityIdentity.getPrincipal().getName();
|
||||
|
||||
LOG.infof("AUDIT: user=%s action=%s resource=%s timestamp=%s",
|
||||
|
||||
LOG.infof("AUDIT: user=%s action=%s resource=%s timestamp=%s",
|
||||
user, action, resource, Instant.now());
|
||||
}
|
||||
}
|
||||
|
||||
+105
-105
@@ -36,25 +36,25 @@ Kapsamlı ve okunabilir testler için bu yapılandırılmış yaklaşımı izley
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@DisplayName("As2ProcessingService Unit Tests")
|
||||
class As2ProcessingServiceTest {
|
||||
|
||||
|
||||
@Mock
|
||||
private InvoiceFlowValidator invoiceFlowValidator;
|
||||
|
||||
|
||||
@Mock
|
||||
private EventService eventService;
|
||||
|
||||
|
||||
@Mock
|
||||
private DocumentJobService documentJobService;
|
||||
|
||||
|
||||
@Mock
|
||||
private BusinessRulesPublisher businessRulesPublisher;
|
||||
|
||||
|
||||
@Mock
|
||||
private FileStorageService fileStorageService;
|
||||
|
||||
|
||||
@InjectMocks
|
||||
private As2ProcessingService as2ProcessingService;
|
||||
|
||||
|
||||
private Path testFilePath;
|
||||
private LogContext testLogContext;
|
||||
private InvoiceValidationResult validationResult;
|
||||
@@ -64,17 +64,17 @@ class As2ProcessingServiceTest {
|
||||
void setUp() {
|
||||
// ARRANGE - Ortak test verisi
|
||||
testFilePath = Path.of("/tmp/test-invoice.xml");
|
||||
|
||||
|
||||
testLogContext = new LogContext();
|
||||
testLogContext.put(As2Constants.STRUCTURE_ID, "STRUCT-001");
|
||||
testLogContext.put(As2Constants.FILE_NAME, "invoice.xml");
|
||||
testLogContext.put(As2Constants.AS2_FROM, "PARTNER-001");
|
||||
|
||||
|
||||
validationResult = new InvoiceValidationResult();
|
||||
validationResult.setValid(true);
|
||||
validationResult.setSize(1024L);
|
||||
validationResult.setDocumentHash("abc123");
|
||||
|
||||
|
||||
documentInfo = new StoredDocumentInfo();
|
||||
documentInfo.setPath("s3://bucket/path/invoice.xml");
|
||||
documentInfo.setSize(1024L);
|
||||
@@ -83,43 +83,43 @@ class As2ProcessingServiceTest {
|
||||
@Nested
|
||||
@DisplayName("processFile için testler")
|
||||
class ProcessFile {
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("CHORUS olmayan dosyayı tüm validasyonlarla başarıyla işlemeli")
|
||||
void givenNonChorusFile_whenProcessFile_thenAllValidationsApplied() throws Exception {
|
||||
// ARRANGE
|
||||
testLogContext.put(As2Constants.CHORUS_FLOW, "false");
|
||||
CustomLog.setCurrentContext(testLogContext);
|
||||
|
||||
|
||||
when(invoiceFlowValidator.validateFlowWithConfig(
|
||||
eq(testFilePath),
|
||||
eq(testFilePath),
|
||||
eq(ValidationFlowConfig.allValidations()),
|
||||
eq(EInvoiceSyntaxFormat.UBL),
|
||||
any(LogContext.class)))
|
||||
.thenReturn(validationResult);
|
||||
|
||||
|
||||
when(invoiceFlowValidator.computeFlowProfile(any(), any()))
|
||||
.thenReturn(FlowProfile.BASIC);
|
||||
|
||||
|
||||
when(fileStorageService.uploadOriginalFile(any(), anyLong(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(documentInfo));
|
||||
|
||||
|
||||
when(documentJobService.createDocumentAndJobEntities(any(), any(), any(), any(), any()))
|
||||
.thenReturn(new BusinessRulesPayload());
|
||||
|
||||
|
||||
// ACT
|
||||
assertDoesNotThrow(() -> as2ProcessingService.processFile(testFilePath));
|
||||
|
||||
|
||||
// ASSERT
|
||||
verify(invoiceFlowValidator).validateFlowWithConfig(
|
||||
eq(testFilePath),
|
||||
eq(ValidationFlowConfig.allValidations()),
|
||||
eq(EInvoiceSyntaxFormat.UBL),
|
||||
any(LogContext.class));
|
||||
|
||||
verify(eventService).createSuccessEvent(any(StoredDocumentInfo.class),
|
||||
|
||||
verify(eventService).createSuccessEvent(any(StoredDocumentInfo.class),
|
||||
eq("PERSISTENCE_BLOB_EVENT_TYPE"));
|
||||
verify(eventService).createSuccessEvent(any(BusinessRulesPayload.class),
|
||||
verify(eventService).createSuccessEvent(any(BusinessRulesPayload.class),
|
||||
eq("BUSINESS_RULES_MESSAGE_SENT"));
|
||||
verify(businessRulesPublisher).publishAsync(any(BusinessRulesPayload.class));
|
||||
}
|
||||
@@ -130,34 +130,34 @@ class As2ProcessingServiceTest {
|
||||
// ARRANGE
|
||||
testLogContext.put(As2Constants.CHORUS_FLOW, "true");
|
||||
CustomLog.setCurrentContext(testLogContext);
|
||||
|
||||
|
||||
when(invoiceFlowValidator.validateFlowWithConfig(
|
||||
eq(testFilePath),
|
||||
eq(testFilePath),
|
||||
eq(ValidationFlowConfig.xsdOnly()),
|
||||
eq(EInvoiceSyntaxFormat.UBL),
|
||||
any(LogContext.class)))
|
||||
.thenReturn(validationResult);
|
||||
|
||||
|
||||
when(fileStorageService.uploadOriginalFile(any(), anyLong(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(documentInfo));
|
||||
|
||||
when(documentJobService.createDocumentAndJobEntities(any(), any(), any(),
|
||||
|
||||
when(documentJobService.createDocumentAndJobEntities(any(), any(), any(),
|
||||
eq(FlowProfile.EXTENDED_CTC_FR), any()))
|
||||
.thenReturn(new BusinessRulesPayload());
|
||||
|
||||
|
||||
// ACT
|
||||
assertDoesNotThrow(() -> as2ProcessingService.processFile(testFilePath));
|
||||
|
||||
|
||||
// ASSERT
|
||||
verify(invoiceFlowValidator).validateFlowWithConfig(
|
||||
eq(testFilePath),
|
||||
eq(ValidationFlowConfig.xsdOnly()),
|
||||
eq(EInvoiceSyntaxFormat.UBL),
|
||||
any(LogContext.class));
|
||||
|
||||
|
||||
verify(documentJobService).createDocumentAndJobEntities(
|
||||
any(), any(), any(),
|
||||
eq(FlowProfile.EXTENDED_CTC_FR),
|
||||
any(), any(), any(),
|
||||
eq(FlowProfile.EXTENDED_CTC_FR),
|
||||
any());
|
||||
}
|
||||
|
||||
@@ -167,31 +167,31 @@ class As2ProcessingServiceTest {
|
||||
// ARRANGE
|
||||
testLogContext.put(As2Constants.CHORUS_FLOW, "false");
|
||||
CustomLog.setCurrentContext(testLogContext);
|
||||
|
||||
|
||||
when(invoiceFlowValidator.validateFlowWithConfig(any(), any(), any(), any()))
|
||||
.thenReturn(validationResult);
|
||||
|
||||
|
||||
when(invoiceFlowValidator.computeFlowProfile(any(), any()))
|
||||
.thenReturn(FlowProfile.BASIC);
|
||||
|
||||
|
||||
documentInfo.setPath(""); // Boş path hatayı tetikler
|
||||
when(fileStorageService.uploadOriginalFile(any(), anyLong(), any(), any()))
|
||||
.thenReturn(CompletableFuture.completedFuture(documentInfo));
|
||||
|
||||
|
||||
// ACT & ASSERT
|
||||
As2ServerProcessingException exception = assertThrows(
|
||||
As2ServerProcessingException.class,
|
||||
() -> as2ProcessingService.processFile(testFilePath)
|
||||
);
|
||||
|
||||
|
||||
assertThat(exception.getMessage())
|
||||
.contains("File path is empty after upload");
|
||||
|
||||
|
||||
verify(eventService).createErrorEvent(
|
||||
eq(documentInfo),
|
||||
eq("FILE_UPLOAD_FAILED"),
|
||||
eq(documentInfo),
|
||||
eq("FILE_UPLOAD_FAILED"),
|
||||
contains("File path is empty"));
|
||||
|
||||
|
||||
verify(businessRulesPublisher, never()).publishAsync(any());
|
||||
}
|
||||
|
||||
@@ -201,18 +201,18 @@ class As2ProcessingServiceTest {
|
||||
// ARRANGE
|
||||
testLogContext.put(As2Constants.CHORUS_FLOW, "false");
|
||||
CustomLog.setCurrentContext(testLogContext);
|
||||
|
||||
|
||||
when(invoiceFlowValidator.validateFlowWithConfig(any(), any(), any(), any()))
|
||||
.thenReturn(validationResult);
|
||||
|
||||
|
||||
when(invoiceFlowValidator.computeFlowProfile(any(), any()))
|
||||
.thenReturn(FlowProfile.BASIC);
|
||||
|
||||
CompletableFuture<StoredDocumentInfo> failedFuture =
|
||||
|
||||
CompletableFuture<StoredDocumentInfo> failedFuture =
|
||||
CompletableFuture.failedFuture(new StorageException("S3 connection failed"));
|
||||
when(fileStorageService.uploadOriginalFile(any(), anyLong(), any(), any()))
|
||||
.thenReturn(failedFuture);
|
||||
|
||||
|
||||
// ACT & ASSERT
|
||||
assertThrows(
|
||||
CompletionException.class,
|
||||
@@ -225,13 +225,13 @@ class As2ProcessingServiceTest {
|
||||
void givenNullFilePath_whenProcessFile_thenThrowsException() {
|
||||
// ARRANGE
|
||||
Path nullPath = null;
|
||||
|
||||
|
||||
// ACT & ASSERT
|
||||
NullPointerException exception = assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> as2ProcessingService.processFile(nullPath)
|
||||
);
|
||||
|
||||
|
||||
verify(invoiceFlowValidator, never()).validateFlowWithConfig(any(), any(), any(), any());
|
||||
}
|
||||
}
|
||||
@@ -287,7 +287,7 @@ class BusinessRulesRouteTest {
|
||||
// ARRANGE
|
||||
MockEndpoint mockRabbitMQ = camelContext.getEndpoint("mock:rabbitmq", MockEndpoint.class);
|
||||
mockRabbitMQ.expectedMessageCount(1);
|
||||
|
||||
|
||||
// Test için gerçek endpoint'i mock ile değiştir
|
||||
camelContext.getRouteController().stopRoute("business-rules-publisher");
|
||||
AdviceWith.adviceWith(camelContext, "business-rules-publisher", advice -> {
|
||||
@@ -295,13 +295,13 @@ class BusinessRulesRouteTest {
|
||||
advice.weaveByToString(".*spring-rabbitmq.*").replace().to("mock:rabbitmq");
|
||||
});
|
||||
camelContext.getRouteController().startRoute("business-rules-publisher");
|
||||
|
||||
|
||||
// ACT
|
||||
producerTemplate.sendBody("direct:business-rules-publisher", testPayload);
|
||||
|
||||
|
||||
// ASSERT — .marshal().json() sonrası body JSON String'dir
|
||||
mockRabbitMQ.assertIsSatisfied(5000);
|
||||
|
||||
|
||||
assertThat(mockRabbitMQ.getExchanges()).hasSize(1);
|
||||
String body = mockRabbitMQ.getExchanges().get(0).getIn().getBody(String.class);
|
||||
assertThat(body).contains("\"documentId\":1");
|
||||
@@ -314,19 +314,19 @@ class BusinessRulesRouteTest {
|
||||
MockEndpoint mockMarshal = new MockEndpoint("mock:marshal");
|
||||
camelContext.addEndpoint("mock:marshal", mockMarshal);
|
||||
mockMarshal.expectedMessageCount(1);
|
||||
|
||||
|
||||
camelContext.getRouteController().stopRoute("business-rules-publisher");
|
||||
AdviceWith.adviceWith(camelContext, "business-rules-publisher", advice -> {
|
||||
advice.weaveAddLast().to("mock:marshal");
|
||||
});
|
||||
camelContext.getRouteController().startRoute("business-rules-publisher");
|
||||
|
||||
|
||||
// ACT
|
||||
producerTemplate.sendBody("direct:business-rules-publisher", testPayload);
|
||||
|
||||
|
||||
// ASSERT
|
||||
mockMarshal.assertIsSatisfied(5000);
|
||||
|
||||
|
||||
String body = mockMarshal.getExchanges().get(0).getIn().getBody(String.class);
|
||||
assertThat(body).contains("\"documentId\":1");
|
||||
assertThat(body).contains("\"flowProfile\":\"BASIC\"");
|
||||
@@ -343,17 +343,17 @@ class BusinessRulesRouteTest {
|
||||
// ARRANGE
|
||||
MockEndpoint mockInvoice = camelContext.getEndpoint("mock:invoice", MockEndpoint.class);
|
||||
mockInvoice.expectedMessageCount(1);
|
||||
|
||||
|
||||
camelContext.getRouteController().stopRoute("document-processing");
|
||||
AdviceWith.adviceWith(camelContext, "document-processing", advice -> {
|
||||
advice.weaveByToString(".*direct:process-invoice.*").replace().to("mock:invoice");
|
||||
});
|
||||
camelContext.getRouteController().startRoute("document-processing");
|
||||
|
||||
|
||||
// ACT
|
||||
producerTemplate.sendBodyAndHeader("direct:process-document",
|
||||
producerTemplate.sendBodyAndHeader("direct:process-document",
|
||||
testPayload, "documentType", "INVOICE");
|
||||
|
||||
|
||||
// ASSERT
|
||||
mockInvoice.assertIsSatisfied(5000);
|
||||
}
|
||||
@@ -364,25 +364,25 @@ class BusinessRulesRouteTest {
|
||||
// ARRANGE
|
||||
MockEndpoint mockError = camelContext.getEndpoint("mock:error", MockEndpoint.class);
|
||||
mockError.expectedMessageCount(1);
|
||||
|
||||
|
||||
camelContext.getRouteController().stopRoute("document-processing");
|
||||
AdviceWith.adviceWith(camelContext, "document-processing", advice -> {
|
||||
advice.weaveByToString(".*direct:validation-error-handler.*")
|
||||
.replace().to("mock:error");
|
||||
});
|
||||
camelContext.getRouteController().startRoute("document-processing");
|
||||
|
||||
|
||||
// Error event oluşturma hatasını gerçek EventService API'si üzerinden simüle et
|
||||
doThrow(new ValidationException("Invalid document"))
|
||||
.when(eventService)
|
||||
.createErrorEvent(any(), eq("VALIDATION_ERROR"), anyString());
|
||||
|
||||
|
||||
// ACT
|
||||
producerTemplate.sendBody("direct:process-document", testPayload);
|
||||
|
||||
|
||||
// ASSERT
|
||||
mockError.assertIsSatisfied(5000);
|
||||
|
||||
|
||||
Exception exception = mockError.getExchanges().get(0).getException();
|
||||
assertThat(exception).isInstanceOf(ValidationException.class);
|
||||
assertThat(exception.getMessage()).contains("Invalid document");
|
||||
@@ -400,13 +400,13 @@ class EventServiceTest {
|
||||
|
||||
@Mock
|
||||
private EventRepository eventRepository;
|
||||
|
||||
|
||||
@Mock
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
|
||||
@InjectMocks
|
||||
private EventService eventService;
|
||||
|
||||
|
||||
private BusinessRulesPayload testPayload;
|
||||
|
||||
@BeforeEach
|
||||
@@ -419,19 +419,19 @@ class EventServiceTest {
|
||||
@Nested
|
||||
@DisplayName("createSuccessEvent için testler")
|
||||
class CreateSuccessEvent {
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("Doğru niteliklerle başarı eventi oluşturulmalı")
|
||||
void givenValidPayload_whenCreateSuccessEvent_thenEventPersisted() throws Exception {
|
||||
// ARRANGE
|
||||
when(objectMapper.writeValueAsString(testPayload)).thenReturn("{\"documentId\":1}");
|
||||
|
||||
|
||||
// ACT
|
||||
assertDoesNotThrow(() ->
|
||||
assertDoesNotThrow(() ->
|
||||
eventService.createSuccessEvent(testPayload, "DOCUMENT_PROCESSED"));
|
||||
|
||||
|
||||
// ASSERT
|
||||
verify(eventRepository).persist(argThat(event ->
|
||||
verify(eventRepository).persist(argThat(event ->
|
||||
event.getType().equals("DOCUMENT_PROCESSED") &&
|
||||
event.getStatus() == EventStatus.SUCCESS &&
|
||||
event.getPayload().equals("{\"documentId\":1}") &&
|
||||
@@ -444,13 +444,13 @@ class EventServiceTest {
|
||||
void givenNullPayload_whenCreateSuccessEvent_thenThrowsException() {
|
||||
// ARRANGE
|
||||
Object nullPayload = null;
|
||||
|
||||
|
||||
// ACT & ASSERT
|
||||
NullPointerException exception = assertThrows(
|
||||
NullPointerException.class,
|
||||
() -> eventService.createSuccessEvent(nullPayload, "EVENT_TYPE")
|
||||
);
|
||||
|
||||
|
||||
assertThat(exception.getMessage()).isEqualTo("Payload cannot be null");
|
||||
verify(eventRepository, never()).persist(any());
|
||||
}
|
||||
@@ -459,20 +459,20 @@ class EventServiceTest {
|
||||
@Nested
|
||||
@DisplayName("createErrorEvent için testler")
|
||||
class CreateErrorEvent {
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("Hata mesajıyla hata eventi oluşturulmalı")
|
||||
void givenError_whenCreateErrorEvent_thenEventPersistedWithMessage() throws Exception {
|
||||
// ARRANGE
|
||||
String errorMessage = "Processing failed";
|
||||
when(objectMapper.writeValueAsString(testPayload)).thenReturn("{\"documentId\":1}");
|
||||
|
||||
|
||||
// ACT
|
||||
assertDoesNotThrow(() ->
|
||||
assertDoesNotThrow(() ->
|
||||
eventService.createErrorEvent(testPayload, "PROCESSING_ERROR", errorMessage));
|
||||
|
||||
|
||||
// ASSERT
|
||||
verify(eventRepository).persist(argThat(event ->
|
||||
verify(eventRepository).persist(argThat(event ->
|
||||
event.getType().equals("PROCESSING_ERROR") &&
|
||||
event.getStatus() == EventStatus.ERROR &&
|
||||
event.getErrorMessage().equals(errorMessage) &&
|
||||
@@ -489,7 +489,7 @@ class EventServiceTest {
|
||||
IllegalArgumentException.class,
|
||||
() -> eventService.createErrorEvent(testPayload, "ERROR", blankMessage)
|
||||
);
|
||||
|
||||
|
||||
assertThat(exception.getMessage()).contains("Error message cannot be blank");
|
||||
}
|
||||
}
|
||||
@@ -505,13 +505,13 @@ class FileStorageServiceTest {
|
||||
|
||||
@Mock
|
||||
private S3Client s3Client;
|
||||
|
||||
|
||||
@Mock
|
||||
private ExecutorService executorService;
|
||||
|
||||
|
||||
@InjectMocks
|
||||
private FileStorageService fileStorageService;
|
||||
|
||||
|
||||
private InputStream testInputStream;
|
||||
private LogContext testLogContext;
|
||||
|
||||
@@ -526,7 +526,7 @@ class FileStorageServiceTest {
|
||||
@Nested
|
||||
@DisplayName("uploadOriginalFile için testler")
|
||||
class UploadOriginalFile {
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("Dosyayı başarıyla yüklemeli ve belge bilgisi döndürmeli")
|
||||
void givenValidFile_whenUpload_thenReturnsDocumentInfo() throws Exception {
|
||||
@@ -535,23 +535,23 @@ class FileStorageServiceTest {
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
return null;
|
||||
}).when(executorService).execute(any(Runnable.class));
|
||||
|
||||
|
||||
when(s3Client.putObject(any(PutObjectRequest.class), any(RequestBody.class)))
|
||||
.thenReturn(PutObjectResponse.builder().build());
|
||||
|
||||
|
||||
// ACT
|
||||
CompletableFuture<StoredDocumentInfo> future =
|
||||
fileStorageService.uploadOriginalFile(testInputStream, 1024L,
|
||||
CompletableFuture<StoredDocumentInfo> future =
|
||||
fileStorageService.uploadOriginalFile(testInputStream, 1024L,
|
||||
testLogContext, InvoiceFormat.UBL);
|
||||
|
||||
|
||||
StoredDocumentInfo result = future.join();
|
||||
|
||||
|
||||
// ASSERT
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getPath()).isNotBlank();
|
||||
assertThat(result.getSize()).isEqualTo(1024L);
|
||||
assertThat(result.getUploadedAt()).isNotNull();
|
||||
|
||||
|
||||
verify(s3Client).putObject(any(PutObjectRequest.class), any(RequestBody.class));
|
||||
}
|
||||
|
||||
@@ -566,12 +566,12 @@ class FileStorageServiceTest {
|
||||
|
||||
when(s3Client.putObject(any(PutObjectRequest.class), any(RequestBody.class)))
|
||||
.thenThrow(new StorageException("S3 unavailable"));
|
||||
|
||||
|
||||
// ACT
|
||||
CompletableFuture<StoredDocumentInfo> future =
|
||||
fileStorageService.uploadOriginalFile(testInputStream, 1024L,
|
||||
CompletableFuture<StoredDocumentInfo> future =
|
||||
fileStorageService.uploadOriginalFile(testInputStream, 1024L,
|
||||
testLogContext, InvoiceFormat.UBL);
|
||||
|
||||
|
||||
// ASSERT
|
||||
assertThatThrownBy(() -> future.join())
|
||||
.isInstanceOf(CompletionException.class)
|
||||
@@ -584,17 +584,17 @@ class FileStorageServiceTest {
|
||||
void givenLogContext_whenUpload_thenContextPropagated() throws Exception {
|
||||
// ARRANGE
|
||||
AtomicReference<LogContext> capturedContext = new AtomicReference<>();
|
||||
|
||||
|
||||
doAnswer(invocation -> {
|
||||
capturedContext.set(CustomLog.getCurrentContext());
|
||||
((Runnable) invocation.getArgument(0)).run();
|
||||
return null;
|
||||
}).when(executorService).execute(any(Runnable.class));
|
||||
|
||||
|
||||
// ACT
|
||||
fileStorageService.uploadOriginalFile(testInputStream, 1024L,
|
||||
fileStorageService.uploadOriginalFile(testInputStream, 1024L,
|
||||
testLogContext, InvoiceFormat.UBL).join();
|
||||
|
||||
|
||||
// ASSERT
|
||||
assertThat(capturedContext.get()).isNotNull();
|
||||
assertThat(capturedContext.get().get("traceId")).isEqualTo("trace-123");
|
||||
@@ -746,7 +746,7 @@ class DocumentIntegrationTest {
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
|
||||
|
||||
<!-- Kapsam raporu oluştur -->
|
||||
<execution>
|
||||
<id>report</id>
|
||||
@@ -755,7 +755,7 @@ class DocumentIntegrationTest {
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
|
||||
|
||||
<!-- Kapsam eşiklerini zorla -->
|
||||
<execution>
|
||||
<id>check</id>
|
||||
@@ -810,14 +810,14 @@ mvn jacoco:check
|
||||
<artifactId>quarkus-junit5-mockito</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Mockito -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- AssertJ (JUnit assertion'larına tercih edilir) -->
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
@@ -825,14 +825,14 @@ mvn jacoco:check
|
||||
<version>3.24.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- REST Assured -->
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Camel Test -->
|
||||
<dependency>
|
||||
<groupId>org.apache.camel.quarkus</groupId>
|
||||
|
||||
@@ -437,28 +437,28 @@ jobs:
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user