Notas de Modri

Notas de pruebas con AWS DynamoDB local y NodeJS

Sun 27 June 2021 / nodejs javascript aws dynamodb testing

TL;DR

El paquete dynamodb-local es una opción para hacer pruebas locales automatizadas sobre AWS DynamoDB en desarrollos con NodeJS.

Sobre AWS SDK para Javascript

Actualmente hay dos versiones mantenidas de la SDK de AWS para Javascript: v2 y v3. La mayoría de los ejemplos y documentación que se encuentran más fácilmente en internet son de la v2.

Una ventaja de la v3 sobre la v2 es que está modularizada, es decir, hay una biblioteca por cada componente, por ejemplo @aws-sdk/client-dynamodb. Por otro lado, la configuración no es un objeto global si no que cada componente tiene su configuración. Para más detalles sobre los cambios pueden ver esta nota.

Levantar DynamoDB local

El objetivo principal de levantar una instancia local de DynamoDB es poder hacer pruebas sin necesidad de conectarse a una instancia en AWS, ya sea por sus costos o por la conexión a internet.

Existen varias maneras de levantar una instancia local de DynamoDB, si bien se explican en la documentación de AWS, se encuentran muy bien resumidas en este artículo que incluye algunos problemas típicos que uno se puede encontrar al intentar levantar una instancia local de DynamoDB.

Otro motivo para usar DynamoDB de manera local es poder armar un mínimo de pruebas de integración, en este caso integrarnos a DynamoDB, para probar que los desarrollos funcionen como se espera sin tener que desplegar o conectarse a un entorno de AWS.

Estas pruebas se podrían ejecutar mediante un script de npm, aislado de las pruebas unitarias. Si bien es posible con un oneliner levantar la instancia, lanzar las pruebas y bajarla, no parece ser la opción más clara y pareciera una solución propensa a errores.

Buscando la manera de levantar y bajar programáticamente la instancia de DynamoDB para poder incorporarlo dentro de las pruebas, es que dimos con dynamodb-local.

Utilizar dynamodb-local

Algunas cosas para tener en cuenta sobre la biblioteca dynamodb-local:

Mantenimiento de dynamodb-local

La biblioteca dynamodb-local al momento de escribir estas líneas parece no estar mantenida, su último commit en github es de hace dos años. Pero parece ser utilizada en otros proyectos, como por ejemplo en jest-dynamodb.

Uso de archivo jar de DynamoDB

La biblioteca dynamodb-local utiliza la versión de DynamoDB descargable que viene como archivo jar (o Java Archive). Es decir, se requiere tener instalado Java 8 o superior para levantar la instancia de DynamoDB de manera local (internamente llama a child_process.spawn).

Configuracion del SDK de AWS

También hay que configurar la SDK de AWS para que se conecte a la instancia local configurando la variable endpoint. No hay que olvidarse también de configurar los parámetros de región y credenciales aunque no se utilicen.

Es decir, se puede poner cualquier valor para la región y credenciales si sólo van a probar DynamoDB con la v2 del SDK o si utilizan la v3 al configurar el módulo de DynamoDB.

Tiempo de inicialización de la instancia de DynamoDB

Cuando dynamodb-local devuelve el proceso levantado, el retorno de DynamoDbLocal.launch, no implica que la instancia de DynamoDB esté lista para recibir peticiones. Puede que tarde algunos segundos, dependiendo del equipo donde está ejecutando.

Ejemplos

La documentación de dynamodb-local es muy breve en cuanto a cómo utilizarla. Consta de dos ejemplos, pero que no están completos para el uso aquí sugerido.

Un brevísimo ejemplo de estructura de código para utilizarlos en una serie de tests que requieran integrarse con DynamoDB:

const DynamoDbLocal = require('dynamodb-local');
// v2 de AWS
const AWS = require('aws-sdk');
// v3 de AWS
const { DynamoDB } = require("@aws-sdk/client-dynamodb");

// Funcion para dormir el proceso si se requiere
// Extraido de https://stackoverflow.com/a/41957152
function sleep(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}   

describe('Tests DynamoDB Local', ()=>{
    // En Windows el 8000 puede estar ocupado
    const dynamoDbPort = 8080;
    // Configuracion AWS SDK v2
    const configAwsV2 = {
        region: 'local',
        endpoint: `http://localhost:${dynamoDbPort}`,
        accessKeyId: 'fakeAccessKeyId',
        secretAccessKey: 'fakeSecretAccessKey'
    };
    // Configuracion AWS SDK v3
    const configAwsV3 = {
        region: 'local',
        endpoint: `http://localhost:${dynamoDbPort}`,
        credentials: {
            accessKeyId: 'fakeAccessKeyId',
            secretAccessKey: 'fakeSecretAccessKey'
        }
    };

    let dynamoDbV2;
    let dynamoDbV3;

    before(async ()=>{
        // Son tests lentos hay que cambiar el timeout
        this.timeout(120000);

        // Proceso creado mediante child_process.spawn
        const dynamoDbInstance = await DynamoDbLocal
                .launch(dynamoLocalPort, null, [], false, true);

        // Que el proceso este levantado no implica
        // que esté listo para recibir peticiones
        // Si da error de conexion se sugiere 
        // hacer sleep unos 10 segundos
        await sleep(10000);

        // Configurar e instanciar DynamoDB en v2
        AWS.config.update(configAwsV2);
        dynamoDbV2 = new AWS.DynamoDB();

        // Configurar en v3
        dynamoDbV3 = new DynamoDB(configAwsV3);

        // Codigo de setup de las tablas y populacion con datos

    });

    after(()=>{
        this.timeout(120000);
        // Envía un kill al proceso levantado en el puerto
        DynamoDbLocal.stop(dynamoDbPort);
    }):

    it('test',()=>{
        // Aqui el test que requieren integrarse con DynamoDB
    });

});

Alternativas a dynamodb-local

Dynalite es un proyecto que apuntaba a implementar una versión local de DynamoDB antes de que la misma existiera. Es una implementación mucho más ligera que DynamoDB local y no requiere Java o docker para utilizarla.

No tiene la funcionalidad completa de DynamoDB, pero por caso DynamoDB local tampoco es una copia fiel de la versión en AWS.

Puede resultar una alternativa útil en el caso de que se quiera hacer pruebas dentro de lo que está implementado sin necesidad de componentes extra.

Modri

A cerca de Modri

Geek. Coder. Google-Fu practicioner. Tech Lead in progress. Opinions are my own.

Comments