javi__codes
6 min readMar 4, 2022

--

Normalmente intento automatizar todo lo que pueda, esto tiene mucho sentido cuando tenemos que hacer algo mas de una vez y el tiempo en automatizar esa tarea es menor que el tiempo de hacer la tarea varias veces, siempre hay que tener en cuenta que automatizar también lleva tiempo. Mientras armo mis automatizaciones me encuentro a menudo armando archivos de configuración que luego utilizo para decirle a esta automatización como debería de comportarse. Esta forma de trabajo me demostró que es la correcta muchas veces pero también hay que tener cuidado con proveer la información correcta en estos archivos de configuración.

Mas adelante nos encontramos comunicando al resto de nuestro team o incluso fuera de nuestro team como se usa nuestra automatización, o incluso tal vez nuestra automatización termina siendo usada en un pipeline, seguramente hicimos nuestra documentación, pero puede que otros no estén al tanto de donde pueden encontrar esta documentación.

Entonces, como hacemos para asegurarnos que los archivos de configuración de nuestra solución son correctos antes de aplicarlos corriendo nuestra automatización?, bueno, eso es lo que vamos a ver hoy en este articulo.

Idea

Imaginemos que tenemos un archivo de terraform que va a construir algunos recursos en la nube, y a este terraform le vamos a entregar un archivo JSON el cual terraform va a interpretar y usar su contenido como valores para los recursos a crear.

Dado que este JSON puede tener cualquier formato (valido) porque fue creado por nosotros, el formato de nuestros tests (y de como lo usamos en terraform) puede variar de lo que veamos en este articulo.

Ejemplo de un archivo de configuración

Por ejemplo, aca tenemos un archivo de configuración genérico que arme para este articulo, contiene arrays, objetos anidados, booleanos y arrays de objetos anidados.

[
{
"vnet_name": "demo-vnet-name-1",
"resource_group_name": "resource_groupname",
"address_space": [
"10.0.0.0/23"
],
"dns_servers": [
"10.0.1.0",
"10.0.0.128"
],
"vnet_location": "eastus2",
"Subnets": {
"name": "misubnet",
"address_prefixes": [
"10.0.0.0/24",
"10.0.0.128/24"
]
},
"Enabled" : true
},
{
"vnet_name": "demo-vneT-name",
"resource_group_name": "resource_groupname",
"address_space": [
"10.0.2.0/24"
],
"dns_servers": [
"10.0.1.12"
],
"vnet_location": "eastus3",
"Subnets": {
"name": "misubnet2",
"address_prefixes": [
"10.0.2.0/24",
"10.0.2.128/24"
]
},
"Enabled" : false
}
]

Este archivo contiene un array con dos definiciones para construir dos recursos “Virtual network” en azure.

Pensando la solución

Lo primero que vamos a hacer es sentarnos, relajarnos, mirar nuestro archivo de configuración y pensar que cosas tiene sentido validar y cuales no, no queremos escribir cientos de tests para cosas que no necesitan validarse, campos como “tags” suelen ser libres y poder contener cualquier valor, no tendría sentido escribir tests para esos campos.

Una vez que sabemos que queremos probar, vamos a listar cuales son esos test que queremos probar.

En este caso quiero probar:

  1. El nombre de vnet_name no esta vacío
  2. Quiero saber que vnet_name sigue mi naming convention (para simplificarlo, tendrá que tener solo 4 secciones)
  3. La vnet_name solo contiene letras minúsculas
  4. La location de los recursos necesita ser una de las “aprobadas” por la compañía

Ahora que tenemos una lista de lo que queremos probar, vamos a escribir nuestros tests.

Pester

Que es pester?

Pester es un framework para escribir tests para powershell, es muy fácil de utilizar y contiene muchos métodos para validar nuestros test y si instalación es tan simple como instalar el modulo “Pester”. Para usar Pester debemos escribir bloques llamados “Descriptions” usando la palabra clave “Describe” donde vamos a separar de forma lógica nuestras validaciones, dentro de nuestros “Describe” podemos tener uno o mas bloques de validaciones descriptos con la palabra clave “It”, cada uno de estos bloques seran reportados como “Passed” o “Failed” dependiendo de si la validación fue correcta o no.

Para correr estos tests vamos a usar el cmdlet “Invoke-Pester” con el flag “-Output Detailed”, de esta forma vamos a poder ver las validaciones exitosas y las fallidas.

Como instalar Pester en Windows

Para instalar Pester es tan simple como instalarlo desde PSGallery usando este link https://pester-docs.netlify.app/docs/introduction/installation

Los pasos a seguir son:

  1. Abrir una terminal de powershell como administrador
  2. Ejecutar el comando Install-Module -Name Pester -Force -SkipPublisherCheck

Listo, ya tenemos todo listo para seguir.

Como funciona Pester

