diff --git a/interop-qa-tests/config/application-dev.properties b/interop-qa-tests/config/application-dev.properties index 4ca39ae285..04d0d67754 100644 --- a/interop-qa-tests/config/application-dev.properties +++ b/interop-qa-tests/config/application-dev.properties @@ -6,6 +6,7 @@ tracing.error.csv.filepath=src/main/resources/tracing/dev/tracing-error.csv #INTEROP GLOBAL PROPERTIES bff.base-url=https://selfcare.dev.interop.pagopa.it/0.0/backend-for-frontend m2m.base-url=https://api.dev.interop.pagopa.it/v2 +probing.base-url=https://dev.stato-eservice.interop.pagopa.it session.tokens.duration.seconds=7200 interop-env=dev max-polling-try-ms=50 diff --git a/interop-qa-tests/config/application-qa.properties b/interop-qa-tests/config/application-qa.properties index 9236daedce..db8cfe4aac 100644 --- a/interop-qa-tests/config/application-qa.properties +++ b/interop-qa-tests/config/application-qa.properties @@ -6,6 +6,9 @@ tracing.error.csv.filepath=src/main/resources/tracing/qa/tracing-error.csv authorization.server.token.creation.url=https://auth.qa.interop.pagopa.it/token.oauth2 client.assertion.jwt.audience=auth.qa.interop.pagopa.it/client-assertion bff.base-url=https://selfcare.qa.interop.pagopa.it/1.0/backend-for-frontend +pn.interop.probing.base-url=https://qa.stato-eservice.interop.pagopa.it +pn.interop.probing.bearer-token-kms=eyJhbGciOiAiUlMyNTYiLCAia2lkIjogIjdkMzY4MmJkLWYxNjMtNDRjOS05NTU2LTE1YmJkYmM0ZTYwYyIsICJ0eXAiOiAiSldUIn0.eyJqdGkiOiAiY2M4YzUwMWUtMGMzNC00NzEyLTkxNTUtMjgyM2MyNTU2OTQ5IiwgImlzcyI6ICJxYS5zdGF0by1lc2VydmljZS5pbnRlcm9wLnBhZ29wYS5pdCIsICJhdWQiOiAicWEuc3RhdG8tZXNlcnZpY2UuaW50ZXJvcC5wYWdvcGEuaXQiLCAiaWF0IjogMTc2OTQzMjczMSwgIm5iZiI6IDE3Njk0MzI3MzEsICJleHAiOiAxNzcxMjQ3MTMxfQ.0hpI1bmTJUCAgdOkyUbWDhe-b4qKPsaUIHvul2Nye3G8z9RD-SgvdYgLEFv4-pDJgO-89StsdrC1mc98gfi3X7HY0NRzcJqWW0boMRm0aWJ3eRA9aV8thNJY2wjq-G6fszxZfWXjtHuZVxl5SN1c4qOTsYbpj-ShkSrG5_4Yz9W8UNttOf42xqXa7xtPsboZs_N2dj_f0CXfo70lpay1v_58vvrbb-5U0CXrIIcNnpT9gTwUp7JTwFRYbhdQ2RKMw1EoYLIVPCnp8908p_njF0RxuO4T_7qN-8Yu3DHQ3wO8lSsSzRu3joKMUbjH5rjfu8xlJJpVup3v4NPW9JAKiQ +pn.interop.probing.bearer-token-telemetry=eyJraWQiOiJiNWZFb29tOHYwcmNmZkcxQVdiOUVDR0tEK3RwdkdKNTNtMUtyWGVMUnFJPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJjNmRlYjI1MC02MDkxLTcwZDktYjczOC03YWZhNTIzM2RlNmYiLCJjb2duaXRvOmdyb3VwcyI6WyJ1c2VycyJdLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuZXUtc291dGgtMS5hbWF6b25hd3MuY29tXC9ldS1zb3V0aC0xX1VGQUVBSW5SRiIsImNsaWVudF9pZCI6IjF2MXM3bHB0ZGVodWwxbHJ1MWRkcGoyNGE2Iiwib3JpZ2luX2p0aSI6ImVlYWMyNTI1LWE4MzctNDU1YS04YmQyLWFiYzY1ZWFlZGMwZSIsImV2ZW50X2lkIjoiMWRkNThjNWUtMTdkNy00OWRjLTk2NzMtZjE4ZDllYTBhYjkyIiwidG9rZW5fdXNlIjoiYWNjZXNzIiwic2NvcGUiOiJhd3MuY29nbml0by5zaWduaW4udXNlci5hZG1pbiIsImF1dGhfdGltZSI6MTc2OTQzNzI2NiwiZXhwIjoxNzY5NTIzNjY2LCJpYXQiOjE3Njk0MzcyNjYsImp0aSI6ImZhOWM1YjIwLTRjMDAtNGU0ZS04MzY2LWZlMzJmNzcyOTM3YiIsInVzZXJuYW1lIjoibmljY29sb2NhY2FjZSJ9.PICy_bfY9mM2-KpBFCIVvo4mIKEGv64mP2Bg378_XaJ22aW92px8mPNRlvXE4_2tjin_McHJvSsiB95d_tqvRFrqwt5sBcib0V8fiQlK4wNFlulb1UodH3JpKA1Kj9t6Rct_2kAIkU-6MjeaTnL36ghxbr4I2xlnVmss3OAVjGzzCFTNMICVLn5zvva0H85HEMAxueRPTuw28h5i4PdRtCVZuRpnhdRGwshr9ma-KgtC_TuTe46-mscEfxuXIJ05PfGvaN4awq08P0rX3aKE2lh89I_gyues01KmvRyv_s4nB-3iru2Qi-BDh3pzZqgx1rBspom9xhbyMJ447TI2Ew interop-env=qa #INTEROP GLOBAL PROPERTIES diff --git a/interop-qa-tests/config/application.properties b/interop-qa-tests/config/application.properties index 98700e8902..db436bb5d4 100644 --- a/interop-qa-tests/config/application.properties +++ b/interop-qa-tests/config/application.properties @@ -15,6 +15,9 @@ tracing.error.csv.filepath=src/main/resources/tracing/dev/tracing-error.csv #INTEROP GLOBAL PROPERTIES bff.base-url=https://selfcare.qa.interop.pagopa.it/1.0/backend-for-frontend m2m.base-url=https://api.qa.interop.pagopa.it/v2 +pn.interop.probing.base-url=https://qa.stato-eservice.interop.pagopa.it +pn.interop.probing.bearer-token-kms=eyJhbGciOiAiUlMyNTYiLCAia2lkIjogIjdkMzY4MmJkLWYxNjMtNDRjOS05NTU2LTE1YmJkYmM0ZTYwYyIsICJ0eXAiOiAiSldUIn0.eyJqdGkiOiAiY2M4YzUwMWUtMGMzNC00NzEyLTkxNTUtMjgyM2MyNTU2OTQ5IiwgImlzcyI6ICJxYS5zdGF0by1lc2VydmljZS5pbnRlcm9wLnBhZ29wYS5pdCIsICJhdWQiOiAicWEuc3RhdG8tZXNlcnZpY2UuaW50ZXJvcC5wYWdvcGEuaXQiLCAiaWF0IjogMTc2OTQzMjczMSwgIm5iZiI6IDE3Njk0MzI3MzEsICJleHAiOiAxNzcxMjQ3MTMxfQ.0hpI1bmTJUCAgdOkyUbWDhe-b4qKPsaUIHvul2Nye3G8z9RD-SgvdYgLEFv4-pDJgO-89StsdrC1mc98gfi3X7HY0NRzcJqWW0boMRm0aWJ3eRA9aV8thNJY2wjq-G6fszxZfWXjtHuZVxl5SN1c4qOTsYbpj-ShkSrG5_4Yz9W8UNttOf42xqXa7xtPsboZs_N2dj_f0CXfo70lpay1v_58vvrbb-5U0CXrIIcNnpT9gTwUp7JTwFRYbhdQ2RKMw1EoYLIVPCnp8908p_njF0RxuO4T_7qN-8Yu3DHQ3wO8lSsSzRu3joKMUbjH5rjfu8xlJJpVup3v4NPW9JAKiQ +pn.interop.probing.bearer-token-telemetry=eyJraWQiOiJiNWZFb29tOHYwcmNmZkcxQVdiOUVDR0tEK3RwdkdKNTNtMUtyWGVMUnFJPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJjNmRlYjI1MC02MDkxLTcwZDktYjczOC03YWZhNTIzM2RlNmYiLCJjb2duaXRvOmdyb3VwcyI6WyJ1c2VycyJdLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuZXUtc291dGgtMS5hbWF6b25hd3MuY29tXC9ldS1zb3V0aC0xX1VGQUVBSW5SRiIsImNsaWVudF9pZCI6IjF2MXM3bHB0ZGVodWwxbHJ1MWRkcGoyNGE2Iiwib3JpZ2luX2p0aSI6ImVlYWMyNTI1LWE4MzctNDU1YS04YmQyLWFiYzY1ZWFlZGMwZSIsImV2ZW50X2lkIjoiMWRkNThjNWUtMTdkNy00OWRjLTk2NzMtZjE4ZDllYTBhYjkyIiwidG9rZW5fdXNlIjoiYWNjZXNzIiwic2NvcGUiOiJhd3MuY29nbml0by5zaWduaW4udXNlci5hZG1pbiIsImF1dGhfdGltZSI6MTc2OTQzNzI2NiwiZXhwIjoxNzY5NTIzNjY2LCJpYXQiOjE3Njk0MzcyNjYsImp0aSI6ImZhOWM1YjIwLTRjMDAtNGU0ZS04MzY2LWZlMzJmNzcyOTM3YiIsInVzZXJuYW1lIjoibmljY29sb2NhY2FjZSJ9.PICy_bfY9mM2-KpBFCIVvo4mIKEGv64mP2Bg378_XaJ22aW92px8mPNRlvXE4_2tjin_McHJvSsiB95d_tqvRFrqwt5sBcib0V8fiQlK4wNFlulb1UodH3JpKA1Kj9t6Rct_2kAIkU-6MjeaTnL36ghxbr4I2xlnVmss3OAVjGzzCFTNMICVLn5zvva0H85HEMAxueRPTuw28h5i4PdRtCVZuRpnhdRGwshr9ma-KgtC_TuTe46-mscEfxuXIJ05PfGvaN4awq08P0rX3aKE2lh89I_gyues01KmvRyv_s4nB-3iru2Qi-BDh3pzZqgx1rBspom9xhbyMJ447TI2Ew session.tokens.duration.seconds=7200 interop-env=qa max-polling-try-ms=50 diff --git a/interop-qa-tests/pom.xml b/interop-qa-tests/pom.xml index 222c5d6e42..b1b9165a62 100644 --- a/interop-qa-tests/pom.xml +++ b/interop-qa-tests/pom.xml @@ -16,11 +16,11 @@ 2.20.1 2.11.0 2.5.12 - 1.6.5 + 2.2.42 3.0.2 1.9.1 1.18.30 - 5.7.2 + 5.10.2 @@ -44,6 +44,12 @@ ${aws.sdk.version} + + software.amazon.awssdk + cognitoidentityprovider + ${aws.sdk.version} + + com.google.code.gson @@ -79,7 +85,7 @@ - io.swagger + io.swagger.core.v3 swagger-annotations ${swagger.version} @@ -139,6 +145,16 @@ cucumber-reporting ${cucumber.reporting.version} test + + + + + org.slf4j + slf4j-api + + @@ -208,10 +224,10 @@ - io.github.dvgaba - easy-random-core - 7.1.1 - test + io.github.dvgaba + easy-random-core + 7.1.1 + test @@ -227,39 +243,41 @@ commons-fileupload 1.5 - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.2.5 - - - - cucumber.junit-platform.naming-strategy=long - - - - - - - org.openapitools - openapi-generator-maven-plugin - 5.4.0 - - - generate-bff-client - - generate - - process-resources - + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + + cucumber.junit-platform.naming-strategy=long + + + + + + + org.openapitools + openapi-generator-maven-plugin + 7.19.0 + + + generate-bff-client + + generate + + process-resources + OffsetDateTime=java.lang.String - https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/develop/packages/api-clients/open-api/bffApi.yml + + https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/tags/2.12.0/packages/api-clients/open-api/bffApi.yml + java resttemplate false @@ -317,6 +335,107 @@ + + + generate-probing-external-interop-client + + generate + + process-resources + + + OffsetDateTime=java.lang.String + + + + https://raw.githubusercontent.com/pagopa/interop-probing-core/refs/heads/develop/packages/api-clients/open-api/probingApi.yaml + + + java + resttemplate + + false + false + + + + it.pagopa.interop.generated.openapi.clients.probing.api + + + it.pagopa.interop.generated.openapi.clients.probing.model + + + java8 + none + source + false + true + false + + + @com.fasterxml.jackson.annotation.JsonInclude( + com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL + ) + + + + + false + + + + + + + generate-probing-statistics-interop-client + + generate + + process-resources + + + OffsetDateTime=java.lang.String + + + + https://raw.githubusercontent.com/pagopa/interop-probing-core/refs/heads/develop/packages/api-clients/open-api/probingStatisticsApi.yaml + + + java + resttemplate + + false + false + + + + it.pagopa.interop.generated.openapi.clients.probingStatistics.api + + + it.pagopa.interop.generated.openapi.clients.probingStatistics.model + + + java8 + none + source + false + true + false + + + @com.fasterxml.jackson.annotation.JsonInclude( + com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL + ) + + + + + false + + + + + generate-m2mGateway-client @@ -328,7 +447,9 @@ OffsetDateTime=java.lang.String - https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/develop/packages/api-clients/open-api/m2mGatewayApi.yml + + https://raw.githubusercontent.com/pagopa/interop-be-monorepo/refs/heads/develop/packages/api-clients/open-api/m2mGatewayApi.yml + java resttemplate false @@ -355,33 +476,33 @@ - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 17 - 17 - - - org.mapstruct - mapstruct-processor - ${org.mapstruct.version} - - - org.projectlombok - lombok - ${lombok.version} - - - org.projectlombok - lombok-mapstruct-binding - 0.2.0 - - - - + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 17 + 17 + + + org.mapstruct + mapstruct-processor + ${org.mapstruct.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + + diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/IEServiceClient.java b/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/IEServiceClient.java index f1ca985508..9e1a92f566 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/IEServiceClient.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/IEServiceClient.java @@ -1,39 +1,12 @@ package it.pagopa.interop.agreement.service; import it.pagopa.interop.authorization.service.utils.SettableBearerToken; -import it.pagopa.interop.generated.openapi.clients.bff.model.AgreementApprovalPolicy; -import it.pagopa.interop.generated.openapi.clients.bff.model.AgreementState; -import it.pagopa.interop.generated.openapi.clients.bff.model.CatalogEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.CatalogEServices; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDescriptionUpdateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDescriptorState; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDoc; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceMode; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServicePersonalDataFlagUpdateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceRiskAnalysis; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceRiskAnalysisSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateInstances; -import it.pagopa.interop.generated.openapi.clients.bff.model.FileResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.InstanceEServiceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.PresignedUrl; -import it.pagopa.interop.generated.openapi.clients.bff.model.ProducerEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.ProducerEServiceDetails; -import it.pagopa.interop.generated.openapi.clients.bff.model.ProducerEServices; -import it.pagopa.interop.generated.openapi.clients.bff.model.TemplateInstanceInterfaceRESTSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorDocumentSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorQuotas; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorTemplateInstanceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceTemplateInstanceDescriptorQuotas; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceTemplateInstanceSeed; +import it.pagopa.interop.generated.openapi.clients.bff.model.*; +import org.springframework.http.ResponseEntity; + import java.io.File; import java.util.List; import java.util.UUID; -import org.springframework.http.ResponseEntity; public interface IEServiceClient extends SettableBearerToken { CreatedEServiceDescriptor createEService(EServiceSeed eserviceSeed); diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/EServiceApiClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/EServiceApiClientImpl.java index f7e6a521af..a4fcea3f62 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/EServiceApiClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/EServiceApiClientImpl.java @@ -1,44 +1,10 @@ package it.pagopa.interop.agreement.service.impl; -import static java.util.Objects.isNull; - import it.pagopa.interop.agreement.service.IEServiceClient; import it.pagopa.interop.conf.InteropClientConfigs; import it.pagopa.interop.generated.openapi.clients.bff.ApiClient; import it.pagopa.interop.generated.openapi.clients.bff.api.EservicesApi; -import it.pagopa.interop.generated.openapi.clients.bff.model.AgreementApprovalPolicy; -import it.pagopa.interop.generated.openapi.clients.bff.model.AgreementState; -import it.pagopa.interop.generated.openapi.clients.bff.model.CatalogEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.CatalogEServices; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDescriptionUpdateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDescriptorState; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDoc; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceMode; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServicePersonalDataFlagUpdateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceRiskAnalysis; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceRiskAnalysisSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateInstances; -import it.pagopa.interop.generated.openapi.clients.bff.model.FileResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.InstanceEServiceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.PresignedUrl; -import it.pagopa.interop.generated.openapi.clients.bff.model.ProducerEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.ProducerEServiceDetails; -import it.pagopa.interop.generated.openapi.clients.bff.model.ProducerEServices; -import it.pagopa.interop.generated.openapi.clients.bff.model.TemplateInstanceInterfaceRESTSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorDocumentSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorQuotas; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorTemplateInstanceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceTemplateInstanceDescriptorQuotas; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceTemplateInstanceSeed; -import java.io.File; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; +import it.pagopa.interop.generated.openapi.clients.bff.model.*; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.http.ResponseEntity; @@ -48,21 +14,18 @@ import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.ProducerEServiceDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorAgreementApprovalPolicySeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceDescriptorSeed; - import java.io.File; +import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.UUID; +import static java.util.Objects.isNull; + @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Retryable( - retryFor = { HttpServerErrorException.class }, + retryFor = {HttpServerErrorException.class}, backoff = @Backoff(delay = 2000) ) public class EServiceApiClientImpl implements IEServiceClient { @@ -166,7 +129,11 @@ public CatalogEServiceDescriptor getCatalogEServiceDescriptor(UUID eserviceId, U } public File getEServiceDocumentById(UUID eServiceId, UUID descriptorId, UUID documentId) { - return eservicesApi.getEServiceDocumentById(eServiceId, descriptorId, documentId); + try { + return eservicesApi.getEServiceDocumentById(eServiceId, descriptorId, documentId).getFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } } public EServiceDoc updateEServiceDocumentById(UUID eServiceId, UUID descriptorId, UUID documentId, UpdateEServiceDescriptorDocumentSeed updateEServiceDescriptorDocumentSeed) { @@ -186,7 +153,11 @@ public CreatedEServiceDescriptor cloneEServiceByDescriptor(UUID eServiceId, UUID } public File getEServiceConsumers(UUID eServiceId) { - return eservicesApi.getEServiceConsumers(eServiceId); + try { + return eservicesApi.getEServiceConsumers(eServiceId).getFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } } public EServiceRiskAnalysis getEServiceRiskAnalysis(UUID eServiceId, UUID riskAnalysisId) { @@ -215,18 +186,18 @@ public void updateEServicePersonalDataFlagAfterPublication(UUID eServiceId, ESer @Override public ResponseEntity createEServiceInstanceFromTemplateWithHttpInfo( - UUID templateId, InstanceEServiceSeed instanceEServiceSeed) { + UUID templateId, InstanceEServiceSeed instanceEServiceSeed) { /* DEV. NOTE 10/03/2025: al momento InstanceEServiceSeed è required dalla API, tuttavia - * nessuno dei suoi campi lo è; per comodità si permette a questo metodo di passare NULL - * mappandolo con un'istanza vuota. */ + * nessuno dei suoi campi lo è; per comodità si permette a questo metodo di passare NULL + * mappandolo con un'istanza vuota. */ return this.eservicesApi.createEServiceInstanceFromTemplateWithHttpInfo( - templateId, - isNull(instanceEServiceSeed) ? new InstanceEServiceSeed() : instanceEServiceSeed); + templateId, + isNull(instanceEServiceSeed) ? new InstanceEServiceSeed() : instanceEServiceSeed); } @Override public ResponseEntity getEServiceTemplateInstancesWithHttpInfo( - UUID templateId) { + UUID templateId) { /* Di default l'api NON restituisce le istanze in stato DRAFT, invece si chiedono in * questo modo tutte quante */ List states = Arrays.stream(EServiceDescriptorState.values()).toList(); @@ -235,8 +206,8 @@ public ResponseEntity getEServiceTemplateInstancesWit @Override public ResponseEntity getEServiceTemplateInstancesWithHttpInfo( - UUID templateId, Integer offset, Integer limit, String producerName, - List states) { + UUID templateId, Integer offset, Integer limit, String producerName, + List states) { return this.eservicesApi.getEServiceTemplateInstancesWithHttpInfo(templateId, offset, limit, producerName, states); } @@ -247,7 +218,7 @@ public ResponseEntity upgradeEServiceInstanceWithHttpInfo(UUID @Override public ResponseEntity getProducerEServiceDescriptorWithHttpInfo( - UUID eserviceId, UUID descriptorId) { + UUID eserviceId, UUID descriptorId) { return this.eservicesApi.getProducerEServiceDescriptorWithHttpInfo(eserviceId, descriptorId); } @@ -261,17 +232,17 @@ public ResponseEntity getProducerEServicesWithHttpInfo( @Override public ResponseEntity updateEServiceTemplateInstanceByIdWithHttpInfo( - UUID eServiceId, - UpdateEServiceTemplateInstanceSeed updateEServiceTemplateInstanceSeed + UUID eServiceId, + UpdateEServiceTemplateInstanceSeed updateEServiceTemplateInstanceSeed ) { return this.eservicesApi.updateEServiceTemplateInstanceByIdWithHttpInfo(eServiceId, updateEServiceTemplateInstanceSeed); } @Override public ResponseEntity updateDraftDescriptorTemplateInstanceWithHttpInfo( - UUID eServiceId, - UUID descriptorId, - UpdateEServiceDescriptorTemplateInstanceSeed updateEServiceDescriptorTemplateInstanceSeed + UUID eServiceId, + UUID descriptorId, + UpdateEServiceDescriptorTemplateInstanceSeed updateEServiceDescriptorTemplateInstanceSeed ) { return this.eservicesApi.updateDraftDescriptorTemplateInstanceWithHttpInfo(eServiceId, descriptorId, updateEServiceDescriptorTemplateInstanceSeed); } @@ -279,34 +250,34 @@ public ResponseEntity updateDraftDescriptorTemplateInstanceWith @Override public ResponseEntity updateTemplateInstanceDescriptorWithHttpInfo( - UUID eServiceId, - UUID descriptorId, - UpdateEServiceTemplateInstanceDescriptorQuotas descriptorQuotas + UUID eServiceId, + UUID descriptorId, + UpdateEServiceTemplateInstanceDescriptorQuotas descriptorQuotas ) { return this.eservicesApi.updateTemplateInstanceDescriptorWithHttpInfo(eServiceId, descriptorId, descriptorQuotas); } @Override public ResponseEntity getProducerEServiceDetailsWithHttpInfo( - UUID eserviceId) { + UUID eserviceId) { return this.eservicesApi.getProducerEServiceDetailsWithHttpInfo(eserviceId); } @Override public ResponseEntity addEServiceTemplateInstanceInterfaceRestWithHttpInfo( - UUID eServiceId, UUID descriptorId, - TemplateInstanceInterfaceRESTSeed templateInstanceInterfaceRESTSeed) { + UUID eServiceId, UUID descriptorId, + TemplateInstanceInterfaceRESTSeed templateInstanceInterfaceRESTSeed) { return this.eservicesApi.addEServiceTemplateInstanceInterfaceRestWithHttpInfo(eServiceId, descriptorId, templateInstanceInterfaceRESTSeed); } @Override public void editAgreementApprovalPolicy(UUID eServiceId, UUID descriptorId, - AgreementApprovalPolicy policy) { + AgreementApprovalPolicy policy) { eservicesApi.updateAgreementApprovalPolicy( - eServiceId, - descriptorId, - new UpdateEServiceDescriptorAgreementApprovalPolicySeed() - .agreementApprovalPolicy(policy) + eServiceId, + descriptorId, + new UpdateEServiceDescriptorAgreementApprovalPolicySeed() + .agreementApprovalPolicy(policy) ); } diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/M2MClientsClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/M2MClientsClientImpl.java index ca5238c0fb..3feb030b99 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/M2MClientsClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/agreement/service/impl/M2MClientsClientImpl.java @@ -5,7 +5,6 @@ import it.pagopa.interop.generated.openapi.clients.m2mGateway.ApiClient; import it.pagopa.interop.generated.openapi.clients.m2mGateway.api.ClientsApi; import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.Purposes; -import java.util.UUID; import lombok.EqualsAndHashCode; import lombok.ToString; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -13,6 +12,8 @@ import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; +import java.util.UUID; + @ToString @EqualsAndHashCode @Component @@ -44,7 +45,7 @@ public Purposes getClientPurposes(UUID clientId) { @Override public Purposes getClientPurposes(UUID clientId, int offset, int limit) { - return clientsApi.getClientPurposes(clientId, offset, limit); + return clientsApi.getClientPurposes(clientId, offset, limit, null, null); } @Override diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/impl/AuthorizationClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/impl/AuthorizationClientImpl.java index 884916a247..3b15ab8911 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/impl/AuthorizationClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/impl/AuthorizationClientImpl.java @@ -5,20 +5,7 @@ import it.pagopa.interop.conf.InteropClientConfigs; import it.pagopa.interop.generated.openapi.clients.bff.ApiClient; import it.pagopa.interop.generated.openapi.clients.bff.api.ClientsApi; -import it.pagopa.interop.generated.openapi.clients.bff.model.Client; -import it.pagopa.interop.generated.openapi.clients.bff.model.ClientKind; -import it.pagopa.interop.generated.openapi.clients.bff.model.ClientSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.CompactClients; -import it.pagopa.interop.generated.openapi.clients.bff.model.CompactUser; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.InlineObject6; -import it.pagopa.interop.generated.openapi.clients.bff.model.InlineObject7; -import it.pagopa.interop.generated.openapi.clients.bff.model.KeySeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.PublicKey; -import it.pagopa.interop.generated.openapi.clients.bff.model.PublicKeys; -import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeAdditionDetailsSeed; -import java.util.List; -import java.util.UUID; +import it.pagopa.interop.generated.openapi.clients.bff.model.*; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.retry.annotation.Backoff; @@ -27,6 +14,9 @@ import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; +import java.util.List; +import java.util.UUID; + @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Retryable( @@ -125,12 +115,12 @@ public void removeClientPurpose(UUID clientId, UUID purposeId) { @Override public CreatedResource addUsersToClient(UUID clientId, Users users) { - return clientsApi.addUsersToClient(clientId, new InlineObject7().userIds(users.getUserIds())); + return clientsApi.addUsersToClient(clientId, new AddUsersToClientRequest().userIds(users.getUserIds())); } @Override public Client editClientAdmin(UUID clientId, ClientAdminConfig adminConfig) { - InlineObject6 inlineObject3 = new InlineObject6() + SetAdminToClientRequest inlineObject3 = new SetAdminToClientRequest() .adminId(adminConfig.getAdminId()); return clientsApi.setAdminToClient(clientId, inlineObject3); } diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/utils/PollingService.java b/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/utils/PollingService.java index e01f9952ac..0ccf35ffc4 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/utils/PollingService.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/authorization/service/utils/PollingService.java @@ -33,4 +33,31 @@ public T makePolling(Supplier promise, Predicate shouldStop, String er throw new PollingPredicateException("Eventual consistency error: " + errorMessage); } + + public static T makePolling( + Supplier promise, + Predicate shouldStop, + String errorMessage, + int maxPollingTry, + long pollingSleepMillis + ) { + try { + for (int i = 0; i < maxPollingTry; i++) { + Thread.sleep(pollingSleepMillis); + + T response = promise.get(); + + if (shouldStop.test(response)) { + return response; + } + } + } catch (InterruptedException e) { + log.error("Unexpected thread interruption during polling: {}", e.getMessage()); + Thread.currentThread().interrupt(); + } catch (Exception e) { + throw new IllegalArgumentException("Error during polling: " + e.getMessage()); + } + + throw new PollingPredicateException("Eventual consistency error: " + errorMessage); + } } diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/common/IHttpExecutor.java b/interop-qa-tests/src/main/java/it/pagopa/interop/common/IHttpExecutor.java index 7d38843d36..9fda277df1 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/common/IHttpExecutor.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/common/IHttpExecutor.java @@ -1,10 +1,10 @@ package it.pagopa.interop.common; -import java.util.function.Function; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import java.util.function.Function; import java.util.function.Supplier; -import org.springframework.http.ResponseEntity; public interface IHttpExecutor { HttpStatus performCall(Supplier promise); @@ -23,4 +23,8 @@ public interface IHttpExecutor { Object getResponse(); String getErrorMessage(); void setRawResponse(int statusCode, Object rawBody); + + void snapshot(); + + void resetFormSnapshot(); } diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/common/client/AbstractClient.java b/interop-qa-tests/src/main/java/it/pagopa/interop/common/client/AbstractClient.java index 394ddc6dcd..3da62e6c5c 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/common/client/AbstractClient.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/common/client/AbstractClient.java @@ -5,33 +5,40 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; - +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; @Getter @Slf4j -public abstract class AbstractClient { +public abstract class AbstractClient { @Setter protected IHttpExecutor httpCallExecutor; public Optional performOperation(IOperation operation) { - // Esegue la chiamata HTTP httpCallExecutor.performCall(operation.getApiCaller()); + return mapIf2xx(operation.getResultExtractor()); + } - // Recupera la risposta e l'esito della chiamata (cast se necessario) - @SuppressWarnings("unchecked") - E rawResponse = (E) httpCallExecutor.getResponse(); - var response = httpCallExecutor.getResponseStatus(); + public Optional performOperation(Supplier> promise) { + httpCallExecutor.performCall(promise, ResponseEntity::getStatusCode); + return mapIf2xx((ResponseEntity re) -> re != null ? re.getBody() : null); + } - // Se la risposta è positiva, estrae e restituisce il risultato - if (response.is2xxSuccessful()) { - return Optional.ofNullable(operation.getResultExtractor().apply(rawResponse)); + private Optional mapIf2xx(Function extractor) { + HttpStatus status = httpCallExecutor.getResponseStatus(); + if (status == null || !status.is2xxSuccessful()) { + log.warn("HTTP call failed with status: {}", status != null ? status.value() : "null"); + return Optional.empty(); } - // In caso di errore, loggare o gestire in altro modo se necessario - log.warn("HTTP call failed with status: {}", response.value()); - return Optional.empty(); + @SuppressWarnings("unchecked") + E rawResponse = (E) httpCallExecutor.getResponse(); + + return Optional.ofNullable(extractor.apply(rawResponse)); } } diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/common/client/AuthenticatorCognito.java b/interop-qa-tests/src/main/java/it/pagopa/interop/common/client/AuthenticatorCognito.java new file mode 100644 index 0000000000..92a2f6a55f --- /dev/null +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/common/client/AuthenticatorCognito.java @@ -0,0 +1,60 @@ +package it.pagopa.interop.common.client; + +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient; +import software.amazon.awssdk.services.cognitoidentityprovider.model.AuthFlowType; +import software.amazon.awssdk.services.cognitoidentityprovider.model.CognitoIdentityProviderException; +import software.amazon.awssdk.services.cognitoidentityprovider.model.InitiateAuthRequest; +import software.amazon.awssdk.services.cognitoidentityprovider.model.InitiateAuthResponse; + +import java.util.Map; + +public class AuthenticatorCognito { + + private final String username; + private final String password; + private final String clientId; + private final CognitoIdentityProviderClient client; + + public AuthenticatorCognito(String username, String password, String clientId, Region region) { + if (username == null || password == null || clientId == null) { + throw new IllegalArgumentException("Username, password e clientId sono obbligatori"); + } + this.username = username; + this.password = password; + this.clientId = clientId; + + this.client = CognitoIdentityProviderClient.builder() + .region(region) // es: Region.EU_CENTRAL_1 + .build(); + } + + /** + * Esegue login con USER_PASSWORD_AUTH e restituisce un JWT + */ + public String generateJwtToken() { + try { + InitiateAuthRequest authRequest = InitiateAuthRequest.builder() + .authFlow(AuthFlowType.USER_PASSWORD_AUTH) + .clientId(clientId) + .authParameters(Map.of( + "USERNAME", username, + "PASSWORD", password + )) + .build(); + + InitiateAuthResponse response = client.initiateAuth(authRequest); + + if (response.authenticationResult() == null || + response.authenticationResult().idToken() == null) { + throw new RuntimeException("Token JWT non restituito da Cognito"); + } + + return response.authenticationResult().idToken(); + + } catch (CognitoIdentityProviderException e) { + throw new RuntimeException("Errore durante l'autenticazione Cognito: " + e.awsErrorDetails().errorMessage(), e); + } + } +} + diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/conf/InteropClientConfigs.java b/interop-qa-tests/src/main/java/it/pagopa/interop/conf/InteropClientConfigs.java index 17c4eb0ad7..c4fe8d0840 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/conf/InteropClientConfigs.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/conf/InteropClientConfigs.java @@ -15,6 +15,7 @@ public class InteropClientConfigs { @Value("${m2m.base-url}") private String m2mBaseUrl; + @Value("${remote-wellknown-url}") private String remoteWellknownUrl; diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/delegate/service/impl/DelegationApiClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/delegate/service/impl/DelegationApiClientImpl.java index d35c8ba64b..cb1625cb63 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/delegate/service/impl/DelegationApiClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/delegate/service/impl/DelegationApiClientImpl.java @@ -5,7 +5,10 @@ import it.pagopa.interop.delegate.service.IDelegationApiClient; import it.pagopa.interop.generated.openapi.clients.bff.ApiClient; import it.pagopa.interop.generated.openapi.clients.bff.api.DelegationsApi; -import it.pagopa.interop.generated.openapi.clients.bff.model.*; +import it.pagopa.interop.generated.openapi.clients.bff.model.CompactDelegations; +import it.pagopa.interop.generated.openapi.clients.bff.model.Delegation; +import it.pagopa.interop.generated.openapi.clients.bff.model.DelegationKind; +import it.pagopa.interop.generated.openapi.clients.bff.model.DelegationState; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.retry.annotation.Backoff; @@ -15,6 +18,7 @@ import org.springframework.web.client.RestTemplate; import java.io.File; +import java.io.IOException; import java.util.List; import java.util.UUID; @@ -56,7 +60,11 @@ public Delegation getDelegation(UUID delegationId) { @Override public File getDelegationContract(UUID delegationId, UUID contractId) { - return delegationsApi.getDelegationContract(delegationId, contractId); + try { + return delegationsApi.getDelegationContract(delegationId, contractId).getFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/IEServiceTemplateClient.java b/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/IEServiceTemplateClient.java index 7b09b2a0ec..747e05bb55 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/IEServiceTemplateClient.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/IEServiceTemplateClient.java @@ -2,12 +2,12 @@ import it.pagopa.interop.authorization.service.utils.SettableBearerToken; import it.pagopa.interop.generated.openapi.clients.bff.model.*; +import org.springframework.core.io.Resource; +import org.springframework.http.ResponseEntity; import java.io.File; import java.util.List; import java.util.UUID; -import org.springframework.core.io.Resource; -import org.springframework.http.ResponseEntity; public interface IEServiceTemplateClient extends SettableBearerToken { enum EServiceTemplateDocumentKind { @@ -98,7 +98,7 @@ File getDocument( UUID documentId ); - ResponseEntity getDocumentWithHttpInfo( + ResponseEntity getDocumentWithHttpInfo( UUID eServiceTemplateId, UUID eServiceTemplateVersionId, UUID documentId diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/impl/EServiceTemplateApiClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/impl/EServiceTemplateApiClientImpl.java index 2af77684fd..c6f64e7297 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/impl/EServiceTemplateApiClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/e_service_template/impl/EServiceTemplateApiClientImpl.java @@ -5,10 +5,6 @@ import it.pagopa.interop.generated.openapi.clients.bff.ApiClient; import it.pagopa.interop.generated.openapi.clients.bff.api.EserviceTemplatesApi; import it.pagopa.interop.generated.openapi.clients.bff.model.*; - -import java.io.File; -import java.util.List; -import java.util.UUID; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.core.io.Resource; @@ -19,6 +15,11 @@ import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.UUID; + /* TODO considerato che le varianti con HTTP info conservano lo stato di errore potrebbe essere preferibile utilizzare solo quelle, rimuovere le altre e adattare gli utilizzi di conseguenza */ @Component @@ -260,11 +261,15 @@ public File getDocument( UUID eServiceTemplateVersionId, UUID documentId ) { - return this.eserviceTemplatesApi.getEServiceTemplateDocumentById(eServiceTemplateId, eServiceTemplateVersionId, documentId); + try { + return this.eserviceTemplatesApi.getEServiceTemplateDocumentById(eServiceTemplateId, eServiceTemplateVersionId, documentId).getFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override - public ResponseEntity getDocumentWithHttpInfo( + public ResponseEntity getDocumentWithHttpInfo( UUID eServiceTemplateId, UUID eServiceTemplateVersionId, UUID documentId diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/probing/config/ProbingClientConfigs.java b/interop-qa-tests/src/main/java/it/pagopa/interop/probing/config/ProbingClientConfigs.java new file mode 100644 index 0000000000..535b33b894 --- /dev/null +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/probing/config/ProbingClientConfigs.java @@ -0,0 +1,40 @@ +package it.pagopa.interop.probing.config; + + +import lombok.Getter; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@Component +public class ProbingClientConfigs { + + /** + * Token da usare per le probing-api, non possiamo staccarlo in autonomia, + * bisogna fornire una client_assertion al team dev il quale ci fornirà un token a lunga scadenza (3 settimane) + */ + private String bearerTokenKms; + + private String baseUrl; + + /** + * Token da usare per le probing-statistics-api, non possiamo staccarlo in autonomia, + * il flow cognito è SRP(Secure Remote Password) e non abbiamo tutte le info, AWS QA non ha nessun sistema cognito dichiarato + * ed evidentemente punta altrove. + *

