Notas de pruebas con AWS DynamoDB local y NodeJS
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
:
- No parece estar mantenida
- Utiliza la versión descargable de DynamoDB (archivo
jar
) - Requiere configurar el SDK de AWS para poder utilizarlo
- La instancia levantada puede no estar lista para usar inmediantamente
- Falta de ejemplos completos de uso
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.