diff --git a/Dockerfile b/Dockerfile index dc06a35..3523a3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9-eclipse-temurin-17 as compilador +FROM maven:3.9-eclipse-temurin-25 as compilador RUN echo "Se crea carpeta de servidor" && \ mkdir app @@ -10,7 +10,7 @@ RUN echo "Se compila la aplicación" && \ mvn clean package -DskipTests && \ cp -f server.app/target/*.jar ./servidor.jar -FROM eclipse-temurin:17-jre +FROM eclipse-temurin:25-jre LABEL version=1.0.0 LABEL description="Jonnattan Griffiths" diff --git a/README.md b/README.md index 64235cf..0db252e 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,183 @@ -# Emulador de algunas cosas interesantes - -Emula el comportamiento de algunas aplicaciones que me siven para el desarrollo mobile -Ideal para hacer pruebas en desarrollo, se utilizara este servidor con mi pagina de prueba - -## -Utiliza Spring boot durante el desarrollo - -## -Está programado en JAVA con Spring boot y una conexión a base de datos MySQL - +# Emulator Server API [![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-black.svg)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) -[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) -[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) -[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) -[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) -[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) -[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) +[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) +[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=bugs)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) +[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) +[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=jonnattangc_java.server&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=jonnattangc_java.server) + +--- + +## Resumen + +Emulador de APIs de terceros construido para apoyar el desarrollo mobile y pruebas de integración. Expone endpoints REST que replican el comportamiento de servicios de pago, tokenización, autenticación y gestión de tarjetas, y persiste transacciones, tarjetas, usuarios y configuraciones en MySQL. + +## Tecnologías + +| Componente | Versión | +|---------------------|----------| +| Java | 21 | +| Spring Boot | 4.0.5 | +| MySQL Connector | 8.0.33 | +| Lombok | 1.18.38 | +| BouncyCastle | 1.70 | +| Apache HttpClient | 4.5.14 | +| Log4j2 | 2.21.0 | +| JUnit | 4.13.1 | +| Maven | 3.9 | + +## Arquitectura + +Proyecto Maven multi-módulo: + +| Módulo | Responsabilidad | +|-------------------|----------------------------------------------------------------------------------| +| `server.app` | Aplicación Spring Boot. Controllers REST y punto de entrada (`Application.java`). | +| `server.services` | Lógica de negocio, configuración, seguridad, criptografía y utilidades. | +| `server.dao` | Repositorios Spring Data JPA. | +| `server.domain` | Entidades JPA (`Card`, `Transaction`, `User`, `Device`, `Configuration`) y enums. | +| `server.json` | DTOs de request/response y serialización Jackson. | + +``` +java.server/ +├── server.app/ # Controllers y bootstrap Spring Boot +├── server.services/ # Servicios, configuración y utilidades +├── server.dao/ # Repositorios JPA +├── server.domain/ # Entidades y enums +├── server.json/ # DTOs +├── Dockerfile +├── docker-compose.yml +└── pom.xml # POM raíz +``` + +## Endpoints + +> Base path: `${CONTEXT}` (por defecto `/emulator`). Todos los ejemplos omiten el context path. + +### Configuración dinámica — `/config` + +| Método | Path | Request | Response | Descripción | +|--------|-------------------|----------------------------------|-----------------------------------|-----------------------------------------------| +| POST | `/config/create` | `AppConfigurationRequestDTO` | `String` | Crea configuración para un endpoint. | +| POST | `/config/update` | `AppConfigurationRequestDTO` | `String` | Actualiza configuración existente. | +| POST | `/config/save` | `AppConfigurationRequestDTO` | `String` | Persiste la configuración. | +| GET | `/config/list` | — | `AppListConfigurationDTOResponse` | Lista todas las configuraciones. | + +### Pagos y Tokens (TecApi) — `CetipaController` + +| Método | Path | Request | Response | Descripción | +|--------|---------------------------------------------------|--------------------------------------------|----------------|-----------------------------------------------------------| +| POST | `/pay/ptm/v1/authorizations` | `EdrPayAuthorizeRequestDTO` | `IEmulator` | Autoriza una transacción de pago. | +| POST | `/pay/ptm/v1/voids` | `EdrPaymentReverseRequestDTO` | `IEmulator` | Reversa o anula una transacción autorizada. | +| POST | `/tsp/ttm/v1/enrollments` | `EdrTokenEnrollmentRequestDTO` | `IEmulator` | Enrola un dispositivo o tarjeta. | +| POST | `/tsp/ttm/v1/par/search` | `EdrTokenGetDigitalPanRequestDTO` | `IEmulator` | Búsqueda de tarjeta digital (PAR). | +| GET | `/tsp/ttm/v1/tokens/{token}` | — | `IEmulator` | Obtiene el detalle del token. | +| POST | `/tsp/ttm/v1/tokens/{token}/acquired` | — | `String` | Notifica que el token fue adquirido. | +| POST | `/tsp/ttm/v1/tokens/{token}/cryptograms` | `EdrPaymentCreateCryptogramRequestDTO` | `IEmulator` | Genera criptograma para el token. | +| POST | `/pay/prm/v1/requestors/{requestor}/logon` | `EdrPaymentLogonRequestDTO` | `IEmulator` | Logon PRM (Payment Requestor). Retorna `access_token` en header. | +| POST | `/tsp/trm/v1/requestors/{requestor}/logon` | `EdrTokenLogonRequestDTO` | `IEmulator` | Logon TRM (Token Requestor). Retorna `access_token` en header. | + +### Commerce — `/commerceapps` + +| Método | Path | Request | Response | Descripción | +|--------|---------------------------|---------------------------|----------------------------|------------------------------------------| +| POST | `/commerceapps/sendMail` | Body crudo | `CommerceMailResponseDTO` | Simula envío de email desde Commerce. | +| POST | `/commerceapps/getToken` | `MultiValueMap` (headers) | `CommerceTokenResponseDTO` | Emite token de acceso emulado. | + +### CXP (proxy ChileExpress) — `/cxp` + +| Método | Path | Request | Response | Descripción | +|--------|-------------|-------------------------|---------------------|----------------------------------------------------------| +| POST | `/cxp/**` | `HttpServletRequest` | `ICxpResponse` | Reenvía POST al backend CXP configurado dinámicamente. | +| GET | `/cxp/**` | `HttpServletRequest` | `String` | Reenvía GET al backend CXP configurado dinámicamente. | + +### Logon externos — `/edr` + +| Método | Path | Request | Response | Descripción | +|--------|---------------------------|---------------------------|------------|---------------------------------| +| POST | `/edr/login/tickettest` | `MultiValueMap` (headers) | `String` | Logon de prueba (EDR). | +| POST | `/edr/login/ticket` | `MultiValueMap` (headers) | `String` | Logon EDR. | +| POST | `/edr/login/beanuj` | `MultiValueMap` (headers) | `String` | Logon JUNAEB. | + +### EDR-EGD Foods + +| Método | Path | Request | Response | Descripción | +|--------|-----------------------------|-----------------------|---------------|------------------------------------------| +| ANY | `/api/v1/foods/cards/**` | `HttpServletRequest` | `IEmulator` | Búsqueda y procesamiento de tarjetas. | + +### Página personal — `/page` + +| Método | Path | Request | Response | Descripción | +|--------|----------------------|--------------------------------------|---------------|--------------------------------------| +| POST | `/page/users/save` | `MultiValueMap` (form-urlencoded) | `IEmulator` | Registra un usuario nuevo (CORS). | +| GET | `/page/users` | — | `IEmulator` | Lista los usuarios (CORS). | + +## Configuración + +La aplicación selecciona su perfil activo mediante la variable `ENV` (`local`, `dev`, `prod`). + +### Variables de entorno + +| Variable | Descripción | Default | +|--------------|-------------------------------------------------|---------------| +| `ENV` | Perfil Spring activo. | `dev` | +| `PORT` | Puerto HTTP del servidor. | `8089` | +| `CONTEXT` | Context path de la aplicación. | `/emulator` | +| `BD_ADDR` | Host MySQL. | — | +| `BD_PORT` | Puerto MySQL. | `3306` | +| `BD_NAME` | Nombre del esquema. | — | +| `BD_USER` | Usuario MySQL. | — | +| `BD_PASS` | Password MySQL. | — | +| `LOG_LEVEL` | Nivel de logging (`DEBUG`, `INFO`, ...). | `INFO` | +| `AES_KEY` | Clave AES para cifrado (32+ caracteres). | — | + +### Persistencia + +- JDBC URL: `jdbc:mysql://${BD_ADDR}:${BD_PORT}/${BD_NAME}?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true` +- Pool: HikariCP (`max-pool-size=10`, `connection-timeout=30s`). +- DDL: `hibernate.ddl-auto=update` en ambientes de desarrollo. +- Perfil `local` usa H2 en memoria. + +## Ejecución + +### Maven + +```bash +export ENV=local +export PORT=8089 +export CONTEXT=/emulator +export LOG_LEVEL=DEBUG +export AES_KEY='' +export BD_ADDR=localhost +export BD_PORT=3306 +export BD_NAME=emulator +export BD_USER=emulator +export BD_PASS='' + +mvn clean package +java -Xmx1024m -Xms512m -jar server.app/target/server.app-1.2.0-SNAPSHOT.jar +``` + +### Docker + +```bash +docker build -t java-server:v1 . +docker-compose up -d +``` + +`docker-compose.yml` publica el puerto `8089` y lee las variables desde `../envs/java_server.env`. El `Dockerfile` usa build multi-stage con Maven 3.9 y Eclipse Temurin 25 como runtime. + +## Seguridad + +Consulta [SECURITY.md](./SECURITY.md) para la política de reporte de vulnerabilidades. + +## Licencia + +Ver [LICENSE](./LICENSE). diff --git a/docker-compose.yml b/docker-compose.yml index 6f08d09..7580be6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,10 +6,10 @@ services: restart: always deploy: replicas: 1 - env_file: - - ../envs/java_server.env + env_file: + - ../envs/java_server.env networks: - - db-net + - db-net ports: - 8089:8089 networks: diff --git a/pom.xml b/pom.xml index 9fdf662..f57c9d9 100644 --- a/pom.xml +++ b/pom.xml @@ -21,13 +21,13 @@ 21 1.2.0-SNAPSHOT 4.0.5 - 4.13.1 1.1.4 2.6.1 1.1.4 1.0.0 1.18.38 4.2.1 + 0.8.12 @@ -43,12 +43,6 @@ ${spring.boot.version} test - - junit - junit - ${junit.version} - test - org.springframework.boot spring-boot-dependencies @@ -154,6 +148,26 @@ + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + prepare-agent + + prepare-agent + + + + report + verify + + report + + + + \ No newline at end of file diff --git a/server.app/pom.xml b/server.app/pom.xml index b8de5ed..da98c18 100644 --- a/server.app/pom.xml +++ b/server.app/pom.xml @@ -18,8 +18,8 @@ - junit - junit + org.junit.jupiter + junit-jupiter test diff --git a/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppCommeController.java b/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppCommeController.java index 6e8a414..ab7fc57 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppCommeController.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppCommeController.java @@ -21,11 +21,11 @@ /** * Controlles respuesta a la APPs Cmc - * + * * @author Jonnattan Griffiths * @since Programa EMULADOR * @version 1.0 del 30-09-2020 - * + * */ @RestController @RequestMapping("/commerceapps") @@ -43,8 +43,9 @@ public ResponseEntity sendMail(HttpServletRequest reque int dato = -1; ServletInputStream sis = request.getInputStream(); ByteBuffer bb = ByteBuffer.allocate(1024); - while ((dato = sis.read()) != -1) + while ((dato = sis.read()) != -1) { bb.put((byte) dato); + } bb.flip(); int len = bb.remaining(); String body = ""; @@ -69,6 +70,6 @@ public ResponseEntity getToken(@RequestHeader MultiVal token.setAccess_token("1111111222222333334444455555666677788899"); token.setExpires_in(10); token.setToken_type("Emnulado"); - return new ResponseEntity(token, HttpStatus.OK); + return new ResponseEntity<>(token, HttpStatus.OK); } } diff --git a/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppController.java b/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppController.java index fe3060f..156c359 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppController.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/controllers/AppController.java @@ -2,10 +2,8 @@ import cl.jonnattan.emulator.dto.AppListConfigurationDTOResponse; -import cl.jonnattan.emulator.dto.ints.IEmulator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; @@ -25,20 +23,23 @@ * Controller de configuraci'on de emulador * Sirve para configurar como queremos que respondan los servicios * ac'a definidos - * + * * @author Jonnattan Griffiths * @since Programa EMULADOR * @version 1.0 del 22-06-2020 - * + * */ @RestController @RequestMapping("/config") public class AppController { private static final Logger logger = LoggerFactory.getLogger(AppController.class); - - @Autowired - private IConfigurations configService; + + private final IConfigurations configService; + + public AppController(IConfigurations configService) { + this.configService = configService; + } @PostMapping(value = "/update") public ResponseEntity update(@Valid @RequestBody AppConfigurationRequestDTO request) { @@ -82,16 +83,16 @@ public ResponseEntity save(@Valid @RequestBody AppConfigurationRequestDT return new ResponseEntity<>(success, status); } - @GetMapping(value = "/list") - public ResponseEntity list(){ - logger.info(UtilConst.LINE); - HttpStatus status = HttpStatus.OK; - AppListConfigurationDTOResponse response = null; - try { - response = configService.getConfigurations(); - } catch (ConfException e) { - status = e.getStatus(); - } - return new ResponseEntity(response, status); - } + @GetMapping(value = "/list") + public ResponseEntity list(){ + logger.info(UtilConst.LINE); + HttpStatus status = HttpStatus.OK; + AppListConfigurationDTOResponse response = null; + try { + response = configService.getConfigurations(); + } catch (ConfException e) { + status = e.getStatus(); + } + return new ResponseEntity<>(response, status); + } } diff --git a/server.app/src/main/java/cl/jonnattan/emulator/controllers/CetipaController.java b/server.app/src/main/java/cl/jonnattan/emulator/controllers/CetipaController.java index d48d96a..2fb1c20 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/controllers/CetipaController.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/controllers/CetipaController.java @@ -1,10 +1,9 @@ package cl.jonnattan.emulator.controllers; import java.util.UUID; -import java.util.logging.Logger; - -import org.springframework.beans.factory.annotation.Autowired; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -32,39 +31,41 @@ import cl.jonnattan.emulator.interfaces.ITrm; import cl.jonnattan.emulator.utils.ConfException; import cl.jonnattan.emulator.utils.EmulatorException; +import cl.jonnattan.emulator.utils.UtilConst; import jakarta.validation.Valid; /** * Controlles principal de emulador - * + * * @author Jonnattan Griffiths * @since Programa EMULADOR * @version 1.0 del 22-06-2020 - * + * */ @RestController @RequestMapping("/") public class CetipaController { - private static final Logger logger = Logger.getLogger(CetipaController.class.getName()); - - @Autowired - private ITransactions transactionService; - @Autowired - private ITrm trmService; + private static final Logger logger = LoggerFactory.getLogger(CetipaController.class); - @Autowired - private IPrm prmService; + private final ITransactions transactionService; + private final ITrm trmService; + private final IPrm prmService; + private final ICard cardService; + private final IConfigurations configService; - @Autowired - private ICard cardService; - - @Autowired - private IConfigurations configService; + public CetipaController(ITransactions transactionService, ITrm trmService, IPrm prmService, ICard cardService, + IConfigurations configService) { + this.transactionService = transactionService; + this.trmService = trmService; + this.prmService = prmService; + this.cardService = cardService; + this.configService = configService; + } /** * Autorizar transaccion - * + * * @param transaction * @param headersRx * @return @@ -102,8 +103,8 @@ public ResponseEntity reverse(@Valid @RequestBody EdrPaymentReverseRe IEmulator response = null; HttpHeaders headersTx = new HttpHeaders(); // Se pasa el mismo requestid - String id = headersRx.get("requestid").get(0); - headersTx.add("requestid", id); + String id = headersRx.get(UtilConst.REQUEST_ID).get(0); + headersTx.add(UtilConst.REQUEST_ID, id); HttpStatus status = HttpStatus.OK; try { configService.evaluateEndpoint("/pay/ptm/v1/voids"); @@ -125,7 +126,7 @@ public ResponseEntity reverse(@Valid @RequestBody EdrPaymentReverseRe /** * Enrola una tarjeta en apitec. - * + * * @param request * @param headersRx * @return @@ -152,11 +153,11 @@ public ResponseEntity deviceEnroll(@Valid @RequestBody EdrTokenEnroll ((ErrorData) response).setMessage(e.getMessage()); } - return new ResponseEntity(response, headersTx, status); + return new ResponseEntity<>(response, headersTx, status); } /** - * + * * @param request * @param headersRx * @return @@ -183,11 +184,11 @@ public ResponseEntity deviceSearch(@Valid @RequestBody EdrTokenGetDig ((ErrorData) response).setMessage(e.getMessage()); } - return new ResponseEntity(response, headersTx, status); + return new ResponseEntity<>(response, headersTx, status); } /** - * + * * @param request * @param headersRx * @return @@ -212,11 +213,11 @@ public ResponseEntity getToken(@PathVariable String token, @RequestHe ((ErrorData) response).setCode(e.getCode()); ((ErrorData) response).setMessage(e.getMessage()); } - return new ResponseEntity(response, headersTx, status); + return new ResponseEntity<>(response, headersTx, status); } /** - * + * * @param request * @param headersRx * @return @@ -228,20 +229,20 @@ public ResponseEntity getAcquire(@PathVariable String token, @RequestHea HttpHeaders headersTx = new HttpHeaders(); HttpStatus status = HttpStatus.OK; - String requestid = headerRx.get("requestid").get(0); - String client_id = headerRx.get("client_id").get(0); - String access_token = headerRx.get("access_token").get(0); + String requestid = headerRx.get(UtilConst.REQUEST_ID).get(0); + String clientId = headerRx.get(UtilConst.CLIENT_ID).get(0); + String accessToken = headerRx.get(UtilConst.ACCESS_TOKEN).get(0); - logger.info("requestid : " + requestid); - logger.info("client_id : " + client_id); - logger.info("access_token: " + access_token); - logger.info("token : " + token); + logger.info("requestid : {}", requestid); + logger.info("client_id : {}", clientId); + logger.info("access_token: {}", accessToken); + logger.info("token : {}", token); - return new ResponseEntity("OK", headersTx, status); + return new ResponseEntity<>("OK", headersTx, status); } /** - * + * * @param requestor * @param request * @param header @@ -260,12 +261,13 @@ public ResponseEntity logingout(@PathVariable String requestor, // Este token es muy importante. Apitec lo cambi'o hace poco a un valor m'as // grande - String accessToken = "EMULATOR-PAYMENT"; - for (int i = 0; i < 100; i++) - accessToken += "-" + UUID.randomUUID().toString(); + StringBuilder accessToken = new StringBuilder("EMULATOR-PAYMENT"); + for (int i = 0; i < 100; i++) { + accessToken.append("-").append(UUID.randomUUID().toString()); + } - headersTx.add("access_token", accessToken); - logger.info("PRM Response Header[access_token]: " + accessToken); + headersTx.add(UtilConst.ACCESS_TOKEN, accessToken.toString()); + logger.info("PRM Response Header[access_token]: {}", accessToken); } catch (EmulatorException e) { status = HttpStatus.CONFLICT; response = new ErrorData(); @@ -277,11 +279,11 @@ public ResponseEntity logingout(@PathVariable String requestor, ((ErrorData) response).setCode(e.getCode()); ((ErrorData) response).setMessage(e.getMessage()); } - return new ResponseEntity(response, headersTx, status); + return new ResponseEntity<>(response, headersTx, status); } /** - * + * * @param requestor * @param request * @param headersRx @@ -297,15 +299,16 @@ public ResponseEntity logingout(@PathVariable String requestor, try { configService.evaluateEndpoint("/tsp/trm/v1/requestors/{requestor}/logon"); response = trmService.logon(requestor, headersRx, request); - - - String accessToken = "EMULATOR-TOKEN"; - for (int i = 0; i < 100; i++) - accessToken += "-" + UUID.randomUUID().toString(); - headersTx.add("access_token", accessToken); - logger.info("TRM Response Header[access_token]: " + accessToken); - + + StringBuilder accessToken = new StringBuilder("EMULATOR-TOKEN"); + for (int i = 0; i < 100; i++) { + accessToken.append("-").append(UUID.randomUUID().toString()); + } + + headersTx.add(UtilConst.ACCESS_TOKEN, accessToken.toString()); + logger.info("TRM Response Header[access_token]: {}", accessToken); + } catch (EmulatorException e) { status = HttpStatus.CONFLICT; response = new ErrorData(); @@ -317,12 +320,12 @@ public ResponseEntity logingout(@PathVariable String requestor, ((ErrorData) response).setCode(e.getCode()); ((ErrorData) response).setMessage(e.getMessage()); } - return new ResponseEntity(response, headersTx, status); + return new ResponseEntity<>(response, headersTx, status); } /** * Obtiene los datos relacionados con el criptograma - * + * * @param token * @param request * @param headersRx @@ -349,7 +352,7 @@ public ResponseEntity cryptograms(@PathVariable String token, ((ErrorData) response).setCode(e.getCode()); ((ErrorData) response).setMessage(e.getMessage()); } - return new ResponseEntity(response, headersTx, status); + return new ResponseEntity<>(response, headersTx, status); } } diff --git a/server.app/src/main/java/cl/jonnattan/emulator/controllers/CxpController.java b/server.app/src/main/java/cl/jonnattan/emulator/controllers/CxpController.java index 04d51dc..fb749bd 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/controllers/CxpController.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/controllers/CxpController.java @@ -1,8 +1,7 @@ package cl.jonnattan.emulator.controllers; -import java.util.logging.Logger; - -import org.springframework.beans.factory.annotation.Autowired; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -20,18 +19,23 @@ /** * Controlles de conf de emulador - * + * * @author Jonnattan Griffiths - * @since Programa EMULADOR + * @since Programa EMULADOR * @version 1.0 del 11-05-2021 - * + * */ @RestController @RequestMapping("/cxp") public class CxpController { - private static final Logger logger = Logger.getLogger(CxpController.class.getName()); - @Autowired - private ICxp cxpService; + + private static final Logger logger = LoggerFactory.getLogger(CxpController.class); + + private final ICxp cxpService; + + public CxpController(ICxp cxpService) { + this.cxpService = cxpService; + } @PostMapping(value = "/**") public ResponseEntity postCxp(HttpServletRequest request, @RequestHeader HttpHeaders headerRx) { diff --git a/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrController.java b/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrController.java index f72c4f7..1dc4e92 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrController.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrController.java @@ -1,8 +1,7 @@ package cl.jonnattan.emulator.controllers; -import java.util.logging.Logger; - -import org.springframework.beans.factory.annotation.Autowired; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -20,27 +19,30 @@ /** * Controlles principal de emulador - * + * * @author Jonnattan Griffiths - * @since Programa EMULADOR + * @since Programa EMULADOR * @version 1.0 del 22-06-2020 - * + * */ @RestController @RequestMapping("/edr") public class EdrController { - private static final Logger logger = Logger.getLogger(EdrController.class.getName()); - @Autowired - private IEdr edrService; + private static final Logger logger = LoggerFactory.getLogger(EdrController.class); + + private final IEdr edrService; + private final IConfigurations configService; - @Autowired - private IConfigurations configService; + public EdrController(IEdr edrService, IConfigurations configService) { + this.edrService = edrService; + this.configService = configService; + } @PostMapping(path = "/login/tickettest", consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE }, produces = { MediaType.APPLICATION_FORM_URLENCODED_VALUE }) public ResponseEntity handleNonBrowserSubmissions(@RequestHeader MultiValueMap headersRx) { logger.info("****************************/login/ticket****************************"); - logger.info("REALM: " + headersRx.get("realm")); + logger.info("REALM: {}", headersRx.get("realm")); return new ResponseEntity<>("Thank you for submitting feedback", HttpStatus.OK); } diff --git a/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrEgdController.java b/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrEgdController.java index d45075b..3510cf8 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrEgdController.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/controllers/EdrEgdController.java @@ -1,9 +1,7 @@ package cl.jonnattan.emulator.controllers; -import java.util.logging.Logger; - - -import org.springframework.beans.factory.annotation.Autowired; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -21,22 +19,25 @@ /** * Controlles principal de emulador - * + * * @author Jonnattan Griffiths * @since Programa EMULADOR * @version 1.0 del 22-06-2020 - * + * */ @RestController @RequestMapping("/") public class EdrEgdController { - private static final Logger logger = Logger.getLogger(EdrEgdController.class.getName()); - @Autowired - private ICard cardService; + private static final Logger logger = LoggerFactory.getLogger(EdrEgdController.class); - @Autowired - private IConfigurations configService; + private final ICard cardService; + private final IConfigurations configService; + + public EdrEgdController(ICard cardService, IConfigurations configService) { + this.cardService = cardService; + this.configService = configService; + } @RequestMapping(value = "/api/v1/foods/cards/**") public ResponseEntity edgCardSearch(HttpServletRequest request, @RequestHeader HttpHeaders headerRx) { @@ -59,7 +60,7 @@ public ResponseEntity edgCardSearch(HttpServletRequest request, @Requ ((ErrorData) response).setCode(e.getCode()); ((ErrorData) response).setMessage(e.getMessage()); } - return new ResponseEntity(response, headersTx, status); + return new ResponseEntity<>(response, headersTx, status); } } diff --git a/server.app/src/main/java/cl/jonnattan/emulator/controllers/PageController.java b/server.app/src/main/java/cl/jonnattan/emulator/controllers/PageController.java index 3cc2639..26bfb4d 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/controllers/PageController.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/controllers/PageController.java @@ -3,7 +3,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -25,16 +24,17 @@ import cl.jonnattan.emulator.interfaces.IPage; import cl.jonnattan.emulator.utils.ConfException; import cl.jonnattan.emulator.utils.EmulatorException; +import cl.jonnattan.emulator.utils.UtilConst; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; /** * Controller para solicitudes desde la web personal - * + * * @author Jonnattan Griffiths * @since Programa EMULADOR * @version 1.0 del 20-02-2023 - * + * */ @RestController @RequestMapping("/page") @@ -42,18 +42,20 @@ public class PageController { private static final Logger logger = LoggerFactory.getLogger(PageController.class); - @Autowired - private IPage pageService; + private final IPage pageService; + private final IConfigurations configService; + + public PageController(IPage pageService, IConfigurations configService) { + this.pageService = pageService; + this.configService = configService; + } - @Autowired - private IConfigurations configService; @CrossOrigin(origins = "*") @PostMapping(path = "/users/save", consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE }, produces = { MediaType.TEXT_HTML_VALUE }) - public ResponseEntity save(@Valid @RequestParam MultiValueMap params, HttpServletRequest request, @RequestHeader HttpHeaders headers) { - logger.info("---------------------------------------------------------------------------------------"); + logger.info(UtilConst.LINE); HttpStatus status = HttpStatus.OK; IEmulator response = null; HttpHeaders headersTx = new HttpHeaders(); diff --git a/server.app/src/main/resources/application-dev.yml b/server.app/src/main/resources/application-dev.yml index 30b176c..86bcdce 100644 --- a/server.app/src/main/resources/application-dev.yml +++ b/server.app/src/main/resources/application-dev.yml @@ -28,8 +28,6 @@ spring: jackson: date-format: "yyyy-MM-dd'T'HH:mm:ss" - serialization: - WRITE_DATES_WITH_ZONE_ID: true server: address: 0.0.0.0 diff --git a/server.app/src/test/java/cl/jonnattan/emulator/controllers/AppCommeControllerTest.java b/server.app/src/test/java/cl/jonnattan/emulator/controllers/AppCommeControllerTest.java new file mode 100644 index 0000000..07f3445 --- /dev/null +++ b/server.app/src/test/java/cl/jonnattan/emulator/controllers/AppCommeControllerTest.java @@ -0,0 +1,75 @@ +package cl.jonnattan.emulator.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; + +import cl.jonnattan.emulator.dto.CommerceMailResponseDTO; +import cl.jonnattan.emulator.dto.CommerceTokenResponseDTO; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; + +class AppCommeControllerTest { + + private final AppCommeController controller = new AppCommeController(); + + @Test + void sendMail_conBody_retornaOK() throws IOException { + HttpServletRequest req = mock(HttpServletRequest.class); + ByteArrayInputStream bais = new ByteArrayInputStream("{\"a\":1}".getBytes()); + when(req.getInputStream()).thenReturn(stream(bais)); + + ResponseEntity rsp = controller.sendMail(req, new LinkedMultiValueMap<>()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void sendMail_ioError_retornaOK() throws IOException { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getInputStream()).thenThrow(new IOException("boom")); + + ResponseEntity rsp = controller.sendMail(req, new LinkedMultiValueMap<>()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void getToken_retornaTokenConAccessToken() { + ResponseEntity rsp = controller.getToken(new LinkedMultiValueMap<>()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + assertNotNull(rsp.getBody().getAccess_token()); + } + + private ServletInputStream stream(ByteArrayInputStream bais) { + return new ServletInputStream() { + @Override + public int read() { + return bais.read(); + } + + @Override + public boolean isFinished() { + return bais.available() == 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener listener) { + // noop + } + }; + } +} diff --git a/server.app/src/test/java/cl/jonnattan/emulator/controllers/AppControllerTest.java b/server.app/src/test/java/cl/jonnattan/emulator/controllers/AppControllerTest.java new file mode 100644 index 0000000..5980ca3 --- /dev/null +++ b/server.app/src/test/java/cl/jonnattan/emulator/controllers/AppControllerTest.java @@ -0,0 +1,101 @@ +package cl.jonnattan.emulator.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import cl.jonnattan.emulator.dto.AppConfigurationRequestDTO; +import cl.jonnattan.emulator.dto.AppListConfigurationDTOResponse; +import cl.jonnattan.emulator.enums.TypeResponse; +import cl.jonnattan.emulator.interfaces.IConfigurations; +import cl.jonnattan.emulator.utils.ConfException; + +@ExtendWith(MockitoExtension.class) +class AppControllerTest { + + @Mock + private IConfigurations configService; + + @InjectMocks + private AppController controller; + + private AppConfigurationRequestDTO req() { + AppConfigurationRequestDTO dto = new AppConfigurationRequestDTO(); + dto.setEndPoint("/x"); + dto.setError(Boolean.TRUE); + dto.setCode("500"); + dto.setMessage("m"); + dto.setType(500); + return dto; + } + + @Test + void update_ok_retornaOK() throws ConfException { + when(configService.updateConfigurations(any())).thenReturn("ok"); + ResponseEntity rsp = controller.update(req()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void update_excepcion_retornaStatusDeExcepcion() throws ConfException { + when(configService.updateConfigurations(any())) + .thenThrow(new ConfException("err", "500", TypeResponse.HTTP_RESPONSE_500)); + ResponseEntity rsp = controller.update(req()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, rsp.getStatusCode()); + } + + @Test + void create_ok_retornaOK() throws ConfException { + when(configService.createConfigurations(any())).thenReturn("ok"); + ResponseEntity rsp = controller.create(req()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void create_error_retornaStatusDeExcepcion() throws ConfException { + when(configService.createConfigurations(any())) + .thenThrow(new ConfException("x", "400", TypeResponse.HTTP_RESPONSE_400)); + ResponseEntity rsp = controller.create(req()); + assertEquals(HttpStatus.BAD_REQUEST, rsp.getStatusCode()); + } + + @Test + void save_ok_retornaOK() throws ConfException { + when(configService.saveConfigurations(any())).thenReturn("ok"); + ResponseEntity rsp = controller.save(req()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void save_error_retornaStatusDeExcepcion() throws ConfException { + when(configService.saveConfigurations(any())) + .thenThrow(new ConfException("x", "409", TypeResponse.HTTP_RESPONSE_409)); + ResponseEntity rsp = controller.save(req()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void list_ok_retornaOK() throws ConfException { + when(configService.getConfigurations()).thenReturn(new AppListConfigurationDTOResponse()); + ResponseEntity rsp = controller.list(); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + assertNotNull(rsp.getBody()); + } + + @Test + void list_error_retornaStatusDeExcepcion() throws ConfException { + when(configService.getConfigurations()) + .thenThrow(new ConfException("x", "503", TypeResponse.HTTP_RESPONSE_503)); + ResponseEntity rsp = controller.list(); + assertEquals(HttpStatus.SERVICE_UNAVAILABLE, rsp.getStatusCode()); + } +} diff --git a/server.app/src/test/java/cl/jonnattan/emulator/controllers/CetipaControllerTest.java b/server.app/src/test/java/cl/jonnattan/emulator/controllers/CetipaControllerTest.java new file mode 100644 index 0000000..77b56c8 --- /dev/null +++ b/server.app/src/test/java/cl/jonnattan/emulator/controllers/CetipaControllerTest.java @@ -0,0 +1,202 @@ +package cl.jonnattan.emulator.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import cl.jonnattan.emulator.dto.EdrPayAuthorizeRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentAuthorizeResponseDTO; +import cl.jonnattan.emulator.dto.EdrPaymentCreateCryptogramRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentCreateCryptogramResponseDTO; +import cl.jonnattan.emulator.dto.EdrPaymentLogonRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentLogonResponseDTO; +import cl.jonnattan.emulator.dto.EdrPaymentReverseRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentReverseResponseDTO; +import cl.jonnattan.emulator.dto.EdrTokenEnrollResponseDTO; +import cl.jonnattan.emulator.dto.EdrTokenEnrollmentRequestDTO; +import cl.jonnattan.emulator.dto.EdrTokenGetDigitalPanRequestDTO; +import cl.jonnattan.emulator.dto.EdrTokenGetDigitalPanResponseDTO; +import cl.jonnattan.emulator.dto.EdrTokenGetTokenResponseDTO; +import cl.jonnattan.emulator.dto.EdrTokenLogonRequestDTO; +import cl.jonnattan.emulator.dto.EdrTokenLogonResponseDTO; +import cl.jonnattan.emulator.dto.ints.IEmulator; +import cl.jonnattan.emulator.enums.TypeResponse; +import cl.jonnattan.emulator.interfaces.ICard; +import cl.jonnattan.emulator.interfaces.IConfigurations; +import cl.jonnattan.emulator.interfaces.IPrm; +import cl.jonnattan.emulator.interfaces.ITransactions; +import cl.jonnattan.emulator.interfaces.ITrm; +import cl.jonnattan.emulator.utils.ConfException; +import cl.jonnattan.emulator.utils.EmulatorException; +import cl.jonnattan.emulator.utils.UtilConst; + +@ExtendWith(MockitoExtension.class) +class CetipaControllerTest { + + @Mock + private ITransactions transactionService; + @Mock + private ITrm trmService; + @Mock + private IPrm prmService; + @Mock + private ICard cardService; + @Mock + private IConfigurations configService; + + @InjectMocks + private CetipaController controller; + + private HttpHeaders headersConRequestId() { + HttpHeaders h = new HttpHeaders(); + h.put(UtilConst.REQUEST_ID, Collections.singletonList("RX-1")); + h.put(UtilConst.CLIENT_ID, Collections.singletonList("CLT")); + h.put(UtilConst.ACCESS_TOKEN, Collections.singletonList("TKN")); + return h; + } + + @Test + void authorizations_ok_retornaOK() throws Exception { + when(transactionService.createTransaction(any(), any())).thenReturn(new EdrPaymentAuthorizeResponseDTO()); + ResponseEntity rsp = controller.authorizations(new EdrPayAuthorizeRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void authorizations_emulatorException_retornaConflict() throws Exception { + when(transactionService.createTransaction(any(), any())).thenThrow(new EmulatorException("e", "500")); + ResponseEntity rsp = controller.authorizations(new EdrPayAuthorizeRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void authorizations_confException_retornaStatusDeExcepcion() throws Exception { + doThrow(new ConfException("e", "500", TypeResponse.HTTP_RESPONSE_500)).when(configService) + .evaluateEndpoint(anyString()); + ResponseEntity rsp = controller.authorizations(new EdrPayAuthorizeRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, rsp.getStatusCode()); + } + + @Test + void reverse_ok_retornaOK() throws Exception { + when(transactionService.reverseTransaction(any(), any())).thenReturn(new EdrPaymentReverseResponseDTO()); + ResponseEntity rsp = controller.reverse(new EdrPaymentReverseRequestDTO(), headersConRequestId()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void reverse_emulatorException_retornaConflict() throws Exception { + when(transactionService.reverseTransaction(any(), any())).thenThrow(new EmulatorException("e", "500")); + ResponseEntity rsp = controller.reverse(new EdrPaymentReverseRequestDTO(), headersConRequestId()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void deviceEnroll_ok_retornaOK() throws Exception { + when(cardService.enrollDevice(any(), any())).thenReturn(new EdrTokenEnrollResponseDTO()); + ResponseEntity rsp = controller.deviceEnroll(new EdrTokenEnrollmentRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void deviceEnroll_error_retornaConflict() throws Exception { + when(cardService.enrollDevice(any(), any())).thenThrow(new EmulatorException("x")); + ResponseEntity rsp = controller.deviceEnroll(new EdrTokenEnrollmentRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void deviceSearch_ok_retornaOK() throws Exception { + when(cardService.cardSearch(any(), any())).thenReturn(new EdrTokenGetDigitalPanResponseDTO()); + ResponseEntity rsp = controller.deviceSearch(new EdrTokenGetDigitalPanRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void deviceSearch_error_retornaStatusDeExcepcion() throws Exception { + doThrow(new ConfException("x", "409", TypeResponse.HTTP_RESPONSE_409)).when(configService) + .evaluateEndpoint(anyString()); + ResponseEntity rsp = controller.deviceSearch(new EdrTokenGetDigitalPanRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void getToken_ok_retornaOK() throws Exception { + when(cardService.getToken(any(), any())).thenReturn(new EdrTokenGetTokenResponseDTO()); + ResponseEntity rsp = controller.getToken("TKN", new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void getToken_error_retornaConflict() throws Exception { + when(cardService.getToken(any(), any())).thenThrow(new EmulatorException("e")); + ResponseEntity rsp = controller.getToken("TKN", new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void getAcquire_ok_retornaOK() { + ResponseEntity rsp = controller.getAcquire("TKN", headersConRequestId()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + assertNotNull(rsp.getBody()); + } + + @Test + void logingoutPrm_ok_retornaOK() throws Exception { + when(prmService.logon(any(), any(), any())).thenReturn(new EdrPaymentLogonResponseDTO()); + ResponseEntity rsp = controller.logingout("R1", new EdrPaymentLogonRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void logingoutPrm_error_retornaConflict() throws Exception { + when(prmService.logon(any(), any(), any())).thenThrow(new EmulatorException("x")); + ResponseEntity rsp = controller.logingout("R1", new EdrPaymentLogonRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void logingoutTrm_ok_retornaOK() throws Exception { + when(trmService.logon(any(), any(), any())).thenReturn(new EdrTokenLogonResponseDTO()); + ResponseEntity rsp = controller.logingout("R1", new EdrTokenLogonRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void logingoutTrm_error_retornaConflict() throws Exception { + when(trmService.logon(any(), any(), any())).thenThrow(new EmulatorException("x")); + ResponseEntity rsp = controller.logingout("R1", new EdrTokenLogonRequestDTO(), new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void cryptograms_ok_retornaOK() throws Exception { + when(transactionService.createCriptogram(any(), any(), any())) + .thenReturn(new EdrPaymentCreateCryptogramResponseDTO()); + ResponseEntity rsp = controller.cryptograms("TKN", new EdrPaymentCreateCryptogramRequestDTO(), + new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void cryptograms_error_retornaConflict() throws Exception { + when(transactionService.createCriptogram(any(), any(), any())).thenThrow(new EmulatorException("e")); + ResponseEntity rsp = controller.cryptograms("TKN", new EdrPaymentCreateCryptogramRequestDTO(), + new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } +} diff --git a/server.app/src/test/java/cl/jonnattan/emulator/controllers/CxpControllerTest.java b/server.app/src/test/java/cl/jonnattan/emulator/controllers/CxpControllerTest.java new file mode 100644 index 0000000..e22598d --- /dev/null +++ b/server.app/src/test/java/cl/jonnattan/emulator/controllers/CxpControllerTest.java @@ -0,0 +1,67 @@ +package cl.jonnattan.emulator.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import cl.jonnattan.emulator.dto.cxp.CxpResponseDTO; +import cl.jonnattan.emulator.dto.cxp.ICxpResponse; +import cl.jonnattan.emulator.interfaces.ICxp; +import cl.jonnattan.emulator.utils.EmulatorException; +import jakarta.servlet.http.HttpServletRequest; + +@ExtendWith(MockitoExtension.class) +class CxpControllerTest { + + @Mock + private ICxp cxpService; + + @InjectMocks + private CxpController controller; + + @Test + void postCxp_ok_retornaOK() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(cxpService.processPostRequest(any(), any())).thenReturn(new CxpResponseDTO()); + + ResponseEntity rsp = controller.postCxp(req, new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void postCxp_error_retornaConflict() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(cxpService.processPostRequest(any(), any())).thenThrow(new EmulatorException("err")); + + ResponseEntity rsp = controller.postCxp(req, new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void getCxp_ok_retornaOK() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(cxpService.processGetRequest(any(), any())).thenReturn("ok"); + + ResponseEntity rsp = controller.getCxp(req, new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void getCxp_error_retornaConflict() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(cxpService.processGetRequest(any(), any())).thenThrow(new EmulatorException("err")); + + ResponseEntity rsp = controller.getCxp(req, new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } +} diff --git a/server.app/src/test/java/cl/jonnattan/emulator/controllers/EdrControllerTest.java b/server.app/src/test/java/cl/jonnattan/emulator/controllers/EdrControllerTest.java new file mode 100644 index 0000000..134794d --- /dev/null +++ b/server.app/src/test/java/cl/jonnattan/emulator/controllers/EdrControllerTest.java @@ -0,0 +1,93 @@ +package cl.jonnattan.emulator.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import cl.jonnattan.emulator.enums.TypeResponse; +import cl.jonnattan.emulator.interfaces.IConfigurations; +import cl.jonnattan.emulator.interfaces.IEdr; +import cl.jonnattan.emulator.utils.ConfException; +import cl.jonnattan.emulator.utils.EmulatorException; + +@ExtendWith(MockitoExtension.class) +class EdrControllerTest { + + @Mock + private IEdr edrService; + @Mock + private IConfigurations configService; + + @InjectMocks + private EdrController controller; + + private MultiValueMap headers() { + MultiValueMap h = new LinkedMultiValueMap<>(); + h.put("realm", Collections.singletonList("test")); + return h; + } + + @Test + void handleNonBrowserSubmissions_retornaOk() { + ResponseEntity rsp = controller.handleNonBrowserSubmissions(headers()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void loginTicket_ok_retornaOK() throws Exception { + when(edrService.loginEdenred(any())).thenReturn("TOKEN"); + ResponseEntity rsp = controller.loginTicket(headers()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void loginTicket_emulatorException_retornaConflict() throws Exception { + when(edrService.loginEdenred(any())).thenThrow(new EmulatorException("err")); + ResponseEntity rsp = controller.loginTicket(headers()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void loginTicket_confException_retornaStatusDeExcepcion() throws Exception { + doThrow(new ConfException("x", "500", TypeResponse.HTTP_RESPONSE_500)).when(configService) + .evaluateEndpoint(anyString()); + ResponseEntity rsp = controller.loginTicket(headers()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, rsp.getStatusCode()); + } + + @Test + void loginJunaeb_ok_retornaOK() throws Exception { + when(edrService.loginEdenred(any())).thenReturn("TOKEN"); + ResponseEntity rsp = controller.loginJunaeb(headers()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void loginJunaeb_error_retornaConflict() throws Exception { + when(edrService.loginEdenred(any())).thenThrow(new EmulatorException("err")); + ResponseEntity rsp = controller.loginJunaeb(headers()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void loginJunaeb_confException_retornaStatusDeExcepcion() throws Exception { + doThrow(new ConfException("x", "503", TypeResponse.HTTP_RESPONSE_503)).when(configService) + .evaluateEndpoint(anyString()); + ResponseEntity rsp = controller.loginJunaeb(headers()); + assertEquals(HttpStatus.SERVICE_UNAVAILABLE, rsp.getStatusCode()); + } +} diff --git a/server.app/src/test/java/cl/jonnattan/emulator/controllers/EdrEgdControllerTest.java b/server.app/src/test/java/cl/jonnattan/emulator/controllers/EdrEgdControllerTest.java new file mode 100644 index 0000000..b371f96 --- /dev/null +++ b/server.app/src/test/java/cl/jonnattan/emulator/controllers/EdrEgdControllerTest.java @@ -0,0 +1,66 @@ +package cl.jonnattan.emulator.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import cl.jonnattan.emulator.dto.ints.IEmulator; +import cl.jonnattan.emulator.dto.user.UserListDTOResponse; +import cl.jonnattan.emulator.enums.TypeResponse; +import cl.jonnattan.emulator.interfaces.ICard; +import cl.jonnattan.emulator.interfaces.IConfigurations; +import cl.jonnattan.emulator.utils.ConfException; +import cl.jonnattan.emulator.utils.EmulatorException; +import jakarta.servlet.http.HttpServletRequest; + +@ExtendWith(MockitoExtension.class) +class EdrEgdControllerTest { + + @Mock + private ICard cardService; + @Mock + private IConfigurations configService; + + @InjectMocks + private EdrEgdController controller; + + @Test + void edgCardSearch_ok_retornaOK() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(cardService.processTNP(any(), any())).thenReturn(new UserListDTOResponse()); + + ResponseEntity rsp = controller.edgCardSearch(req, new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void edgCardSearch_emulatorException_retornaConflict() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(cardService.processTNP(any(), any())).thenThrow(new EmulatorException("e", "5000")); + + ResponseEntity rsp = controller.edgCardSearch(req, new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void edgCardSearch_confException_retornaStatusDeExcepcion() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + doThrow(new ConfException("e", "500", TypeResponse.HTTP_RESPONSE_500)).when(configService) + .evaluateEndpoint(anyString()); + + ResponseEntity rsp = controller.edgCardSearch(req, new HttpHeaders()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, rsp.getStatusCode()); + } +} diff --git a/server.app/src/test/java/cl/jonnattan/emulator/controllers/PageControllerTest.java b/server.app/src/test/java/cl/jonnattan/emulator/controllers/PageControllerTest.java new file mode 100644 index 0000000..ddf0a84 --- /dev/null +++ b/server.app/src/test/java/cl/jonnattan/emulator/controllers/PageControllerTest.java @@ -0,0 +1,108 @@ +package cl.jonnattan.emulator.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import cl.jonnattan.emulator.dto.ErrorData; +import cl.jonnattan.emulator.dto.ints.IEmulator; +import cl.jonnattan.emulator.dto.user.UserListDTOResponse; +import cl.jonnattan.emulator.enums.TypeResponse; +import cl.jonnattan.emulator.interfaces.IConfigurations; +import cl.jonnattan.emulator.interfaces.IPage; +import cl.jonnattan.emulator.utils.ConfException; +import cl.jonnattan.emulator.utils.EmulatorException; +import jakarta.servlet.http.HttpServletRequest; + +@ExtendWith(MockitoExtension.class) +class PageControllerTest { + + @Mock + private IPage pageService; + @Mock + private IConfigurations configService; + + @InjectMocks + private PageController controller; + + @Test + void save_ok_retornaOK() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/page/users/save"); + when(pageService.save(any(), any())).thenReturn(new UserListDTOResponse()); + + MultiValueMap params = new LinkedMultiValueMap<>(); + ResponseEntity rsp = controller.save(params, req, new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void save_emulatorException_retornaConflict() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/page/users/save"); + when(pageService.save(any(), any())).thenThrow(new EmulatorException("x", "500")); + + MultiValueMap params = new LinkedMultiValueMap<>(); + ResponseEntity rsp = controller.save(params, req, new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void save_confException_retornaStatusDeExcepcion() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/page/users/save"); + doThrow(new ConfException("x", "400", TypeResponse.HTTP_RESPONSE_400)).when(configService) + .evaluateEndpoint(anyString()); + + MultiValueMap params = new LinkedMultiValueMap<>(); + ResponseEntity rsp = controller.save(params, req, new HttpHeaders()); + assertEquals(HttpStatus.BAD_REQUEST, rsp.getStatusCode()); + } + + @Test + void getUsers_ok_retornaOK() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/page/users"); + when(pageService.getUsers(any())).thenReturn(new UserListDTOResponse()); + + ResponseEntity rsp = controller.getUsers(req, new HttpHeaders()); + assertEquals(HttpStatus.OK, rsp.getStatusCode()); + } + + @Test + void getUsers_error_retornaConflict() throws Exception { + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/page/users"); + when(pageService.getUsers(any())).thenThrow(new EmulatorException("x")); + + ResponseEntity rsp = controller.getUsers(req, new HttpHeaders()); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } + + @Test + void handleException_emulatorException_retornaConflictConErrorData() { + ResponseEntity rsp = controller.handleException(new EmulatorException("e", "500"), null); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + assertEquals(ErrorData.class, rsp.getBody().getClass()); + } + + @Test + void handleException_excepcionGenerica_retornaConflict() { + ResponseEntity rsp = controller.handleException(new RuntimeException("x"), null); + assertEquals(HttpStatus.CONFLICT, rsp.getStatusCode()); + } +} diff --git a/server.services/pom.xml b/server.services/pom.xml index df391db..0c8251a 100644 --- a/server.services/pom.xml +++ b/server.services/pom.xml @@ -49,6 +49,11 @@ junit-jupiter test + + org.springframework.boot + spring-boot-starter-test + test + commons-codec commons-codec diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/AppConfigService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/AppConfigService.java index a31b0b8..df3e5b6 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/AppConfigService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/AppConfigService.java @@ -4,7 +4,6 @@ import cl.jonnattan.emulator.dto.AppListConfigurationDTOResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,8 +21,11 @@ public class AppConfigService implements IConfigurations { private static final Logger logger = LoggerFactory.getLogger(AppConfigService.class); - @Autowired - private IDaoConfiguration configRepository; + private final IDaoConfiguration configRepository; + + public AppConfigService(IDaoConfiguration configRepository) { + this.configRepository = configRepository; + } @Override @Transactional @@ -32,26 +34,29 @@ public String updateConfigurations(AppConfigurationRequestDTO request) throws Co String response = "Se actualiza configuración"; try { Configuration conf = configRepository.findByEndpoint(request.getEndPoint()); - if (conf != null) { - if (request.getError().booleanValue()) { - conf.setCode(request.getCode()); - conf.setMessage(request.getMessage()); - conf.setType(TypeResponse.getType(request.getType())); - conf.setError(request.getError()); - } else { - conf.setCode(null); - conf.setMessage(null); - conf.setType(TypeResponse.HTTP_RESPONSE_200); - conf.setError(false); - } - logger.info("************** UPDATE CONFIGURACION **************** "); - logger.info("Se reporta Código error: {}", conf.getCode()); - logger.info("Se reporta Mensaje error: {}", conf.getMessage()); - logger.info("Se reporta Tipo error: {}", conf.getType()); - logger.info("************************************************* "); - configRepository.save(conf); - } else + if (conf == null) { createConfigurations(request); + return response; + } + if (request.getError().booleanValue()) { + conf.setCode(request.getCode()); + conf.setMessage(request.getMessage()); + conf.setType(TypeResponse.getType(request.getType())); + conf.setError(request.getError()); + } else { + conf.setCode(null); + conf.setMessage(null); + conf.setType(TypeResponse.HTTP_RESPONSE_200); + conf.setError(false); + } + logger.info("************** UPDATE CONFIGURACION **************** "); + logger.info("Se reporta Código error: {}", conf.getCode()); + logger.info("Se reporta Mensaje error: {}", conf.getMessage()); + logger.info("Se reporta Tipo error: {}", conf.getType()); + logger.info("************************************************* "); + configRepository.save(conf); + } catch (ConfException e) { + throw e; } catch (Exception e) { throw new ConfException("[" + e.getMessage() + "] Actualizando Configuración"); } @@ -100,38 +105,41 @@ public String saveConfigurations(AppConfigurationRequestDTO request) throws Conf Configuration conf = configRepository.findByEndpoint(request.getEndPoint()); if (conf != null) { response = updateConfigurations(request); - } else + } else { response = createConfigurations(request); + } + } catch (ConfException e) { + throw e; } catch (Exception e) { throw new ConfException(e.getMessage()); } return response; } - @Override - @Transactional(readOnly = true) - public AppListConfigurationDTOResponse getConfigurations() throws ConfException { - logger.info("Service para listar las configuraciones"); - AppListConfigurationDTOResponse configurations = new AppListConfigurationDTOResponse(); - List list = configurations.getConfigurations(); - try { - Iterable confs = configRepository.findAll(); - for(Configuration c : confs) { - AppConfigurationResponseDTO config = new AppConfigurationResponseDTO(); - config.setType( c.getType().getValue() ); - config.setCode( c.getCode() ); - config.setMessage( c.getMessage() ); - config.setError( c.getError() ); - config.setEndPoint( c.getEndpoint() ); - config.setLastUpdate( c.getUpdatedAt() ); - list.add( config ); - } - configurations.setConfigurations( list ); - } catch (Exception e) { - throw new ConfException(e.getMessage()); - } - return configurations; - } + @Override + @Transactional(readOnly = true) + public AppListConfigurationDTOResponse getConfigurations() throws ConfException { + logger.info("Service para listar las configuraciones"); + AppListConfigurationDTOResponse configurations = new AppListConfigurationDTOResponse(); + List list = configurations.getConfigurations(); + try { + Iterable confs = configRepository.findAll(); + for(Configuration c : confs) { + AppConfigurationResponseDTO config = new AppConfigurationResponseDTO(); + config.setType( c.getType().getValue() ); + config.setCode( c.getCode() ); + config.setMessage( c.getMessage() ); + config.setError( c.getError() ); + config.setEndPoint( c.getEndpoint() ); + config.setLastUpdate( c.getUpdatedAt() ); + list.add( config ); + } + configurations.setConfigurations( list ); + } catch (Exception e) { + throw new ConfException(e.getMessage()); + } + return configurations; + } @SuppressWarnings("null") @Override diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/CardService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/CardService.java index 91b8bbb..d5cd803 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/CardService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/CardService.java @@ -8,7 +8,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -39,14 +38,15 @@ public class CardService implements ICard { private static final Logger logger = LoggerFactory.getLogger(CardService.class); - @Autowired - private IDaoCard cardRepository; + private final IDaoCard cardRepository; + private final IDaoDevice deviceRepository; + private final IUtilities util; - @Autowired - private IDaoDevice deviceRepository; - - @Autowired - private IUtilities util; + public CardService(IDaoCard cardRepository, IDaoDevice deviceRepository, IUtilities util) { + this.cardRepository = cardRepository; + this.deviceRepository = deviceRepository; + this.util = util; + } @Override @Transactional @@ -72,7 +72,7 @@ public EdrTokenGetDigitalPanResponseDTO cardSearch(EdrTokenGetDigitalPanRequestD Long rId = Long.parseLong(request.getRequestorInfo().getRid()); String dataCard = request.getCardInfo().getData().getProfile(); - String cardNumber = "**** **** **** ****"; + String cardNumber = UtilConst.MASKED_CARD; // Card Info es un json que trae el numero de tarjeta... String msg = util.decryptRSA(dataCard); @@ -81,8 +81,9 @@ public EdrTokenGetDigitalPanResponseDTO cardSearch(EdrTokenGetDigitalPanRequestD String tokenCard = util.getTokenCard(clientId); if (map != null) { cardNumber = (String) map.get("fpan"); - if (cardNumber != null) + if (cardNumber != null) { tokenCard = util.getTokenCard(cardNumber); + } } // busca la tarjeta inscrita Card card = cardRepository.findByCardNumber(cardNumber); @@ -129,8 +130,9 @@ public IEmulator processTNP(HttpServletRequest request, HttpHeaders headerRx) th if (dataInUrl.indexOf("actions") > 0) { action = EActions.getAction(dataInUrl); - if (!action.equals(EActions.NONE)) + if (!action.equals(EActions.NONE)) { dataInUrl = dataInUrl.replace(action.getEnd(), ""); + } dataInUrl = dataInUrl.trim(); } @@ -142,8 +144,9 @@ public IEmulator processTNP(HttpServletRequest request, HttpHeaders headerRx) th int dato = -1; ServletInputStream sis = request.getInputStream(); ByteBuffer bb = ByteBuffer.allocate(1024); - while ((dato = sis.read()) != -1) + while ((dato = sis.read()) != -1) { bb.put((byte) dato); + } bb.flip(); int len = bb.remaining(); String body = ""; @@ -219,7 +222,7 @@ private ActivatePaymentMethodResponseDTO processAssignPinTNP(Card card, String b /** * Procesa busqueda de tarjetas TNP - * + * * @param tokenCipher * @param card * @return @@ -239,7 +242,7 @@ private GetPaymentMethodInfoResponseDTO processSearchTNP(final String tokenCiphe response.setData(data); String[] strs = { "EMULATOR", "EDG", "SERVICES" }; - meta.setStatus("ACTIVE"); + meta.setStatus(UtilConst.STATUS_ACTIVE); meta.setMessages(strs); response.setMeta(meta); return response; @@ -262,25 +265,27 @@ public EdrTokenGetTokenResponseDTO getToken(String token, HttpHeaders headerRx) // el token es del device Device device = deviceRepository.findByToken(token); - if (device != null) { - logger.info("Dispositivo encontrado encontrado: {} ", token); - EdrTokenGetTokenResponseDTO.TokenInfo tokeninfo = new EdrTokenGetTokenResponseDTO.TokenInfo(); - EdrTokenGetTokenResponseDTO.Profile profile = new EdrTokenGetTokenResponseDTO.Profile(); - // con el card asociado al enrolamiento - Card card = cardRepository.findByToken(device.getCard()); - if (card != null) { - String toCipher = "{\"dpan\":\"" + card.getCardNumber() + "\",\"cvv\":\"123\",\"dexp\":\"12/21\"}"; - logger.info("DATA: {}", toCipher); - profile.setProfile(util.encryptRSA(toCipher)); - tokeninfo.setData(profile); - tokeninfo.setReference(device.getToken()); - tokeninfo.setStatus("ACTIVE"); - response.setTokeninfo(tokeninfo); - } else - throw new EmulatorException("No existe tarjeta para token", "5001"); - } else + if (device == null) { throw new EmulatorException("No existe tarjeta para token", "5001"); - + } + logger.info("Dispositivo encontrado encontrado: {} ", token); + EdrTokenGetTokenResponseDTO.TokenInfo tokeninfo = new EdrTokenGetTokenResponseDTO.TokenInfo(); + EdrTokenGetTokenResponseDTO.Profile profile = new EdrTokenGetTokenResponseDTO.Profile(); + // con el card asociado al enrolamiento + Card card = cardRepository.findByToken(device.getCard()); + if (card == null) { + throw new EmulatorException("No existe tarjeta para token", "5001"); + } + String toCipher = "{\"dpan\":\"" + card.getCardNumber() + "\",\"cvv\":\"123\",\"dexp\":\"12/21\"}"; + logger.info("DATA: {}", toCipher); + profile.setProfile(util.encryptRSA(toCipher)); + tokeninfo.setData(profile); + tokeninfo.setReference(device.getToken()); + tokeninfo.setStatus(UtilConst.STATUS_ACTIVE); + response.setTokeninfo(tokeninfo); + + } catch (EmulatorException e) { + throw e; } catch (Exception e) { logger.error("Error: ", e); throw new EmulatorException(e.getMessage() != null ? e.getMessage() : "Error desconocido"); @@ -312,7 +317,7 @@ public EdrTokenEnrollResponseDTO enrollDevice(EdrTokenEnrollmentRequestDTO reque String dataCard = request.getCardInfo().getData().getProfile(); - String cardNumber = "**** **** **** ****"; + String cardNumber = UtilConst.MASKED_CARD; String msg = util.decryptRSA(dataCard); logger.info("CardInfo: {}", msg); @@ -321,62 +326,63 @@ public EdrTokenEnrollResponseDTO enrollDevice(EdrTokenEnrollmentRequestDTO reque String tokenCard = util.getTokenCard(clientId); if (map != null) { cardNumber = (String) map.get("fpan"); - if (cardNumber != null) + if (cardNumber != null) { tokenCard = util.getTokenCard(cardNumber); + } } logger.info("CARD: {} TOKEN: {}", cardNumber, tokenCard); - if (cardNumber.equals("**** **** **** ****")) { + if (cardNumber.equals(UtilConst.MASKED_CARD)) { throw new EmulatorException("Tarjeta no existe, el metodo search dijo puras mentiras", "5000"); - } else { - Card card = cardRepository.findByCardNumber(cardNumber); - if (card != null) { - logger.info("Los token de tarjetas son: {}", - (tokenCard.equals(card.getToken()) ? "IGUALES" : "DISTINTOS")); - if (card.getToken().equals(tokenCard)) { - Device device = deviceRepository.findByCard(card.getToken()); - if (device != null) { - logger.info("Dispositivo ya existe, el token es: {}", device.getToken()); - EdrTokenEnrollResponseDTO.TokenInfo tokenInfo = new EdrTokenEnrollResponseDTO.TokenInfo(); - tokenInfo.setHref("EMULATOR-REF"); - tokenInfo.setReference(device.getToken()); - tokenInfo.setReason("REASON-EMULATOR "); - tokenInfo.setStatus("ACTIVE"); - response.setTokenInfo(tokenInfo); - - CardInfo cardInfo = new CardInfo(); - cardInfo.setReference(device.getToken()); - response.setCardInfo(cardInfo); - response.setReference(card.getToken()); - - } else { - String tokenDevice = util.SHA256(body); - logger.info("Dispositivo nuevo, el token es: {}", tokenDevice); - - device = new Device(); - device.setRequest(body); - - device.setToken(tokenDevice); - device.setCard(card.getToken()); - deviceRepository.save(device); - - EdrTokenEnrollResponseDTO.TokenInfo tokenInfo = new EdrTokenEnrollResponseDTO.TokenInfo(); - tokenInfo.setHref("EMULATOR-REF"); - tokenInfo.setReference(tokenDevice); - tokenInfo.setReason("REASON-EMULATOR "); - tokenInfo.setStatus("ACTIVE"); - response.setTokenInfo(tokenInfo); - - CardInfo cardInfo = new CardInfo(); - cardInfo.setReference(card.getToken()); - response.setCardInfo(cardInfo); - response.setReference(card.getToken()); - } + } + Card card = cardRepository.findByCardNumber(cardNumber); + if (card != null) { + logger.info("Los token de tarjetas son: {}", + (tokenCard.equals(card.getToken()) ? "IGUALES" : "DISTINTOS")); + if (card.getToken().equals(tokenCard)) { + Device device = deviceRepository.findByCard(card.getToken()); + if (device != null) { + logger.info("Dispositivo ya existe, el token es: {}", device.getToken()); + EdrTokenEnrollResponseDTO.TokenInfo tokenInfo = new EdrTokenEnrollResponseDTO.TokenInfo(); + tokenInfo.setHref(UtilConst.REF_EMULATOR); + tokenInfo.setReference(device.getToken()); + tokenInfo.setReason(UtilConst.REASON_EMULATOR); + tokenInfo.setStatus(UtilConst.STATUS_ACTIVE); + response.setTokenInfo(tokenInfo); + + CardInfo cardInfo = new CardInfo(); + cardInfo.setReference(device.getToken()); + response.setCardInfo(cardInfo); + response.setReference(card.getToken()); + + } else { + String tokenDevice = util.SHA256(body); + logger.info("Dispositivo nuevo, el token es: {}", tokenDevice); + + device = new Device(); + device.setRequest(body); + + device.setToken(tokenDevice); + device.setCard(card.getToken()); + deviceRepository.save(device); + + EdrTokenEnrollResponseDTO.TokenInfo tokenInfo = new EdrTokenEnrollResponseDTO.TokenInfo(); + tokenInfo.setHref(UtilConst.REF_EMULATOR); + tokenInfo.setReference(tokenDevice); + tokenInfo.setReason(UtilConst.REASON_EMULATOR); + tokenInfo.setStatus(UtilConst.STATUS_ACTIVE); + response.setTokenInfo(tokenInfo); + + CardInfo cardInfo = new CardInfo(); + cardInfo.setReference(card.getToken()); + response.setCardInfo(cardInfo); + response.setReference(card.getToken()); } } - } + } catch (EmulatorException e) { + throw e; } catch (Exception e) { logger.error("Error: ", e); throw new EmulatorException(e.getMessage()); diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/CxpService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/CxpService.java index 0e3d464..eb1038e 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/CxpService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/CxpService.java @@ -6,7 +6,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; @@ -33,11 +32,8 @@ private enum Enviroments { STAGING, DEVELOP, PRODUCTION } - @Autowired - private RestTemplate restTemplateWithTimeout; - - @Autowired - private IUtilities util; + private final RestTemplate restTemplateWithTimeout; + private final IUtilities util; @Value("${cxp.urls}") private String address; @@ -60,6 +56,11 @@ private enum Enviroments { private Enviroments enviroment = Enviroments.DEVELOP; + public CxpService(RestTemplate restTemplateWithTimeout, IUtilities util) { + this.restTemplateWithTimeout = restTemplateWithTimeout; + this.util = util; + } + @PostConstruct public void init() { enviroment = Enviroments.values()[index - 1]; @@ -119,8 +120,9 @@ public ICxpResponse processPostRequest(HttpServletRequest request, HttpHeaders h String msg = String.format("Enviroment %s - Use ApiKey[%s]",enviroment, newKey); logger.info("{}", msg); StringBuilder text = new StringBuilder("keys: "); - for (String skey : geokeys) + for (String skey : geokeys) { text.append(String.format("%s ",skey)); + } logger.info("{}", text); msg = String.format("Endpoint Proxy: %s",url); @@ -137,7 +139,7 @@ public ICxpResponse processPostRequest(HttpServletRequest request, HttpHeaders h response = res.getBody(); } catch (Exception e) { - e.printStackTrace(); + logger.error("Error de comunicacion", e); throw new EmulatorException("Error de comunicacion"); } @@ -146,7 +148,7 @@ public ICxpResponse processPostRequest(HttpServletRequest request, HttpHeaders h /** * Imprime en pantalla - * + * * @param request * @param header * @throws IOException @@ -157,8 +159,9 @@ private String printHeaderAndPayload(final HttpServletRequest request, final Htt int dato = -1; ServletInputStream sis = request.getInputStream(); ByteBuffer bb = ByteBuffer.allocate(4096); - while ((dato = sis.read()) != -1) + while ((dato = sis.read()) != -1) { bb.put((byte) dato); + } bb.flip(); int len = bb.remaining(); String body = ""; @@ -188,23 +191,18 @@ public String processGetRequest(HttpServletRequest request, HttpHeaders header) String response = ""; String uri = request.getRequestURI(); - try { - - if (uri.contains("/dev") || uri.contains("/develop")) { - response = String.format("Enviroment change from %s to Develop",enviroment.name()); - enviroment = Enviroments.DEVELOP; - } else if (uri.contains("/qa") || uri.contains("/quality") || uri.contains("/staging")) { - response = String.format("Enviroment change from %s to Staging",enviroment.name()); - enviroment = Enviroments.STAGING; - } else if (uri.contains("/prod") && uri.contains("/production")) { - response = String.format("Enviroment change from %s to Production",enviroment.name()); - enviroment = Enviroments.PRODUCTION; - } else { - response = String.format("Enviroment not change. Actually is %s",enviroment.name()); - throw new EmulatorException(response); - } - } catch (Exception e) { - e.printStackTrace(); + if (uri.contains("/dev") || uri.contains("/develop")) { + response = String.format("Enviroment change from %s to Develop",enviroment.name()); + enviroment = Enviroments.DEVELOP; + } else if (uri.contains("/qa") || uri.contains("/quality") || uri.contains("/staging")) { + response = String.format("Enviroment change from %s to Staging",enviroment.name()); + enviroment = Enviroments.STAGING; + } else if (uri.contains("/prod") && uri.contains("/production")) { + response = String.format("Enviroment change from %s to Production",enviroment.name()); + enviroment = Enviroments.PRODUCTION; + } else { + response = String.format("Enviroment not change. Actually is %s",enviroment.name()); + throw new EmulatorException(response); } logger.info("Response: {}", response); return response; diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/EdrService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/EdrService.java index 2155170..d1876bc 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/EdrService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/EdrService.java @@ -2,7 +2,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -25,17 +24,18 @@ public class EdrService implements IEdr { private static final Logger logger = LoggerFactory.getLogger(EdrService.class); - @Autowired - private ObjectMapper objectMapper; - - @Autowired - private IDaoUser userRepository; - - @Autowired - private IUtilities util; - - @Autowired - private RestTemplate restTemplateWithTimeout; + private final ObjectMapper objectMapper; + private final IDaoUser userRepository; + private final IUtilities util; + private final RestTemplate restTemplateWithTimeout; + + public EdrService(ObjectMapper objectMapper, IDaoUser userRepository, IUtilities util, + RestTemplate restTemplateWithTimeout) { + this.objectMapper = objectMapper; + this.userRepository = userRepository; + this.util = util; + this.restTemplateWithTimeout = restTemplateWithTimeout; + } @Transactional @Override @@ -57,8 +57,9 @@ public String loginEdenred(MultiValueMap headerRx) throws Emulat String textRealLogin = realLogin(name, pass, realm); - if (textRealLogin != null) + if (textRealLogin != null) { accesstoken = textRealLogin; + } User user = userRepository.findByNameUserAndPassword(name, pass); if (user != null) { user.setAccessToken(accesstoken); @@ -89,7 +90,7 @@ public String loginEdenred(MultiValueMap headerRx) throws Emulat /** * Realiza el login en la pagina - * + * * @param name * @param pass * @param realm @@ -107,8 +108,9 @@ private String realLogin(final String name, final String pass, final String real httpHeaders.set("realm", realm); // ticket x defecto String url = "https://certificacion.edenred.cl/EdenredPrivateWebPortal/sitefinity/Authenticate/SWT"; - if (realm.contains("EdenredJunaebWebPortal")) + if (realm.contains("EdenredJunaebWebPortal")) { url = "https://certificacion.edenred.cl/EdenredJunaebWebPortal/Sitefinity/Authenticate/SWT"; + } HttpEntity request = new HttpEntity<>(httpHeaders); logger.info("endpoint: {} ", url); @@ -117,8 +119,9 @@ private String realLogin(final String name, final String pass, final String real logger.info("Response: {}", msg); body = response.getBody(); - if (body == null || !body.contains("wrap_access_token")) + if (body == null || !body.contains("wrap_access_token")) { body = null; + } } catch (NumberFormatException e) { logger.error("Error", e); diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/PageService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/PageService.java index e546fab..8161543 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/PageService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/PageService.java @@ -5,7 +5,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -29,11 +28,13 @@ public class PageService implements IPage { private static final Logger logger = LoggerFactory.getLogger(PageService.class); - @Autowired - private IDaoUser userRepository; + private final IDaoUser userRepository; + private final IUtilities util; - @Autowired - private IUtilities util; + public PageService(IDaoUser userRepository, IUtilities util) { + this.userRepository = userRepository; + this.util = util; + } @Override public IEmulator getUsers(final HttpHeaders header) throws EmulatorException { @@ -42,8 +43,9 @@ public IEmulator getUsers(final HttpHeaders header) throws EmulatorException { Iterable users = userRepository.findAll(); response = new UserListDTOResponse(); List list = ((UserListDTOResponse) response).getUsers(); - for (User user : users) + for (User user : users) { list.add(entityToDto(user)); + } } catch (Exception e) { throw new EmulatorException("Error obteniendo usuario", "6500"); } @@ -52,7 +54,7 @@ public IEmulator getUsers(final HttpHeaders header) throws EmulatorException { /** * Convierte el Entity en un DTO - * + * * @param user * @return */ @@ -95,8 +97,9 @@ public IEmulator save(final MultiValueMap params, final HttpHead User entity = null; - if (dto.getNameUser() == null || dto.getNameUser().isEmpty()) + if (dto.getNameUser() == null || dto.getNameUser().isEmpty()) { throw new EmulatorException("Campo Mail es Obligacion", "6500"); + } entity = userRepository.findByRut(dto.getRut()); entity = entity == null ? userRepository.findByMail(dto.getMail()) : entity; @@ -124,8 +127,10 @@ public IEmulator save(final MultiValueMap params, final HttpHead User userbd = userRepository.save(entity); response = new UserSaveResponse(); ((UserSaveResponse) response).setId(userbd.getId()); + } catch (EmulatorException e) { + throw e; } catch (Exception e) { - e.printStackTrace(); + logger.error("Error guardando usuario", e); throw new EmulatorException("Error guardando usuario", "6500"); } return response; diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/PrmService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/PrmService.java index deaa50f..b6eb386 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/PrmService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/PrmService.java @@ -4,7 +4,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; @@ -21,8 +20,11 @@ public class PrmService implements IPrm { private static final Logger logger = LoggerFactory.getLogger(PrmService.class); - @Autowired - ObjectMapper objectMapper; + private final ObjectMapper objectMapper; + + public PrmService(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } @Override public EdrPaymentLogonResponseDTO logon(String requestor, HttpHeaders headerRx, EdrPaymentLogonRequestDTO request) diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/TransactionService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/TransactionService.java index 6c002c0..6ea4cff 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/TransactionService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/TransactionService.java @@ -5,7 +5,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -33,15 +32,18 @@ public class TransactionService implements ITransactions { private static final Logger logger = LoggerFactory.getLogger(TransactionService.class); - @Autowired - private IDaoTransaction transactionRepository; - @Autowired - private IDaoCard cardRepository; - @Autowired - private IDaoDevice deviceRepository; - - @Autowired - private IUtilities util; + private final IDaoTransaction transactionRepository; + private final IDaoCard cardRepository; + private final IDaoDevice deviceRepository; + private final IUtilities util; + + public TransactionService(IDaoTransaction transactionRepository, IDaoCard cardRepository, + IDaoDevice deviceRepository, IUtilities util) { + this.transactionRepository = transactionRepository; + this.cardRepository = cardRepository; + this.deviceRepository = deviceRepository; + this.util = util; + } @Override @Transactional @@ -70,10 +72,12 @@ public EdrPaymentAuthorizeResponseDTO createTransaction(EdrPayAuthorizeRequestDT if (device != null) { logger.info("Card: {}", device.getCard()); Card card = cardRepository.findByToken(device.getCard()); - if (card != null) + if (card != null) { cardNumber = card.getCardNumber(); - } else + } + } else { logger.info("####### dispositivo no encontrado"); + } } } String msg = util.decryptRSA(dataCard); @@ -107,9 +111,9 @@ public EdrPaymentAuthorizeResponseDTO createTransaction(EdrPayAuthorizeRequestDT response.setTransaction(request.getTransaction()); // Esto es lo que importa para IONIX EdrPaymentAuthorizeResponseDTO.Transactionex trans = new EdrPaymentAuthorizeResponseDTO.Transactionex(); - trans.setStatus("APPROVED"); - trans.setAvailablebalance("1005260.0"); - trans.setResponsecode("200"); + trans.setStatus(UtilConst.STATUS_APPROVED); + trans.setAvailablebalance(UtilConst.DEFAULT_BALANCE); + trans.setResponsecode(UtilConst.RESPONSE_CODE_200); trans.setAuthnumber(authId); response.setTransactionex(trans); @@ -140,33 +144,35 @@ public EdrPaymentReverseResponseDTO reverseTransaction(EdrPaymentReverseRequestD String idTransaction = request.getTransactionVoid().getAuthorization().getId(); Transaction transaction = transactionRepository.findByAuthorizationId(idTransaction); - if (transaction != null) { - if (transaction.getStatus().equals(TransactionStatus.AUTHORIZED)) { - transactionRepository.saveStatusById(TransactionStatus.REVERSED, transaction.getId(), new Date()); - response.setRequestorInfo(request.getRequestorInfo()); - response.setTransactionVoid(request.getTransactionVoid()); - - // Esto es lo que importa para IONIX - EdrPaymentReverseResponseDTO.Transactionex trans = new EdrPaymentReverseResponseDTO.Transactionex(); - trans.setStatus("APPROVED"); - trans.setAvailablebalance("1005260.0"); - trans.setResponsecode("200"); - trans.setAuthnumber(idTransaction); - trans.setMcc("EMULATOR-MCC"); - response.setTransactionex(trans); - // se devuelve la plata a la tarjeta - Card card = cardRepository.findByCardNumber(transaction.getCard()); - if (card != null) { - Long value = card.getAmount(); - value += Long.parseLong(transaction.getAmount()); - trans.setAvailablebalance(String.format("%.1f",(double) value)); - cardRepository.saveAmountById(value, card.getId(), new Date()); - } - } else - throw new EmulatorException("Transaction invalid status"); - } else + if (transaction == null) { throw new EmulatorException("Transaction not found"); + } + if (!transaction.getStatus().equals(TransactionStatus.AUTHORIZED)) { + throw new EmulatorException("Transaction invalid status"); + } + transactionRepository.saveStatusById(TransactionStatus.REVERSED, transaction.getId(), new Date()); + response.setRequestorInfo(request.getRequestorInfo()); + response.setTransactionVoid(request.getTransactionVoid()); + + // Esto es lo que importa para IONIX + EdrPaymentReverseResponseDTO.Transactionex trans = new EdrPaymentReverseResponseDTO.Transactionex(); + trans.setStatus(UtilConst.STATUS_APPROVED); + trans.setAvailablebalance(UtilConst.DEFAULT_BALANCE); + trans.setResponsecode(UtilConst.RESPONSE_CODE_200); + trans.setAuthnumber(idTransaction); + trans.setMcc(UtilConst.EMULATOR_MCC); + response.setTransactionex(trans); + // se devuelve la plata a la tarjeta + Card card = cardRepository.findByCardNumber(transaction.getCard()); + if (card != null) { + Long value = card.getAmount(); + value += Long.parseLong(transaction.getAmount()); + trans.setAvailablebalance(String.format("%.1f",(double) value)); + cardRepository.saveAmountById(value, card.getId(), new Date()); + } + } catch (EmulatorException e) { + throw e; } catch (Exception e) { logger.error("Error: ", e); throw new EmulatorException("Error reversando transacción", "32441"); @@ -194,7 +200,7 @@ public EdrPaymentCreateCryptogramResponseDTO createCriptogram(EdrPaymentCreateCr } EdrPaymentCreateCryptogramResponseDTO.TokenInfo tokenInfo = new EdrPaymentCreateCryptogramResponseDTO.TokenInfo(); EdrPaymentCreateCryptogramResponseDTO.CripData data = new EdrPaymentCreateCryptogramResponseDTO.CripData(); - data.setAtc("ATC-EMULATOR"); + data.setAtc(UtilConst.ATC_EMULATOR); data.setCriptogram(cryptogram); tokenInfo.setData(data); tokenInfo.setReference("REF-EMULATOR"); diff --git a/server.services/src/main/java/cl/jonnattan/emulator/services/TrmService.java b/server.services/src/main/java/cl/jonnattan/emulator/services/TrmService.java index 64d0c8f..e29619b 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/services/TrmService.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/services/TrmService.java @@ -4,7 +4,6 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; @@ -22,8 +21,11 @@ public class TrmService implements ITrm { private static final Logger logger = LoggerFactory.getLogger(TrmService.class); - @Autowired - ObjectMapper objectMapper; + private final ObjectMapper objectMapper; + + public TrmService(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } @Override public EdrTokenLogonResponseDTO logon(String requetor, HttpHeaders headerRx, EdrTokenLogonRequestDTO request) @@ -33,12 +35,12 @@ public EdrTokenLogonResponseDTO logon(String requetor, HttpHeaders headerRx, Edr try { String body = objectMapper.writeValueAsString(request); String header = objectMapper.writeValueAsString(headerRx); - - List list = headerRx.get("requestid"); + + List list = headerRx.get(UtilConst.REQUEST_ID); String requestId = list != null && !list.isEmpty() ? list.get(0) : UtilConst.NO_INFO; - list = headerRx.get("client_id"); + list = headerRx.get(UtilConst.CLIENT_ID); String clientId = list != null && !list.isEmpty() ? list.get(0) : UtilConst.NO_INFO; - list = headerRx.get("access_token"); + list = headerRx.get(UtilConst.ACCESS_TOKEN); String accessToken = list != null && !list.isEmpty() ? list.get(0) : UtilConst.NO_INFO; logger.info("requestid : {}", requestId); @@ -47,7 +49,7 @@ public EdrTokenLogonResponseDTO logon(String requetor, HttpHeaders headerRx, Edr logger.info("Request Body : {}", body); logger.info("Request Header: {}", header); - + } catch (JsonProcessingException e) { logger.error("Error: ", e); throw new EmulatorException(e.getMessage()); @@ -58,18 +60,18 @@ public EdrTokenLogonResponseDTO logon(String requetor, HttpHeaders headerRx, Edr private EdrTokenLogonResponseDTO getTest() { EdrTokenLogonResponseDTO response = new EdrTokenLogonResponseDTO(); - + List tsps = new ArrayList<>(); EdrTokenLogonResponseDTO.Tsp tsp = new EdrTokenLogonResponseDTO.Tsp(); tsp.setId("2e936958-9fbf-11e4-89d3-123b93f75cba"); tsp.setPriority(1); tsps.add(tsp); - + EdrTokenLogonResponseDTO.Enrollment enroll = new EdrTokenLogonResponseDTO.Enrollment(); List list = new ArrayList<>(); list.add("PAN_16"); enroll.setParams( list ); - + List bins = new ArrayList<>(); //-------------------------------------- EdrTokenLogonResponseDTO.Bin bin = new EdrTokenLogonResponseDTO.Bin(); diff --git a/server.services/src/main/java/cl/jonnattan/emulator/utils/UtilConst.java b/server.services/src/main/java/cl/jonnattan/emulator/utils/UtilConst.java index e32c4b8..9eea39c 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/utils/UtilConst.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/utils/UtilConst.java @@ -8,6 +8,7 @@ private UtilConst() { public static final String CRYPTO_PREF = "CRIPTOGRAM-EMULATOR-"; public static final String DEFAULT_CARD = "XXXXXXXXXXXXXXXX"; + public static final String MASKED_CARD = "**** **** **** ****"; public static final String NO_INFO = "Sin Información"; public static final String TEXT_TO_ENDPOINT = " para enpoint: "; public static final String CXP_SUSB_KEY = "ocp-apim-subscription-key"; @@ -17,6 +18,15 @@ private UtilConst() { public static final String REQUEST_ID = "requestid"; public static final String CLIENT_ID = "client_id"; public static final String ACCESS_TOKEN = "access_token"; - + + public static final String STATUS_APPROVED = "APPROVED"; + public static final String STATUS_ACTIVE = "ACTIVE"; + public static final String RESPONSE_CODE_200 = "200"; + public static final String DEFAULT_BALANCE = "1005260.0"; + public static final String EMULATOR_MCC = "EMULATOR-MCC"; + public static final String ATC_EMULATOR = "ATC-EMULATOR"; + public static final String REF_EMULATOR = "EMULATOR-REF"; + public static final String REASON_EMULATOR = "REASON-EMULATOR "; + public static final String LINE = "---------------------------------------------------------------------------------------"; } diff --git a/server.services/src/main/java/cl/jonnattan/emulator/utils/Utilities.java b/server.services/src/main/java/cl/jonnattan/emulator/utils/Utilities.java index 639ede7..4a80887 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/utils/Utilities.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/utils/Utilities.java @@ -4,7 +4,8 @@ import java.util.Map; import org.bouncycastle.util.encoders.Base64; -import org.springframework.beans.factory.annotation.Autowired; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.fasterxml.jackson.core.JsonProcessingException; @@ -17,17 +18,20 @@ @Component public class Utilities implements IUtilities { - @Autowired - private EncrypterBusinessLogicService rsaCipher; + private static final Logger logger = LoggerFactory.getLogger(Utilities.class); - @Autowired - private ObjectMapper objectMapper; + private final EncrypterBusinessLogicService rsaCipher; + private final ObjectMapper objectMapper; + private final ICipher aesCipher; + private final ISignature signature; - @Autowired - private ICipher aesCipher; - - @Autowired - private ISignature signature; + public Utilities(EncrypterBusinessLogicService rsaCipher, ObjectMapper objectMapper, ICipher aesCipher, + ISignature signature) { + this.rsaCipher = rsaCipher; + this.objectMapper = objectMapper; + this.aesCipher = aesCipher; + this.signature = signature; + } @Override public long cksumSHA256(String data) { @@ -48,7 +52,7 @@ public String decryptRSA(String data) { byte[] decryptedData = rsaCipher.decrypt(encryptedData); result = new String(decryptedData); } catch (Exception e) { - e.printStackTrace(); + logger.error("Error decryptRSA", e); result = ""; } } @@ -66,7 +70,7 @@ public String encryptRSA(String data) { result = new String(bytes); } catch (Exception e) { - e.printStackTrace(); + logger.error("Error encryptRSA", e); result = ""; } } @@ -79,7 +83,7 @@ public String toJson(Object obj) { try { resp = (obj != null) ? objectMapper.writeValueAsString(obj) : "NULL"; } catch (JsonProcessingException e) { - e.printStackTrace(); + logger.error("Error toJson", e); resp = "ERROR Convirtiendo a JSON"; } return resp; @@ -92,7 +96,7 @@ public Map toMap(String json) { try { map = objectMapper.readValue(json, Map.class); } catch (IOException | NullPointerException e) { - e.printStackTrace(); + logger.error("Error toMap", e); } return map; } @@ -104,7 +108,7 @@ public String decryptAES(String data) { try { result = aesCipher.decrypt(data); } catch (Exception e) { - e.printStackTrace(); + logger.error("Error decryptAES", e); result = ""; } } diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/AppConfigServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/AppConfigServiceTest.java new file mode 100644 index 0000000..a6da960 --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/AppConfigServiceTest.java @@ -0,0 +1,161 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import cl.jonnattan.emulator.Configuration; +import cl.jonnattan.emulator.daos.IDaoConfiguration; +import cl.jonnattan.emulator.dto.AppConfigurationRequestDTO; +import cl.jonnattan.emulator.dto.AppListConfigurationDTOResponse; +import cl.jonnattan.emulator.enums.TypeResponse; +import cl.jonnattan.emulator.utils.ConfException; + +@ExtendWith(MockitoExtension.class) +class AppConfigServiceTest { + + @Mock + private IDaoConfiguration configRepository; + + @InjectMocks + private AppConfigService service; + + private AppConfigurationRequestDTO buildRequest(Boolean error) { + AppConfigurationRequestDTO dto = new AppConfigurationRequestDTO(); + dto.setEndPoint("/test/endpoint"); + dto.setError(error); + dto.setCode("500"); + dto.setMessage("Error simulado"); + dto.setType(500); + return dto; + } + + @Test + void updateConfigurations_existenteConError_actualizaYGuarda() throws ConfException { + Configuration existing = new Configuration(); + existing.setEndpoint("/test/endpoint"); + when(configRepository.findByEndpoint("/test/endpoint")).thenReturn(existing); + + String result = service.updateConfigurations(buildRequest(Boolean.TRUE)); + + assertEquals("Se actualiza configuración", result); + verify(configRepository).save(existing); + assertEquals("500", existing.getCode()); + } + + @Test + void updateConfigurations_existenteSinError_limpiaCampos() throws ConfException { + Configuration existing = new Configuration(); + when(configRepository.findByEndpoint(any())).thenReturn(existing); + + service.updateConfigurations(buildRequest(Boolean.FALSE)); + + assertEquals(null, existing.getCode()); + assertEquals(null, existing.getMessage()); + assertEquals(TypeResponse.HTTP_RESPONSE_200, existing.getType()); + verify(configRepository).save(existing); + } + + @Test + void updateConfigurations_noExiste_delegaEnCreate() throws ConfException { + when(configRepository.findByEndpoint(any())).thenReturn(null); + + String result = service.updateConfigurations(buildRequest(Boolean.TRUE)); + + assertNotNull(result); + verify(configRepository).save(any(Configuration.class)); + } + + @Test + void createConfigurations_conError_guardaConfiguracion() throws ConfException { + String result = service.createConfigurations(buildRequest(Boolean.TRUE)); + + assertEquals("Se crea configuración", result); + verify(configRepository).save(any(Configuration.class)); + } + + @Test + void createConfigurations_sinError_guardaConTipoOK() throws ConfException { + service.createConfigurations(buildRequest(Boolean.FALSE)); + verify(configRepository).save(any(Configuration.class)); + } + + @Test + void saveConfigurations_existente_llamaUpdate() throws ConfException { + Configuration existing = new Configuration(); + when(configRepository.findByEndpoint("/test/endpoint")).thenReturn(existing, existing); + + String result = service.saveConfigurations(buildRequest(Boolean.TRUE)); + + assertNotNull(result); + verify(configRepository).save(any(Configuration.class)); + } + + @Test + void saveConfigurations_noExiste_llamaCreate() throws ConfException { + when(configRepository.findByEndpoint(any())).thenReturn(null); + + String result = service.saveConfigurations(buildRequest(Boolean.TRUE)); + + assertNotNull(result); + verify(configRepository).save(any(Configuration.class)); + } + + @Test + void getConfigurations_retornaListaConElementos() throws ConfException { + Configuration c = new Configuration(); + c.setEndpoint("/e"); + c.setCode("500"); + c.setMessage("m"); + c.setError(Boolean.TRUE); + c.setType(TypeResponse.HTTP_RESPONSE_500); + when(configRepository.findAll()).thenReturn(Collections.singletonList(c)); + + AppListConfigurationDTOResponse result = service.getConfigurations(); + + assertNotNull(result); + assertEquals(1, result.getConfigurations().size()); + } + + @Test + void evaluateEndpoint_sinConfiguracion_noLanza() throws ConfException { + when(configRepository.findByEndpoint(any())).thenReturn(null); + service.evaluateEndpoint("/cualquiera"); + verify(configRepository).findByEndpoint("/cualquiera"); + } + + @Test + void evaluateEndpoint_conError_lanzaConfException() { + Configuration c = new Configuration(); + c.setError(Boolean.TRUE); + c.setCode("503"); + c.setMessage("Servicio caído"); + c.setType(TypeResponse.HTTP_RESPONSE_503); + when(configRepository.findByEndpoint(any())).thenReturn(c); + + ConfException ex = assertThrows(ConfException.class, () -> service.evaluateEndpoint("/e")); + assertEquals("503", ex.getCode()); + } + + @Test + void evaluateEndpoint_sinError_noLanza() throws ConfException { + Configuration c = new Configuration(); + c.setError(Boolean.FALSE); + when(configRepository.findByEndpoint(any())).thenReturn(c); + + service.evaluateEndpoint("/e"); + verify(configRepository, never()).save(any()); + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/CardServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/CardServiceTest.java new file mode 100644 index 0000000..2bde4d0 --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/CardServiceTest.java @@ -0,0 +1,268 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; + +import cl.jonnattan.emulator.Card; +import cl.jonnattan.emulator.Device; +import cl.jonnattan.emulator.daos.IDaoCard; +import cl.jonnattan.emulator.daos.IDaoDevice; +import cl.jonnattan.emulator.dto.EdrTokenEnrollResponseDTO; +import cl.jonnattan.emulator.dto.EdrTokenEnrollmentRequestDTO; +import cl.jonnattan.emulator.dto.EdrTokenGetDigitalPanRequestDTO; +import cl.jonnattan.emulator.dto.EdrTokenGetDigitalPanResponseDTO; +import cl.jonnattan.emulator.dto.EdrTokenGetTokenResponseDTO; +import cl.jonnattan.emulator.dto.ints.IEmulator; +import cl.jonnattan.emulator.interfaces.IUtilities; +import cl.jonnattan.emulator.utils.EmulatorException; +import cl.jonnattan.emulator.utils.UtilConst; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; + +@ExtendWith(MockitoExtension.class) +class CardServiceTest { + + @Mock + private IDaoCard cardRepository; + @Mock + private IDaoDevice deviceRepository; + @Mock + private IUtilities util; + + @InjectMocks + private CardService service; + + private EdrTokenGetDigitalPanRequestDTO buildSearchRequest() { + EdrTokenGetDigitalPanRequestDTO r = new EdrTokenGetDigitalPanRequestDTO(); + EdrTokenGetDigitalPanRequestDTO.RequestorInfo ri = new EdrTokenGetDigitalPanRequestDTO.RequestorInfo(); + ri.setRid("123"); + r.setRequestorInfo(ri); + EdrTokenGetDigitalPanRequestDTO.CardInfo ci = new EdrTokenGetDigitalPanRequestDTO.CardInfo(); + EdrTokenGetDigitalPanRequestDTO.ProfileData pd = new EdrTokenGetDigitalPanRequestDTO.ProfileData(); + pd.setProfile("CIPHER-PROFILE"); + ci.setData(pd); + r.setCardInfo(ci); + return r; + } + + @Test + void cardSearch_tarjetaEncontrada_retornaResponse() throws EmulatorException { + EdrTokenGetDigitalPanRequestDTO req = buildSearchRequest(); + Map map = new HashMap<>(); + map.put("fpan", "4242424242424242"); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptRSA(any())).thenReturn("{}"); + when(util.toMap(any())).thenReturn(map); + when(util.getTokenCard(any())).thenReturn("TOKEN-X"); + Card card = new Card(); + card.setCardNumber("4242424242424242"); + card.setToken("TOKEN-X"); + when(cardRepository.findByCardNumber("4242424242424242")).thenReturn(card); + + EdrTokenGetDigitalPanResponseDTO response = service.cardSearch(req, new HttpHeaders()); + + assertNotNull(response); + assertNotNull(response.getCardInfo()); + } + + @Test + void cardSearch_tarjetaNoExiste_laRegistraYResponde() throws EmulatorException { + EdrTokenGetDigitalPanRequestDTO req = buildSearchRequest(); + Map map = new HashMap<>(); + map.put("fpan", "99"); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptRSA(any())).thenReturn("{}"); + when(util.toMap(any())).thenReturn(map); + when(util.getTokenCard(any())).thenReturn("TK"); + when(cardRepository.findByCardNumber(any())).thenReturn(null); + when(cardRepository.save(any())).thenAnswer(inv -> { + Card c = inv.getArgument(0); + c.setId(1L); + return c; + }); + + EdrTokenGetDigitalPanResponseDTO response = service.cardSearch(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void cardSearch_error_lanzaEmulatorException() { + EdrTokenGetDigitalPanRequestDTO req = buildSearchRequest(); + when(util.toJson(any())).thenThrow(new RuntimeException("boom")); + assertThrows(EmulatorException.class, () -> service.cardSearch(req, new HttpHeaders())); + } + + @Test + void getToken_deviceNoExiste_lanzaEmulatorException() { + when(deviceRepository.findByToken("X")).thenReturn(null); + EmulatorException ex = assertThrows(EmulatorException.class, + () -> service.getToken("X", new HttpHeaders())); + assertNotNull(ex.getMessage()); + } + + @Test + void getToken_deviceSinCard_lanzaEmulatorException() { + Device d = new Device(); + d.setCard("C1"); + when(deviceRepository.findByToken("TK")).thenReturn(d); + when(cardRepository.findByToken("C1")).thenReturn(null); + + assertThrows(EmulatorException.class, () -> service.getToken("TK", new HttpHeaders())); + } + + @Test + void getToken_ok_retornaTokenInfo() throws EmulatorException { + Device d = new Device(); + d.setCard("C1"); + d.setToken("TKN"); + when(deviceRepository.findByToken("TK")).thenReturn(d); + Card c = new Card(); + c.setCardNumber("4242"); + when(cardRepository.findByToken("C1")).thenReturn(c); + when(util.encryptRSA(any())).thenReturn("CIPHER"); + + EdrTokenGetTokenResponseDTO response = service.getToken("TK", new HttpHeaders()); + + assertNotNull(response); + assertNotNull(response.getTokeninfo()); + } + + @Test + void enrollDevice_cardNoIdentificada_lanzaEmulatorException() { + EdrTokenEnrollmentRequestDTO req = buildEnrollRequest(); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptRSA(any())).thenReturn("{}"); + when(util.toMap(any())).thenReturn(new HashMap<>()); + when(util.getTokenCard(any())).thenReturn("TK"); + + EmulatorException ex = assertThrows(EmulatorException.class, + () -> service.enrollDevice(req, new HttpHeaders())); + assertNotNull(ex.getMessage()); + } + + @Test + void enrollDevice_cardYDeviceExisten_retornaExistente() throws EmulatorException { + EdrTokenEnrollmentRequestDTO req = buildEnrollRequest(); + Map map = new HashMap<>(); + map.put("fpan", "4242"); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptRSA(any())).thenReturn("{}"); + when(util.toMap(any())).thenReturn(map); + when(util.getTokenCard(any())).thenReturn("TK-CARD"); + + Card card = new Card(); + card.setToken("TK-CARD"); + when(cardRepository.findByCardNumber("4242")).thenReturn(card); + Device d = new Device(); + d.setToken("DEV-TOKEN"); + when(deviceRepository.findByCard("TK-CARD")).thenReturn(d); + + EdrTokenEnrollResponseDTO response = service.enrollDevice(req, new HttpHeaders()); + + assertNotNull(response); + assertNotNull(response.getTokenInfo()); + } + + @Test + void enrollDevice_cardExisteSinDevice_creaNuevo() throws EmulatorException { + EdrTokenEnrollmentRequestDTO req = buildEnrollRequest(); + Map map = new HashMap<>(); + map.put("fpan", "4242"); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptRSA(any())).thenReturn("{}"); + when(util.toMap(any())).thenReturn(map); + when(util.getTokenCard(any())).thenReturn("TK-CARD"); + when(util.SHA256(any())).thenReturn("NEW-DEVICE-TK"); + + Card card = new Card(); + card.setToken("TK-CARD"); + when(cardRepository.findByCardNumber("4242")).thenReturn(card); + when(deviceRepository.findByCard("TK-CARD")).thenReturn(null); + + EdrTokenEnrollResponseDTO response = service.enrollDevice(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void processTNP_tarjetaNueva_guardaYRetorna() throws Exception { + HttpServletRequest req = mockTnpRequest("/api/v1/foods/cards/ENCODED"); + HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer XYZ"); + headers.add(UtilConst.X_CLIENT_ID, "client"); + headers.add(UtilConst.X_CLIENT_SECRET, "secret"); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptAES(any())).thenReturn("4242"); + when(util.SHA256(any())).thenReturn("SHA"); + when(cardRepository.findByCardNumber("4242")).thenReturn(null); + when(cardRepository.save(any())).thenAnswer(inv -> { + Card c = inv.getArgument(0); + c.setId(10L); + return c; + }); + + IEmulator response = service.processTNP(req, headers); + + assertNotNull(response); + } + + private EdrTokenEnrollmentRequestDTO buildEnrollRequest() { + EdrTokenEnrollmentRequestDTO r = new EdrTokenEnrollmentRequestDTO(); + EdrTokenEnrollmentRequestDTO.CardInfo ci = new EdrTokenEnrollmentRequestDTO.CardInfo(); + EdrTokenEnrollmentRequestDTO.ProfileData pd = new EdrTokenEnrollmentRequestDTO.ProfileData(); + pd.setProfile("CIPHER"); + ci.setData(pd); + r.setCardInfo(ci); + return r; + } + + private HttpServletRequest mockTnpRequest(String uri) throws IOException { + HttpServletRequest req = org.mockito.Mockito.mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn(uri); + ByteArrayInputStream bais = new ByteArrayInputStream(new byte[0]); + when(req.getInputStream()).thenReturn(new ServletInputStream() { + @Override + public int read() { + return bais.read(); + } + + @Override + public boolean isFinished() { + return bais.available() == 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener listener) { + // noop + } + }); + return req; + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/CxpServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/CxpServiceTest.java new file mode 100644 index 0000000..52952e8 --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/CxpServiceTest.java @@ -0,0 +1,156 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.client.RestTemplate; + +import cl.jonnattan.emulator.dto.cxp.CxpResponseDTO; +import cl.jonnattan.emulator.dto.cxp.ICxpResponse; +import cl.jonnattan.emulator.interfaces.IUtilities; +import cl.jonnattan.emulator.utils.EmulatorException; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; + +@ExtendWith(MockitoExtension.class) +class CxpServiceTest { + + @Mock + private RestTemplate restTemplateWithTimeout; + @Mock + private IUtilities util; + + @InjectMocks + private CxpService service; + + @BeforeEach + void init() { + ReflectionTestUtils.setField(service, "address", "http://a,http://b,http://c"); + ReflectionTestUtils.setField(service, "keysOt", "k1,k2,k3"); + ReflectionTestUtils.setField(service, "keysGeo", "g1,g2,g3"); + ReflectionTestUtils.setField(service, "keysCotizacion", "c1,c2,c3"); + ReflectionTestUtils.setField(service, "index", 2); + service.init(); + } + + @Test + void processPostRequest_rating_usaCotKey() throws Exception { + HttpServletRequest req = mockRequest("/cxp/rating/api/v1.0/rates/courier"); + CxpResponseDTO body = new CxpResponseDTO(); + ResponseEntity rsp = ResponseEntity.ok(body); + when(restTemplateWithTimeout.postForEntity(any(String.class), any(HttpEntity.class), eq(CxpResponseDTO.class))) + .thenReturn(rsp); + when(util.toJson(any())).thenReturn("{}"); + + ICxpResponse response = service.processPostRequest(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void processPostRequest_transportOrders_usaOtKey() throws Exception { + HttpServletRequest req = mockRequest("/cxp/transport-orders/api/v1.0/transport-orders"); + CxpResponseDTO body = new CxpResponseDTO(); + when(restTemplateWithTimeout.postForEntity(any(String.class), any(HttpEntity.class), eq(CxpResponseDTO.class))) + .thenReturn(ResponseEntity.ok(body)); + when(util.toJson(any())).thenReturn("{}"); + + ICxpResponse response = service.processPostRequest(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void processPostRequest_errorRest_lanzaEmulatorException() throws Exception { + HttpServletRequest req = mockRequest("/cxp/otro"); + when(util.toJson(any())).thenReturn("{}"); + when(restTemplateWithTimeout.postForEntity(any(String.class), any(HttpEntity.class), eq(CxpResponseDTO.class))) + .thenThrow(new RuntimeException("boom")); + + assertThrows(EmulatorException.class, () -> service.processPostRequest(req, new HttpHeaders())); + } + + @Test + void processGetRequest_dev_cambiaAmbiente() throws Exception { + HttpServletRequest req = Mockito.mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/cxp/dev"); + + String response = service.processGetRequest(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void processGetRequest_qa_cambiaAmbiente() throws Exception { + HttpServletRequest req = Mockito.mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/cxp/qa"); + + String response = service.processGetRequest(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void processGetRequest_prodProduction_cambiaAmbiente() throws Exception { + HttpServletRequest req = Mockito.mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/cxp/prod/production"); + + String response = service.processGetRequest(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void processGetRequest_uriInvalida_lanzaEmulatorException() { + HttpServletRequest req = Mockito.mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/cxp/otro"); + + assertThrows(EmulatorException.class, () -> service.processGetRequest(req, new HttpHeaders())); + } + + private HttpServletRequest mockRequest(String uri) throws IOException { + HttpServletRequest req = Mockito.mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn(uri); + ByteArrayInputStream bais = new ByteArrayInputStream("{\"body\":1}".getBytes()); + when(req.getInputStream()).thenReturn(new ServletInputStream() { + @Override + public int read() { + return bais.read(); + } + + @Override + public boolean isFinished() { + return bais.available() == 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener listener) { + // noop + } + }); + return req; + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/EdrServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/EdrServiceTest.java new file mode 100644 index 0000000..906e04b --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/EdrServiceTest.java @@ -0,0 +1,91 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import cl.jonnattan.emulator.User; +import cl.jonnattan.emulator.daos.IDaoUser; +import cl.jonnattan.emulator.interfaces.IUtilities; +import cl.jonnattan.emulator.utils.EmulatorException; + +@ExtendWith(MockitoExtension.class) +class EdrServiceTest { + + @Mock + private ObjectMapper objectMapper; + @Mock + private IDaoUser userRepository; + @Mock + private IUtilities util; + @Mock + private RestTemplate restTemplateWithTimeout; + + @InjectMocks + private EdrService service; + + private MultiValueMap buildHeaders(String realm) { + MultiValueMap h = new LinkedMultiValueMap<>(); + h.put("wrap_name", Collections.singletonList("john")); + h.put("wrap_password", Collections.singletonList("pwd")); + h.put("realm", Collections.singletonList(realm)); + return h; + } + + @Test + void loginEdenred_usuarioExistente_actualizaToken() throws Exception { + when(objectMapper.writeValueAsString(any())).thenReturn("{}"); + when(util.SHA256(any())).thenReturn("HASH-TOKEN"); + when(util.toJson(any())).thenReturn("{}"); + ResponseEntity rsp = ResponseEntity.ok("no_token_here"); + when(restTemplateWithTimeout.postForEntity(any(String.class), any(HttpEntity.class), eq(String.class))) + .thenReturn(rsp); + + User existing = new User(); + existing.setId(1L); + when(userRepository.findByNameUserAndPassword("john", "pwd")).thenReturn(existing); + + String result = service.loginEdenred(buildHeaders("EdenredPrivateWebPortal")); + + assertNotNull(result); + } + + @Test + void loginEdenred_usuarioNoExiste_creaUsuario() throws Exception { + when(objectMapper.writeValueAsString(any())).thenReturn("{}"); + when(util.SHA256(any())).thenReturn("HASH"); + when(util.toJson(any())).thenReturn("{}"); + when(restTemplateWithTimeout.postForEntity(any(String.class), any(HttpEntity.class), eq(String.class))) + .thenReturn(ResponseEntity.ok(null)); + when(userRepository.findByNameUserAndPassword(any(), any())).thenReturn(null); + + String result = service.loginEdenred(buildHeaders("EdenredJunaebWebPortal")); + + assertNotNull(result); + } + + @Test + void loginEdenred_errorEnProceso_lanzaEmulatorException() throws Exception { + when(objectMapper.writeValueAsString(any())).thenThrow(new RuntimeException("boom")); + EmulatorException ex = assertThrows(EmulatorException.class, + () -> service.loginEdenred(buildHeaders("x"))); + assertNotNull(ex.getMessage()); + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/PageServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/PageServiceTest.java new file mode 100644 index 0000000..e1d8637 --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/PageServiceTest.java @@ -0,0 +1,123 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Collections; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import cl.jonnattan.emulator.User; +import cl.jonnattan.emulator.daos.IDaoUser; +import cl.jonnattan.emulator.dto.ints.IEmulator; +import cl.jonnattan.emulator.dto.user.UserListDTOResponse; +import cl.jonnattan.emulator.dto.user.UserSaveResponse; +import cl.jonnattan.emulator.enums.EUserType; +import cl.jonnattan.emulator.interfaces.IUtilities; +import cl.jonnattan.emulator.utils.EmulatorException; + +@ExtendWith(MockitoExtension.class) +class PageServiceTest { + + @Mock + private IDaoUser userRepository; + + @Mock + private IUtilities util; + + @InjectMocks + private PageService service; + + private User buildUser() { + User u = new User(); + u.setId(1L); + u.setRut("11111111-1"); + u.setMail("a@b.cl"); + u.setNameUser("user"); + u.setFullName("Nombre"); + u.setAge(30); + u.setAddress("Dir"); + u.setCity("Stgo"); + u.setMobile("9"); + u.setType(EUserType.NORMAL); + return u; + } + + @Test + void getUsers_retornaListaMapeada() throws EmulatorException { + when(userRepository.findAll()).thenReturn(Arrays.asList(buildUser(), buildUser())); + + IEmulator response = service.getUsers(new HttpHeaders()); + + assertInstanceOf(UserListDTOResponse.class, response); + assertEquals(2, ((UserListDTOResponse) response).getUsers().size()); + } + + @Test + void getUsers_cuandoFalla_lanzaEmulatorException() { + when(userRepository.findAll()).thenThrow(new RuntimeException("boom")); + EmulatorException ex = assertThrows(EmulatorException.class, () -> service.getUsers(new HttpHeaders())); + assertEquals("6500", ex.getCode()); + } + + @Test + void save_usuarioNuevo_creaYRetornaId() throws EmulatorException { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.put("userName", Collections.singletonList("nuevo")); + params.put("rut", Collections.singletonList("22222222-2")); + params.put("mail", Collections.singletonList("x@y.cl")); + params.put("pass", Collections.singletonList("secret")); + params.put("type", Collections.singletonList("Normal")); + params.put("age", Collections.singletonList("25")); + + when(userRepository.findByRut(any())).thenReturn(null); + when(userRepository.findByMail(any())).thenReturn(null); + when(util.SHA256(any())).thenReturn("HASH"); + User saved = buildUser(); + saved.setId(999L); + when(userRepository.save(any())).thenReturn(saved); + + IEmulator response = service.save(params, new HttpHeaders()); + + assertInstanceOf(UserSaveResponse.class, response); + assertEquals(999L, ((UserSaveResponse) response).getId()); + } + + @Test + void save_usuarioExiste_actualiza() throws EmulatorException { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.put("userName", Collections.singletonList("existe")); + params.put("rut", Collections.singletonList("11111111-1")); + params.put("type", Collections.singletonList("Administrador")); + + User u = buildUser(); + when(userRepository.findByRut(any())).thenReturn(u); + when(userRepository.save(any())).thenReturn(u); + + IEmulator response = service.save(params, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void save_sinNameUser_lanzaEmulatorException() { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.put("rut", Collections.singletonList("X")); + + EmulatorException ex = assertThrows(EmulatorException.class, + () -> service.save(params, new HttpHeaders())); + assertEquals("6500", ex.getCode()); + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/PrmServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/PrmServiceTest.java new file mode 100644 index 0000000..d77c814 --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/PrmServiceTest.java @@ -0,0 +1,46 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; + +import cl.jonnattan.emulator.dto.EdrPaymentLogonRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentLogonResponseDTO; +import cl.jonnattan.emulator.utils.EmulatorException; + +@ExtendWith(MockitoExtension.class) +class PrmServiceTest { + + @Mock + private ObjectMapper objectMapper; + + @InjectMocks + private PrmService service; + + @Test + void logon_ok_retornaResponseDTO() throws Exception { + when(objectMapper.writeValueAsString(any())).thenReturn("{}"); + EdrPaymentLogonResponseDTO response = service.logon("REQ", new HttpHeaders(), new EdrPaymentLogonRequestDTO()); + assertNotNull(response); + } + + @Test + void logon_jsonError_lanzaEmulatorException() throws Exception { + when(objectMapper.writeValueAsString(any())).thenThrow(new JsonProcessingException("boom") { + private static final long serialVersionUID = 1L; + }); + assertThrows(EmulatorException.class, + () -> service.logon("REQ", new HttpHeaders(), new EdrPaymentLogonRequestDTO())); + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/TransactionServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/TransactionServiceTest.java new file mode 100644 index 0000000..116427a --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/TransactionServiceTest.java @@ -0,0 +1,209 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; + +import cl.jonnattan.emulator.Card; +import cl.jonnattan.emulator.Device; +import cl.jonnattan.emulator.Transaction; +import cl.jonnattan.emulator.daos.IDaoCard; +import cl.jonnattan.emulator.daos.IDaoDevice; +import cl.jonnattan.emulator.daos.IDaoTransaction; +import cl.jonnattan.emulator.dto.Authorization; +import cl.jonnattan.emulator.dto.EdrPayAuthorizeRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentAuthorizeResponseDTO; +import cl.jonnattan.emulator.dto.EdrPaymentCreateCryptogramRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentCreateCryptogramResponseDTO; +import cl.jonnattan.emulator.dto.EdrPaymentReverseRequestDTO; +import cl.jonnattan.emulator.dto.EdrPaymentReverseResponseDTO; +import cl.jonnattan.emulator.dto.TransactionVoid; +import cl.jonnattan.emulator.enums.TransactionStatus; +import cl.jonnattan.emulator.interfaces.IUtilities; +import cl.jonnattan.emulator.utils.EmulatorException; +import cl.jonnattan.emulator.utils.UtilConst; + +@ExtendWith(MockitoExtension.class) +class TransactionServiceTest { + + @Mock + private IDaoTransaction transactionRepository; + @Mock + private IDaoCard cardRepository; + @Mock + private IDaoDevice deviceRepository; + @Mock + private IUtilities util; + + @InjectMocks + private TransactionService service; + + private static final ObjectMapper mapper = new ObjectMapper(); + + private EdrPayAuthorizeRequestDTO buildAuthRequest() throws Exception { + String json = "{\"token\":{\"data\":\"CIPHER-DATA\"},\"transaction\":{\"amount\":\"1000\"}}"; + return mapper.readValue(json, EdrPayAuthorizeRequestDTO.class); + } + + private EdrPaymentReverseRequestDTO buildReverseRequest(String authId) { + EdrPaymentReverseRequestDTO req = new EdrPaymentReverseRequestDTO(); + TransactionVoid tv = new TransactionVoid(); + Authorization auth = new Authorization(); + auth.setId(authId); + tv.setAuthorization(auth); + req.setTransactionVoid(tv); + return req; + } + + @Test + void createTransaction_conDispositivoYTarjeta_responde() throws Exception { + EdrPayAuthorizeRequestDTO req = buildAuthRequest(); + Map map = new HashMap<>(); + map.put("cryptogram", UtilConst.CRYPTO_PREF + "XYZ"); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptRSA("CIPHER-DATA")).thenReturn("{\"cryptogram\":\"CRIPTOGRAM-EMULATOR-XYZ\"}"); + when(util.toMap(any())).thenReturn(map); + when(util.cksumSHA256(any())).thenReturn(12345L); + Device device = new Device(); + device.setCard("TOKEN-CARD"); + when(deviceRepository.findByCryptogram(any())).thenReturn(device); + Card card = new Card(); + card.setCardNumber("4242424242424242"); + card.setId(1L); + card.setAmount(100000L); + when(cardRepository.findByToken("TOKEN-CARD")).thenReturn(card); + when(cardRepository.findByCardNumber("4242424242424242")).thenReturn(card); + + EdrPaymentAuthorizeResponseDTO response = service.createTransaction(req, new HttpHeaders()); + + assertNotNull(response); + assertEquals(UtilConst.STATUS_APPROVED, response.getTransactionex().getStatus()); + assertEquals(UtilConst.RESPONSE_CODE_200, response.getTransactionex().getResponsecode()); + } + + @Test + void createTransaction_sinDispositivo_usaDefaultCard() throws Exception { + EdrPayAuthorizeRequestDTO req = buildAuthRequest(); + Map map = new HashMap<>(); + map.put("cryptogram", UtilConst.CRYPTO_PREF + "N/A"); + + when(util.toJson(any())).thenReturn("{}"); + when(util.decryptRSA(any())).thenReturn("{}"); + when(util.toMap(any())).thenReturn(map); + when(util.cksumSHA256(any())).thenReturn(999L); + when(deviceRepository.findByCryptogram(any())).thenReturn(null); + + EdrPaymentAuthorizeResponseDTO response = service.createTransaction(req, new HttpHeaders()); + + assertNotNull(response); + } + + @Test + void createTransaction_cuandoFalla_lanzaEmulatorException() throws Exception { + EdrPayAuthorizeRequestDTO req = buildAuthRequest(); + when(util.toJson(any())).thenThrow(new RuntimeException("boom")); + + EmulatorException ex = assertThrows(EmulatorException.class, + () -> service.createTransaction(req, new HttpHeaders())); + assertEquals("5544", ex.getCode()); + } + + @Test + void reverseTransaction_transaccionAutorizada_devuelveAPROBADO() throws EmulatorException { + EdrPaymentReverseRequestDTO req = buildReverseRequest("AUTH-1"); + + Transaction tx = new Transaction(); + tx.setId(1L); + tx.setStatus(TransactionStatus.AUTHORIZED); + tx.setCard("4242"); + tx.setAmount("500"); + + Card card = new Card(); + card.setId(1L); + card.setAmount(1000L); + + when(util.toJson(any())).thenReturn("{}"); + when(transactionRepository.findByAuthorizationId("AUTH-1")).thenReturn(tx); + when(cardRepository.findByCardNumber("4242")).thenReturn(card); + + EdrPaymentReverseResponseDTO response = service.reverseTransaction(req, new HttpHeaders()); + + assertEquals(UtilConst.STATUS_APPROVED, response.getTransactionex().getStatus()); + assertEquals(UtilConst.EMULATOR_MCC, response.getTransactionex().getMcc()); + } + + @Test + void reverseTransaction_transaccionNoExiste_lanzaEmulatorException() { + EdrPaymentReverseRequestDTO req = buildReverseRequest("NOEXISTE"); + + when(util.toJson(any())).thenReturn("{}"); + when(transactionRepository.findByAuthorizationId("NOEXISTE")).thenReturn(null); + + assertThrows(EmulatorException.class, () -> service.reverseTransaction(req, new HttpHeaders())); + } + + @Test + void reverseTransaction_estadoInvalido_lanzaEmulatorException() { + EdrPaymentReverseRequestDTO req = buildReverseRequest("X"); + + Transaction tx = new Transaction(); + tx.setStatus(TransactionStatus.REVERSED); + + when(util.toJson(any())).thenReturn("{}"); + when(transactionRepository.findByAuthorizationId("X")).thenReturn(tx); + + assertThrows(EmulatorException.class, () -> service.reverseTransaction(req, new HttpHeaders())); + } + + @Test + void createCriptogram_conDevice_retornaCriptograma() throws EmulatorException { + EdrPaymentCreateCryptogramRequestDTO req = new EdrPaymentCreateCryptogramRequestDTO(); + when(util.toJson(any())).thenReturn("{}"); + when(util.SHA256(any())).thenReturn("HASH"); + Device device = new Device(); + device.setId(99L); + when(deviceRepository.findByToken("TKN")).thenReturn(device); + + EdrPaymentCreateCryptogramResponseDTO response = service.createCriptogram(req, new HttpHeaders(), "TKN"); + + assertNotNull(response); + assertEquals(UtilConst.ATC_EMULATOR, response.getTokenInfo().getData().getAtc()); + } + + @Test + void createCriptogram_sinDevice_retornaIgual() throws EmulatorException { + EdrPaymentCreateCryptogramRequestDTO req = new EdrPaymentCreateCryptogramRequestDTO(); + when(util.toJson(any())).thenReturn("{}"); + when(util.SHA256(any())).thenReturn("HASH"); + when(deviceRepository.findByToken("TKN")).thenReturn(null); + + EdrPaymentCreateCryptogramResponseDTO response = service.createCriptogram(req, new HttpHeaders(), "TKN"); + + assertNotNull(response); + } + + @Test + void createCriptogram_cuandoFalla_lanzaEmulatorException() { + EdrPaymentCreateCryptogramRequestDTO req = new EdrPaymentCreateCryptogramRequestDTO(); + when(util.toJson(any())).thenThrow(new RuntimeException("boom")); + + EmulatorException ex = assertThrows(EmulatorException.class, + () -> service.createCriptogram(req, new HttpHeaders(), "TKN")); + assertEquals("5423", ex.getCode()); + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/services/TrmServiceTest.java b/server.services/src/test/java/cl/jonnattan/emulator/services/TrmServiceTest.java new file mode 100644 index 0000000..64bac9f --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/services/TrmServiceTest.java @@ -0,0 +1,46 @@ +package cl.jonnattan.emulator.services; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; + +import cl.jonnattan.emulator.dto.EdrTokenLogonRequestDTO; +import cl.jonnattan.emulator.dto.EdrTokenLogonResponseDTO; +import cl.jonnattan.emulator.utils.EmulatorException; + +@ExtendWith(MockitoExtension.class) +class TrmServiceTest { + + @Mock + private ObjectMapper objectMapper; + + @InjectMocks + private TrmService service; + + @Test + void logon_ok_retornaResponseDTO() throws Exception { + when(objectMapper.writeValueAsString(any())).thenReturn("{}"); + EdrTokenLogonResponseDTO response = service.logon("REQ", new HttpHeaders(), new EdrTokenLogonRequestDTO()); + assertNotNull(response); + } + + @Test + void logon_jsonError_lanzaEmulatorException() throws Exception { + when(objectMapper.writeValueAsString(any())).thenThrow(new JsonProcessingException("boom") { + private static final long serialVersionUID = 1L; + }); + assertThrows(EmulatorException.class, + () -> service.logon("REQ", new HttpHeaders(), new EdrTokenLogonRequestDTO())); + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/utils/ExceptionsTest.java b/server.services/src/test/java/cl/jonnattan/emulator/utils/ExceptionsTest.java new file mode 100644 index 0000000..9205b94 --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/utils/ExceptionsTest.java @@ -0,0 +1,63 @@ +package cl.jonnattan.emulator.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +import cl.jonnattan.emulator.enums.TypeResponse; + +class ExceptionsTest { + + @Test + void emulatorException_constructorSoloMensaje_codeDefecto() { + EmulatorException ex = new EmulatorException("err"); + assertEquals("err", ex.getMessage()); + assertEquals("-1", ex.getCode()); + } + + @Test + void emulatorException_constructorConCode() { + EmulatorException ex = new EmulatorException("err", "500"); + assertEquals("500", ex.getCode()); + } + + @Test + void confException_constructorBasico_defaults() { + ConfException ex = new ConfException("err"); + assertEquals("-1", ex.getCode()); + assertEquals(TypeResponse.HTTP_RESPONSE_200, ex.getType()); + assertEquals(HttpStatus.OK, ex.getStatus()); + } + + @Test + void confException_setters_actualizanValores() { + ConfException ex = new ConfException("err"); + ex.setCode("42"); + ex.setType(TypeResponse.HTTP_RESPONSE_500); + assertEquals("42", ex.getCode()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, ex.getStatus()); + } + + @Test + void confException_getStatus_mapeaTodosLosTipos() { + assertEquals(HttpStatus.OK, mapStatus(TypeResponse.HTTP_RESPONSE_200)); + assertEquals(HttpStatus.BAD_REQUEST, mapStatus(TypeResponse.HTTP_RESPONSE_400)); + assertEquals(HttpStatus.CONFLICT, mapStatus(TypeResponse.HTTP_RESPONSE_409)); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, mapStatus(TypeResponse.HTTP_RESPONSE_500)); + assertEquals(HttpStatus.SERVICE_UNAVAILABLE, mapStatus(TypeResponse.HTTP_RESPONSE_503)); + } + + private HttpStatus mapStatus(TypeResponse type) { + ConfException ex = new ConfException("m", "c", type); + return ex.getStatus(); + } + + @Test + void confException_constructorCompleto_asignaTodo() { + ConfException ex = new ConfException("m", "c", TypeResponse.HTTP_RESPONSE_400); + assertEquals("c", ex.getCode()); + assertEquals(TypeResponse.HTTP_RESPONSE_400, ex.getType()); + assertEquals(HttpStatus.BAD_REQUEST, ex.getStatus()); + } +} diff --git a/server.services/src/test/java/cl/jonnattan/emulator/utils/UtilitiesTest.java b/server.services/src/test/java/cl/jonnattan/emulator/utils/UtilitiesTest.java new file mode 100644 index 0000000..a301655 --- /dev/null +++ b/server.services/src/test/java/cl/jonnattan/emulator/utils/UtilitiesTest.java @@ -0,0 +1,147 @@ +package cl.jonnattan.emulator.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import cl.jonnattan.emulator.interfaces.ICipher; +import cl.jonnattan.emulator.interfaces.ISignature; + +@ExtendWith(MockitoExtension.class) +class UtilitiesTest { + + @Mock + private EncrypterBusinessLogicService rsaCipher; + @Mock + private ObjectMapper objectMapper; + @Mock + private ICipher aesCipher; + @Mock + private ISignature signature; + + @InjectMocks + private Utilities utilities; + + @Test + void cksumSHA256_retornaLong() { + when(signature.cksum("data")).thenReturn(100L); + long result = utilities.cksumSHA256("data"); + assertTrue(result > 100L); + } + + @Test + void sha256_delegaEnSignature() { + when(signature.getSignature("x")).thenReturn("HASH"); + assertEquals("HASH", utilities.SHA256("x")); + } + + @Test + void decryptRSA_dataNull_retornaVacio() { + assertEquals("", utilities.decryptRSA(null)); + } + + @Test + void decryptRSA_error_retornaVacio() throws Exception { + when(rsaCipher.decrypt(any())).thenThrow(new RuntimeException("boom")); + String result = utilities.decryptRSA("YQ=="); // "a" en base64 + assertEquals("", result); + } + + @Test + void decryptRSA_ok_retornaTexto() throws Exception { + when(rsaCipher.decrypt(any())).thenReturn("hola".getBytes()); + String result = utilities.decryptRSA("YQ=="); + assertEquals("hola", result); + } + + @Test + void encryptRSA_dataNull_retornaVacio() { + assertEquals("", utilities.encryptRSA(null)); + } + + @Test + void encryptRSA_ok_retornaBase64() throws Exception { + when(rsaCipher.encrypt(any())).thenReturn("hola".getBytes()); + String result = utilities.encryptRSA("hola"); + assertNotNull(result); + assertTrue(result.length() > 0); + } + + @Test + void encryptRSA_error_retornaVacio() throws Exception { + when(rsaCipher.encrypt(any())).thenThrow(new RuntimeException("boom")); + assertEquals("", utilities.encryptRSA("hola")); + } + + @Test + void toJson_objNull_retornaNULL() { + assertEquals("NULL", utilities.toJson(null)); + } + + @Test + void toJson_ok_serializa() throws Exception { + when(objectMapper.writeValueAsString(any())).thenReturn("{\"a\":1}"); + assertEquals("{\"a\":1}", utilities.toJson(new Object())); + } + + @Test + void toJson_error_retornaTextoError() throws Exception { + when(objectMapper.writeValueAsString(any())).thenThrow(new JsonProcessingException("boom") { + private static final long serialVersionUID = 1L; + }); + assertEquals("ERROR Convirtiendo a JSON", utilities.toJson(new Object())); + } + + @Test + void toMap_error_retornaNull() throws Exception { + when(objectMapper.readValue(any(String.class), any(Class.class))).thenThrow(new NullPointerException("boom")); + assertEquals(null, utilities.toMap("{}")); + } + + @Test + void toMap_ok_retornaMap() throws Exception { + Map expected = new HashMap<>(); + expected.put("k", "v"); + when(objectMapper.readValue(any(String.class), any(Class.class))).thenReturn(expected); + assertEquals(expected, utilities.toMap("{}")); + } + + @Test + void decryptAES_null_retornaVacio() { + assertEquals("", utilities.decryptAES(null)); + } + + @Test + void decryptAES_ok_retornaPlano() throws Exception { + when(aesCipher.decrypt("CIPHER")).thenReturn("PLANO"); + assertEquals("PLANO", utilities.decryptAES("CIPHER")); + } + + @Test + void decryptAES_error_retornaVacio() throws Exception { + when(aesCipher.decrypt(any())).thenThrow(new RuntimeException("boom")); + assertEquals("", utilities.decryptAES("CIPHER")); + } + + @Test + void getTokenCard_retornaVeinteCaracteres() { + when(signature.getSignature(any())) + .thenReturn("abcdef0123456789abcdef0123456789abcdef0123456789"); + String result = utilities.getTokenCard("data"); + assertEquals(20, result.length()); + } +}