Proyecto 02 — Test Data Management en mainframe

Proceso TDM en z/OS

Proyecto
Personal — IBM Z Xplore
Rol
Diseño y desarrollo completo
Entorno
z/OS · ISPF · SDSF
Estado
Funcionando

Reto → Solución → Resultado

01
El reto

En banca no se puede probar con datos reales de clientes: los entornos de pruebas los usa mucha más gente y el RGPD lo prohíbe. Pero las pruebas necesitan datos realistas. El Test Data Management resuelve justo eso, y quería entenderlo de principio a fin, no solo de oídas.

02
La solución

Construí en un mainframe real (IBM Z Xplore) un proceso TDM completo: un JCL de 7 pasos encadenados con condiciones, con tres programas COBOL que extraen, enmascaran y cargan, más SORT, GDG y VSAM gestionado con IDCAMS. Todo desde ISPF.

03
El resultado

Datos de prueba disfrazados pero válidos, que se refrescan con un solo submit y cuadran en cada paso. Además provoqué y resolví dos incidencias reales: un abend S0C7 con relanzamiento por RESTART y una clave duplicada controlada sin parar la cadena.

La cadena
paso a paso

BORRA
Borra las salidas anteriores: refresco
IEFBR14
SUBSET
Extrae los clientes que piden las pruebas
COBOL · TDMSUBS
MASK
Enmascara nombre, DNI e IBAN
COBOL · TDMMASK
ORDENA
Ordena por clave y guarda histórico
SORT · GDG
DEFVSAM
Crea el VSAM de pruebas vacío
IDCAMS
CARGA
Carga y aparta duplicados (FS 22)
COBOL · TDMCARGA
LISTA
Revisa el contenido final
IDCAMS PRINT

Cada paso solo se ejecuta si el anterior terminó bien (IF paso.RC = 0 THEN). Si algo falla, no se cargan datos a medias en el entorno de pruebas.

Lo más importante de cada pantalla Correcto / se mantiene Dato sensible o error Información de contexto

El fichero de "producción" y su copybook

50 clientes inventados pero con formato real: DNI con la letra bien calculada e IBAN con dígitos de control correctos. Incluye a propósito casos raros (saldos negativos y a cero), como en producción. El copybook CLIENTE describe el registro de 80 posiciones y lo comparten los tres programas.

Fichero de producción con un registro marcado campo a campo
Un registro campo a campo: en rojo lo que identifica a una persona, en verde lo que no.
Copybook CLIENTE
Copybook compartido: antes de cambiarlo hay que revisar a qué programas afecta.
Compilación con COND CODE 0000
Compilación con el procedimiento IGYWCL: COBOL y LKED con COND CODE 0000.

Extraer solo lo que hace falta

El programa TDMSUBS extrae los clientes de Madrid y todos los de saldo negativo, que son los casos que el equipo de pruebas quiere probar. Antes de ejecutar calculé el resultado esperado (15 de 50) y después lo comprobé con los contadores y mirando los datos.

Resultado del paso subset
Leídos 50, escritos 15: justo lo calculado.
Fichero extraído
Los clientes 190 y 330 no son de Madrid: entran por su saldo negativo.

Datos disfrazados, pero válidos y consistentes

El programa TDMMASK disfraza nombre, DNI e IBAN. La clave es que es consistente: el mismo dato real da siempre el mismo dato falso, así que las relaciones entre ficheros se mantienen (integridad referencial). Y el resultado tiene formato válido: se recalcula la letra del DNI y los dígitos de control del IBAN. El ID, el saldo y la provincia no se tocan.

Comparación entre el fichero original y el enmascarado
COMPARE de ISPF: arriba los originales, abajo los mismos clientes enmascarados.
El saldo y la provincia se mantienen
Cambia el DNI, pero saldo y provincia son idénticos, incluidos los negativos.
      * DNI: FORMULA FIJA SOBRE EL NUMERO Y LETRA RECALCULADA.
      * 7919 NO TIENE FACTORES COMUNES CON 10^8: DOS DNI DISTINTOS
      * NUNCA DAN EL MISMO DNI FALSO (SIN CLAVES DUPLICADAS)
       2200-DNI.
           COMPUTE WS-DNI-CALC = WS-DNI-NUM * 7919 + 13579
           COMPUTE WS-DNI-NUM  = FUNCTION MOD(WS-DNI-CALC, 100000000)
           COMPUTE WS-I        = FUNCTION MOD(WS-DNI-NUM, 23) + 1
           MOVE WS-LETRA(WS-I) TO WS-DNI-LETRA
           MOVE WS-DNI TO CLI-DNI.

