Pregunta y alcance
Un servicio en Go presenta fallas intermitentes en pruebas unitarias, de benchmark y de fuzzing. Los desarrolladores quieren muestras de solicitudes, resúmenes de rendimiento y volcados de depuración sin saturar las ejecuciones exitosas de CI ni permitir que las pruebas paralelas se sobrescriban entre sí. Utilizando testing.T.ArtifactDir, testing.B.ArtifactDir y testing.F.ArtifactDir de Go 1.26, diseña una política de artefactos.
Con go test -artifacts, Go 1.26 devuelve un directorio persistente dentro del directorio de salida; sin este flag, el directorio temporal devuelto se elimina al finalizar la prueba. Separa el código que escribe la evidencia de la decisión de retenerla, y permite que el framework de pruebas controle el ciclo de vida del directorio.
Contexto y límites
Enfócate en el código de prueba de Go, el aislamiento de concurrencia, el archivado en CI y los datos confidenciales. La plataforma de CI proporciona la subida, los permisos, la retención y el almacenamiento de objetos; establece el desencadenante de fallas, la nomenclatura, los límites de tamaño, la ofuscación y los límites de reintentos.
Lo que evalúa el entrevistador
- Si distingues los directorios de artefactos para los contextos T, B y F.
- Si las pruebas fallidas retienen evidencia sin convertir las ejecuciones exitosas en ruido permanente.
- Si manejas
t.Parallel, subpruebas, bucles de benchmark y la nomenclatura para la reproducción de fuzzing. - Si los archivos admiten reintentos, son acotados, archivables y rastreables hasta un commit y un nombre de prueba.
- Si los tokens, datos de usuario, URL privadas y volcados de memoria (core dumps) se mantienen fuera de los artefactos públicos de CI.
Respuesta de 30 segundos
“Cada prueba obtiene su directorio mediante ArtifactDir; los nombres de archivo usan la ruta de la prueba, el ID de ejecución y la secuencia del evento en lugar de rutas de espacio de trabajo adivinadas. El código escribe evidencia clave ante fallas, superación de umbrales o diagnósticos explícitos. CI habilita go test -artifacts y archiva el directorio, mientras que los valores predeterminados locales usan un directorio temporal que se limpia. Las escrituras emplean un archivo temporal y renombrado, con límites de bytes y cantidad. Un manifiesto vincula el commit, paquete, prueba, plataforma, hash y estado de ofuscación; un fallo en la subida genera una alerta sin alterar el resultado original de la prueba.”
Solución paso a paso
- Usa un único punto de entrada de artefactos. Una prueba recibe
*testing.T,*testing.Bo*testing.Fy llama a suArtifactDircorrespondiente. No codifiques de forma fijaos.TempDir, el directorio de trabajo ni una ruta privada de CI en la lógica de la prueba.
- Separa la retención de la escritura. El código de prueba puede escribir antes o después de una falla, pero la persistencia solo se espera cuando
go test -artifactsestá habilitado. Las ejecuciones predeterminadas usan un directorio temporal que se limpia; CI habilita explícitamente los artefactos y los sube.
- Diseña nombres concurrentes. Construye una clave lógica a partir del paquete, la prueba, el ID de ejecución, la ruta de la subprueba y una secuencia monotónica. Sanitiza los separadores y caracteres no imprimibles. Las instancias paralelas nunca deben compartir un
debug.jsonfijo.
- Escribe de forma atómica con límites. Crea un archivo temporal en el directorio de artefactos, ciérralo correctamente y luego renómbralo. Aplica límites de bytes y recuento por archivo, por prueba y por ejecución; los desbordamientos generan un resumen en lugar de agotar el ejecutor.
func writeArtifact(t *testing.T, name string, data []byte) {
t.Helper()
dir := t.ArtifactDir()
path := filepath.Join(dir, safeName(name)+".json")
tmp, err := os.CreateTemp(dir, ".partial-")
if err != nil { t.Fatalf("create artifact: %v", err) }
defer tmp.Close()
if _, err := tmp.Write(data); err != nil { t.Fatalf("write artifact: %v", err) }
if err := tmp.Close(); err != nil { t.Fatalf("close artifact: %v", err) }
if err := os.Rename(tmp.Name(), path); err != nil { t.Fatalf("publish artifact: %v", err) }
}El ejemplo omite las comprobaciones de tamaño, la ofuscación y el manejo de nombres de archivo portables; el código de producción debe convertir estos aspectos en restricciones de prueba compartidas.
- Dispara ante fallas o umbrales. Las pruebas fallidas retienen un reproductor mínimo, un resumen de la solicitud, el identificador de traza y un resumen del entorno. Los benchmarks guardan perfiles o muestras solo ante un umbral de regresión o en un modo de diagnóstico explícito. Las pruebas de fuzzing guardan una semilla reproducible y una entrada acotada y ofuscada en lugar de una solicitud confidencial completa.
- Indexa los artefactos de CI. Genera un manifiesto que contenga el SHA del commit, paquete, prueba, versión de Go, SO/arquitectura, ruta relativa, tamaño, hash y estado de ofuscación. Aísla las subidas por ID de ejecución. Un fallo en la subida genera una alerta, pero no debe convertir una aserción fallida en exitosa.
- Asegura y limpia. Elimina tokens, cookies, encabezados Authorization, datos personales y nombres de host privados antes de escribir; deshabilita los core dumps por defecto. Usa permisos de lectura de privilegio mínimo y retención corta, con expiración automática. Las descargas aún requieren una revisión a nivel de contenido.
- Prueba el ciclo de vida. Cubre una subprueba fallida, una subprueba paralela, una ejecución con
go test -artifactsy una ejecución predeterminada. Verifica la limpieza exitosa, la evidencia de fallas indexable, los ID de reintento diferenciados y la preservación de la evidencia local cuando se interrumpe la subida.
Respuesta modelo
Todos los archivos de diagnóstico deben originarse desde ArtifactDir de T, B o F; la lógica de la prueba no debe conocer la ruta física. La persistencia es controlada por go test -artifacts: CI la habilita y archiva, mientras que las ejecuciones locales usan un directorio temporal que se limpia. Los nombres incluyen el paquete, la prueba, la ruta de la subprueba, el ID de ejecución y la secuencia para evitar colisiones paralelas. Las escrituras usan un archivo temporal y renombrado, con límites de bytes y cantidad.
Las pruebas fallidas retienen entradas mínimas, resúmenes de solicitudes y datos del entorno. Los benchmarks retienen perfiles solo cuando se activa un umbral de regresión o un modo de diagnóstico explícito. Las pruebas de fuzzing retienen semillas y entradas reproducibles. La ofuscación se realiza antes de escribir y un manifiesto registra el commit, la versión de Go, la plataforma, los hashes y los tamaños. Un fallo en la subida genera una alerta sin cambiar el estado de la prueba. Las pruebas de regresión cubren el paralelismo, las fallas, el almacenamiento temporal predeterminado y el almacenamiento persistente con -artifacts.
Errores comunes
- Error: Tratar ArtifactDir como permanente → Por qué falla: el directorio temporal predeterminado se elimina tras la prueba → Solución: habilitar
-artifactsen CI y configurar el archivado. - Error: Que cada prueba paralela escriba en
debug.json→ Por qué falla: los archivos se sobrescriben o intercalan → Solución: nombrar según la ruta de la prueba, ID de ejecución y secuencia. - Error: Subir una solicitud HTTP completa ante una falla → Por qué falla: se filtran tokens y datos personales → Solución: ofuscar, resumir y restringir la retención.
- Error: Permitir que un fallo al escribir el artefacto haga que la prueba pase → Por qué falla: se pierde la evidencia de la falla y se ocultan problemas del entorno → Solución: fallar o alertar explícitamente sobre la evidencia requerida sin alterar las aserciones.
- Error: Escribir un perfil en cada iteración de benchmark → Por qué falla: el volumen de artefactos y el tiempo de ejecución se vuelven ilimitados → Solución: recolectar solo ante un umbral de regresión o diagnósticos explícitos.
Preguntas de seguimiento y respuestas
¿Por qué no usar os.TempDir directamente?
ArtifactDir permite que el framework de pruebas y el CI gestionen las decisiones de ciclo de vida, otorga un único contrato a T, B y F, y evita rutas dependientes del ejecutor. os.TempDir es adecuado para archivos auxiliares desechables, no como protocolo de artefactos.
¿Cómo se mantienen reproducibles los artefactos de fuzzing?
Registra la versión de Go, paquete, prueba, semilla, un hash de la entrada acotada y las variables de entorno requeridas. Para entradas excesivamente grandes o confidenciales, almacena un resumen ofuscado y mantén la evidencia completa solo en almacenamiento protegido.
¿Cuándo debe un benchmark escribir artefactos?
Finaliza el benchmark y compara primero su línea base. Escribe un perfil solo tras una regresión frente al umbral, diagnósticos explícitos de -bench o una falla. Incluye el recuento de muestras, CPU, duración y commit para que las ejecuciones normales no se conviertan en archivos permanentes.
¿Debería un fallo en la subida de artefactos hacer fallar el CI?
Una aserción fallida debe fallar. Que un fallo de subida bloquee el lanzamiento depende del nivel de evidencia del equipo, pero al menos debe alertar y preservar una ruta local. El estado de la red no debe camuflarse como el estado de la prueba.
¿Cómo manejas los reintentos?
Genera un ID de ejecución distinto para cada intento. Las claves de archivo contienen commit, plataforma, paquete, prueba e intento. Los índices pueden agrupar intentos, pero los archivos sin procesar nunca se sobrescriben entre sí; registra si un reintento reutilizó la semilla aleatoria.
Referencias
- Notas de lanzamiento de Go 1.26 (Oficial de Go)
- Paquete testing (Oficial de Go)
- Historial de lanzamientos de Go (Oficial de Go)
Lista de verificación para la entrevista
Explica primero el ciclo de vida de ArtifactDir, luego agrega la nomenclatura concurrente, escrituras atómicas, desencadenantes de fallas, manifiestos, ofuscación, archivado en CI y pruebas de regresión.
Conclusión en una sola frase
ArtifactDir proporciona el punto de entrada para el ciclo de vida; los diagnósticos confiables aún necesitan aislamiento, límites, ofuscación, indexación y evidencia reproducible.
Sigue practicando
Si el CI ejecuta pruebas de fuzzing, benchmarks e integración de forma conjunta, diseña un manifiesto compartido, cuotas y un programador de subidas con prioridad ante fallas.