Files
erp-imprimelibros/src/test/java/com/imprimelibros/erp/redsys/RedsysServiceTest.java

151 lines
5.8 KiB
Java

package com.imprimelibros.erp.redsys;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import sis.redsys.api.Signature;
/**
* Tests de integración "locales" contra tu RedsysService
* usando el jar 'apiSha512V2.jar' (sis.redsys.api.*).
*
* Para que el test sea significativo:
* - Define la clave en entorno: REDSYS_SECRET_B64=tu_clave_base64
* - O en propiedad de sistema: -Dredsys.secret.b64=tu_clave_base64
*/
public class RedsysServiceTest {
private RedsysService service;
private static String readSecretFromEnvOrProp() {
String env = System.getenv("REDSYS_SECRET_B64");
if (env != null && !env.isBlank())
return env.trim();
String prop = System.getProperty("redsys.secret.b64");
if (prop != null && !prop.isBlank())
return prop.trim();
return "";
}
private static void setPrivate(Object target, String field, Object value) {
try {
Field f = target.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(target, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@BeforeEach
void setup() {
service = new RedsysService();
// ---- Config mínima para el test ----
setPrivate(service, "merchantCode", "124760810"); // FUC de ejemplo (sandbox)
setPrivate(service, "terminal", "1");
setPrivate(service, "currency", "978");
setPrivate(service, "txType", "0");
setPrivate(service, "urlOk", "http://localhost:8080/pagos/redsys/ok");
setPrivate(service, "urlKo", "http://localhost:8080/pagos/redsys/ko");
setPrivate(service, "urlNotify", "http://localhost:8080/pagos/redsys/notify");
setPrivate(service, "env", "test");
// Clave: del entorno o propiedad. Si queda vacía, los tests se auto-saltan.
setPrivate(service, "secretKeyBase64", readSecretFromEnvOrProp());
}
private boolean secretPresent() {
try {
Field f = service.getClass().getDeclaredField("secretKeyBase64");
f.setAccessible(true);
String key = (String) f.get(service);
return key != null && !key.isBlank();
} catch (Exception e) {
return false;
}
}
@Test
void buildRedirectForm_generates_signature_and_params() throws Exception {
if (!secretPresent()) {
System.out.println("SKIP: define REDSYS_SECRET_B64 o -Dredsys.secret.b64 para ejecutar este test.");
return;
}
// Pedido de ejemplo (usa uno único por intento)
String order = "T" + System.currentTimeMillis(); // p.ej. T1699999999999
long amountCents = 1234L;
var req = new RedsysService.PaymentRequest(order, amountCents, "Test compra");
var form = service.buildRedirectForm(req);
assertNotNull(form);
assertEquals("HMAC_SHA512_V1", form.signatureVersion());
assertNotNull(form.merchantParameters());
assertNotNull(form.signature());
assertTrue(form.action().contains("sis"), "Action debe ser endpoint de Redsys");
// Decodificamos los parámetros para comprobar que incluyen nuestro pedido e
// importe
String json = new String(Base64.getDecoder().decode(form.merchantParameters()), StandardCharsets.UTF_8);
assertTrue(json.contains("\"DS_MERCHANT_ORDER\":\"" + order + "\""));
assertTrue(json.contains("\"DS_MERCHANT_AMOUNT\":\"" + amountCents + "\""));
// Recomputamos firma con el mismo jar y comparamos
String recomputed = Signature.createMerchantSignature(
readSecretFromEnvOrProp(), order, form.merchantParameters());
assertEquals(form.signature(), recomputed, "La firma recomputada debe coincidir");
}
@Test
void validateAndParseNotification_roundtrip_ok() throws Exception {
if (!secretPresent()) {
System.out.println("SKIP: define REDSYS_SECRET_B64 o -Dredsys.secret.b64 para ejecutar este test.");
return;
}
// 1) Simula un pedido real
String order = "N" + System.currentTimeMillis();
long amountCents = 2500L; // 25,00 €
// 2) Construye el JSON de NOTIFICACIÓN (vuelta) con claves Ds_*
Map<String, Object> notifJson = Map.of(
"Ds_Order", order,
"Ds_Amount", String.valueOf(amountCents),
"Ds_Currency", "978",
"Ds_Response", "0" // autorizado
// añade lo que quieras: Ds_AuthorisationCode, etc.
);
// 3) Base64 de ese JSON (exactamente lo que recibirías en
// Ds_MerchantParameters)
String notifJsonStr = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(notifJson);
String dsParams = java.util.Base64.getEncoder().encodeToString(
notifJsonStr.getBytes(java.nio.charset.StandardCharsets.UTF_8));
// 4) Firma de NOTIFICACIÓN (usa la misma API y clave que Redsys)
String dsSignature = sis.redsys.api.Signature.createMerchantSignature(
readSecretFromEnvOrProp(), order, dsParams);
// 5) Llama a tu servicio como lo haría el webhook
RedsysService.RedsysNotification notif = service.validateAndParseNotification(dsSignature, dsParams);
// 6) Asserts
assertEquals(order, notif.order);
assertEquals(amountCents, notif.amountCents);
assertEquals("978", notif.currency);
assertTrue(notif.authorized()); // porque Ds_Response="0"
}
}