diff --git a/openapi/openapi.json b/openapi/openapi.json index bc023a4..c0c03e4 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -1,286 +1,264 @@ { - "openapi": "3.0.1", - "info": { - "title": "cfg-sync", - "description": "Microservice to update configuration schema of Nodo dei Pagamenti", - "termsOfService": "https://www.pagopa.gov.it/", - "version": "0.0.6-3-NOD-866-dev-src" + "openapi" : "3.0.1", + "info" : { + "title" : "cfg-sync", + "description" : "Microservice to update configuration schema of Nodo dei Pagamenti", + "termsOfService" : "https://www.pagopa.gov.it/", + "version" : "0.0.6-3-NOD-866-dev-src" }, - "servers": [ - { - "url": "http://localhost", - "description": "Generated server url" - } - ], - "paths": { - "/ndp/cache": { - "put": { - "tags": [ - "Cache" - ], - "summary": "Force cache configuration to update", - "operationId": "cache", - "responses": { - "200": { - "description": "OK", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "servers" : [ { + "url" : "http://localhost", + "description" : "Generated server url" + } ], + "paths" : { + "/ndp/cache" : { + "put" : { + "tags" : [ "Cache" ], + "summary" : "Force cache configuration to update", + "operationId" : "cache", + "responses" : { + "200" : { + "description" : "OK", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } }, - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SyncStatusResponse" + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/SyncStatusResponse" } } } } }, - "400": { - "description": "Bad Request", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "400" : { + "description" : "Bad Request", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemJson" + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ProblemJson" } } } }, - "401": { - "description": "Unauthorized", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "401" : { + "description" : "Unauthorized", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } } }, - "429": { - "description": "Too many requests", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "429" : { + "description" : "Too many requests", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } } }, - "500": { - "description": "Service unavailable", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "500" : { + "description" : "Service unavailable", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemJson" + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ProblemJson" } } } } }, - "security": [ - { - "ApiKey": [] - } - ] + "security" : [ { + "ApiKey" : [ ] + } ] }, - "parameters": [ - { - "name": "X-Request-Id", - "in": "header", - "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", - "schema": { - "type": "string" - } + "parameters" : [ { + "name" : "X-Request-Id", + "in" : "header", + "description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", + "schema" : { + "type" : "string" } - ] + } ] }, - "/ndp/stand-in": { - "put": { - "tags": [ - "StandIn" - ], - "summary": "Force stand-in configuration to update", - "operationId": "standin", - "responses": { - "200": { - "description": "OK", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "/ndp/stand-in" : { + "put" : { + "tags" : [ "StandIn" ], + "summary" : "Force stand-in configuration to update", + "operationId" : "standin", + "responses" : { + "200" : { + "description" : "OK", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } }, - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SyncStatusResponse" + "content" : { + "application/json" : { + "schema" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/SyncStatusResponse" } } } } }, - "400": { - "description": "Bad Request", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "400" : { + "description" : "Bad Request", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemJson" + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ProblemJson" } } } }, - "401": { - "description": "Unauthorized", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "401" : { + "description" : "Unauthorized", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } } }, - "429": { - "description": "Too many requests", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "429" : { + "description" : "Too many requests", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } } }, - "500": { - "description": "Service unavailable", - "headers": { - "X-Request-Id": { - "description": "This header identifies the call", - "schema": { - "type": "string" + "500" : { + "description" : "Service unavailable", + "headers" : { + "X-Request-Id" : { + "description" : "This header identifies the call", + "schema" : { + "type" : "string" } } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemJson" + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ProblemJson" } } } } }, - "security": [ - { - "ApiKey": [] - } - ] + "security" : [ { + "ApiKey" : [ ] + } ] }, - "parameters": [ - { - "name": "X-Request-Id", - "in": "header", - "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", - "schema": { - "type": "string" - } + "parameters" : [ { + "name" : "X-Request-Id", + "in" : "header", + "description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", + "schema" : { + "type" : "string" } - ] + } ] } }, - "components": { - "schemas": { - "SyncStatusResponse": { - "required": [ - "serviceIdentifier", - "status" - ], - "type": "object", - "properties": { - "serviceIdentifier": { - "type": "string", - "description": "Database service identifier", - "example": "NDP001" + "components" : { + "schemas" : { + "ProblemJson" : { + "type" : "object", + "properties" : { + "title" : { + "type" : "string", + "description" : "A short, summary of the problem type. Written in english and readable for engineers (usually not suited for non technical stakeholders and not localized); example: Service Unavailable" + }, + "status" : { + "maximum" : 600, + "minimum" : 100, + "type" : "integer", + "description" : "The HTTP status code generated by the origin server for this occurrence of the problem.", + "format" : "int32", + "example" : 200 }, - "status": { - "type": "string", - "description": "Database sync status result", - "example": "done", - "enum": [ - "DONE", - "DISABLED", - "ROLLBACK", - "ERROR" - ] + "detail" : { + "type" : "string", + "description" : "A human readable explanation specific to this occurrence of the problem.", + "example" : "There was an error processing the request" } } }, - "ProblemJson": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "A short, summary of the problem type. Written in english and readable for engineers (usually not suited for non technical stakeholders and not localized); example: Service Unavailable" - }, - "status": { - "maximum": 600, - "minimum": 100, - "type": "integer", - "description": "The HTTP status code generated by the origin server for this occurrence of the problem.", - "format": "int32", - "example": 200 + "SyncStatusResponse" : { + "required" : [ "serviceIdentifier", "status" ], + "type" : "object", + "properties" : { + "serviceIdentifier" : { + "type" : "string", + "description" : "Database service identifier", + "example" : "NDP001" }, - "detail": { - "type": "string", - "description": "A human readable explanation specific to this occurrence of the problem.", - "example": "There was an error processing the request" + "status" : { + "type" : "string", + "description" : "Database sync status result", + "example" : "done", + "enum" : [ "DONE", "DISABLED", "ROLLBACK", "ERROR" ] } } } }, - "securitySchemes": { - "ApiKey": { - "type": "apiKey", - "description": "The API key to access this function app.", - "name": "Ocp-Apim-Subscription-Key", - "in": "header" + "securitySchemes" : { + "ApiKey" : { + "type" : "apiKey", + "description" : "The API key to access this function app.", + "name" : "Ocp-Apim-Subscription-Key", + "in" : "header" } } } -} +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/node/cfgsync/controller/SyncCacheController.java b/src/main/java/it/gov/pagopa/node/cfgsync/controller/SyncCacheController.java index a3f19bb..e087862 100644 --- a/src/main/java/it/gov/pagopa/node/cfgsync/controller/SyncCacheController.java +++ b/src/main/java/it/gov/pagopa/node/cfgsync/controller/SyncCacheController.java @@ -136,7 +136,9 @@ public ResponseEntity> standin() { produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity> cache() { log.debug("[NODE-CFG-SYNC] Force {} configuration to update", TargetRefreshEnum.cache.label); + Map syncStatusEnumMap = apiConfigCacheService.syncCache(); + apiConfigCacheService.syncRiversamento(); List syncStatusResponseList = syncStatusEnumMap.entrySet() .stream() diff --git a/src/main/java/it/gov/pagopa/node/cfgsync/model/TargetRefreshEnum.java b/src/main/java/it/gov/pagopa/node/cfgsync/model/TargetRefreshEnum.java index 2d2c706..5bc94aa 100644 --- a/src/main/java/it/gov/pagopa/node/cfgsync/model/TargetRefreshEnum.java +++ b/src/main/java/it/gov/pagopa/node/cfgsync/model/TargetRefreshEnum.java @@ -3,7 +3,8 @@ public enum TargetRefreshEnum { cache("api-config-cache"), - standin("stand-in-manager"); + standin("stand-in-manager"), + riversamento("riversamento"); public final String label; diff --git a/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheEhConsumer.java b/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheEhConsumer.java index dda2032..234ac7b 100644 --- a/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheEhConsumer.java +++ b/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheEhConsumer.java @@ -7,7 +7,6 @@ import com.azure.messaging.eventhubs.models.EventContext; import com.azure.storage.blob.BlobContainerAsyncClient; import com.azure.storage.blob.BlobContainerClientBuilder; -import it.gov.pagopa.node.cfgsync.model.SyncStatusEnum; import it.gov.pagopa.node.cfgsync.model.TargetRefreshEnum; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -16,7 +15,6 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; -import java.util.Map; @Slf4j @Service @@ -54,11 +52,20 @@ public void processEvent(EventContext eventContext) { TargetRefreshEnum.cache.label, eventContext.getPartitionContext().getPartitionId(), eventContext.getEventData().getSequenceNumber(), eventContext.getEventData().getBodyAsString()); + try { apiConfigCacheService.syncCache(); } catch (Exception ex) { log.error("[{}][ALERT] Generic Error on consumer: {}", TargetRefreshEnum.cache.label, ex.getMessage(), ex); } + + try { + apiConfigCacheService.syncRiversamento(); + } catch (Exception ex) { + log.error("[{}][ALERT] Generic Error on consumer: {}", TargetRefreshEnum.riversamento.label, ex.getMessage(), ex); + } + + } public void processError(ErrorContext errorContext) { diff --git a/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheService.java b/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheService.java index 14d2da3..b1c0018 100644 --- a/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheService.java +++ b/src/main/java/it/gov/pagopa/node/cfgsync/service/ApiConfigCacheService.java @@ -143,11 +143,6 @@ public Map syncCache() { saveNexiPostgres(syncStatusMap, configCache); saveNexiOracle(syncStatusMap, configCache); - if(riversamentoEnabled) { - riversamentoElencoServizi(); - riversamentoCdiPreferences(); - } - return composeSyncStatusMapResult(TargetRefreshEnum.cache.label, syncStatusMap); } catch (FeignException fEx) { log.error("[{}] error: {}", TargetRefreshEnum.cache.label, fEx.getMessage(), fEx); @@ -160,6 +155,15 @@ public Map syncCache() { } } + @Transactional + public void syncRiversamento() { + if(riversamentoEnabled) { + log.info("riversamento elenco servizi e cdi preferences abilitato"); + riversamentoElencoServizi(); + riversamentoCdiPreferences(); + } + } + private void savePagoPA(Map syncStatusMap, ConfigCache configCache) { try { if(apiConfigCacheWritePagoPa) { diff --git a/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiOracleTest.java b/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiOracleTest.java index bb67090..6b3f34d 100644 --- a/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiOracleTest.java +++ b/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiOracleTest.java @@ -84,7 +84,7 @@ class CacheSyncNexiOracleTest { } @Test - void nexioracle() { + void nexioracle() throws InterruptedException { ReflectionTestUtils.setField(cacheManagerService, "riversamentoSource", "nexi-oracle"); ReflectionTestUtils.setField(cacheManagerService, "riversamentoTarget", "nexi-oracle"); @@ -124,6 +124,7 @@ void nexioracle() { assertThat(response.getBody().get(1).getStatus()).isEqualTo(SyncStatusEnum.DONE); assertThat(response.getBody().get(2).getServiceIdentifier()).isEqualTo(NEXIORACLE_SI); assertThat(response.getBody().get(2).getStatus()).isEqualTo(SyncStatusEnum.DONE); + Thread.sleep(5000); List all = nexiCdiPreferencesOracleRepository.findAll(); assertThat(all.size()).isEqualTo(size); assertThat(all.get(0).getSeller()).isEqualTo(arrayList.get(0).getSeller()); diff --git a/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiPostgresTest.java b/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiPostgresTest.java index ce645ea..df864b3 100644 --- a/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiPostgresTest.java +++ b/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncNexiPostgresTest.java @@ -77,7 +77,7 @@ class CacheSyncNexiPostgresTest { } @Test - void nexipostgres() { + void nexipostgres() throws InterruptedException { ReflectionTestUtils.setField(cacheManagerService, "riversamentoSource", "nexi-postgres"); ReflectionTestUtils.setField(cacheManagerService, "riversamentoTarget", "nexi-postgres"); @@ -117,8 +117,154 @@ void nexipostgres() { assertThat(response.getBody().get(1).getStatus()).isEqualTo(SyncStatusEnum.DONE); assertThat(response.getBody().get(2).getServiceIdentifier()).isEqualTo(NEXIORACLE_SI); assertThat(response.getBody().get(2).getStatus()).isEqualTo(SyncStatusEnum.DONE); + Thread.sleep(5000); List all = nexiCdiPreferencesPostgresRepository.findAll(); assertThat(all.size()).isEqualTo(size); + + } + + @Test + void nexipostgres2() throws InterruptedException { + + ReflectionTestUtils.setField(cacheManagerService, "riversamentoEnabled", false); + + long size = Math.round(Math.random()*500); + ArrayList arrayList = new ArrayList(); + for(long i = 0;i> headersCustom = + Map.of( + HEADER_CACHE_ID, List.of(String.valueOf(System.currentTimeMillis())), + HEADER_CACHE_TIMESTAMP, List.of(Instant.now().toString()), + HEADER_CACHE_VERSION, List.of(StringUtils.repeat("*", 50)) + ); + when(apiConfigCacheClient.getCache(anyString())).thenReturn(Response + .builder() + .status(200) + .reason("Mocked") + .headers(headersCustom) + .request(mock(Request.class)) + .body(new byte[0]) + .build()); + cacheManagerService.setApiConfigCacheClient(apiConfigCacheClient); + + ResponseEntity> response = restTemplate.exchange(CACHE_URL, HttpMethod.PUT, null, new ParameterizedTypeReference<>() {}); + + assertThat(response.getBody()).isNotNull(); + assertFalse(response.getHeaders().isEmpty()); + assertFalse(response.getBody().isEmpty()); + assertEquals(3, response.getBody().size()); + assertThat(response.getBody().get(0).getServiceIdentifier()).isEqualTo(PAGOPAPOSTGRES_SI); + assertThat(response.getBody().get(0).getStatus()).isEqualTo(SyncStatusEnum.DONE); + assertThat(response.getBody().get(1).getServiceIdentifier()).isEqualTo(NEXIPOSTGRES_SI); + assertThat(response.getBody().get(1).getStatus()).isEqualTo(SyncStatusEnum.DONE); + assertThat(response.getBody().get(2).getServiceIdentifier()).isEqualTo(NEXIORACLE_SI); + assertThat(response.getBody().get(2).getStatus()).isEqualTo(SyncStatusEnum.DONE); + Thread.sleep(5000); + Long afterCount = nexiCdiPreferencesPostgresRepository.count(); + assertThat(afterCount).isEqualTo(originalcount); + + } + + @Test + void nexipostgres3() throws InterruptedException { + + ReflectionTestUtils.setField(cacheManagerService, "riversamentoSource", "exception"); + ReflectionTestUtils.setField(cacheManagerService, "riversamentoTarget", "nexi-postgres"); + + long size = Math.round(Math.random()*500); + ArrayList arrayList = new ArrayList(); + for(long i = 0;i> headersCustom = + Map.of( + HEADER_CACHE_ID, List.of(String.valueOf(System.currentTimeMillis())), + HEADER_CACHE_TIMESTAMP, List.of(Instant.now().toString()), + HEADER_CACHE_VERSION, List.of(StringUtils.repeat("*", 50)) + ); + when(apiConfigCacheClient.getCache(anyString())).thenReturn(Response + .builder() + .status(200) + .reason("Mocked") + .headers(headersCustom) + .request(mock(Request.class)) + .body(new byte[0]) + .build()); + cacheManagerService.setApiConfigCacheClient(apiConfigCacheClient); + + ResponseEntity> response = restTemplate.exchange(CACHE_URL, HttpMethod.PUT, null, new ParameterizedTypeReference<>() {}); + + assertThat(response.getBody()).isNotNull(); + assertFalse(response.getHeaders().isEmpty()); + assertFalse(response.getBody().isEmpty()); + assertEquals(3, response.getBody().size()); + assertThat(response.getBody().get(0).getServiceIdentifier()).isEqualTo(PAGOPAPOSTGRES_SI); + assertThat(response.getBody().get(0).getStatus()).isEqualTo(SyncStatusEnum.DONE); + assertThat(response.getBody().get(1).getServiceIdentifier()).isEqualTo(NEXIPOSTGRES_SI); + assertThat(response.getBody().get(1).getStatus()).isEqualTo(SyncStatusEnum.DONE); + assertThat(response.getBody().get(2).getServiceIdentifier()).isEqualTo(NEXIORACLE_SI); + assertThat(response.getBody().get(2).getStatus()).isEqualTo(SyncStatusEnum.DONE); + Thread.sleep(1000); + long all = nexiCdiPreferencesPostgresRepository.count(); + assertThat(all).isEqualTo(originalcount); + + } + + @Test + void nexipostgres4() throws InterruptedException { + + ReflectionTestUtils.setField(cacheManagerService, "riversamentoSource", "nexi-postgres"); + ReflectionTestUtils.setField(cacheManagerService, "riversamentoTarget", "exception"); + + long size = Math.round(Math.random()*500); + ArrayList arrayList = new ArrayList(); + for(long i = 0;i> headersCustom = + Map.of( + HEADER_CACHE_ID, List.of(String.valueOf(System.currentTimeMillis())), + HEADER_CACHE_TIMESTAMP, List.of(Instant.now().toString()), + HEADER_CACHE_VERSION, List.of(StringUtils.repeat("*", 50)) + ); + when(apiConfigCacheClient.getCache(anyString())).thenReturn(Response + .builder() + .status(200) + .reason("Mocked") + .headers(headersCustom) + .request(mock(Request.class)) + .body(new byte[0]) + .build()); + cacheManagerService.setApiConfigCacheClient(apiConfigCacheClient); + + ResponseEntity> response = restTemplate.exchange(CACHE_URL, HttpMethod.PUT, null, new ParameterizedTypeReference<>() {}); + + assertThat(response.getBody()).isNotNull(); + assertFalse(response.getHeaders().isEmpty()); + assertFalse(response.getBody().isEmpty()); + assertEquals(3, response.getBody().size()); + assertThat(response.getBody().get(0).getServiceIdentifier()).isEqualTo(PAGOPAPOSTGRES_SI); + assertThat(response.getBody().get(0).getStatus()).isEqualTo(SyncStatusEnum.DONE); + assertThat(response.getBody().get(1).getServiceIdentifier()).isEqualTo(NEXIPOSTGRES_SI); + assertThat(response.getBody().get(1).getStatus()).isEqualTo(SyncStatusEnum.DONE); + assertThat(response.getBody().get(2).getServiceIdentifier()).isEqualTo(NEXIORACLE_SI); + assertThat(response.getBody().get(2).getStatus()).isEqualTo(SyncStatusEnum.DONE); + Thread.sleep(1000); + long all = nexiCdiPreferencesPostgresRepository.count(); + assertThat(all).isEqualTo(originalcount); + } } diff --git a/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncTest.java b/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncTest.java index ab3adbd..9f7f52f 100644 --- a/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncTest.java +++ b/src/test/java/it/gov/pagopa/node/cfgsync/CacheSyncTest.java @@ -168,7 +168,7 @@ void error500ConnectionRefused() { } @Test - void trimCacheVersionOnDb() { + void trimCacheVersionOnDb() throws InterruptedException { long size = Math.round(Math.random()*500); ArrayList arrayList = new ArrayList(); @@ -205,6 +205,7 @@ void trimCacheVersionOnDb() { assertThat(response.getBody().get(1).getStatus()).isEqualTo(SyncStatusEnum.DONE); assertThat(response.getBody().get(2).getServiceIdentifier()).isEqualTo(NEXIORACLE_SI); assertThat(response.getBody().get(2).getStatus()).isEqualTo(SyncStatusEnum.DONE); + Thread.sleep(5000); List all = pagoPaCdiPreferencesPostgresRepository.findAll(); assertThat(all.size()).isEqualTo(size); }