Como mencionamos anteriormente, vamos a crear un bloque Describe para agrupar tests similares y vamos a tener validaciones dentro de cada uno de ellos en blockes It.

Para cada bloque Describe solo tienes que poner el nombre del bloque para que lo puedas identificar en el output del test.

Para los bloques It es diferente, en ellos puedes enviarles un TestCase que es un array de elementos que la validación para a usar para correr la validación en cada uno de los elementos de este array o podrías no usar TestCases y directamente hacer tu evaluación dentro del bloque It.

Cuando escribes una validación realizas una comparación y luego usas un pipe | para enviar el resultado de esa comparación al cmdlet Should este cmdlet contiene algunas opciones que permiten evaluar como interpretar el resultado de la comparación, algunos ejemplos son:

  • Be: Compara que el resultado de la comparación devolvió un valor particular
  • Not: Invierte el resultado de la evaluación
  • BeNullOrEmpty: Verifica si el resultado de la comparación es un string vacío o un null
  • BeGraterThan: Verifica si el resultado de la comparación es mayor a un valor dado
  • BeLessThan: Verifica si el resultado de la comparación es menor a un valor dado

Para ver la lista completa de operaciones, puedes revisar la documentacion de Pester en -> https://pester-docs.netlify.app/docs/commands/Should

Una vez que tengas tu test completo puedes ejecutarlo corriendo el comando Invoke-Pester -Path <file.ps1> y si eres como yo y quieres ver la salida completa del test, puedes agregar -Output Detailed

Un ejemplo de un test

Vamos a usar Pester 5.3.1 en esta guía. Voy a estar dividiendo mis tests para poder explicarlos mejor:

Datos de Pre-test

Antes de ejecutar nuestros tests vamos a necesitar definir algunas cosas.

$configfile = Get-Content -path "./configuration.json" | ConvertFrom-Json -Depth 4# Define the list of approved regions to deploy resources
$Regions = @('eastus2','eastus')
# We create an empty array to pass to our tests
$TestCases = @()
# We populate our test cases creating elements named "Instance" for each entry in our config file
foreach ($item in $configfile) {
$TestCases += @{Instance = $item }
}

Validar vnet_name no esta vacío

Nuestro test seria

Describe "Check vnet_name is defined." -Verbose {
It "Verify the name is set in <Instance.vnet_name>." -TestCases $TestCases -Verbose {
Param($Instance)
$Instance.vnet_name | should -not -Benullorempty
}
}

Aqui estamos usando should, not y benullorempty para comparar con el valor que obtuvimos de nuestro archivo de configuración , Pester ya tiene toda esta funcionalidad para verificar los valores incluida en sus cmdlets.

Verificamos naming convention

Para este ejemplo vamos a asumir que nuestra naming convention simplemente tiene que tener 4 segmentos separados por un -. Esta es una verificación muy sencilla, pero es para dar una idea de como se puede realizar una validación de este tipo. Otra validación importante seria para saber si existen otros recursos con el mismo nombre. Recuerden que pueden tener mas de un block It dentro de un Describe.

Describe "Check naming convention for vnet_name." -Verbose {
It "Verify the vnet_name for <Instance.vnet_name> matches naming convention length." -TestCases $TestCases -Verbose {
Param($Instance)
$Instance.vnet_name.split("-").count | should -be 4
}
}

vnet_name solo contiene letras minúsculas

Este es bastante interesante, vamos a estar usando expresiones regulares (RegEx) para verificar que nuestro naming convention esta todo en minúsculas, las expresiones regulares son muy poderosas y nos van a permitir escribir tests mucho mas completos.

En este ejemplo usamos cmatch para validar usando valores case sensitive.

Describe "Check name for vnet_name should be all lowercase." -Verbose {
It "Verify <Instance.vnet_name> is all lowercase." -TestCases $TestCases -Verbose {
Param($Instance)
$Instance.vnet_name -cmatch "^[^A-Z]*$" | should -be $true
}
}

Verificamos que las locations usadas estan entre las aprobadas

Entre la configuración inicial de nuestros tests definimos una lista de regiones o localizaciones donde podemos desplegar nuestros recursos, vamos a usar esa lista para comparar con el valor de la configuración y verificar que tenemos solo regiones o localizaciones aprobadas en nuestra configuración.

Describe "Check location/region to deploy." -Verbose {
It "Verify if region for <Instance.vnet_name> is approved." -TestCases $TestCases -Verbose {
Param($Instance)
$Regions -contains $Instance.vnet_location | should -be $true
}
}

Notas finales

Espero que encuentren este articulo util, como siempre si les gusto el articulo por favor hagan click en subscribirse, en like y compartanlo, me ayudaria mucho para poder seguir creando contenido.

Pueden encontrar links a todas mis redes en https://linktr.ee/javi__codes

Muchas gracias por leer!!

--

--