SORT, GDG y VSAM de pruebas

El SORT ordena por clave, porque la carga en un VSAM KSDS lo exige, y guarda cada refresco como una generación de un GDG con LIMIT(5): siempre se puede volver a los datos de una versión anterior. Después, IDCAMS borra y vuelve a crear el VSAM (el refresco) y se carga y revisa con PRINT.

SORT y refresco del VSAM
15 entran y 15 salen del SORT (1200 bytes = 15 × 80), y el VSAM anterior se borra entero.
Generaciones del GDG
Una generación nueva por cada ejecución del proceso.
Carga y PRINT del VSAM
DEFINE, REPRO de 15 registros y PRINT con la clave de cada uno.
Tabla de pasos con todos los RC a 00
La cadena completa con todos los pasos en RC 00.

Abend S0C7: diagnóstico y RESTART

Metí a propósito un saldo no numérico en producción. El paso SUBSET abendó con S0C7 y, gracias a las condiciones, ningún paso posterior se ejecutó. Lo diagnostiqué en SDSF, localicé el registro con un FIND de caracteres no numéricos, lo corregí y relancé desde el paso que había fallado, sin repetir lo que ya había ido bien: lo mismo que se hace con Control-M en un entorno real.

Tabla de pasos con el abend S0C7
Qué paso falló y qué pasos no llegaron a ejecutarse (FLUSH).
Mensaje CEE3207S y traceback
El porqué: CEE3207S, programa TDMSUBS, offset +412.
Búsqueda del registro con datos no numéricos
F P'-' 66 74: busca caracteres no numéricos solo en las columnas del saldo.
Relanzamiento con RESTART
RESTART=SUBSET: la cadena se retoma donde falló y termina con RC=0000.

Clave duplicada: FILE STATUS 22

Reproduce un caso real que viví en mi experiencia: un programa que no controlaba los duplicados (SQLCODE -803 en DB2) y paraba la cadena. Aquí el equivalente en VSAM es el file status 22: el registro duplicado va a un fichero de errores, el resto se carga y el paso termina con RC 4 como aviso. Siempre se cumple leídos = cargados + duplicados.

       2000-PROCESO.
           MOVE REG-CLIENTE TO REG-VSAM
           WRITE REG-VSAM
           EVALUATE WS-FS-VSAM
              WHEN '00'
                 ADD 1 TO WS-CARGADOS
              WHEN '22'                       *> CLAVE DUPLICADA
                 PERFORM 2100-DUPLICADO       *> A ERRORES Y SIGUE
              WHEN OTHER                     *> ERROR GRAVE: RC 16
                 MOVE 16 TO RETURN-CODE
                 STOP RUN
           END-EVALUATE