+ * Il token lo si prende da FE facendo accesso con le opportune credenziali, dura 1 giorno. + */ + private String bearerTokenTelemetry; + + public ProbingClientConfigs( + @Value("${pn.interop.probing.base-url}") String baseUrl, + @Value("${pn.interop.probing.bearer-token-kms}") String bearerTokenKms, + @Value("${pn.interop.probing.bearer-token-telemetry}") String bearerTokenTelemetry + ) { + this.baseUrl = baseUrl; + this.bearerTokenKms = bearerTokenKms; + this.bearerTokenTelemetry = bearerTokenTelemetry; + } +} \ No newline at end of file diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/probing/service/IProbingClient.java b/interop-qa-tests/src/main/java/it/pagopa/interop/probing/service/IProbingClient.java new file mode 100644 index 0000000000..95914f052b --- /dev/null +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/probing/service/IProbingClient.java @@ -0,0 +1,74 @@ +package it.pagopa.interop.probing.service; + +import it.pagopa.interop.authorization.service.utils.SettableBearerToken; +import it.pagopa.interop.generated.openapi.clients.probing.model.*; +import it.pagopa.interop.generated.openapi.clients.probingStatistics.model.TelemetryDataEserviceResponse; + +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.util.List; +import java.util.UUID; + +public interface IProbingClient extends SettableBearerToken { + + void getProbingApiHealthStatus(); + + MainDataEserviceResponse getEserviceMainData(Long eserviceRecordId); + + ProbingDataEserviceResponse getEserviceProbingData(Long eserviceRecordId); + + List getAllEservice(); + + List findEserviceByName(String name); + + List findEserviceByProducer(String producer); + + SearchEserviceResponse searchEservices( + Integer limit, + Integer offset, + String eserviceName, + String producerName, + Integer versionNumber, + List state + ); + + void updateEserviceFrequency( + UUID eserviceId, + UUID versionId, + Integer frequency, + OffsetTime startTime, + OffsetTime endTime + ); + + void updateEserviceProbingState( + UUID eserviceId, + UUID versionId, + ChangeProbingStateRequest request + ); + + void updateEserviceState( + UUID eserviceId, + UUID versionId, + ChangeEserviceStateRequest request + ); + + List getEservicesProducers( + Integer limit, + Integer offset, + String producerName + ); + + void getStatisticsHealthStatus(); + + TelemetryDataEserviceResponse statisticsEservices( + Long eserviceRecordId, + Integer pollingFrequency + ); + + TelemetryDataEserviceResponse filteredStatisticsEservices( + Long eserviceRecordId, + Integer pollingFrequency, + OffsetDateTime startDate, + OffsetDateTime endDate + ); +} diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/probing/service/impl/ProbingClient.java b/interop-qa-tests/src/main/java/it/pagopa/interop/probing/service/impl/ProbingClient.java new file mode 100644 index 0000000000..91205ee448 --- /dev/null +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/probing/service/impl/ProbingClient.java @@ -0,0 +1,284 @@ +package it.pagopa.interop.probing.service.impl; + +import it.pagopa.interop.common.client.AbstractClient; +import it.pagopa.interop.generated.openapi.clients.probing.ApiClient; +import it.pagopa.interop.generated.openapi.clients.probing.api.EServicesApi; +import it.pagopa.interop.generated.openapi.clients.probing.api.HealthApi; +import it.pagopa.interop.generated.openapi.clients.probing.model.*; +import it.pagopa.interop.probing.config.ProbingClientConfigs; +import it.pagopa.interop.probing.service.IProbingClient; +import it.pagopa.interop.utils.HttpCallExecutor; +import lombok.ToString; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; + +@ToString +@Component +@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) +public class ProbingClient extends AbstractClient implements IProbingClient { + + private static final DateTimeFormatter UTC_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(java.time.ZoneOffset.UTC); + + + // --- probing (core) --- + private final HealthApi statusApi; + private final EServicesApi eServicesApi; + + // --- probingStatistics --- + private final it.pagopa.interop.generated.openapi.clients.probingStatistics.api.HealthApi statisticsStatusApi; + private final it.pagopa.interop.generated.openapi.clients.probingStatistics.api.TelemetryApi telemetryApi; + + private final RestTemplate restTemplate; + private final String basePath; + + private final String probingBearerTokenKms; + private final String probingBearerTokenTelemetry; + + public ProbingClient(RestTemplate restTemplate, + ProbingClientConfigs probingClientConfigs, + HttpCallExecutor httpCallExecutor) { + this.restTemplate = restTemplate; + this.basePath = probingClientConfigs.getBaseUrl(); + + this.probingBearerTokenKms = probingClientConfigs.getBearerTokenKms(); + this.probingBearerTokenTelemetry = probingClientConfigs.getBearerTokenTelemetry(); + + super.httpCallExecutor = httpCallExecutor; + + // --- probing core --- + ApiClient probingApiClient = createProbingApiClient(probingBearerTokenKms); + this.statusApi = new HealthApi(probingApiClient); + this.eServicesApi = new EServicesApi(probingApiClient); + + // --- probingStatistics --- + it.pagopa.interop.generated.openapi.clients.probingStatistics.ApiClient statsApiClient = + createStatisticsApiClient(probingBearerTokenTelemetry); + this.statisticsStatusApi = new it.pagopa.interop.generated.openapi.clients.probingStatistics.api.HealthApi(statsApiClient); + this.telemetryApi = new it.pagopa.interop.generated.openapi.clients.probingStatistics.api.TelemetryApi(statsApiClient); + } + + @Override + public void setBearerToken(String bearerToken) { + // --- probing core --- + ApiClient probingApiClient = createProbingApiClient(bearerToken); + this.statusApi.setApiClient(probingApiClient); + this.eServicesApi.setApiClient(probingApiClient); + + // --- probingStatistics --- + it.pagopa.interop.generated.openapi.clients.probingStatistics.ApiClient statsApiClient = + createStatisticsApiClient(bearerToken); + this.statisticsStatusApi.setApiClient(statsApiClient); + this.telemetryApi.setApiClient(statsApiClient); + } + + private ApiClient createProbingApiClient(String bearerToken) { + ApiClient apiClient = new ApiClient(restTemplate); + apiClient.setBasePath(basePath); + apiClient.setBearerToken(bearerToken); + return apiClient; + } + + private it.pagopa.interop.generated.openapi.clients.probingStatistics.ApiClient createStatisticsApiClient(String bearerToken) { + it.pagopa.interop.generated.openapi.clients.probingStatistics.ApiClient apiClient = + new it.pagopa.interop.generated.openapi.clients.probingStatistics.ApiClient(restTemplate); + apiClient.setBasePath(basePath); + apiClient.setBearerToken(bearerToken); + return apiClient; + } + + @Override + public void getProbingApiHealthStatus() { + performOperation(statusApi::getStatusWithHttpInfo); + } + + @Override + public MainDataEserviceResponse getEserviceMainData(Long eserviceRecordId) { + return performOperation(() -> eServicesApi.getEserviceMainDataWithHttpInfo(eserviceRecordId)) + .orElseThrow(() -> new IllegalStateException( + "Errore nel recupero main data e-service (response non 2xx o body nullo)" + )); + } + + @Override + public ProbingDataEserviceResponse getEserviceProbingData(Long eserviceRecordId) { + return performOperation(() -> eServicesApi.getEserviceProbingDataWithHttpInfo(eserviceRecordId)) + .orElseThrow(() -> new IllegalStateException( + "Errore nel recupero probing data e-service (response non 2xx o body nullo)" + )); + } + + @Override + public SearchEserviceResponse searchEservices( + Integer limit, + Integer offset, + String eserviceName, + String producerName, + Integer versionNumber, + List state + ) { + return performOperation(() -> eServicesApi.searchEservicesWithHttpInfo( + limit, offset, eserviceName, producerName, versionNumber, state + )) + .orElseThrow(() -> new IllegalStateException( + "Errore nella ricerca e-services (response non 2xx o body nullo)" + )); + } + + @Override + public List getAllEservice() { + return searchAll(null, null, null, null); + } + + @Override + public List findEserviceByName(String name) { + return searchAll(name, null, null, null); + } + + @Override + public List findEserviceByProducer(String producer) { + return searchAll(null, producer, null, null); + } + + private List searchAll( + String eserviceName, + String producerName, + Integer versionNumber, + List state + ) { + final int limit = 30; + int offset = 0; + + List all = new java.util.ArrayList<>(); + Long totalElements = null; + + while (true) { + SearchEserviceResponse page = searchEservices( + limit, + offset, + eserviceName, + producerName, + versionNumber, + state + ); + + if (page == null) { + break; + } + + if (totalElements == null) { + totalElements = page.getTotalElements(); + } + + List content = page.getContent(); + if (content == null || content.isEmpty()) { + break; + } + + all.addAll(content); + + int previousOffset = offset; + offset += content.size(); + + // Protezione anti-loop: se non avanza interrompi + if (offset == previousOffset) { + break; + } + + // Stop “preciso” se totalElements è presente + if (totalElements != null && offset >= totalElements) { + break; + } + + // Fallback: se pagina più corta del limit, siamo all'ultima + if (content.size() < limit) { + break; + } + } + + return all; + } + + + @Override + public void updateEserviceFrequency(UUID eserviceId, UUID versionId, Integer frequency, OffsetTime startTime, OffsetTime endTime) { + ChangeProbingFrequencyRequest req = new ChangeProbingFrequencyRequest(); + req.setFrequency(frequency); + req.setStartTime(startTime != null + ? startTime.withOffsetSameInstant(ZoneOffset.UTC).toLocalTime().format(DateTimeFormatter.ISO_LOCAL_TIME) + : null + ); + req.setEndTime(endTime != null + ? endTime.withOffsetSameInstant(ZoneOffset.UTC).toLocalTime().format(DateTimeFormatter.ISO_LOCAL_TIME) + : null + ); + + performOperation(() -> eServicesApi.updateEserviceFrequencyWithHttpInfo(eserviceId, versionId, req)); + + if (!super.httpCallExecutor.getResponseStatus().is2xxSuccessful()) { + throw new IllegalStateException("Errore durante l'update della frequency dell'e-ervice con id: " + eserviceId); + } + } + + @Override + public void updateEserviceProbingState(UUID eserviceId, UUID versionId, ChangeProbingStateRequest request) { + performOperation(() -> eServicesApi.updateEserviceProbingStateWithHttpInfo(eserviceId, versionId, request)); + + if (!super.httpCallExecutor.getResponseStatus().is2xxSuccessful()) { + throw new IllegalStateException("Errore durante l'update del probing state dell'e-ervice con id: " + eserviceId); + } + } + + @Override + public void updateEserviceState(UUID eserviceId, UUID versionId, ChangeEserviceStateRequest request) { + performOperation(() -> eServicesApi.updateEserviceStateWithHttpInfo(eserviceId, versionId, request)); + + if (!super.httpCallExecutor.getResponseStatus().is2xxSuccessful()) { + throw new IllegalStateException("Errore durante l'update dell'eservice state con e-service id: " + eserviceId); + } + } + + @Override + public List getEservicesProducers(Integer limit, Integer offset, String producerName) { + return performOperation(() -> eServicesApi.getEservicesProducersWithHttpInfo(limit, offset, producerName)) + .orElseThrow(() -> new IllegalStateException( + "Errore nel recupero producers (response non 2xx o body nullo)" + )); + } + + @Override + public void getStatisticsHealthStatus() { + performOperation(statisticsStatusApi::getStatusWithHttpInfo); + } + + @Override + public it.pagopa.interop.generated.openapi.clients.probingStatistics.model.TelemetryDataEserviceResponse statisticsEservices(Long eserviceRecordId, Integer pollingFrequency) { + return performOperation(() -> telemetryApi.statisticsEservicesWithHttpInfo(eserviceRecordId, pollingFrequency)) + .orElseThrow(() -> new IllegalStateException( + "Errore nel recupero statistiche e-service (response non 2xx o body nullo)" + )); + } + + @Override + public it.pagopa.interop.generated.openapi.clients.probingStatistics.model.TelemetryDataEserviceResponse filteredStatisticsEservices(Long eserviceRecordId, Integer pollingFrequency, OffsetDateTime startDate, OffsetDateTime endDate) { + return performOperation(() -> telemetryApi.filteredStatisticsEservicesWithHttpInfo( + eserviceRecordId, pollingFrequency, toUtcDateTimeFormat(startDate), toUtcDateTimeFormat(endDate) + )) + .orElseThrow(() -> new IllegalStateException( + "Errore nel recupero statistiche filtrate e-service (response non 2xx o body nullo)" + )); + } + + public static String toUtcDateTimeFormat(OffsetDateTime dt) { + if (dt == null) return null; + return UTC_FMT.format(dt.toInstant()); + } +} diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/IPurposeTemplateClient.java b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/IPurposeTemplateClient.java index e2c3d0fe30..8c5bee94c1 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/IPurposeTemplateClient.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/IPurposeTemplateClient.java @@ -22,10 +22,12 @@ public interface IPurposeTemplateClient extends SettableBearerToken { PurposeTemplateWithCompactCreator getPurposeTemplate(UUID purposeTemplateId) throws RestClientException; EServiceDescriptorsPurposeTemplate getPurposeTemplateEServices(UUID purposeTemplateId, Integer offset, Integer limit, List producerIds, String eserviceName) throws RestClientException; File getRiskAnalysisTemplateAnswerAnnotationDocument(UUID purposeTemplateId, UUID answerId, UUID documentId) throws RestClientException; - EServiceDescriptorPurposeTemplate linkEServiceToPurposeTemplate(UUID purposeTemplateId, InlineObject2 inlineObject2) throws RestClientException; + + EServiceDescriptorPurposeTemplate linkEServiceToPurposeTemplate(UUID purposeTemplateId, LinkEServiceToPurposeTemplateRequest request) throws RestClientException; void publishPurposeTemplate(UUID purposeTemplateId) throws RestClientException; void suspendPurposeTemplate(UUID purposeTemplateId) throws RestClientException; - void unlinkEServiceToPurposeTemplate(UUID purposeTemplateId, InlineObject3 inlineObject3) throws RestClientException; + + void unlinkEServiceToPurposeTemplate(UUID purposeTemplateId, LinkEServiceToPurposeTemplateRequest request) throws RestClientException; void unsuspendPurposeTemplate(UUID purposeTemplateId) throws RestClientException; PurposeTemplate updatePurposeTemplate(UUID purposeTemplateId, PurposeTemplateSeed purposeTemplateSeed) throws RestClientException; diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/M2MPurposeClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/M2MPurposeClientImpl.java index 731c71bbbb..a64aa902d4 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/M2MPurposeClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/M2MPurposeClientImpl.java @@ -3,23 +3,15 @@ import it.pagopa.interop.conf.InteropClientConfigs; import it.pagopa.interop.generated.openapi.clients.m2mGateway.ApiClient; import it.pagopa.interop.generated.openapi.clients.m2mGateway.api.PurposesApi; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.Agreement; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.DelegationRef; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.FileDownloadMultipart; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.Purpose; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.PurposeDraftUpdateSeed; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.PurposeVersion; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.PurposeVersionSeed; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.PurposeVersions; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.Purposes; -import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.ReversePurposeDraftUpdateSeed; +import it.pagopa.interop.generated.openapi.clients.m2mGateway.model.*; import it.pagopa.interop.purpose.service.IM2MPurposeClient; -import java.util.UUID; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; +import java.util.UUID; + @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class M2MPurposeClientImpl implements IM2MPurposeClient { @@ -131,7 +123,7 @@ public FileDownloadMultipart downloadPurposeVersionDocument(UUID purposeId, UUID public Purpose patchPurpose(UUID purposeId, PurposePatchRequest body) { return purposesApi.updateDraftPurpose( purposeId, - new PurposeDraftUpdateSeed() + new UpdateDraftPurposeRequest() .title(body.getTitle()) .description(body.getDescription()) .riskAnalysisForm(body.getRiskAnalysisForm()) diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeApiClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeApiClientImpl.java index 0a83838dc1..9c883a06af 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeApiClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeApiClientImpl.java @@ -15,6 +15,7 @@ import org.springframework.web.client.RestTemplate; import java.io.File; +import java.io.IOException; import java.util.List; import java.util.UUID; @@ -127,7 +128,11 @@ public Purposes getProducerPurposes(Integer offset, Integer limit, String q, Lis @Override public File getRiskAnalysisDocument(UUID purposeId, UUID versionId, UUID documentId) { - return purposesApi.getRiskAnalysisDocument(purposeId, versionId, documentId); + try { + return purposesApi.getRiskAnalysisDocument(purposeId, versionId, documentId).getFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeTemplateClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeTemplateClientImpl.java index 7a66cab7ee..49e6075e6b 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeTemplateClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/purpose/service/impl/PurposeTemplateClientImpl.java @@ -16,6 +16,7 @@ import org.springframework.web.client.RestTemplate; import java.io.File; +import java.io.IOException; import java.util.List; import java.util.UUID; @@ -111,12 +112,16 @@ public EServiceDescriptorsPurposeTemplate getPurposeTemplateEServices(UUID purpo @Override public File getRiskAnalysisTemplateAnswerAnnotationDocument(UUID purposeTemplateId, UUID answerId, UUID documentId) throws RestClientException { - return purposesTemplateApi.getRiskAnalysisTemplateAnswerAnnotationDocument(purposeTemplateId, answerId, documentId); + try { + return purposesTemplateApi.getRiskAnalysisTemplateAnswerAnnotationDocument(purposeTemplateId, answerId, documentId).getFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } } @Override - public EServiceDescriptorPurposeTemplate linkEServiceToPurposeTemplate(UUID purposeTemplateId, InlineObject2 inlineObject2) throws RestClientException { - return purposesTemplateApi.linkEServiceToPurposeTemplate(purposeTemplateId, inlineObject2); + public EServiceDescriptorPurposeTemplate linkEServiceToPurposeTemplate(UUID purposeTemplateId, LinkEServiceToPurposeTemplateRequest request) throws RestClientException { + return purposesTemplateApi.linkEServiceToPurposeTemplate(purposeTemplateId, request); } @Override @@ -130,8 +135,8 @@ public void suspendPurposeTemplate(UUID purposeTemplateId) throws RestClientExce } @Override - public void unlinkEServiceToPurposeTemplate(UUID purposeTemplateId, InlineObject3 inlineObject3) throws RestClientException { - purposesTemplateApi.unlinkEServiceToPurposeTemplate(purposeTemplateId, inlineObject3); + public void unlinkEServiceToPurposeTemplate(UUID purposeTemplateId, LinkEServiceToPurposeTemplateRequest req) throws RestClientException { + purposesTemplateApi.unlinkEServiceToPurposeTemplate(purposeTemplateId, req); } @Override diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/tenant/service/impl/TenantsApiClientImpl.java b/interop-qa-tests/src/main/java/it/pagopa/interop/tenant/service/impl/TenantsApiClientImpl.java index a14e7518d6..7008aa7d28 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/tenant/service/impl/TenantsApiClientImpl.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/tenant/service/impl/TenantsApiClientImpl.java @@ -3,24 +3,8 @@ import it.pagopa.interop.conf.InteropClientConfigs; import it.pagopa.interop.generated.openapi.clients.bff.ApiClient; import it.pagopa.interop.generated.openapi.clients.bff.api.TenantsApi; -import it.pagopa.interop.generated.openapi.clients.bff.model.CertifiedAttributesResponse; -import it.pagopa.interop.generated.openapi.clients.bff.model.CertifiedTenantAttributeSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.CompactOrganizations; -import it.pagopa.interop.generated.openapi.clients.bff.model.DeclaredAttributesResponse; -import it.pagopa.interop.generated.openapi.clients.bff.model.DeclaredTenantAttributeSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.InlineObject5; -import it.pagopa.interop.generated.openapi.clients.bff.model.MailSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.RequesterCertifiedAttributes; -import it.pagopa.interop.generated.openapi.clients.bff.model.Tenant; -import it.pagopa.interop.generated.openapi.clients.bff.model.TenantDelegatedFeaturesFlagsUpdateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.TenantFeatureType; -import it.pagopa.interop.generated.openapi.clients.bff.model.Tenants; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateVerifiedTenantAttributeSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.VerifiedAttributesResponse; -import it.pagopa.interop.generated.openapi.clients.bff.model.VerifiedTenantAttributeSeed; +import it.pagopa.interop.generated.openapi.clients.bff.model.*; import it.pagopa.interop.tenant.service.ITenantsApi; -import java.util.List; -import java.util.UUID; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.retry.annotation.Backoff; @@ -29,6 +13,9 @@ import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; +import java.util.List; +import java.util.UUID; + @Component @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Retryable( @@ -114,7 +101,7 @@ public void revokeCertifiedAttribute(UUID tenantId, UUID attributeId) { @Override public void revokeVerifiedAttribute(UUID tenantId, UUID attributeId, UUID agreementId) { - tenantsApi.revokeVerifiedAttribute(tenantId, attributeId, new InlineObject5().agreementId(agreementId)); + tenantsApi.revokeVerifiedAttribute(tenantId, attributeId, new RevokeVerifiedAttributeRequest().agreementId(agreementId)); } @Override diff --git a/interop-qa-tests/src/main/java/it/pagopa/interop/utils/HttpCallExecutor.java b/interop-qa-tests/src/main/java/it/pagopa/interop/utils/HttpCallExecutor.java index a1bf03bad7..a2d6c59f0d 100644 --- a/interop-qa-tests/src/main/java/it/pagopa/interop/utils/HttpCallExecutor.java +++ b/interop-qa-tests/src/main/java/it/pagopa/interop/utils/HttpCallExecutor.java @@ -1,7 +1,5 @@ package it.pagopa.interop.utils; -import static java.util.Objects.isNull; - import it.pagopa.interop.common.IHttpExecutor; import lombok.Data; import lombok.Getter; @@ -16,6 +14,8 @@ import java.util.function.Function; import java.util.function.Supplier; +import static java.util.Objects.isNull; + @Slf4j @Getter @Data @@ -26,6 +26,10 @@ public class HttpCallExecutor implements IHttpExecutor { private String errorMessage; private Object response; + private HttpStatus snapResponseStatus; + private Object snapResponse; + private String snapErrorMessage; + @Override public HttpStatus performCall(Supplier promise) { try { @@ -83,4 +87,18 @@ public void setRawResponse(int statusCode, Object rawBody) { this.response = rawBody; } + @Override + public void snapshot() { + this.snapResponseStatus = this.responseStatus; + this.snapResponse = this.response; + this.snapErrorMessage = this.errorMessage; + } + + @Override + public void resetFormSnapshot() { + this.responseStatus = this.snapResponseStatus; + this.response = this.snapResponse; + this.errorMessage = this.snapErrorMessage; + } + } diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/agreement/AgreementCommonSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/agreement/AgreementCommonSteps.java index d5592952db..9a20705fa1 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/agreement/AgreementCommonSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/agreement/AgreementCommonSteps.java @@ -158,6 +158,8 @@ public void tenantHasAlreadyCreatedAndPublishedEService(String tenantType, int t clientTokenConfigurator.setBearerToken(identityService.getToken(tenantType, null)); // Create e-services and publish descriptors List eServiceDescriptorList = new ArrayList<>(); + List eServiceNames = new ArrayList<>(); + for (int i = 0; i < totalEservices; i++) { // Create e-service and descriptor int randomInt = ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE); @@ -176,10 +178,12 @@ public void tenantHasAlreadyCreatedAndPublishedEService(String tenantType, int t sharedStepsContext.getEServicesCommonContext().setPublicationTimestamp(OffsetDateTime.now()); // Add the e-service to the list of published ones eServiceDescriptorList.add(eServiceDescriptor); + eServiceNames.add(eserviceName); } // Set the first e-service and descriptor if (!eServiceDescriptorList.isEmpty()) { EServicesCommonContext eServicesCommonContext = sharedStepsContext.getEServicesCommonContext(); + eServicesCommonContext.setName(eServiceNames.get(0)); eServicesCommonContext.setPublishedEservicesIds(eServiceDescriptorList); EServiceDescriptor firstDescriptor = eServiceDescriptorList.get(0); eServicesCommonContext.setEserviceId(firstDescriptor.getEServiceId()); diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/CertifiedAttributeCreationSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/CertifiedAttributeCreationSteps.java index fbc30538fa..76cc933ae3 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/CertifiedAttributeCreationSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/CertifiedAttributeCreationSteps.java @@ -8,7 +8,8 @@ import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; -import org.apache.commons.lang.math.RandomUtils; + +import java.util.concurrent.ThreadLocalRandom; public class CertifiedAttributeCreationSteps { private final SharedStepsContext sharedStepsContext; @@ -32,7 +33,7 @@ public void createCertifiedAttribute() { clientTokenConfigurator.setBearerToken(sharedStepsContext.getUserToken()); httpCallExecutor.performCall(() -> clientTokenConfigurator.getAttributeApiClient().createCertifiedAttributeRE( new CertifiedAttributeSeed() - .name("new certified attribute %d".formatted(RandomUtils.nextInt())) + .name("new certified attribute %d".formatted(ThreadLocalRandom.current().nextInt())) .description("description test"))); } diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/DeclaredAttributeCreationSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/DeclaredAttributeCreationSteps.java index 924892433c..3f5cd9da85 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/DeclaredAttributeCreationSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/DeclaredAttributeCreationSteps.java @@ -9,12 +9,12 @@ import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; import it.pagopa.pn.interop.cucumber.steps.common.AttributeCommonContext; -import java.time.OffsetDateTime; - import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; -import org.apache.commons.lang.math.RandomUtils; import org.springframework.http.ResponseEntity; +import java.time.OffsetDateTime; +import java.util.concurrent.ThreadLocalRandom; + public class DeclaredAttributeCreationSteps { private final SharedStepsContext sharedStepsContext; private final ClientTokenConfigurator clientTokenConfigurator; @@ -34,7 +34,7 @@ public DeclaredAttributeCreationSteps( @When("l'utente crea un attributo dichiarato") public void createDeclaredAttribute() { - String attributeName = "new declared attribute %d".formatted(RandomUtils.nextInt()); + String attributeName = "new declared attribute %d".formatted(ThreadLocalRandom.current().nextInt()); String attributeDescription = "description test"; clientTokenConfigurator.setBearerToken(sharedStepsContext.getUserToken()); httpCallExecutor.performCall(() -> clientTokenConfigurator.getAttributeApiClient().createDeclaredAttributeRE( diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/VerifiedAttributeCreationSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/VerifiedAttributeCreationSteps.java index 20c3059509..2b03c17fcd 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/VerifiedAttributeCreationSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/attribute/VerifiedAttributeCreationSteps.java @@ -9,12 +9,12 @@ import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; import it.pagopa.pn.interop.cucumber.steps.common.AttributeCommonContext; -import java.time.OffsetDateTime; - import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; -import org.apache.commons.lang.math.RandomUtils; import org.springframework.http.ResponseEntity; +import java.time.OffsetDateTime; +import java.util.concurrent.ThreadLocalRandom; + public class VerifiedAttributeCreationSteps { private final SharedStepsContext sharedStepsContext; private final ClientTokenConfigurator clientTokenConfigurator; @@ -34,7 +34,7 @@ public VerifiedAttributeCreationSteps( @When("l'utente crea un attributo verificato") public void createVerifiedAttribute() { - String attributeName = "new verified attribute %d".formatted(RandomUtils.nextInt()); + String attributeName = "new verified attribute %d".formatted(ThreadLocalRandom.current().nextInt()); String attributeDescription = "description test"; clientTokenConfigurator.setBearerToken(sharedStepsContext.getUserToken()); httpCallExecutor.performCall(() -> clientTokenConfigurator.getAttributeApiClient().createVerifiedAttributeRE( diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/catalog/EServiceConsumersDownloadSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/catalog/EServiceConsumersDownloadSteps.java index f2e5fb1a27..0c1c0e64a2 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/catalog/EServiceConsumersDownloadSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/catalog/EServiceConsumersDownloadSteps.java @@ -5,9 +5,9 @@ import it.pagopa.interop.authorization.service.identity.IdentityService; import it.pagopa.interop.generated.openapi.clients.bff.model.AgreementState; import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; -import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; import it.pagopa.pn.interop.cucumber.steps.common.EServicesCommonContext; +import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; import java.util.UUID; diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/config/InteropCucumberSpringIntegration.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/config/InteropCucumberSpringIntegration.java index 5f62492074..4f992b4337 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/config/InteropCucumberSpringIntegration.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/config/InteropCucumberSpringIntegration.java @@ -3,11 +3,7 @@ import io.cucumber.spring.CucumberContextConfiguration; import it.pagopa.interop.agreement.service.IAgreementClient; import it.pagopa.interop.agreement.service.IEServiceClient; -import it.pagopa.interop.agreement.service.impl.AgreementClientImpl; -import it.pagopa.interop.agreement.service.impl.EServiceApiClientImpl; -import it.pagopa.interop.agreement.service.impl.M2MAgreementClientImpl; -import it.pagopa.interop.agreement.service.impl.M2MClientsClientImpl; -import it.pagopa.interop.agreement.service.impl.M2MTenantClientImpl; +import it.pagopa.interop.agreement.service.impl.*; import it.pagopa.interop.attribute.service.IAttributeApiClient; import it.pagopa.interop.attribute.service.impl.AttributeApiClientImpl; import it.pagopa.interop.attribute.service.impl.M2MCertifiedAttributeClientImpl; @@ -38,6 +34,8 @@ import it.pagopa.interop.eservice.service.mapper.EServiceAttributeMapperImpl; import it.pagopa.interop.event.mapper.M2MEventMapperImpl; import it.pagopa.interop.event.service.M2MEventClientImpl; +import it.pagopa.interop.probing.config.ProbingClientConfigs; +import it.pagopa.interop.probing.service.impl.ProbingClient; import it.pagopa.interop.purpose.RiskAnalysisDataInitializer; import it.pagopa.interop.purpose.service.IPurposeTemplateClient; import it.pagopa.interop.purpose.service.impl.M2MPurposeClientImpl; @@ -56,21 +54,13 @@ import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.M2MDataPreparationService; import it.pagopa.pn.interop.cucumber.steps.e_service_template.shared.EServiceTemplateStepContext; import it.pagopa.pn.interop.cucumber.steps.e_service_template.shared.EServiceTemplateTestAssistant; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.assistant.EServiceDelegationPatchOperationsAssistant; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.assistant.EServiceDescriptionPatchOperationsAssistant; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.assistant.EServiceNamePatchOperationsAssistant; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.assistant.EServicePatchContext; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.assistant.EServicePatchOperationsAssistant; +import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.assistant.*; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.descriptor.assistant.EServiceDescriptorPatchContext; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.descriptor.assistant.EServiceDescriptorPatchOperationsAssistant; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.descriptor.assistant.EServiceDescriptorQuotasPatchOperationsAssistant; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.descriptor.mapper.EServiceDescriptorMapperImpl; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.descriptor.mapper.EServiceDescriptorQuotasMapperImpl; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.mapper.DocumentMapperImpl; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.mapper.EServiceDelegationMapperImpl; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.mapper.EServiceDescriptionMapperImpl; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.mapper.EServiceMapperImpl; -import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.mapper.EServiceNameMapperImpl; +import it.pagopa.pn.interop.cucumber.steps.m2m.eservice.mapper.*; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice_template.assistant.EServiceTemplatePatchContext; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice_template.assistant.EServiceTemplatePatchOperationsAssistant; import it.pagopa.pn.interop.cucumber.steps.m2m.eservice_template.mapper.EServiceTemplateMapperImpl; @@ -121,6 +111,7 @@ TracingFileUtils.class, BlobFileCreator.class, TracingClientConfigs.class, + ProbingClientConfigs.class, DevAbstractInteropTracingClient.class, QAAbstractInteropTracingClient.class, CommonUtils.class, @@ -183,7 +174,8 @@ ISelfcareClient.class, SelfcareClientImpl.class, IPurposeTemplateClient.class, - PurposeTemplateClientImpl.class + PurposeTemplateClientImpl.class, + ProbingClient.class }) @EnableScheduling @EnableConfigurationProperties diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/delegate/DelegationCommonStep.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/delegate/DelegationCommonStep.java index 1d7e578ce6..c3531cf324 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/delegate/DelegationCommonStep.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/delegate/DelegationCommonStep.java @@ -168,6 +168,12 @@ public void thenStatusCodeIs(int statusCode) { else Assertions.assertEquals(statusCode, actualStatusCode); } + @Then("la response riporta lo status code {int}") + public void statusCodeIs(int statusCode) { + int actualStatusCode = httpCallExecutor.getResponseStatus().value(); + Assertions.assertEquals(statusCode, actualStatusCode); + } + boolean isSuccessful(int statusCode) { return statusCode >= 200 && statusCode < 300; } diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/quota/EServiceTemplateQuotaUpdateSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/quota/EServiceTemplateQuotaUpdateSteps.java index 83ab31dc90..cba065c234 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/quota/EServiceTemplateQuotaUpdateSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/quota/EServiceTemplateQuotaUpdateSteps.java @@ -1,9 +1,5 @@ package it.pagopa.pn.interop.cucumber.steps.e_service_template.quota; -import static java.lang.Math.abs; -import static java.util.Objects.nonNull; -import static org.assertj.core.api.Assertions.fail; - import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import it.pagopa.interop.authorization.service.utils.PollingPredicateException; @@ -14,11 +10,16 @@ import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateVersionQuotasUpdateSeed; import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; -import java.util.UUID; import lombok.Data; -import org.apache.commons.lang.math.RandomUtils; import org.springframework.http.ResponseEntity; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +import static java.lang.Math.abs; +import static java.util.Objects.nonNull; +import static org.assertj.core.api.Assertions.fail; + /** Cucumber steps involving quotas of E-service templates */ @Data public class EServiceTemplateQuotaUpdateSteps { @@ -50,7 +51,7 @@ public void editEServiceTemplateVersionQuotas() { } private EServiceTemplateVersionQuotasUpdateSeed nextQuotasUpdateSeed() { - int dailyCallsPerConsumer = RandomUtils.nextInt(1_000_000_000); // numero massimo supportato + int dailyCallsPerConsumer = ThreadLocalRandom.current().nextInt(1_000_000_000); // numero massimo supportato return new EServiceTemplateVersionQuotasUpdateSeed() .voucherLifespan(86400) .dailyCallsTotal(dailyCallsPerConsumer + 1) diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/shared/EServiceTemplateTestAssistant.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/shared/EServiceTemplateTestAssistant.java index cf76343bad..786321ce67 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/shared/EServiceTemplateTestAssistant.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/shared/EServiceTemplateTestAssistant.java @@ -1,11 +1,5 @@ package it.pagopa.pn.interop.cucumber.steps.e_service_template.shared; -import static java.util.Objects.nonNull; -import static java.util.Objects.requireNonNull; -import static org.apache.commons.lang3.StringUtils.isNotEmpty; -import static org.assertj.core.api.Assertions.fail; - -import com.google.common.io.Files; import it.pagopa.interop.authorization.service.identity.IdentityService; import it.pagopa.interop.authorization.service.utils.PollingPredicateException; import it.pagopa.interop.authorization.service.utils.PollingService; @@ -14,31 +8,14 @@ import it.pagopa.interop.e_service_template.IEServiceTemplateClient.EServiceTemplateDocumentKind; import it.pagopa.interop.e_service_template.mapper.DescriptorAttributesMapper; import it.pagopa.interop.e_service_template.mapper.RiskAnalysisMapper; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.DescriptorAttributes; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDoc; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateAttributesSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateRiskAnalysis; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateRiskAnalysisSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateVersionAttributeSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateVersionDetails; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceTemplateVersionState; -import it.pagopa.interop.generated.openapi.clients.bff.model.TenantKind; -import it.pagopa.interop.generated.openapi.clients.bff.model.UpdateEServiceTemplateVersionSeed; +import it.pagopa.interop.generated.openapi.clients.bff.model.*; import it.pagopa.interop.purpose.domain.RiskAnalysis; import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; import it.pagopa.pn.interop.cucumber.steps.common.EServiceTemplateDocumentInfo; import it.pagopa.pn.interop.cucumber.steps.common.EServiceTemplateInfo; import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.UUID; -import java.util.function.BiConsumer; -import java.util.function.Predicate; import lombok.Data; -import org.apache.commons.lang.math.RandomUtils; import org.jeasy.random.EasyRandom; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; @@ -47,6 +24,19 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.BiConsumer; +import java.util.function.Predicate; + +import static java.util.Objects.nonNull; +import static java.util.Objects.requireNonNull; +import static org.apache.commons.lang3.StringUtils.isNotEmpty; +import static org.assertj.core.api.Assertions.fail; + /** It contains general utility functions used across all other classes. */ @Data @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @@ -286,7 +276,7 @@ private void checkDocumentAddedToEServiceTemplateVersion(UUID eServiceTemplateId * sia inviando che ricevendo, anziché restituire void o un * oggetto File restituiscano un'oggetto hash di qualche tipo; a quel * punto qui basterà confrontare i valori hash. */ - return res.getStatusCode().is2xxSuccessful() && nonNull(res.getBody()) && Arrays.equals(Files.toByteArray(res.getBody()), lastAddedDocument.body()); + return res.getStatusCode().is2xxSuccessful() && nonNull(res.getBody()) && Arrays.equals(java.nio.file.Files.readAllBytes(res.getBody().getFile().toPath()), lastAddedDocument.body()); } catch (IOException e) { throw new RuntimeException("Errore nella lettura del body binario della risposta HTTP: %s".formatted(res), e); } @@ -301,7 +291,7 @@ private void checkDocumentAddedToEServiceTemplateVersion(UUID eServiceTemplateId public String buildPrettyName(EServiceTemplateDocumentKind kind) { return "e-service-template-%s-%d-%d".formatted(kind.toString(), sharedStepsContext.getTestSeed(), - RandomUtils.nextInt(1_000_000)); + ThreadLocalRandom.current().nextInt(1_000_000)); } public void addRiskAnalysisToEServiceTemplateSuccessfully() { diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/version/crud/EServiceTemplateVersionCreateSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/version/crud/EServiceTemplateVersionCreateSteps.java index 5c81776752..77dd7e3079 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/version/crud/EServiceTemplateVersionCreateSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/e_service_template/version/crud/EServiceTemplateVersionCreateSteps.java @@ -1,6 +1,5 @@ package it.pagopa.pn.interop.cucumber.steps.e_service_template.version.crud; -import com.google.common.base.Predicates; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; @@ -13,10 +12,11 @@ import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; import it.pagopa.pn.interop.cucumber.steps.common.EServiceTemplateInfo; import it.pagopa.pn.interop.cucumber.steps.e_service_template.shared.EServiceTemplateTestAssistant; -import java.util.UUID; import lombok.Data; import org.springframework.http.ResponseEntity; +import java.util.UUID; + /** Cucumber steps involving creation, editing, viewing or deletion * of E-service template versions */ // TODO perché @Data? Considerarne rimozione da questa e dalle altre classi @@ -70,7 +70,10 @@ public void addEServiceTemplateVersion(EServiceTemplateVersionState state) { @Then("la creazione di una ulteriore versione nell'e-service template è stata effettuata correttamente") public void checkEServiceTemplateVersionCreated() { - testAssistant.checkEServiceTemplateVersion(Predicates.alwaysTrue(), "La versione dell'e-service template non è stata creata correttamente"); + testAssistant.checkEServiceTemplateVersion( + x -> true, + "La versione dell'e-service template non è stata creata correttamente" + ); } @Then("la creazione di una ulteriore versione in stato {eServiceTemplateVersionState} nell'e-service template è stata effettuata correttamente") diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/m2m/common/ScenarioHttpCallExecutor.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/m2m/common/ScenarioHttpCallExecutor.java index ee305524c6..e2d990b0b4 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/m2m/common/ScenarioHttpCallExecutor.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/m2m/common/ScenarioHttpCallExecutor.java @@ -2,13 +2,13 @@ import io.cucumber.spring.ScenarioScope; import it.pagopa.interop.common.IHttpExecutor; -import java.util.function.Function; import lombok.Data; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpStatusCodeException; +import java.util.function.Function; import java.util.function.Supplier; @Component @@ -20,6 +20,10 @@ public class ScenarioHttpCallExecutor implements IHttpExecutor { private Object response; private String errorMessage; + private HttpStatus snapResponseStatus; + private Object snapResponse; + private String snapErrorMessage; + @Override public T performCallSavingBodyResponse(Supplier> promise) { T body = performCall(promise, ResponseEntity::getStatusCode).getBody(); @@ -73,5 +77,19 @@ public void setRawResponse(int statusCode, Object rawBody) { this.response = rawBody; } + @Override + public void snapshot() { + this.snapResponseStatus = this.responseStatus; + this.snapResponse = this.response; + this.snapErrorMessage = this.errorMessage; + } + + @Override + public void resetFormSnapshot() { + this.responseStatus = this.snapResponseStatus; + this.response = this.snapResponse; + this.errorMessage = this.snapErrorMessage; + } + } diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/m2m/common/utils/AbstractResolver.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/m2m/common/utils/AbstractResolver.java new file mode 100644 index 0000000000..441b8d2e89 --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/m2m/common/utils/AbstractResolver.java @@ -0,0 +1,44 @@ +package it.pagopa.pn.interop.cucumber.steps.m2m.common.utils; + +import it.pagopa.pn.interop.cucumber.utility.enums.ResolvableToken; + +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract class AbstractResolver { + + protected T resolveOrParse( + String raw, + Function nonTokenParser, + Supplier actualSupplier, + Supplier expectedSupplier, + Supplier randomSupplier, + Supplier blankSupplier + ) { + if (raw == null) return nonTokenParser.apply(null); + + ResolvableToken token = ResolvableToken.from(raw); + if (token == null) { + return nonTokenParser.apply(raw); + } + + return switch (token) { + case ACTUAL -> actualSupplier != null ? actualSupplier.get() : null; + case EXPECTED -> expectedSupplier != null ? expectedSupplier.get() : null; + case RANDOM -> randomSupplier != null ? randomSupplier.get() : null; + case BLANK -> blankSupplier != null ? blankSupplier.get() : null; + case NULL -> null; + default -> throw new IllegalArgumentException("Unknown token: " + token); + }; + } + + // overload comodo quando BLANK/RANDOM non servono + protected T resolveOrParse( + String raw, + Function nonTokenParser, + Supplier actualSupplier, + Supplier expectedSupplier + ) { + return resolveOrParse(raw, nonTokenParser, actualSupplier, expectedSupplier, null, null); + } +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/ProbingLoadSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/ProbingLoadSteps.java new file mode 100644 index 0000000000..bdc60ad9ed --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/ProbingLoadSteps.java @@ -0,0 +1,256 @@ +package it.pagopa.pn.interop.cucumber.steps.probing; + +import io.cucumber.datatable.DataTable; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import it.pagopa.interop.generated.openapi.clients.probing.model.ChangeProbingStateRequest; +import it.pagopa.interop.generated.openapi.clients.probing.model.ProbingDataEserviceResponse; +import it.pagopa.interop.probing.service.impl.ProbingClient; +import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; +import it.pagopa.pn.interop.cucumber.steps.probing.model.EserviceRow; +import lombok.extern.slf4j.Slf4j; +import org.assertj.core.api.Assertions; + +import java.time.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.*; +import java.util.concurrent.atomic.LongAdder; + +import static it.pagopa.pn.interop.cucumber.utility.StepParser.dateTimeOrNull; +import static it.pagopa.pn.interop.cucumber.utility.StepParser.durationOrNull; + +@Slf4j +public class ProbingLoadSteps { + private final ProbingClient probingClient; + + private int totalEservices; + private int workers; + + private int frequencyMinutes; + private String startDateExpr; + private String endDateExpr; + + private int waitPeriods; // quanti periodi aspettare + private Duration extraWait; // buffer oltre ai periodi + private Duration recentTolerance; // tolleranza + + // calcolati + private Duration waitDuration; + + // Timestamp riferimento: quando abilito + private Instant enableTimeUtc; + + public ProbingLoadSteps(ProbingClient probingClient, SharedStepsContext sharedStepsContext) { + this.probingClient = probingClient; + this.probingClient.setHttpCallExecutor(sharedStepsContext.getHttpCallExecutor()); + } + + @Given("preparo il load test probing con:") + public void setup(DataTable table) { + Map row = table.asMaps().get(0); + + totalEservices = Integer.parseInt(row.get("totalEservices")); + workers = Integer.parseInt(row.get("workers")); + + frequencyMinutes = Integer.parseInt(row.get("frequency")); + startDateExpr = row.get("startDate"); + endDateExpr = row.get("endDate"); + + waitPeriods = Integer.parseInt(row.get("waitPeriods")); + extraWait = durationOrNull(row.get("extraWait")); + recentTolerance = durationOrNull(row.get("recentTolerance")); + + Assertions.assertThat(totalEservices).as("totalEservices").isGreaterThan(0); + Assertions.assertThat(workers).as("workers").isGreaterThan(0); + + Assertions.assertThat(frequencyMinutes).as("frequency").isGreaterThanOrEqualTo(1); + Assertions.assertThat(waitPeriods).as("waitPeriods").isGreaterThanOrEqualTo(1); + Assertions.assertThat(extraWait).as("extraWait").isNotNull(); + Assertions.assertThat(recentTolerance).as("recentTolerance").isNotNull(); + + // Attesa = N * frequency + buffer + waitDuration = Duration.ofMinutes((long) frequencyMinutes * (long) waitPeriods).plus(extraWait); + + log.info("LOAD setup: total={}, workers={}, frequency={}m, window=[{}, {}], waitPeriods={}, extraWait={}, waitDuration={}, recentTolerance={}", + totalEservices, workers, frequencyMinutes, startDateExpr, endDateExpr, waitPeriods, extraWait, waitDuration, recentTolerance + ); + } + + @When("aggiorno scheduling in parallelo per tutti gli eservice") + public void updateSchedulingParallel() { + OffsetDateTime startUtc = dateTimeOrNull(startDateExpr); + OffsetDateTime endUtc = dateTimeOrNull(endDateExpr); + + Assertions.assertThat(endUtc).as("endDate deve essere dopo startDate").isAfter(startUtc); + + runParallelRange(totalEservices, idx -> { + EserviceRow row = EserviceRow.atIndex(idx); + + probingClient.updateEserviceFrequency(row.getEserviceId(), row.getVersionId(), frequencyMinutes, startUtc.toOffsetTime(), endUtc.toOffsetTime()); + }, "updateScheduling"); + } + + @And("abilito probing in parallelo per tutti gli eservice") + public void enableParallel() { + // momento a partire dal quale mi aspetto aggiornamenti + enableTimeUtc = Instant.now(); + + runParallelRange(totalEservices, idx -> { + EserviceRow row = EserviceRow.atIndex(idx); + + ChangeProbingStateRequest req = new ChangeProbingStateRequest().probingEnabled(true); + probingClient.updateEserviceProbingState(row.getEserviceId(), row.getVersionId(), req); + }, "enableProbing"); + + log.info("Enable completato. enableTimeUtc={}", enableTimeUtc); + } + + @And("attendo N periodi di frequency più extraWait") + public void waitNPeriodsPlusExtra() { + log.info("Attendo {}", waitDuration); + sleep(waitDuration); + } + + @Then("verifico in parallelo che responseReceived sia valorizzata e aggiornata dopo l'enable per tutti gli eservice") + public void verifyAllUpdatedAfterEnable() { + Assertions.assertThat(enableTimeUtc).as("enableTimeUtc").isNotNull(); + + Instant minAllowed = enableTimeUtc.minus(recentTolerance); + log.info("Verifica: responseReceived deve essere >= {} (enableTimeUtc={} minus tolerance={})", + minAllowed, enableTimeUtc, recentTolerance + ); + + ConcurrentLinkedQueue notOk = new ConcurrentLinkedQueue<>(); + + // Una sola GET per e-service + runParallelRange(totalEservices, idx -> { + Instant last = readLastResponseInstant(idx); + + if (last == null) { + notOk.add("idx=" + idx + " responseReceived=null"); + return; + } + + if (last.isBefore(minAllowed)) { + notOk.add("idx=" + idx + " responseReceived=" + last + " < minAllowed=" + minAllowed); + } + }, "verifyAllOnce"); + + if (!notOk.isEmpty()) { + List top = notOk.stream().limit(30).toList(); + throw new AssertionError( + "Verifica fallita: " + notOk.size() + "/" + totalEservices + " eservice non aggiornati dopo l'enable.\n" + + "Parametri: frequency=" + frequencyMinutes + "m, waitPeriods=" + waitPeriods + ", extraWait=" + extraWait + + ", waitDuration=" + waitDuration + ", tolerance=" + recentTolerance + "\n" + + "Esempi (max 30):\n" + String.join("\n", top) + ); + } + + log.info("OK: tutti gli eservice risultano aggiornati dopo l'enable."); + } + + @And("disabilito probing in parallelo per tutti gli eservice") + public void disableParallel() { + runParallelRange(totalEservices, idx -> { + EserviceRow row = EserviceRow.atIndex(idx); + + UUID eserviceId = row.getEserviceId(); + UUID versionId = row.getVersionId(); + + ChangeProbingStateRequest req = new ChangeProbingStateRequest().probingEnabled(false); + probingClient.updateEserviceProbingState(eserviceId, versionId, req); + }, "disableProbing"); + } + + private Instant readLastResponseInstant(int idx) { + EserviceRow row = EserviceRow.atIndex(idx); + + Long recordId = row.getId(); + ProbingDataEserviceResponse resp = probingClient.getEserviceProbingData(recordId); + Assertions.assertThat(resp).as("ProbingDataEserviceResponse").isNotNull(); + + String rr = resp.getResponseReceived(); + if (rr == null || rr.isBlank()) return null; + + // 1) UTC standard + try { + return Instant.parse(rr); + } catch (Exception ignored) { + } + try { + return OffsetDateTime.parse(rr).toInstant(); + } catch (Exception ignored) { + } + + // 2) fallback legacy (solo orario) + try { + OffsetTime ot = OffsetTime.parse(rr); + return ot.atDate(LocalDate.now()).toInstant(); + } catch (Exception e) { + throw new IllegalArgumentException("responseReceived non parsabile: '" + rr + "'", e); + } + } + + private void runParallelRange(int total, ThrowingIntConsumer fn, String phase) { + ExecutorService pool = Executors.newFixedThreadPool(workers); + try { + LongAdder ok = new LongAdder(); + ConcurrentLinkedQueue errors = new ConcurrentLinkedQueue<>(); + List> futures = new ArrayList<>(total); + + long start = System.nanoTime(); + + for (int i = 0; i < total; i++) { + final int idx = i; + futures.add(pool.submit(() -> { + try { + fn.accept(idx); + ok.increment(); + } catch (Exception e) { + errors.add("idx=" + idx + " -> " + e.getMessage()); + } + })); + } + + for (Future f : futures) { + try { + f.get(); + } catch (Exception e) { + errors.add("future -> " + e.getMessage()); + } + } + + long ms = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start); + log.info("Phase '{}' completata: {} ok / {} tot in {}ms (workers={})", + phase, ok.sum(), total, ms, workers + ); + + if (!errors.isEmpty()) { + List top = errors.stream().limit(30).toList(); + throw new AssertionError( + "Phase '" + phase + "' fallita: errors=" + errors.size() + ", ok=" + ok.sum() + "/" + total + "\n" + + "Esempi (max 30):\n" + String.join("\n", top) + ); + } + } finally { + pool.shutdownNow(); + } + } + + @FunctionalInterface + private interface ThrowingIntConsumer { + void accept(int value) throws Exception; + } + + private static void sleep(Duration d) { + try { + Thread.sleep(d.toMillis()); + } catch (InterruptedException ignored) { + } + } +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/ProbingSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/ProbingSteps.java new file mode 100644 index 0000000000..4453fe2a3d --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/ProbingSteps.java @@ -0,0 +1,620 @@ +package it.pagopa.pn.interop.cucumber.steps.probing; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import it.pagopa.interop.authorization.service.utils.PollingService; +import it.pagopa.interop.common.IHttpExecutor; +import it.pagopa.interop.generated.openapi.clients.probing.model.*; +import it.pagopa.interop.generated.openapi.clients.probingStatistics.model.TelemetryDataEserviceResponse; +import it.pagopa.interop.probing.service.impl.ProbingClient; +import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; +import it.pagopa.pn.interop.cucumber.steps.probing.model.EserviceRow; +import it.pagopa.pn.interop.cucumber.steps.probing.model.ProbingContext; +import it.pagopa.pn.interop.cucumber.steps.probing.utils.ProbingResolver; +import it.pagopa.pn.interop.cucumber.steps.probing.utils.ProbingUtils; +import it.pagopa.pn.interop.cucumber.utility.StepParser; +import lombok.extern.slf4j.Slf4j; +import org.assertj.core.api.Assertions; +import org.springframework.http.HttpStatus; + +import java.time.*; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static it.pagopa.pn.interop.cucumber.steps.probing.utils.ProbingUtils.matchesAllFilters; +import static it.pagopa.pn.interop.cucumber.utility.StepParser.*; + +@Slf4j +public class ProbingSteps { + + private final IHttpExecutor httpCallExecutor; + private final ProbingClient probingClient; + private final ProbingContext probingContext; + private final ProbingResolver resolver; + + public ProbingSteps(ProbingClient probingClient, SharedStepsContext sharedStepsContext) { + this.httpCallExecutor = sharedStepsContext.getHttpCallExecutor(); + this.probingClient = probingClient; + this.probingClient.setHttpCallExecutor(httpCallExecutor); + this.probingContext = new ProbingContext(); + this.resolver = new ProbingResolver(probingContext); + } + + @And("il microservizio {string} risulta attivo") + public void getStatus(String ms) { + final int maxTry = 30; // ~30 secondi + final long sleepMs = 1_000L; // 1 secondo + + switch (ms) { + case "probing-api" -> PollingService.makePolling( + () -> { + probingClient.getProbingApiHealthStatus(); + return httpCallExecutor.getResponseStatus(); + }, + HttpStatus::is2xxSuccessful, + "Il ms " + ms + " dovrebbe risultare attivo", + maxTry, + sleepMs + ); + + case "probing-statistics-api" -> PollingService.makePolling( + () -> { + probingClient.getStatisticsHealthStatus(); + return httpCallExecutor.getResponseStatus(); + }, + HttpStatus::is2xxSuccessful, + "Il ms " + ms + " dovrebbe risultare attivo", + maxTry, + sleepMs + ); + + default -> throw new IllegalArgumentException("Il microservizio " + ms + " non esiste"); + } + } + + @When("recupero la lista dei producers con limit {string} e offset {string} e producerName {string}") + public void getProducersWithProducerName(String limit, String offset, String producerName) { + Integer limitValue = nullableInteger(limit); + Integer offsetValue = nullableInteger(offset); + String producerTarget = StepParser.nullOrValue(producerName); + + try { + List producers = + probingClient.getEservicesProducers(limitValue, offsetValue, producerTarget); + + Assertions.assertThat(producers) + .as("La lista dei producer non deve essere null") + .isNotNull(); + + if (httpCallExecutor.getResponseStatus().is2xxSuccessful() && producerTarget != null && !producers.isEmpty()) { + + Assertions.assertThat(producers) + .as("Tutti i risultati devono avere producerName='%s'", producerTarget) + .allSatisfy(p -> + Assertions.assertThat(p.getValue()) + .as("producerName del singolo elemento non deve essere null") + .isNotNull() + ); + + Assertions.assertThat(producers) + .as("Tutti i risultati devono matchare producerName='%s'", producerTarget) + .allMatch(p -> p.getValue().equals(producerTarget)); + } + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("vengono recuperati dal catalogo gli e-service con limit {string} e offset {string} e filtri eserviceName {string}, producerName {string}, versionNumber {string}, state {string}") + public void getEServiceCatalogWithPaginationAndFilters(String limit, String offset, String eserviceName, String producerName, String versionNumber, String state) { + Integer limitValue = nullableInteger(limit); + Integer offsetValue = nullableInteger(offset); + + String nameFilter = resolver.resolveEserviceName(eserviceName); + String producerFilter = resolver.resolveProducer(producerName); + Integer versionFilter = StepParser.nullableInteger(versionNumber); + List stateFilter = StepParser.singletonListNullable(StepParser.nullOrValue(state), EserviceStateFE::fromValue); + + SearchEserviceResponse response; + + try { + response = probingClient.searchEservices( + limitValue, + offsetValue, + nameFilter, + producerFilter, + versionFilter, + stateFilter + ); + + Assertions.assertThat(response).as("La response non deve essere null").isNotNull(); + ProbingUtils.EserviceFilters appliedFilters = new ProbingUtils.EserviceFilters(nameFilter, producerFilter, versionFilter, stateFilter); + assertResultsMatchFilters(response, appliedFilters); + + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("viene modificato lo stato di probing dell'e-service con id {string} e id versione {string} in {string}") + @When("viene modificato lo stato di probing dell'e-service con id {string} e id versione {string} in {string} e si verifica che coincida con quanto atteso") + public void setProbingState(String eserviceId, String versionId, String probingEnabled) { + UUID eserviceUuid = resolver.resolveEserviceId(eserviceId); + UUID versionUuid = resolver.resolveVersionId(versionId); + Long eserviceRecordId = resolver.getEserviceRecordId(); + + ChangeProbingStateRequest probingState = new ChangeProbingStateRequest() + .probingEnabled(nullableBoolean(probingEnabled)); + + try { + probingClient.updateEserviceProbingState(eserviceUuid, versionUuid, probingState); + httpCallExecutor.snapshot(); + + EserviceRow expected = probingContext.getExpectedEserviceRow(); + expected.setProbingEnabled(Boolean.parseBoolean(probingEnabled)); + + PollingService.makePolling( + () -> probingClient.getEserviceProbingData(eserviceRecordId), + resp -> resp.getProbingEnabled().equals(Boolean.valueOf(probingEnabled)), + "Errore durante il setting di probingEnabled per l'eservice con eserviceRecordId '" + eserviceRecordId + "'", + 30, + 1_000L + ); + + httpCallExecutor.resetFormSnapshot(); + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("viene modificato lo stato operativo dell'e-service con id {string} e id versione {string} in {string}") + @When("viene modificato lo stato operativo dell'e-service con id {string} e id versione {string} in {string} e si verifica che coincida con quanto atteso") + public void setOperationalState(String eserviceId, String versionId, String eserviceState) { + UUID eserviceUuid = resolver.resolveEserviceId(eserviceId); + UUID versionUuid = resolver.resolveVersionId(versionId); + Long eserviceRecordId = resolver.getEserviceRecordId(); + EserviceStateBE stateBE = resolver.resolveEserviceStateBE(eserviceState); + + ChangeEserviceStateRequest operationalState = new ChangeEserviceStateRequest() + .eServiceState(parseNullableSafe(eserviceState, EserviceStateBE::fromValue)); + + try { + probingClient.updateEserviceState(eserviceUuid, versionUuid, operationalState); + EserviceRow expected = probingContext.getExpectedEserviceRow(); + expected.setState(stateBE.getValue()); + + httpCallExecutor.snapshot(); + + PollingService.makePolling( + () -> probingClient.getEserviceProbingData(eserviceRecordId), + resp -> resp.getEserviceActive().equals(stateBE.equals(EserviceStateBE.ACTIVE)), + "Errore durante il setting dell'eserviceState per l'eservice con eserviceRecordId '" + eserviceRecordId + "'", + 30, + 1_000L + ); + + httpCallExecutor.resetFormSnapshot(); + + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("aggiorno i parametri di probing dell'e-service con eserviceId {string} e versionId {string} impostando frequency {string}, startDate {string}, endDate {string}") + @When("vengono aggiornati i parametri di probing dell'e-service con eserviceId {string} e versionId {string} impostando frequency {string}, startDate {string}, endDate {string} e si verifica che coincidano con quanto atteso") + public void setEserviceFrequency(String eserviceId, String versionId, String frequency, String startDate, String endDate) { + UUID eserviceUuid = resolver.resolveEserviceId(eserviceId); + UUID versionUuid = resolver.resolveVersionId(versionId); + Integer frequencyValue = resolver.resolveFrequency(frequency); + OffsetTime startValue = resolver.resolvePollingStartTime(startDate); + OffsetTime endValue = resolver.resolvePollingEndTime(endDate); + + try { + probingClient.updateEserviceFrequency(eserviceUuid, versionUuid, frequencyValue, startValue, endValue); + + Long eserviceRecordId = resolver.getEserviceRecordId(); + EserviceRow expected = probingContext.getExpectedEserviceRow(); + expected.setPollingFrequency(frequencyValue); + httpCallExecutor.snapshot(); + + PollingService.makePolling( + () -> probingClient.getEserviceMainData(eserviceRecordId), + resp -> resp.getPollingFrequency() == expected.getPollingFrequency(), + "Errore durante il setting di probingEnabled per l'eservice con eserviceRecordId '" + eserviceRecordId + "'", + 30, + 1_000L + ); + + httpCallExecutor.resetFormSnapshot(); + + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("vengono recuperati i main data dell'e-service con eserviceRecordId {string}") + public void getEserviceMainData(String eserviceRecordId) { + Long recordId = resolver.resolveEserviceRecordId(eserviceRecordId); + + try { + MainDataEserviceResponse response = probingClient.getEserviceMainData(recordId); + Assertions.assertThat(response).as("La response contenente i metadati anagrafici dell'e-service non deve essere null").isNotNull(); + + EserviceRow actual = probingContext.getActualEserviceRow(); + actual.setPollingFrequency(response.getPollingFrequency()); + + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("vengono recuperati i dati di probing dell'e-service con eserviceRecordId {string}") + public void getEserviceProbingData(String eserviceRecordId) { + Long recordId = resolver.resolveEserviceRecordId(eserviceRecordId); + + try { + ProbingDataEserviceResponse response = probingClient.getEserviceProbingData(recordId); + Assertions.assertThat(response).as("La response contenente i dati di probing dell'e-service non deve essere null").isNotNull(); + + EserviceRow actual = probingContext.getActualEserviceRow(); + actual.setProbingEnabled(response.getProbingEnabled()); + actual.setState(response.getState().getValue()); + + probingContext.setLastResponseTime(response.getResponseReceived() != null ? OffsetDateTime.parse(response.getResponseReceived()) : null); + + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("viene recuperata la telemetria pubblica dell'e-service con eserviceRecordId {string} e pollingFrequency {string}") + public void getEservicePublicTelemetry(String eserviceRecordId, String pollingFrequency) { + Long recordIdValue = resolver.resolveEserviceRecordId(eserviceRecordId); + Integer poolingFrequencyValue = resolver.resolveFrequency(pollingFrequency); + + try { + TelemetryDataEserviceResponse response = probingClient.statisticsEservices(recordIdValue, poolingFrequencyValue); + Assertions.assertThat(response).as("La response contenente la telemetria pubblica dell'e-service non deve essere null").isNotNull(); + + if (httpCallExecutor.getResponseStatus().is2xxSuccessful()) { + probingContext.getActualTelemetry().add(response); + } + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @When("viene recuperata la telemetria dell'e-service con eserviceRecordId {string} e impostando pollingFrequency {string} , startDate {string} , endDate {string}") + public void getEserviceTelemetry(String eserviceRecordId, String pollingFrequency, String startDate, String endDate) { + Long recordIdValue = resolver.resolveEserviceRecordId(eserviceRecordId); + Integer poolingFrequencyValue = resolver.resolveFrequency(pollingFrequency); + OffsetDateTime startDateValue = dateTimeOrNull(startDate); + OffsetDateTime endDateValue = dateTimeOrNull(endDate); + + try { + TelemetryDataEserviceResponse response = probingClient.filteredStatisticsEservices(recordIdValue, poolingFrequencyValue, startDateValue, endDateValue); + Assertions.assertThat(response).as("La response contenente la telemetria dell'e-service non deve essere null").isNotNull(); + + probingContext.getActualTelemetry().add(response); + } catch (IllegalStateException e) { + log.warn(e.getMessage()); + } + } + + @Given("vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo") + public void getEserviceRow() { + EserviceRow eserviceRow = EserviceRow.atIndex(probingContext.getThreadNumber()); + probingContext.setActualEserviceRow(eserviceRow); + probingContext.setExpectedEserviceRow(eserviceRow); + } + + @Given("vengono calcolate le informazioni di probing relative ad un e-service con health check {word} presente a catalogo") + public void getEserviceRowWithOutcome(String outcomeStr) { + EserviceRow.Outcome outcome = EserviceRow.Outcome.valueOf(outcomeStr.toUpperCase()); + + int okCount = ProbingContext.ESERVICE_OK_COUNT; + int errorCount = ProbingContext.ESERVICE_KO_COUNT; + int randomCount = ProbingContext.ESERVICE_RANDOM_COUNT; + + EserviceRow row = EserviceRow.pickByOutcome(outcome, okCount, errorCount, randomCount); + + probingContext.setActualEserviceRow(row); + probingContext.setExpectedEserviceRow(row); + } + + @Then("verifica che la responseReceived sia aggiornata coerentemente rispetto la frequency {string}, clockScheduler {string}, startDate {string}, endDate {string}") + public void assertScheduler(String pollingFrequency, String clockScheduler, String startDate, String endDate) throws Exception { + + // --- Inputs + Duration tick = resolver.resolveSchedulerInterval(clockScheduler); + Assertions.assertThat(tick) + .as("clockScheduler deve essere valorizzato e > 0") + .isNotNull() + .isGreaterThan(Duration.ZERO); + + int freqMinutes = resolver.resolveFrequency(pollingFrequency); + Assertions.assertThat(freqMinutes) + .as("pollingFrequency (minutes) deve essere >= 1") + .isGreaterThanOrEqualTo(1); + + OffsetTime start = resolver.resolvePollingStartTime(startDate); + OffsetTime end = resolver.resolvePollingEndTime(endDate); + + Assertions.assertThat(start).as("startDate non deve essere null").isNotNull(); + Assertions.assertThat(end).as("endDate non deve essere null").isNotNull(); + Assertions.assertThat(end).as("endDate deve essere dopo startDate").isAfter(start); + + // --- Instants + LocalDate today = LocalDate.now(); + Instant startI = start.atDate(today).toInstant(); + Instant endI = end.atDate(today).toInstant(); + + // --- Policy (solo tick + jitter) + Duration jitter = Duration.ofSeconds(20); + Duration unit = tick.plus(jitter); + Duration notAdvancingTolerance = Duration.ofSeconds(2); + Duration boundaryBuffer = Duration.ofSeconds(1); + + Instant now = Instant.now(); + + // --- AFTER: fuori finestra + if (!now.isBefore(endI)) { + assertNotAdvancing(unit, notAdvancingTolerance, + "Il probing sta avanzando DOPO la finestra attesa"); + return; + } + + // --- BEFORE: fuori finestra (non deve avanzare fino allo start) + if (now.isBefore(startI)) { + Duration untilStart = Duration.between(now, startI); + Duration observe = min(unit, untilStart.minus(boundaryBuffer)); + + if (!observe.isNegative() && !observe.isZero()) { + assertNotAdvancing(observe, notAdvancingTolerance, + "Il probing sta avanzando PRIMA della finestra attesa"); + } + + // best effort: prova a entrare in finestra al massimo entro 1 unit + waitUntil(startI, unit); + + now = Instant.now(); + if (!now.isBefore(endI)) { + // finestra scaduta durante l'attesa + return; + } + if (now.isBefore(startI)) { + // non siamo entrati (attesa cappata): stop qui + return; + } + } + + // --- INSIDE: siamo in finestra + now = Instant.now(); + if (now.isBefore(endI)) { + verifyInsideWindow(endI, now, unit, notAdvancingTolerance, tick, jitter); + + // --- STOP: aspetta end (max 1 unit) e poi non deve avanzare per 1 unit + waitUntil(endI, unit); + // assorbe eventuale update tardivo, poi verifica stabilità + assertStopsAfterEnd(unit, notAdvancingTolerance, + "Il probing non si è fermato stabilmente dopo endDate"); + } + } + + private void verifyInsideWindow( + Instant endI, + Instant now, + Duration unit, + Duration notAdvancingTolerance, + Duration tick, + Duration jitter + ) throws Exception { + + Duration untilEnd = Duration.between(now, endI); + if (untilEnd.isNegative() || untilEnd.isZero()) return; + + // Se manca meno di 1 unit alla fine finestra, non ha senso pretendere advancing: best effort + if (untilEnd.compareTo(unit) < 0) { + observeAndValidateInside(endI, untilEnd.plusSeconds(2), notAdvancingTolerance, + "Dentro finestra ma troppo vicini alla endDate per pretendere un update (unit=" + unit + ")"); + return; + } + + // Altrimenti: mi aspetto almeno 1 update entro 1 unit (tick + jitter) + assertAdvancingWithin(unit, + "Il probing non sta avanzando durante la finestra (atteso >=1 update entro 1 unit=" + unit + + ", tick=" + tick + ", jitter=" + jitter + ")"); + } + + + @Then("verifica che la responseReceived NON sia aggiornata quando probing è disabilitato") + public void assertSchedulerWhenProbingDisabled() throws Exception { + Duration observe = Duration.ofSeconds(30); + Duration tolerance = Duration.ofSeconds(2); + + assertNotAdvancing(observe, tolerance, "Il probing sta aggiornando anche se probingEnabled=false"); + } + + @And("la telemetria dell'e-service risulta aggiornata con successo") + public void assertTelemetry() { + EserviceRow row = probingContext.getActualEserviceRow(); + List actualTelemetry = probingContext.getActualTelemetry(); + + Assertions.assertThat(actualTelemetry) + .as("La telemetria dell'e-service non deve essere vuota") + .isNotEmpty() + .allSatisfy(t -> Assertions.assertThat(t).isNotNull()); + + for (TelemetryDataEserviceResponse t : actualTelemetry) { + + Assertions.assertThat(t.getPerformances()).as("performances non deve essere null").isNotNull(); + Assertions.assertThat(t.getFailures()).as("failures non deve essere null").isNotNull(); + Assertions.assertThat(t.getPercentages()).as("percentages non deve essere null").isNotNull(); + + boolean hasKoFailure = t.getFailures().stream() + .anyMatch(f -> f != null && "KO".equalsIgnoreCase(String.valueOf(f.getStatus()))); + + boolean hasOkPercentage = t.getPercentages().stream() + .anyMatch(p -> p != null && "OK".equalsIgnoreCase(String.valueOf(p.getStatus()))); + + // opzionale ma utile: performance “sensate” + boolean hasAnyPerformance = !t.getPerformances().isEmpty(); + boolean hasNonNegativeResponseTime = t.getPerformances().stream() + .filter(Objects::nonNull) + .allMatch(p -> p.getResponseTime() >= 0); + + Assertions.assertThat(hasNonNegativeResponseTime) + .as("responseTime deve essere >= 0 quando presente") + .isTrue(); + + // Pattern "tutto OK" + boolean looksLikeOk = !hasKoFailure && hasOkPercentage && hasAnyPerformance; + + // Pattern "tutto KO" (in questo caso non richiedo per forza percentages KO, perché non hai mostrato payload KO completo) + boolean looksLikeKo = hasKoFailure && !hasOkPercentage; + + switch (row.getOutcome()) { + case OK -> { + Assertions.assertThat(looksLikeOk) + .as("Outcome OK: mi aspetto un pattern coerente di successo (no KO failures + OK percentages + performances)") + .isTrue(); + } + case ERROR -> { + Assertions.assertThat(looksLikeKo) + .as("Outcome ERROR: mi aspetto un pattern coerente di KO (KO failures + no OK percentages)") + .isTrue(); + } + case RANDOM -> { + boolean mixed = hasKoFailure && hasOkPercentage; + + Assertions.assertThat(looksLikeOk || looksLikeKo || mixed) + .as("Outcome RANDOM: accetto pattern OK, KO oppure misto (potrei essere 'sfortunato' e beccare tutto OK o tutto KO)") + .isTrue(); + + Assertions.assertThat(hasAnyPerformance || !t.getFailures().isEmpty() || !t.getPercentages().isEmpty()) + .as("Outcome RANDOM: mi aspetto almeno un contenuto tra performances/failures/percentages") + .isTrue(); + } + default -> throw new IllegalStateException("Outcome non gestito: " + row.getOutcome()); + } + } + } + + @And("lo stato di probing dell'e-service viene aggiornato con valore {string}") + public void assertEserviceState(String eserviceState) { + EserviceStateBE stateBE = resolver.resolveEserviceStateBE(eserviceState); + EserviceRow actual = probingContext.getActualEserviceRow(); + + Assertions.assertThat(actual.getState()) + .as("Lo stato operativo dell'e-service non coincide con quello atteso") + .isEqualTo(stateBE.getValue()); + } + + private void assertNotAdvancing(Duration observe, Duration tolerance, String message) throws Exception { + Instant t1 = readLastResponseTime(); + TimeUnit.MILLISECONDS.sleep(observe.toMillis()); + Instant t2 = readLastResponseTime(); + + long deltaMillis = t2.toEpochMilli() - t1.toEpochMilli(); // niente abs + + Assertions.assertThat(deltaMillis) + .as(message + " (delta=" + deltaMillis + "ms, tolerance=" + tolerance.toMillis() + "ms)") + .isBetween(0L, tolerance.toMillis()); // non deve diminuire, né avanzare troppo + } + + private void assertAdvancingWithin(Duration observe, String message) throws Exception { + Instant t1 = readLastResponseTime(); + + long deadlineNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(observe.toMillis()); + long stepMillis = 1000L; // 1s step: frequency è in minuti, non serve più fitto + + while (System.nanoTime() < deadlineNanos) { + TimeUnit.MILLISECONDS.sleep(stepMillis); + Instant t2 = readLastResponseTime(); + if (t2.isAfter(t1)) { + return; + } + } + + Instant tFinal = readLastResponseTime(); + long deltaMillis = tFinal.toEpochMilli() - t1.toEpochMilli(); + Assertions.fail(message + " (delta=" + deltaMillis + "ms, observe=" + observe.toMillis() + "ms)"); + } + + private void observeAndValidateInside(Instant endI, Duration observe, Duration tolerance, String message) throws Exception { + Instant baseline = readLastResponseTime(); + + long deadlineNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(observe.toMillis()); + long stepMillis = 1000L; + + while (System.nanoTime() < deadlineNanos) { + TimeUnit.MILLISECONDS.sleep(stepMillis); + Instant current = readLastResponseTime(); + + if (current.isAfter(baseline)) { + // Se è avanzato, deve comunque non superare end (+ tolleranza) + Instant endPlusTol = endI.plusMillis(tolerance.toMillis()); + Assertions.assertThat(current) + .as(message + " (lastResponseTime avanzato ma oltre endDate)") + .isBeforeOrEqualTo(endPlusTol); + + baseline = current; // aggiorno baseline e continuo a osservare + } + } + } + + private void assertStopsAfterEnd(Duration unit, Duration tolerance, String message) throws Exception { + // Fase 1: assorbi un eventuale update tardivo (1 unit) + TimeUnit.MILLISECONDS.sleep(unit.toMillis()); + + // Fase 2: ora deve essere stabile per 1 unit + assertNotAdvancing(unit, tolerance, message); + } + + + private void waitUntil(Instant target, Duration maxWait) throws Exception { + Instant now = Instant.now(); + if (!now.isBefore(target)) return; + + long msToWait = target.toEpochMilli() - now.toEpochMilli(); + long capped = Math.min(msToWait, maxWait.toMillis()); + if (capped > 0) TimeUnit.MILLISECONDS.sleep(capped); + } + + private Duration min(Duration a, Duration b) { + return a.compareTo(b) <= 0 ? a : b; + } + + private Instant readLastResponseTime() { + Long eserviceRecordId = resolver.getEserviceRecordId(); + this.getEserviceMainData(String.valueOf(eserviceRecordId)); + this.getEserviceProbingData(String.valueOf(eserviceRecordId)); + + return probingContext.getLastResponseTime().toInstant(); + } + + private void assertResultsMatchFilters(SearchEserviceResponse response, ProbingUtils.EserviceFilters filters) { + List items = response.getContent(); + if (items == null || items.isEmpty()) return; // niente da validare + + // Se tutti i filtri sono null, non serve validare + if (filters.eserviceName() == null && isNullOrBlank(filters.producerName()) + && filters.versionNumber() == null && filters.states() == null) { + return; + } + + for (SearchEserviceContent item : items) { + Assertions.assertThat(matchesAllFilters(item, filters)) + .as("Risultato non coerente con filtri: item=%s, filters=%s", item, filters) + .isTrue(); + } + } + + private boolean isNullOrBlank(String value) { + return value == null || value.trim().isEmpty(); + } +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/EserviceRow.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/EserviceRow.java new file mode 100644 index 0000000000..7407c28c66 --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/EserviceRow.java @@ -0,0 +1,249 @@ +package it.pagopa.pn.interop.cucumber.steps.probing.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.util.List; +import java.util.UUID; + +import static it.pagopa.pn.interop.cucumber.steps.probing.utils.ProbingUtils.italyToday; + +@Getter +@Setter +@AllArgsConstructor +public class EserviceRow { + private Long id; + private UUID eserviceId; + private UUID versionId; + private String eserviceName; + private String producerName; + private String eserviceTechnology; // "REST" | "SOAP" + private List basePath; // nello script: array con 1 stringa + private List audience; + private String state; + private int versionNumber; + private int lockVersion; + private boolean probingEnabled; + private OffsetTime pollingStartTime; + private OffsetTime pollingEndTime; + private int pollingFrequency; + private Outcome outcome; + + public enum Outcome {OK, ERROR, RANDOM} + + // ------------------------ + // Costanti default (come nello script) + // ------------------------ + private static final OffsetTime POLLING_START_DEFAULT = italyToday(LocalTime.of(8, 0, 0)); + private static final OffsetTime POLLING_END_DEFAULT = italyToday(LocalTime.of(17, 0, 0)); + private static final int POLLING_FREQUENCY_DEFAULT = 15; + private static final boolean PROBING_ENABLED_DEFAULT = false; + + private static final String STATE_DEFAULT = "ACTIVE"; + private static final int VERSION_NUMBER_DEFAULT = 1; + private static final int LOCK_VERSION_DEFAULT = 0; + + private static final String REST_PREFIX = "/rest/interop/probing/"; + private static final String SOAP_PREFIX = "/soap/interop/probing/"; + + private static final String DEFAULT_BASE_HOST = "http://probing-be-eservice-mock.qa:8080"; + + // ------------------------ + // Convenience: stato endpoint + // ------------------------ + public boolean isOk() { + return outcome == Outcome.OK; + } + + public boolean isRandom() { + return outcome == Outcome.RANDOM; + } + + public boolean isKo() { + return outcome == Outcome.ERROR; + } // KO = ERROR + + // ------------------------ + // Factory methods + // ------------------------ + + /** + * Come nello script: outcome deterministico in base a i (gs) e ai count. + */ + public static EserviceRow atIndex(long i, int okCount, int errorCount, int randomCount, String baseHost) { + if (i <= 0) throw new IllegalArgumentException("Index i must be >= 1"); + int total = okCount + errorCount + randomCount; + if (total <= 0) throw new IllegalArgumentException("Total eservices count must be > 0"); + if (i > total) throw new IllegalArgumentException("Index i must be <= total (" + total + ")"); + + String resolvedHost = (baseHost == null || baseHost.isBlank()) ? DEFAULT_BASE_HOST : baseHost; + + UUID eserviceId = uuidFromLongSeed(i); + UUID versionId = uuidFromLongSeed(1_000_000_000L + i); + + String eserviceName = nameFromIndex(i); + String producerName = "Producer " + (((i - 1) % 50) + 1); + + // Script: CASE WHEN (gs % 2) = 0 THEN 'SOAP' ELSE 'REST' + boolean isEven = (i % 2) == 0; + String technology = isEven ? "SOAP" : "REST"; + + Outcome outcome = outcomeForIndex(i, okCount, errorCount); + + // Script: v_base_host + (/soap|/rest) + (ok|error|random) + '/status' + String endpointPrefix = isEven ? SOAP_PREFIX : REST_PREFIX; + String outcomePath = switch (outcome) { + case OK -> "ok"; + case ERROR -> "error"; + case RANDOM -> "random"; + }; + + List basePath = List.of( + resolvedHost + endpointPrefix + outcomePath + "/status" + ); + + List audience = List.of( + "AUD_" + (((i - 1) % 20) + 1) + ); + + return new EserviceRow( + i, + eserviceId, + versionId, + eserviceName, + producerName, + technology, + basePath, + audience, + STATE_DEFAULT, + VERSION_NUMBER_DEFAULT, + LOCK_VERSION_DEFAULT, + PROBING_ENABLED_DEFAULT, + POLLING_START_DEFAULT, + POLLING_END_DEFAULT, + POLLING_FREQUENCY_DEFAULT, + outcome + ); + } + + /** + * Restituisce un EserviceRow coerente con lo script dato l'Outcome richiesto. + * Usa il primo indice valido per quell'outcome. + */ + public static EserviceRow pickByOutcome( + Outcome outcome, + int okCount, + int errorCount, + int randomCount + ) { + int total = okCount + errorCount + randomCount; + if (total <= 0) { + throw new IllegalArgumentException("Total eservices count must be > 0"); + } + + long index; + + switch (outcome) { + case OK -> { + if (okCount <= 0) { + throw new IllegalArgumentException("No OK eservices available"); + } + index = 1L; + } + case ERROR -> { + if (errorCount <= 0) { + throw new IllegalArgumentException("No ERROR eservices available"); + } + index = 1L + okCount; + } + case RANDOM -> { + if (randomCount <= 0) { + throw new IllegalArgumentException("No RANDOM eservices available"); + } + index = 1L + okCount + errorCount; + } + default -> throw new IllegalStateException("Unsupported outcome: " + outcome); + } + + return atIndex(index, okCount, errorCount, randomCount, DEFAULT_BASE_HOST); + } + + + /** + * Overload "comodo": usa i default dello script per host e count. + * (Se vuoi, puoi anche rimuoverlo e forzare sempre i parametri.) + */ + public static EserviceRow atIndex(long i) { + // default come tuo script di esempio: ok=1, error=0, random=1 + return atIndex(i, 1, 0, 1, DEFAULT_BASE_HOST); + } + + public static EserviceRow fromName(String eserviceName, int okCount, int errorCount, int randomCount, String baseHost) { + return atIndex(indexFromName(eserviceName), okCount, errorCount, randomCount, baseHost); + } + + public static EserviceRow fromName(String eserviceName) { + return atIndex(indexFromName(eserviceName)); + } + + // ------------------------ + // Utilities pubbliche + // ------------------------ + + public static String nameFromIndex(long i) { + if (i <= 0) throw new IllegalArgumentException("Index i must be >= 1"); + return "ESVC-" + String.format("%08d", i); + } + + public static int indexFromName(String eserviceName) { + if (eserviceName == null) throw new IllegalArgumentException("Name is null"); + if (!eserviceName.matches("^ESVC-\\d{8}$")) { + throw new IllegalArgumentException("Invalid name format. Expected ESVC-XXXXXXXX (8 digits)."); + } + return Integer.parseInt(eserviceName.substring(5)); + } + + /** + * Replica della CASE dello script: + * WHEN gs <= okCount THEN ok + * WHEN gs <= okCount + errorCount THEN error + * ELSE random + */ + public static Outcome outcomeForIndex(long i, int okCount, int errorCount) { + if (i <= okCount) return Outcome.OK; + if (i <= (long) okCount + errorCount) return Outcome.ERROR; + return Outcome.RANDOM; + } + + // ------------------------ + // Replica di uuid_from_int(seed) + // ------------------------ + + private static UUID uuidFromLongSeed(long seed) { + String hex32 = md5Hex(Long.toString(seed)); // md5(seed::text) su Postgres + String uuidStr = + hex32.substring(0, 8) + "-" + + hex32.substring(8, 12) + "-" + + hex32.substring(12, 16) + "-" + + hex32.substring(16, 20) + "-" + + hex32.substring(20, 32); + return UUID.fromString(uuidStr); + } + + private static String md5Hex(String s) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(s.getBytes(StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(32); + for (byte b : digest) sb.append(String.format("%02x", b)); + return sb.toString(); + } catch (Exception e) { + throw new RuntimeException("MD5 not available", e); + } + } +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/ProbingContext.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/ProbingContext.java new file mode 100644 index 0000000000..c9fc7f8bef --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/ProbingContext.java @@ -0,0 +1,42 @@ +package it.pagopa.pn.interop.cucumber.steps.probing.model; + +import it.pagopa.interop.generated.openapi.clients.probing.model.SearchEserviceContent; +import it.pagopa.interop.generated.openapi.clients.probingStatistics.model.TelemetryDataEserviceResponse; +import lombok.Getter; +import lombok.Setter; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +@Getter +@Setter +public class ProbingContext{ + public static int ESERVICE_OK_COUNT = 10_000; + public static int ESERVICE_KO_COUNT = 5_000; + public static int ESERVICE_RANDOM_COUNT = 5_000; + public static int ESERVICE_SIZE = ESERVICE_OK_COUNT + ESERVICE_KO_COUNT + ESERVICE_RANDOM_COUNT; + + public static int SCHEDULER_INTERVAL = 3; + + final Integer threadNumber; + private static final AtomicInteger COUNTER = new AtomicInteger(0); + + private List actualResults; + private EserviceRow actualEserviceRow; + private EserviceRow expectedEserviceRow; + private OffsetDateTime lastResponseTime; + private List actualTelemetry = new ArrayList<>(); + private List expectedTelemetry = new ArrayList<>(); + + public ProbingContext() { + this.threadNumber = nextEserviceIndex(); + } + + private static int nextEserviceIndex() { + return COUNTER.updateAndGet(current -> + current >= ESERVICE_SIZE ? 1 : current + 1 + ); + } +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/ProbingResponse.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/ProbingResponse.java new file mode 100644 index 0000000000..280a5ccd0b --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/model/ProbingResponse.java @@ -0,0 +1,15 @@ +package it.pagopa.pn.interop.cucumber.steps.probing.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +@Getter +@Setter +@AllArgsConstructor +public class ProbingResponse { + private Integer probingFrequency; + private LocalDateTime lastResponseTime; +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/utils/ProbingResolver.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/utils/ProbingResolver.java new file mode 100644 index 0000000000..71bc1b4c0a --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/utils/ProbingResolver.java @@ -0,0 +1,171 @@ +package it.pagopa.pn.interop.cucumber.steps.probing.utils; + +import it.pagopa.interop.generated.openapi.clients.probing.model.EserviceStateBE; +import it.pagopa.pn.interop.cucumber.steps.m2m.common.utils.AbstractResolver; +import it.pagopa.pn.interop.cucumber.steps.probing.model.ProbingContext; +import it.pagopa.pn.interop.cucumber.utility.StepParser; +import lombok.RequiredArgsConstructor; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.util.UUID; + +@RequiredArgsConstructor +public class ProbingResolver extends AbstractResolver { + + private final ProbingContext probingContext; + + public UUID resolveEserviceId(String raw) { + return resolveOrParse( + raw, + StepParser::uuidOrRandomOrNull, + () -> probingContext.getActualEserviceRow().getEserviceId(), + () -> probingContext.getExpectedEserviceRow().getEserviceId(), + UUID::randomUUID, + null + ); + } + + public UUID resolveVersionId(String raw) { + return resolveOrParse( + raw, + StepParser::uuidOrRandomOrNull, + () -> probingContext.getActualEserviceRow().getVersionId(), + () -> probingContext.getExpectedEserviceRow().getVersionId(), + UUID::randomUUID, + null + ); + } + + public Long resolveEserviceRecordId(String raw) { + return resolveOrParse( + raw, + StepParser::longOrRandomOrNull, + this::getEserviceRecordId, + this::getEserviceRecordId, + () -> 1L + (long) (Math.random() * Long.MAX_VALUE), + null + ); + } + + public String resolveEserviceName(String raw) { + return resolveOrParse( + raw, + v -> v, // non token: ritorna raw + () -> probingContext.getActualEserviceRow().getEserviceName(), + () -> probingContext.getExpectedEserviceRow().getEserviceName(), + null, + () -> "" + ); + } + + public String resolveProducer(String raw) { + return resolveOrParse( + raw, + v -> v, + () -> probingContext.getActualEserviceRow().getProducerName(), + () -> probingContext.getExpectedEserviceRow().getProducerName(), + null, + () -> "" + ); + } + + public EserviceStateBE resolveEserviceStateBE(String raw) { + return resolveOrParse( + raw, + v -> v == null ? null : EserviceStateBE.fromValue(v), + () -> EserviceStateBE.fromValue(probingContext.getActualEserviceRow().getState()), + () -> EserviceStateBE.fromValue(probingContext.getExpectedEserviceRow().getState()), + null, + null + ); + } + + public Long getEserviceRecordId() { + return probingContext.getActualEserviceRow().getId(); + } + + public Integer resolveFrequency(String raw) { + if (raw == null) return null; + + // 1) delta (+N / -N) + int delta = resolveIntegerDelta(raw); + + // 2) parte base (prima di + / -) -> se non c'è operatore resta tutta la stringa + String basePart = raw; + int plusIdx = raw.indexOf('+'); + int minusIdx = raw.indexOf('-', 1); // evita il "-" iniziale tipo "-1" + int opIdx = plusIdx >= 0 ? plusIdx : minusIdx; + if (opIdx >= 0) { + basePart = raw.substring(0, opIdx).trim(); + } + + // 3) risolvi base: token -> actual/expected/random/null, altrimenti parse int + Integer baseValue = resolveOrParse( + basePart, + StepParser::intOrRandomOrNull, // NON token + () -> probingContext.getActualEserviceRow().getPollingFrequency(), + () -> probingContext.getExpectedEserviceRow().getPollingFrequency(), + ProbingResolver::randomPositiveInt, + null + ); + + // 4) applica delta + if (baseValue == null) return null; + return baseValue + delta; + } + + public Duration resolveSchedulerInterval(String row) { + String normalizedRow = StepParser.normalize(row); + return Duration.ofMinutes(normalizedRow == null ? ProbingContext.SCHEDULER_INTERVAL : Integer.parseInt(row)); + } + + private static int randomPositiveInt() { + return 1 + (int) (Math.random() * Integer.MAX_VALUE); + } + + public OffsetTime resolvePollingStartTime(String raw) { + return resolveOrParse( + raw, + v -> { + OffsetDateTime dt = StepParser.dateTimeOrNull(v); + return dt == null ? null : ProbingUtils.italyToday(dt.toLocalTime()); + }, + () -> probingContext.getActualEserviceRow().getPollingStartTime(), + () -> probingContext.getExpectedEserviceRow().getPollingStartTime() + ); + } + + public OffsetTime resolvePollingEndTime(String raw) { + return resolveOrParse( + raw, + v -> { + OffsetDateTime dt = StepParser.dateTimeOrNull(v); + return dt == null ? null : ProbingUtils.italyToday(dt.toLocalTime()); + }, + () -> probingContext.getActualEserviceRow().getPollingEndTime(), + () -> probingContext.getExpectedEserviceRow().getPollingEndTime() + ); + } + + + private Integer resolveIntegerDelta(String raw) { + if (raw == null) return 0; + + String token = raw.trim(); + + int plusIdx = token.indexOf('+'); + int minusIdx = token.indexOf('-', 1); + + if (plusIdx > -1) { + return Integer.parseInt(token.substring(plusIdx + 1).trim()); + } + + if (minusIdx > -1) { + return -Integer.parseInt(token.substring(minusIdx + 1).trim()); + } + + return 0; + } +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/utils/ProbingUtils.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/utils/ProbingUtils.java new file mode 100644 index 0000000000..ccb3d0f6ed --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/probing/utils/ProbingUtils.java @@ -0,0 +1,68 @@ +package it.pagopa.pn.interop.cucumber.steps.probing.utils; + +import it.pagopa.interop.generated.openapi.clients.probing.model.EserviceStateFE; +import it.pagopa.interop.generated.openapi.clients.probing.model.SearchEserviceContent; + +import java.time.*; +import java.util.List; + +public class ProbingUtils { + + private static final ZoneId ROME = ZoneId.of("Europe/Rome"); + + public record EserviceFilters(String eserviceName, String producerName, Integer versionNumber, + List states) { + } + + public static OffsetTime italyToday(LocalTime time) { + // “oggi” secondo l’Italia + LocalDate todayRome = LocalDate.now(ROME); + + // offset corretto per oggi in Italia (CET/CEST) + ZoneOffset offset = ZonedDateTime.of(todayRome, time, ROME).getOffset(); + + return OffsetTime.of(time.withNano(0), offset); + } + + public static boolean matchesAllFilters(SearchEserviceContent item, EserviceFilters f) { + if (item == null) return false; + + if (f.eserviceName() != null) { + String actual = safeTrim(item.getEserviceName()); + String expected = safeTrim(f.eserviceName()); + if (!containsIgnoreCase(actual, expected)) return false; + } + + if (f.producerName() != null) { + String actual = safeTrim(item.getProducerName()); + String expected = safeTrim(f.producerName()); + if (!equalsIgnoreCase(actual, expected)) return false; + } + + if (f.versionNumber() != null) { + Integer actual = item.getVersionNumber(); + if (actual == null || !actual.equals(f.versionNumber())) return false; + } + + if (f.states() != null && !f.states().isEmpty()) { + EserviceStateFE actual = item.getState(); + return actual != null && f.states().contains(actual); + } + + return true; + } + + private static String safeTrim(String s) { + return s == null ? null : s.trim(); + } + + private static boolean equalsIgnoreCase(String a, String b) { + if (a == null || b == null) return false; + return a.equalsIgnoreCase(b); + } + + private static boolean containsIgnoreCase(String a, String b) { + if (a == null || b == null) return false; + return a.toLowerCase().contains(b.toLowerCase()); + } +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purpose/PurposeRiskAnalysisDocumentDownloadSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purpose/PurposeRiskAnalysisDocumentDownloadSteps.java index 20bac0c594..2b6667673b 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purpose/PurposeRiskAnalysisDocumentDownloadSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purpose/PurposeRiskAnalysisDocumentDownloadSteps.java @@ -10,10 +10,9 @@ import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeVersionDocument; import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeVersionSeed; import it.pagopa.interop.purpose.domain.CreatedEserviceVersion; -import it.pagopa.interop.utils.HttpCallExecutor; import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; -import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; +import it.pagopa.pn.interop.cucumber.steps.datapreparationservice.BFFDataPreparationService; import it.pagopa.pn.interop.cucumber.utility.CommonUtils; import org.junit.jupiter.api.Assertions; diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purposetemplate/PurposeTemplateSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purposetemplate/PurposeTemplateSteps.java index 30f738e5e2..be8453d5de 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purposetemplate/PurposeTemplateSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/purposetemplate/PurposeTemplateSteps.java @@ -1,53 +1,16 @@ package it.pagopa.pn.interop.cucumber.steps.purposetemplate; -import static org.assertj.core.api.Assertions.assertThat; - import io.cucumber.java.en.And; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import it.pagopa.interop.authorization.service.utils.PollingService; import it.pagopa.interop.common.IHttpExecutor; -import it.pagopa.interop.generated.openapi.clients.bff.model.Agreement; -import it.pagopa.interop.generated.openapi.clients.bff.model.CatalogPurposeTemplates; -import it.pagopa.interop.generated.openapi.clients.bff.model.CompactPurposeTemplateEService; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatedResource; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatorPurposeTemplate; -import it.pagopa.interop.generated.openapi.clients.bff.model.CreatorPurposeTemplates; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDescriptorPurposeTemplateWithCompactEServiceAndDescriptor; -import it.pagopa.interop.generated.openapi.clients.bff.model.EServiceDescriptorsPurposeTemplate; -import it.pagopa.interop.generated.openapi.clients.bff.model.InlineObject2; -import it.pagopa.interop.generated.openapi.clients.bff.model.InlineObject3; -import it.pagopa.interop.generated.openapi.clients.bff.model.PatchPurposeUpdateFromTemplateContent; -import it.pagopa.interop.generated.openapi.clients.bff.model.Purpose; -import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeFromTemplateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeTemplate; -import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeTemplateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeTemplateState; -import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeTemplateWithCompactCreator; -import it.pagopa.interop.generated.openapi.clients.bff.model.PurposeVersionState; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisFormSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisFormTemplate; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisFormTemplateSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisTemplateAnswer; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisTemplateAnswerAnnotation; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisTemplateAnswerAnnotationDocument; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisTemplateAnswerAnnotationSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisTemplateAnswerRequest; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisTemplateAnswerResponse; -import it.pagopa.interop.generated.openapi.clients.bff.model.RiskAnalysisTemplateAnswerSeed; -import it.pagopa.interop.generated.openapi.clients.bff.model.TargetTenantKind; +import it.pagopa.interop.generated.openapi.clients.bff.model.*; import it.pagopa.interop.purpose.service.IPurposeApiClient; import it.pagopa.interop.purpose.service.IPurposeTemplateClient; import it.pagopa.pn.interop.cucumber.steps.ClientTokenConfigurator; import it.pagopa.pn.interop.cucumber.steps.SharedStepsContext; import it.pagopa.pn.interop.cucumber.utility.BlobFileCreator; -import java.io.File; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Stream; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -55,6 +18,12 @@ import org.springframework.core.io.Resource; import org.springframework.http.HttpStatus; +import java.io.File; +import java.util.*; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + @Slf4j public class PurposeTemplateSteps { @@ -360,10 +329,10 @@ public void linkPurposeTemplateToEservice(boolean exists) { UUID eServiceId = sharedStepsContext.getEServicesCommonContext().getEserviceId(); UUID ptId = exists ? createdPurposeTemplate.getId() : UUID.randomUUID(); - InlineObject2 inlineObject = new InlineObject2(); - inlineObject.setEserviceId(eServiceId); + LinkEServiceToPurposeTemplateRequest request = new LinkEServiceToPurposeTemplateRequest(); + request.setEserviceId(eServiceId); - httpCallExecutor.performCall(() -> purposeTemplateClient.linkEServiceToPurposeTemplate(ptId, inlineObject)); + httpCallExecutor.performCall(() -> purposeTemplateClient.linkEServiceToPurposeTemplate(ptId, request)); } @Then("si effettua la get degli e-service associati al purpose template {exists}") @@ -412,10 +381,10 @@ public void unlinkPurposeTemplateToEservice(boolean exists) { UUID ptId = exists ? createdPurposeTemplate.getId() : UUID.randomUUID(); - InlineObject3 o3 = new InlineObject3(); - o3.setEserviceId(eServiceId); + LinkEServiceToPurposeTemplateRequest request = new LinkEServiceToPurposeTemplateRequest(); + request.setEserviceId(eServiceId); - httpCallExecutor.performCall(() -> purposeTemplateClient.unlinkEServiceToPurposeTemplate(ptId, o3)); + httpCallExecutor.performCall(() -> purposeTemplateClient.unlinkEServiceToPurposeTemplate(ptId, request)); if (exists) { if (httpCallExecutor.getResponseStatus().is2xxSuccessful()) { pollingService.makePolling( diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/tracing/TracingSteps.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/tracing/TracingSteps.java index 9d29b65c49..a8fb644cba 100644 --- a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/tracing/TracingSteps.java +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/steps/tracing/TracingSteps.java @@ -6,12 +6,7 @@ import io.cucumber.java.en.When; import it.pagopa.interop.authorization.service.utils.PollingService; import it.pagopa.interop.authorization.service.utils.SettableBearerToken; -import it.pagopa.interop.client.b2b.generated.openapi.clients.interop.tracing.model.GetTracingErrorsResponse; -import it.pagopa.interop.client.b2b.generated.openapi.clients.interop.tracing.model.GetTracingErrorsResponseResults; -import it.pagopa.interop.client.b2b.generated.openapi.clients.interop.tracing.model.GetTracingsResponse; -import it.pagopa.interop.client.b2b.generated.openapi.clients.interop.tracing.model.GetTracingsResponseResults; -import it.pagopa.interop.client.b2b.generated.openapi.clients.interop.tracing.model.SubmitTracingResponse; -import it.pagopa.interop.client.b2b.generated.openapi.clients.interop.tracing.model.TracingState; +import it.pagopa.interop.client.b2b.generated.openapi.clients.interop.tracing.model.*; import it.pagopa.interop.tracing.service.IInteropTracingClient; import it.pagopa.pn.interop.cucumber.utility.TracingFileUtils; import org.junit.jupiter.api.Assertions; @@ -39,7 +34,6 @@ public class TracingSteps { /** * Dependency injection - * @param pnPollingFactory {@link PnPollingFactory} * @param interopTracingClient {@link IInteropTracingClient} * @param tracingFileUtils {@link TracingFileUtils} * @param pollingService {@link PollingService} @@ -65,7 +59,7 @@ public void updateCsv() { selectOperator("tenant1"); GetTracingsResponse tracingsResponse = interopTracingClient.getTracings(OFFSET_VALUE, LIMIT_VALUE, null); submissionDate = tracingsResponse.getResults().stream() - .map(GetTracingsResponseResults::getDate) + .map(GetTracingsResponseResultsInner::getDate) .min(LocalDate::compareTo) .map(date -> date.minusDays(1)) .orElseGet(() -> LocalDate.now().minusDays(1)); @@ -146,7 +140,7 @@ private void getTracingErrors(UUID tracingId) { public void verifyGetTracingErrorResponse() { Assertions.assertNotNull(getTracingErrorsResponse, "There was an error while retrieving the tracing error!"); Assertions.assertNotNull(getTracingErrorsResponse.getResults()); - List expectedResult = List.of( + List expectedResult = List.of( createExpectedResponse("INVALID_STATUS_CODE", "status: Invalid HTTP status code", "0e1e4c98-6f2e-4f55-90e3-45f7d3f1dbf8", 1), createExpectedResponse("INVALID_DATE", String.format("date: Date field (2024-08-25) in csv is different from tracing date (%s).", submissionDate.toString()), "0e1e4c98-6f2e-4f55-90e3-45f7d3f1dbf8", 1), createExpectedResponse("PURPOSE_NOT_FOUND", "purpose_id: Invalid purpose id 0e1e4c98-6f2e-4f55-90e3-45f7d3f1dbf8.", "0e1e4c98-6f2e-4f55-90e3-45f7d3f1dbf8", 1), @@ -182,7 +176,7 @@ private void recoverError(String tracingId, Resource resource) { public void checkReturnedTracingId() { Assertions.assertTrue(getTracingsResponse.getResults() .stream() - .map(GetTracingsResponseResults::getTracingId) + .map(GetTracingsResponseResultsInner::getTracingId) .anyMatch(tracingId -> tracingId.equals(submitTracingResponse.getTracingId().toString()))); } @@ -215,7 +209,7 @@ public void getHealthStatus() { public void recoverMissingCsvForDate(String fileType) { Assertions.assertNotNull(getTracingsResponse, "There was an error while retrieving the tracing with MISSING status!"); Assertions.assertFalse(getTracingsResponse.getResults().isEmpty(), "No tracing with MISSING status found!"); - GetTracingsResponseResults tracingsResponseResults = getTracingsResponse.getResults().get(0); + GetTracingsResponseResultsInner tracingsResponseResults = getTracingsResponse.getResults().get(0); tracingFileUtils.updateCsv(tracingsResponseResults.getDate()); submissionDate = tracingsResponseResults.getDate(); uploadCsv(fileType); @@ -227,7 +221,7 @@ public void waitForStatus(String state) { () -> interopTracingClient.getTracings(0, 50, List.of(TracingState.fromValue(state))), res -> res.getResults().stream() .filter(x -> x.getTracingId().equals(submitTracingResponse.getTracingId().toString())) - .map(GetTracingsResponseResults::getState) + .map(GetTracingsResponseResultsInner::getState) .anyMatch(tracingState -> tracingState.equals(state)), String.format("The TracingId: %s did not reach the desired status: %s", submitTracingResponse.getTracingId().toString(), state) ); @@ -235,7 +229,7 @@ public void waitForStatus(String state) { @Then("viene recuperato il file di tracing appena caricato e si verifica che lo stato sia {string}") public void retrieveTracingAndVerifyStatus(String state) { - GetTracingsResponseResults result; + GetTracingsResponseResultsInner result; int attempt = 0; int totalPages; try { @@ -267,8 +261,8 @@ public void retrieveTracingAndVerifyStatus(String state) { } - private GetTracingErrorsResponseResults createExpectedResponse(String errorCode, String message, String purposeId, Integer rowNumber) { - GetTracingErrorsResponseResults tracingErrorsResponse = new GetTracingErrorsResponseResults(); + private GetTracingErrorsResponseResultsInner createExpectedResponse(String errorCode, String message, String purposeId, Integer rowNumber) { + GetTracingErrorsResponseResultsInner tracingErrorsResponse = new GetTracingErrorsResponseResultsInner(); tracingErrorsResponse.setErrorCode(errorCode); tracingErrorsResponse.setMessage(message); tracingErrorsResponse.setPurposeId(purposeId); diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/utility/StepParser.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/utility/StepParser.java new file mode 100644 index 0000000000..a9887cc3b8 --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/utility/StepParser.java @@ -0,0 +1,204 @@ +package it.pagopa.pn.interop.cucumber.utility; + +import it.pagopa.pn.interop.cucumber.utility.enums.ResolvableToken; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Function; +import java.util.function.Supplier; + +public final class StepParser { + private StepParser() { + } + + public static String normalize(String value) { + if (value == null) return null; + + String v = value.trim(); + ResolvableToken token = ResolvableToken.from(v); + + if (token == ResolvableToken.NULL) return null; + if (token == ResolvableToken.BLANK) return ""; + return v; + } + + private static T parseCore(String value, boolean safe, Supplier randomSupplier, Function parser) { + String v = normalize(value); + if (v == null) return null; + + ResolvableToken token = ResolvableToken.from(v); + + try { + if (token == ResolvableToken.RANDOM && randomSupplier != null) { + return randomSupplier.get(); + } + return parser.apply(v); + } catch (RuntimeException ex) { + if (safe) return null; + throw ex; + } + } + + private static List parseSingletonListCore(String raw, boolean safe, Supplier randomSupplier, Function parser) { + T v = parseCore(raw, safe, randomSupplier, parser); + if (v == null) return null; + + ResolvableToken token = ResolvableToken.from(raw); + if (token == null) return List.of(v); + + List result = new ArrayList<>(); + result.add(null); + + return switch (token) { + case EMPTY_LIST -> List.of(); + case NULL_ELEMENT_LIST -> result; + default -> throw new IllegalArgumentException("Unknown token: " + token); + }; + } + + public static String nullOrBlankOrValue(String value) { + return normalize(value); + } + + public static String nullOrValue(String value) { + String v = normalize(value); + return (v == null || v.isBlank()) ? null : v; + } + + public static T parseNullable(String value, Function parser) { + return parseCore(value, false, null, parser); + } + + public static T parseNullableSafe(String value, Function parser) { + return parseCore(value, true, null, parser); + } + + public static Integer nullableInteger(String value) { + return parseCore(value, true, null, Integer::valueOf); + } + + public static Boolean nullableBoolean(String value) { + return parseCore(value, false, null, Boolean::parseBoolean); + } + + public static UUID uuidOrRandomOrNull(String value) { + return parseCore(value, true, UUID::randomUUID, UUID::fromString); + } + + public static Integer intOrRandomOrNull(String value) { + return parseCore(value, true, () -> ThreadLocalRandom.current().nextInt(), Integer::parseInt); + } + + public static Long longOrRandomOrNull(String value) { + return parseCore(value, true, () -> ThreadLocalRandom.current().nextLong(), Long::parseLong); + } + + public static List singletonListNullable(String value, Function mapper) { + return parseCore( + value, + true, + null, + raw -> { + ResolvableToken token = ResolvableToken.from(raw); + + if (token != null) { + List nullElementList = new ArrayList<>(); + nullElementList.add(null); + + if (token == ResolvableToken.EMPTY_LIST) return List.of(); + if (token == ResolvableToken.NULL_ELEMENT_LIST) return nullElementList; + throw new IllegalStateException("Token non gestito: " + token); + } + + return List.of(mapper.apply(raw)); + }); + } + + public static List singletonFilterList( + String value, + Supplier expectedSupplier, + Supplier actualSupplier, + Function mapper + ) { + return parseCore( + value, + true, + null, + raw -> { + ResolvableToken token = ResolvableToken.from(raw); + + // non-token: mappa il valore e mettilo in lista + if (token == null) { + return List.of(mapper.apply(raw)); + } + + // token generali da filtro + if (token == ResolvableToken.NULL) return null; + if (token == ResolvableToken.BLANK) return null; + if (token == ResolvableToken.EXPECTED) { + return expectedSupplier != null ? List.of(expectedSupplier.get()) : null; + } + if (token == ResolvableToken.ACTUAL) { + return actualSupplier != null ? List.of(actualSupplier.get()) : null; + } + + // token specifici liste + if (token == ResolvableToken.EMPTY_LIST) return List.of(); + + if (token == ResolvableToken.NULL_ELEMENT_LIST) { + return java.util.Collections.singletonList(null); + } + + throw new IllegalStateException("Token non gestito: " + token); + } + ); + } + + public static Duration durationOrNull(String s) { + String normalized = normalize(s); + if (normalized == null) return null; + + s = normalized.trim().toLowerCase(Locale.ROOT); + if (s.endsWith("ms")) return Duration.ofMillis(Long.parseLong(s.substring(0, s.length() - 2))); + if (s.endsWith("s")) return Duration.ofSeconds(Long.parseLong(s.substring(0, s.length() - 1))); + if (s.endsWith("m")) return Duration.ofMinutes(Long.parseLong(s.substring(0, s.length() - 1))); + if (s.endsWith("h")) return Duration.ofHours(Long.parseLong(s.substring(0, s.length() - 1))); + return Duration.parse(s); + } + + public static OffsetDateTime dateTimeOrNull(String raw) { + raw = normalize(raw); + if (raw == null) return null; + + String token = raw.trim(); + String lower = token.toLowerCase(); + + OffsetDateTime now = OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS); + if (lower.equals("now")) return now; + + // now+ / now- con suffisso h/m/s + if (lower.startsWith("now+") || lower.startsWith("now-")) { + boolean plus = lower.charAt(3) == '+'; + String amountPart = lower.substring(4); // es: "15s", "2h", "10m" + + char unit = amountPart.charAt(amountPart.length() - 1); + long value = Long.parseLong(amountPart.substring(0, amountPart.length() - 1)); + + return switch (unit) { + case 'h' -> plus ? now.plusHours(value) : now.minusHours(value); + case 'm' -> plus ? now.plusMinutes(value) : now.minusMinutes(value); + case 's' -> plus ? now.plusSeconds(value) : now.minusSeconds(value); + default -> throw new IllegalArgumentException("Unità non supportata nel token: " + token); + }; + } + + return OffsetDateTime.parse(token); + } + +} diff --git a/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/utility/enums/ResolvableToken.java b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/utility/enums/ResolvableToken.java new file mode 100644 index 0000000000..4b8afaf05e --- /dev/null +++ b/interop-qa-tests/src/test/java/it/pagopa/pn/interop/cucumber/utility/enums/ResolvableToken.java @@ -0,0 +1,35 @@ +package it.pagopa.pn.interop.cucumber.utility.enums; + +public enum ResolvableToken { + ACTUAL("%actual"), + NULL("%null"), + EXPECTED("%expected"), + RANDOM("%random"), + BLANK("%blank"), + + EMPTY_LIST("%empty_list"), + NULL_ELEMENT_LIST("%null_element_list"); + + private final String value; + + ResolvableToken(String value) { + this.value = value; + } + + public String value() { + return value; + } + + public static ResolvableToken from(String raw) { + if (raw == null) return null; + + String normalized = raw.trim().toLowerCase(); + for (ResolvableToken token : values()) { + if (token.value.equals(normalized)) { + return token; + } + } + return null; + } +} + diff --git a/interop-qa-tests/src/test/resources/it/pagopa/pn/cucumber/probing/probing.feature b/interop-qa-tests/src/test/resources/it/pagopa/pn/cucumber/probing/probing.feature new file mode 100644 index 0000000000..a0843f6b0b --- /dev/null +++ b/interop-qa-tests/src/test/resources/it/pagopa/pn/cucumber/probing/probing.feature @@ -0,0 +1,296 @@ +Feature: Probing + + Scenario Outline: [GET_STATUS] - Health probing-ms check + Given il microservizio risulta attivo + Then la response riporta lo status code 200 + + Examples: + | ms | + | "probing-api" | + | "probing-statistics-api" | + + Scenario Outline: [GET_ESERVICES_CATALOG] - Consultazione e-service presenti nel catalogo probing (multi-filtro) + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When vengono recuperati dal catalogo gli e-service con limit "" e offset "" e filtri eserviceName "", producerName "", versionNumber "", state "" + Then la response riporta lo status code + + Examples: + # --- Baseline / boundaries (no filters) --- + | limit | offset | eserviceName | producerName | versionNumber | state | statusCode | + | 10 | 0 | %null | %null | %null | %null | 200 | + | 1 | 0 | %null | %null | %null | %null | 200 | + | 100 | 0 | %null | %null | %null | %null | 200 | + + # --- Single filter --- + | 10 | 0 | %expected | %null | %null | %null | 200 | + | 10 | 0 | %null | %expected | %null | %null | 200 | + | 10 | 0 | %null | %null | 1 | %null | 200 | + | 10 | 0 | %null | %null | %null | ACTIVE | 200 | + + # --- Multi-filter (AND) --- + | 10 | 0 | %expected | %expected | %null | %null | 200 | + | 10 | 0 | %null | %expected | 1 | %null | 200 | + | 10 | 0 | %expected | %expected | 1 | ACTIVE | 200 | + + # --- Required params missing --- + | %null | 0 | %null | %null | %null | %null | 400 | + | 10 | %null | %null | %null | %null | %null | 400 | + + # --- Pagination invalid values --- + | 0 | 0 | %null | %null | %null | %null | 400 | + | 101 | 0 | %null | %null | %null | %null | 400 | + | 10 | -1 | %null | %null | %null | %null | 400 | + + # --- Filter values edge cases (%blank treated as no filter) --- + | 10 | 0 | %blank | %null | %null | %null | 200 | + | 10 | 0 | %null | %blank | %null | %null | 200 | + + # --- versionNumber invalid --- + | 10 | 0 | %null | %null | 0 | %null | 400 | + | 10 | 0 | %null | %null | -1 | %null | 400 | + + Scenario Outline: [UPDATE_FREQUENCY] - Aggiornamento frequency e finestra temporale per e-service + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When vengono aggiornati i parametri di probing dell'e-service con eserviceId "" e versionId "" impostando frequency "", startDate "", endDate "" e si verifica che coincidano con quanto atteso + Then la response riporta lo status code + + Examples: + # Happy paths + | eserviceId | versionId | frequency | startDate | endDate | statusCode | + | %actual | %actual | %actual | %actual | %actual | 204 | + | %actual | %actual | %actual+10 | %actual | %actual | 204 | + | %actual | %actual | %actual | now+1h | now+2h | 204 | + + # Frequency invalid + | %actual | %actual | -1 | %actual | %actual | 400 | + | %actual | %actual | 0 | %actual | %actual | 400 | + + # Window invalid + | %actual | %actual | %actual | now+2h | now+1h | 400 | + | %actual | %actual | %actual | %null | now+2h | 400 | + | %actual | %actual | %actual | now+1h | %null | 400 | + + # Not found (wrong ids) + | %null | %actual | %actual | %actual | %actual | 400 | + | %actual | %null | %actual | %actual | %actual | 400 | + | %random | %actual | %actual | %actual | %actual | 404 | + | %actual | %random | %actual | %actual | %actual | 404 | + + Scenario Outline: [UPDATE_PROBING_STATE] - Modifica stato di probing con combinazioni id/versione + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When viene modificato lo stato di probing dell'e-service con id "" e id versione "" in "" e si verifica che coincida con quanto atteso + Then la response riporta lo status code + + Examples: + # Happy paths + | eserviceId | versionId | probingEnabled | statusCode | + | %actual | %actual | true | 204 | + | %actual | %actual | false | 204 | + + # ProbingEnabled invalid + | %actual | %actual | %null | 400 | + + # eserviceId/versionId invalid + | %actual | %null | true | 400 | + | %null | %actual | true | 400 | + + # Not found (wrong ids) + | %actual | %random | true | 404 | + | %random | %actual | true | 404 | + + Scenario Outline: [UPDATE_OPERATIONAL_STATE] - Modifica stato operativo con combinazioni id/versione + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When viene modificato lo stato operativo dell'e-service con id "" e id versione "" in "" e si verifica che coincida con quanto atteso + Then la response riporta lo status code + + Examples: + # Happy paths + | eserviceId | versionId | eserviceState | statusCode | + | %actual | %actual | ACTIVE | 204 | + | %actual | %actual | INACTIVE | 204 | + + # EserviceState invalid + | %actual | %actual | %null | 400 | + + # eserviceId/versionId invalid + | %actual | %null | ACTIVE | 400 | + | %null | %actual | ACTIVE | 400 | + + # Not found (wrong ids) + | %actual | %random | ACTIVE | 404 | + | %random | %actual | ACTIVE | 404 | + + Scenario Outline: [GET_PRODUCERS] - Recupero lista producers con paginazione + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When recupero la lista dei producers con limit "" e offset "" e producerName "" + Then la response riporta lo status code + + Examples: + # Happy paths + | limit | offset | producer | statusCode | + | 30 | 0 | %expected | 200 | + | 1 | 0 | %expected | 200 | + | 100 | 0 | %expected | 200 | + | 30 | 10 | %expected | 200 | + | 30 | 0 | %null | 200 | + | 30 | 0 | %blank | 200 | + + # Required params missing + | %null | 0 | %expected | 400 | + | 10 | %null | %expected | 400 | + + # Pagination invalid values + | 0 | 0 | %expected | 400 | + | -1 | 0 | %expected | 400 | + | 101 | 0 | %expected | 400 | + | 10 | -1 | %expected | 400 | + | 0 | -1 | %expected | 400 | + + # producerName edge cases (should not 400) + | 30 | 0 | NOT_EXISTING_PRODUCER | 200 | + + Scenario Outline: [GET_ESERVICE_MAIN_DATA] - Recupera i metadati anagrafici di un e-service tramite il suo eserviceRecordId + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When vengono recuperati i main data dell'e-service con eserviceRecordId "" + Then la response riporta lo status code + + Examples: + | eserviceRecordId | statusCode | + | %actual | 200 | + | %null | 400 | + | -1 | 400 | + | %random | 404 | + + Scenario Outline: [GET_ESERVICE_PROBING_DATA] - Recupera i dati di probing di un e-service tramite il suo eserviceRecordId + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When vengono recuperati i dati di probing dell'e-service con eserviceRecordId "" + Then la response riporta lo status code + + Examples: + | eserviceRecordId | statusCode | + | %actual | 200 | + | %null | 400 | + | -1 | 400 | + | %random | 404 | + + # NOTA: Lo status code 200 è previsto anche per il caso di un eserviceRecordId random per i motivi descritti nel ticket + # https://pagopa.atlassian.net/browse/PIN-9090 + Scenario Outline: [GET_ESERVICE_PUBLIC_TELEMETRY] - Recupera la telemetria pubblica di un e-service tramite il suo eserviceRecordId + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When viene recuperata la telemetria pubblica dell'e-service con eserviceRecordId "" e pollingFrequency "" + Then la response riporta lo status code + + Examples: + # Happy paths + | eserviceRecordId | frequency | statusCode | + | %actual | %actual | 200 | + | %random | %actual | 200 | + + # Frequency invalid values + | %actual | %null | 400 | + | %actual | -1 | 400 | + + # eserviceRecordId invalid values + | %null | %actual | 400 | + + # NOTA: Lo status code 200 è previsto anche per il caso di un eserviceRecordId random per i motivi descritti nel ticket + # https://pagopa.atlassian.net/browse/PIN-9090 + Scenario Outline: [GET_ESERVICE_TELEMETRY] - Recupera la telemetria di un e-service tramite il suo eserviceRecordId e filtro temporale + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When viene recuperata la telemetria dell'e-service con eserviceRecordId "" e impostando pollingFrequency "" , startDate "" , endDate "" + Then la response riporta lo status code + + Examples: + # Happy paths + | eserviceRecordId | frequency | startDate | endDate | statusCode | + | %actual | %actual | now-20h | now-10h | 200 | + | %random | %actual | now-20h | now-10h | 200 | + + # eserviceRecordId invalid values + | %null | %actual | now-20h | now-10h | 400 | + | -1 | %actual | now-20h | now-10h | 400 | + + # frequency invalid values + | %actual | %null | now-20h | now-10h | 400 | + | %actual | -1 | now-20h | now-10h | 400 | + + # startDate invalid values + | %actual | %actual | %null | now-10h | 400 | + + # endDate invalid values + | %actual | %actual | now-20h | %null | 400 | + + Scenario Outline: [SCHEDULING] - Update frequency aggiorna lo scheduling + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + When vengono aggiornati i parametri di probing dell'e-service con eserviceId "%expected" e versionId "%expected" impostando frequency "", startDate "", endDate "" e si verifica che coincidano con quanto atteso + And viene modificato lo stato di probing dell'e-service con id "%expected" e id versione "%expected" in "true" e si verifica che coincida con quanto atteso + Then verifica che la responseReceived sia aggiornata coerentemente rispetto la frequency "", clockScheduler "", startDate "", endDate "" + And viene modificato lo stato di probing dell'e-service con id "%expected" e id versione "%expected" in "false" e si verifica che coincida con quanto atteso + + Examples: + # BEFORE window (inizia tra poco): deve NON avanzare prima dello start, + # e poi (se la finestra è abbastanza lunga) deve avanzare almeno una volta dentro. + | frequency | clockScheduler | startDate | endDate | + | 1 | 3 | now+1m | now+5m | + + # IN window (già dentro): finestra lunga -> atteso almeno 1 update + | 1 | 3 | now-5m | now+5m | + + # AFTER window (finita da poco): deve NON avanzare dopo end + | 1 | 3 | now-10m | now-1m | + + # Boundary start (start = now): finestra lunga -> atteso almeno 1 update + | 1 | 3 | now | now+5m | + + # Boundary end (end = now): deve NON avanzare (siamo fuori finestra) + | 1 | 3 | now-10m | now | + + # Start & stop nello stesso test (finestra corta): NON pretendere update, + # ma se accade deve rispettare end e poi deve fermarsi. + | 1 | 3 | now | now+2m | + + # Window shorter than period: NON pretendere update + | 5 | 3 | now | now+2m | + + Scenario Outline: [SCHEDULING_2] - Probing disabled non aggiorna mai + Given vengono calcolate le informazioni di probing relative ad un e-service presente a catalogo + And viene modificato lo stato di probing dell'e-service con id "%expected" e id versione "%expected" in "false" e si verifica che coincida con quanto atteso + When vengono aggiornati i parametri di probing dell'e-service con eserviceId "%expected" e versionId "%expected" impostando frequency "", startDate "", endDate "" e si verifica che coincidano con quanto atteso + Then verifica che la responseReceived NON sia aggiornata quando probing è disabilitato + + Examples: + | frequency | startDate | endDate | + | 1 | now-5m | now+4m | + | 1 | now+1m | now+4m | + | 1 | now-10m | now-1m | + | 5 | now | now+2m | + + Scenario Outline: [PROBING_COMPLETE_PROCESS] - Processo completo di probing con aggiornamento stato e telemetria + Given vengono calcolate le informazioni di probing relative ad un e-service con health check presente a catalogo + And vengono aggiornati i parametri di probing dell'e-service con eserviceId "%expected" e versionId "%expected" impostando frequency "", startDate "", endDate "" e si verifica che coincidano con quanto atteso + And viene modificato lo stato di probing dell'e-service con id "%expected" e id versione "%expected" in "true" e si verifica che coincida con quanto atteso + When verifica che la responseReceived sia aggiornata coerentemente rispetto la frequency "", clockScheduler "3", startDate "", endDate "" + And viene recuperata la telemetria pubblica dell'e-service con eserviceRecordId "%expected" e pollingFrequency "" + And vengono recuperati i dati di probing dell'e-service con eserviceRecordId "%expected" + Then la telemetria dell'e-service risulta aggiornata con successo + And lo stato di probing dell'e-service viene aggiornato con valore "ACTIVE" + And viene modificato lo stato di probing dell'e-service con id "%expected" e id versione "%expected" in "false" e si verifica che coincida con quanto atteso + + Examples: + # BEFORE window (inizia tra poco) + | frequency | startDate | endDate | mockResponse | + | 1 | now+1m | now+10m | OK | + | 1 | now+1m | now+10m | ERROR | + | 1 | now+1m | now+10m | RANDOM | + + Scenario: [LOAD] 20k enable e verifica update dopo N periodi + Given preparo il load test probing con: + | totalEservices | workers | frequency | startDate | endDate | waitPeriods | extraWait | recentTolerance | + | 20000 | 100 | 1 | now-1m | now+10m | 1 | 45s | 45s | + When aggiorno scheduling in parallelo per tutti gli eservice + And abilito probing in parallelo per tutti gli eservice + And attendo N periodi di frequency più extraWait + Then verifico in parallelo che responseReceived sia valorizzata e aggiornata dopo l'enable per tutti gli eservice + And disabilito probing in parallelo per tutti gli eservice + + diff --git a/interop-qa-tests/src/test/resources/utils/probing/qa/populate_eservice.sql b/interop-qa-tests/src/test/resources/utils/probing/qa/populate_eservice.sql new file mode 100644 index 0000000000..a0fd595564 --- /dev/null +++ b/interop-qa-tests/src/test/resources/utils/probing/qa/populate_eservice.sql @@ -0,0 +1,114 @@ +TRUNCATE TABLE qa_probing.eservices CASCADE; + +DO +$$ +DECLARE + -- ===================== + -- CONFIG (MODIFICABILE) + -- ===================== +v_ok_count int := 1; + v_error_count +int := 1; + v_random_count +int := 1; + + v_base_host +text := 'http://probing-be-eservice-mock.qa:8080'; + + -- polling (UTC) + v_polling_start_time +timetz := '08:00:00+00'; + v_polling_end_time +timetz := '17:00:00+00'; + v_polling_frequency +int := 1; + + v_probing_enabled_default +boolean := false; + + v_eservices_count +int := 0; + +BEGIN + v_eservices_count +:= v_ok_count + v_error_count + v_random_count; + + IF +v_eservices_count <= 0 THEN + RAISE EXCEPTION + 'Total eservices count must be > 0 (ok=% , error=% , random=%).', + v_ok_count, v_error_count, v_random_count; +END IF; + +INSERT INTO qa_probing.eservices (id, + eservice_id, + version_id, + eservice_name, + producer_name, + eservice_technology, + base_path, + audience, + state, + version_number, + lock_version, + probing_enabled, + polling_start_time, + polling_end_time, + polling_frequency) + OVERRIDING SYSTEM VALUE +SELECT gs::bigint AS id, + + -- UUID deterministico da gs ( + substr(md5(gs::bigint::text), 1, 8) || '-' || + substr(md5(gs::bigint::text), 9, 4) || '-' || + substr(md5(gs::bigint::text), 13, 4) || '-' || + substr(md5(gs::bigint::text), 17, 4) || '-' || + substr(md5(gs::bigint::text), 21, 12) + )::uuid AS eservice_id, + + -- UUID deterministico da (1000000000 + gs) ( + substr(md5((1000000000 + gs::bigint)::text), 1, 8) || '-' || + substr(md5((1000000000 + gs::bigint)::text), 9, 4) || '-' || + substr(md5((1000000000 + gs::bigint)::text), 13, 4) || '-' || + substr(md5((1000000000 + gs::bigint)::text), 17, 4) || '-' || + substr(md5((1000000000 + gs::bigint)::text), 21, 12) + )::uuid AS version_id, ('ESVC-' || lpad(gs::text, 8, '0')) AS eservice_name, + ('Producer ' || ((gs - 1) % 50 + 1)) AS producer_name, + + -- Tecnologia: deterministica e NON NULL (pari/dispari) + CASE WHEN (gs % 2) = 0 THEN 'SOAP' ELSE 'REST' +END AS eservice_technology, + + -- base_path: host fisso + endpoint coerente con tecnologia + outcome configurabile + ARRAY[ + v_base_host || + CASE WHEN (gs % 2) = 0 + THEN '/soap/interop/probing/' + ELSE '/rest/interop/probing/' +END +|| + CASE + WHEN gs <= v_ok_count THEN 'ok' + WHEN gs <= v_ok_count + v_error_count THEN 'error' + ELSE 'random' +END +|| + '/status' + ]::varchar[] AS base_path, + + ARRAY['AUD_' || (1 + ((gs - 1) % 20))]::varchar[] AS audience, + 'ACTIVE' AS state, + 1 AS version_number, + 0 AS lock_version, + v_probing_enabled_default AS probing_enabled, + v_polling_start_time AS polling_start_time, + v_polling_end_time AS polling_end_time, + v_polling_frequency AS polling_frequency + FROM generate_series(1, v_eservices_count) gs; + + RAISE +NOTICE 'Inserted % rows (ok=% , error=% , random=%).', + v_eservices_count, v_ok_count, v_error_count, v_random_count; + +END +$$;