Skip to content

Commit

Permalink
feat: P4ADEV-1493-wf-payments-reporting-ingestion-worker (#10)
Browse files Browse the repository at this point in the history
Co-authored-by: antonio.torre <[email protected]>
  • Loading branch information
fvuotoeng and antonioT90 authored Jan 3, 2025
1 parent c82fc41 commit eac4057
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/codereview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
working-directory: ./
run: ./gradlew clean build jacocoTestReport
env:
GITHUB_TOKEN: ${{ secret.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Sonar Scan
working-directory: ./
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/security-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Checkout the code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
- name: Build the Docker image
run: docker build . --file Dockerfile --tag localbuild/testimage:latest --build-arg GITHUB_TOKEN=${{ secret.GITHUB_TOKEN }}
run: docker build . --file Dockerfile --tag localbuild/testimage:latest --build-arg GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}
- name: Run the Trivy scan action itself with GitHub Advanced Security code scanning integration enabled
id: scan
uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0
Expand Down
11 changes: 11 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ val openApiToolsVersion = "0.2.6"
val micrometerVersion = "1.4.1"
val p4paActivitiesVersion = "1.23.4"
val postgresJdbcVersion = "42.7.4"
val temporalVersion = "1.27.0"
val protobufJavaVersion = "3.25.5"

dependencies {
implementation("org.springframework.boot:spring-boot-starter")
Expand All @@ -55,6 +57,15 @@ dependencies {
// p4pa activities library
implementation("it.gov.pagopa.payhub:p4pa-payhub-activities:$p4paActivitiesVersion")


implementation("io.temporal:temporal-spring-boot-starter:$temporalVersion"){
exclude(group = "com.google.protobuf", module = "protobuf-java")
}

// updated for security reason
implementation("com.google.protobuf:protobuf-java:$protobufJavaVersion")


//postgres jdbc
implementation("org.postgresql:postgresql:$postgresJdbcVersion")

Expand Down
33 changes: 33 additions & 0 deletions gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,59 @@ com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2=compileClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2=compileClasspath
com.fasterxml.jackson.module:jackson-module-parameter-names:2.18.2=compileClasspath
com.fasterxml.jackson:jackson-bom:2.18.2=compileClasspath
com.google.api.grpc:proto-google-common-protos:2.9.0=compileClasspath
com.google.code.findbugs:jsr305:3.0.2=compileClasspath
com.google.code.gson:gson:2.11.0=compileClasspath
com.google.errorprone:error_prone_annotations:2.28.0=compileClasspath
com.google.guava:failureaccess:1.0.2=compileClasspath
com.google.guava:guava:33.3.1-jre=compileClasspath
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=compileClasspath
com.google.j2objc:j2objc-annotations:3.0.0=compileClasspath
com.google.protobuf:protobuf-java-util:3.22.0=compileClasspath
com.google.protobuf:protobuf-java:3.25.5=compileClasspath
com.uber.m3:tally-core:0.13.0=compileClasspath
com.zaxxer:HikariCP:5.1.0=compileClasspath
io.grpc:grpc-api:1.54.1=compileClasspath
io.grpc:grpc-bom:1.54.1=compileClasspath
io.grpc:grpc-context:1.54.1=compileClasspath
io.grpc:grpc-core:1.54.1=compileClasspath
io.grpc:grpc-netty-shaded:1.54.1=compileClasspath
io.grpc:grpc-protobuf-lite:1.54.1=compileClasspath
io.grpc:grpc-protobuf:1.54.1=compileClasspath
io.grpc:grpc-services:1.54.1=compileClasspath
io.grpc:grpc-stub:1.54.1=compileClasspath
io.micrometer:context-propagation:1.1.2=compileClasspath
io.micrometer:micrometer-bom:1.9.9=compileClasspath
io.micrometer:micrometer-commons:1.14.2=compileClasspath
io.micrometer:micrometer-core:1.14.2=compileClasspath
io.micrometer:micrometer-jakarta9:1.14.2=compileClasspath
io.micrometer:micrometer-observation:1.14.2=compileClasspath
io.micrometer:micrometer-tracing-bridge-otel:1.4.1=compileClasspath
io.micrometer:micrometer-tracing:1.4.1=compileClasspath
io.nexusrpc:nexus-sdk:0.3.0-alpha=compileClasspath
io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator:2.9.0-alpha=compileClasspath
io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:2.9.0=compileClasspath
io.opentelemetry.semconv:opentelemetry-semconv:1.25.0-alpha=compileClasspath
io.opentelemetry:opentelemetry-api:1.43.0=compileClasspath
io.opentelemetry:opentelemetry-bom:1.25.0=compileClasspath
io.opentelemetry:opentelemetry-context:1.43.0=compileClasspath
io.opentelemetry:opentelemetry-extension-trace-propagators:1.43.0=compileClasspath
io.opentelemetry:opentelemetry-sdk-common:1.43.0=compileClasspath
io.opentelemetry:opentelemetry-sdk-logs:1.43.0=compileClasspath
io.opentelemetry:opentelemetry-sdk-metrics:1.43.0=compileClasspath
io.opentelemetry:opentelemetry-sdk-trace:1.43.0=compileClasspath
io.opentelemetry:opentelemetry-sdk:1.43.0=compileClasspath
io.opentracing:opentracing-api:0.33.0=compileClasspath
io.swagger.core.v3:swagger-annotations-jakarta:2.2.25=compileClasspath
io.swagger.core.v3:swagger-core-jakarta:2.2.25=compileClasspath
io.swagger.core.v3:swagger-models-jakarta:2.2.25=compileClasspath
io.temporal:temporal-opentracing:1.27.0=compileClasspath
io.temporal:temporal-sdk:1.27.0=compileClasspath
io.temporal:temporal-serviceclient:1.27.0=compileClasspath
io.temporal:temporal-spring-boot-autoconfigure:1.27.0=compileClasspath
io.temporal:temporal-spring-boot-starter:1.27.0=compileClasspath
io.temporal:temporal-test-server:1.27.0=compileClasspath
io.temporal:temporal-testing:1.27.0=compileClasspath
it.gov.pagopa.payhub:p4pa-payhub-activities:1.23.4=compileClasspath
jakarta.activation:jakarta.activation-api:2.1.3=compileClasspath
jakarta.annotation:jakarta.annotation-api:2.1.1=compileClasspath
Expand All @@ -49,6 +80,7 @@ org.apache.tomcat.embed:tomcat-embed-core:10.1.34=compileClasspath
org.apache.tomcat.embed:tomcat-embed-el:10.1.34=compileClasspath
org.apache.tomcat.embed:tomcat-embed-websocket:10.1.34=compileClasspath
org.aspectj:aspectjweaver:1.9.22.1=compileClasspath
org.checkerframework:checker-qual:3.43.0=compileClasspath
org.hibernate.orm:hibernate-core:6.6.4.Final=compileClasspath
org.jspecify:jspecify:1.0.0=compileClasspath
org.openapitools:jackson-databind-nullable:0.2.6=compileClasspath
Expand All @@ -62,6 +94,7 @@ org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0=compileClasspath
org.springframework.boot:spring-boot-actuator-autoconfigure:3.4.1=compileClasspath
org.springframework.boot:spring-boot-actuator:3.4.1=compileClasspath
org.springframework.boot:spring-boot-autoconfigure:3.4.1=compileClasspath
org.springframework.boot:spring-boot-dependencies:2.7.18=compileClasspath
org.springframework.boot:spring-boot-starter-actuator:3.4.1=compileClasspath
org.springframework.boot:spring-boot-starter-data-jpa:3.4.1=compileClasspath
org.springframework.boot:spring-boot-starter-jdbc:3.4.1=compileClasspath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {"it.gov.pagopa", "it.gov.pagopa.payhub.activities"})
@ComponentScan(basePackages = {"it.gov.pagopa.pu.worker", "it.gov.pagopa.payhub.activities"})
public class WorkerApplication {

public static void main(String[] args) {
Expand Down
15 changes: 15 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,20 @@ spring:
username: "\${PU_DB_USER}"
password: "\${PU_DB_PASSWORD}"
driverClassName: "org.postgresql.Driver"
temporal:
connection:
enable-https: "\${TEMPORAL_SERVER_ENABLE_HTTPS:false}"
target: "\${TEMPORAL_SERVER_HOST:localhost}:\${TEMPORAL_SERVER_PORT:7233}"
target.namespace: "\${TEMPORAL_SERVER_NAMESPACE:default}"

# Listing workers and registered activities
workers:
- task-queue: PaymentsReportingIngestionWF
name: PaymentsReportingIngestionWF
activity-beans:
- paymentsReportingIngestionFlowFileActivityImpl
- sendEmailIngestionFlowActivityImpl
- updateIngestionFlowStatusActivityImpl

management:
endpoint:
Expand All @@ -23,3 +36,5 @@ management:
exposure.include: "*"
web:
exposure.include: info, health


Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package it.gov.pagopa.pu.worker;

import com.uber.m3.tally.NoopScope;
import io.temporal.activity.ActivityOptions;
import io.temporal.api.common.v1.WorkflowExecution;
import io.temporal.api.enums.v1.WorkflowExecutionStatus;
import io.temporal.api.workflow.v1.WorkflowExecutionInfo;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowOptions;
import io.temporal.internal.client.WorkflowClientHelper;
import io.temporal.spring.boot.WorkflowImpl;
import io.temporal.workflow.Workflow;
import io.temporal.workflow.WorkflowInterface;
import io.temporal.workflow.WorkflowMethod;
import it.gov.pagopa.payhub.activities.activity.ingestionflow.UpdateIngestionFlowStatusActivity;
import it.gov.pagopa.payhub.activities.activity.ingestionflow.UpdateIngestionFlowStatusActivityImpl;
import it.gov.pagopa.payhub.activities.activity.ingestionflow.email.SendEmailIngestionFlowActivity;
import it.gov.pagopa.payhub.activities.activity.ingestionflow.email.SendEmailIngestionFlowActivityImpl;
import it.gov.pagopa.payhub.activities.activity.paymentsreporting.PaymentsReportingIngestionFlowFileActivity;
import it.gov.pagopa.payhub.activities.activity.paymentsreporting.PaymentsReportingIngestionFlowFileActivityImpl;
import it.gov.pagopa.pu.worker.ingestionflowfile.repository.IngestionFlowFileRepository;
import it.gov.pagopa.pu.worker.paymentsreporting.repository.PaymentsReportingRepository;
import jakarta.persistence.EntityManagerFactory;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.bean.override.mockito.MockitoBean;

import java.time.Duration;
import java.util.function.Consumer;

@SpringBootTest(classes = WorkerApplication.class)
@EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
@TestPropertySource(properties = {
"spring.temporal.test-server.enabled: true",
"spring.temporal.workers-auto-discovery.packages: it.gov.pagopa.pu.worker"
})
class TemporalSpringBootIntegrationTest {

//region base test configuration code
@MockitoBean
private EntityManagerFactory entityManagerFactoryMock;
@MockitoBean
private IngestionFlowFileRepository ingestionFlowFileRepositoryMock;
@MockitoBean
private PaymentsReportingRepository paymentsReportingRepositoryMock;

@Autowired
private WorkflowClient temporalClient;

protected static <T> T buildActivityStub(Class<T> activityClass) {
return Workflow.newActivityStub(activityClass, ActivityOptions.newBuilder().setStartToCloseTimeout(Duration.ofSeconds(1)).build());
}

@SuppressWarnings("SameParameterValue")
protected <T> void execute(Class<T> wfInterface, String taskQueue, Consumer<T> wfStarter){
String workflowId = "wfId";
T wf = buildWorkflowStub(wfInterface, taskQueue, workflowId);
wfStarter.accept(wf);
waitUntilWfCompletion(workflowId);
}

protected <T> T buildWorkflowStub(Class<T> workflowClass, String taskQueue, String workflowId) {
return temporalClient.newWorkflowStub(
workflowClass,
WorkflowOptions.newBuilder()
.setTaskQueue(taskQueue)
.setWorkflowId(workflowId)
.build());
}

protected void waitUntilWfCompletion(String workflowId) {
WorkflowExecutionInfo info;
do {
info = WorkflowClientHelper.describeWorkflowInstance(temporalClient.getWorkflowServiceStubs(), "default", WorkflowExecution.newBuilder().setWorkflowId(workflowId).build(), new NoopScope());
} while (!WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_COMPLETED.equals(info.getStatus()));
}
//endregion

private static final String TASK_QUEUE = "PaymentsReportingIngestionWF";

@MockitoBean(enforceOverride = true)
private PaymentsReportingIngestionFlowFileActivityImpl fileActivityMock;
@MockitoBean(enforceOverride = true)
private SendEmailIngestionFlowActivityImpl emailActivityMock;
@MockitoBean(enforceOverride = true)
private UpdateIngestionFlowStatusActivityImpl statusActivityMock;

@WorkflowInterface
public interface PaymentsReportingIngestionDummyWF {
@WorkflowMethod
void execute(Long ingestionFlowFileId);
}

@WorkflowImpl(taskQueues = TASK_QUEUE)
public static class PaymentsReportingIngestionDummyWFImpl implements PaymentsReportingIngestionDummyWF {

@Override
public void execute(Long ingestionFlowFileId) {
buildActivityStub(PaymentsReportingIngestionFlowFileActivity.class).processFile(ingestionFlowFileId);
buildActivityStub(UpdateIngestionFlowStatusActivity.class).updateStatus(ingestionFlowFileId, "STATUS");
buildActivityStub(SendEmailIngestionFlowActivity.class).sendEmail(ingestionFlowFileId, true);
}
}

@Test
void test() {
// Given
long ingestionFlowFileId = 1L;

// When
execute(PaymentsReportingIngestionDummyWF.class, TASK_QUEUE, wf -> wf.execute(ingestionFlowFileId));

// Then
Mockito.verify(fileActivityMock).processFile(ingestionFlowFileId);
Mockito.verify(statusActivityMock).updateStatus(ingestionFlowFileId, "STATUS");
Mockito.verify(emailActivityMock).sendEmail(ingestionFlowFileId, true);
}
}

0 comments on commit eac4057

Please sign in to comment.