Mensaje de clave duplicada y contadores
16 = 15 + 1. En el log solo aparece el ID, nunca datos personales.
Job con CC 0004
CC 0004: un aviso visible de un vistazo, no un fallo.
Fichero de errores
El duplicado, ya enmascarado igual que el original: así se detecta que era el mismo cliente.
Ver el JCL completo del proceso
//TDMPROC  JOB ,MSGLEVEL=(2,0),NOTIFY=&SYSUID
//*  BORRA LAS SALIDAS DE LA EJECUCION ANTERIOR
//BORRA    EXEC PGM=IEFBR14
//DD1      DD DSN=Z76766.TDM.CLIENTES.SUBSET,
//            DISP=(MOD,DELETE,DELETE),SPACE=(TRK,(1,1))
//DD2      DD DSN=Z76766.TDM.CLIENTES.MASK,
//            DISP=(MOD,DELETE,DELETE),SPACE=(TRK,(1,1))
//DD3      DD DSN=Z76766.TDM.CLIENTES.ERRORES,
//            DISP=(MOD,DELETE,DELETE),SPACE=(TRK,(1,1))
//*  PASO 1: SUBSET - CLIENTES DE MADRID Y SALDO NEGATIVO
//SUBSET   EXEC PGM=TDMSUBS
//STEPLIB  DD DSN=&SYSUID..LOAD,DISP=SHR
//ENTRADA  DD DSN=Z76766.TDM.CLIENTES.PROD,DISP=SHR
//SALIDA   DD DSN=Z76766.TDM.CLIENTES.SUBSET,
//            DISP=(NEW,CATLG,DELETE),SPACE=(TRK,(1,1)),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
//SYSOUT   DD SYSOUT=*
//*  PASO 2: ENMASCARAMIENTO
// IF SUBSET.RC = 0 THEN
//MASK     EXEC PGM=TDMMASK
//STEPLIB  DD DSN=&SYSUID..LOAD,DISP=SHR
//ENTRADA  DD DSN=Z76766.TDM.CLIENTES.SUBSET,DISP=SHR
//SALIDA   DD DSN=Z76766.TDM.CLIENTES.MASK,
//            DISP=(NEW,CATLG,DELETE),SPACE=(TRK,(1,1)),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
//SYSOUT   DD SYSOUT=*
// ENDIF
//*  PASO 3: ORDENA POR ID Y GUARDA UNA GENERACION NUEVA
// IF MASK.RC = 0 THEN
//ORDENA   EXEC PGM=SORT
//SYSOUT   DD SYSOUT=*
//SORTIN   DD DSN=Z76766.TDM.CLIENTES.MASK,DISP=SHR
//SORTOUT  DD DSN=Z76766.TDM.CLIENTES.HIST(+1),
//            DISP=(NEW,CATLG,DELETE),SPACE=(TRK,(1,1)),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
//SYSIN    DD *
  SORT FIELDS=(1,6,CH,A)
/*
// ENDIF
//*  PASO 4: CREA EL VSAM DE PRUEBAS VACIO (REFRESCO)
// IF ORDENA.RC = 0 THEN
//DEFVSAM  EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE Z76766.TDM.CLIENTES.KSDS CLUSTER PURGE
  SET MAXCC = 0
  DEFINE CLUSTER (NAME(Z76766.TDM.CLIENTES.KSDS) -
         INDEXED KEYS(6 0) RECORDSIZE(80 80)      -
         TRACKS(1 1))                             -
         DATA  (NAME(Z76766.TDM.CLIENTES.KSDS.DATA))  -
         INDEX (NAME(Z76766.TDM.CLIENTES.KSDS.INDEX))
/*
// ENDIF
//*  PASO 5: CARGA CON CONTROL DE DUPLICADOS (FILE STATUS 22)
// IF DEFVSAM.RC = 0 THEN
//CARGA    EXEC PGM=TDMCARGA
//STEPLIB  DD DSN=&SYSUID..LOAD,DISP=SHR
//ENTRADA  DD DSN=Z76766.TDM.CLIENTES.HIST(+1),DISP=SHR
//VSAMCLI  DD DSN=Z76766.TDM.CLIENTES.KSDS,DISP=SHR
//ERRORES  DD DSN=Z76766.TDM.CLIENTES.ERRORES,
//            DISP=(NEW,CATLG,DELETE),SPACE=(TRK,(1,1)),
//            DCB=(RECFM=FB,LRECL=80,BLKSIZE=0)
//SYSOUT   DD SYSOUT=*
// ENDIF
//*  PASO 6: REVISA EL CONTENIDO DEL VSAM
// IF CARGA.RC <= 4 THEN
//LISTA    EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  PRINT INDATASET(Z76766.TDM.CLIENTES.KSDS) CHARACTER
/*
// ENDIF

Qué se consiguió

↻
Refresco con un solo submit

Datos de prueba limpios en cada ejecución, con histórico de los últimos 5 refrescos en un GDG.

✓
Todo cuadra

50 → 15 → 15 → 15, y leídos = cargados + duplicados. Contadores en cada paso y ningún dato personal en los logs.

◎
Incidencias resueltas

S0C7 diagnosticado y relanzado con RESTART; clave duplicada apartada sin parar la cadena.

Tecnologías usadas

COBOL JCL VSAM KSDS IDCAMS DFSORT GDG ISPF SDSF z/OS

Programadora COBOL
en entornos mainframe

Batch, JCL, DB2 y Control-M, con experiencia real en banca.