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 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" } }