BLOG

Register To Our Blog

SFTT #2: Using Cognito in serverless integration testing

Welcome to the second edition of Serverless from the Trenches, our series of bite-sized blog posts aimed at developers and DevOps working in serverless. Each article will focus on a different technique or tool to solve a real-world problem and – hopefully – help make your work in serverless more productive.

This week we look at how to add Cognito to your integration tests flow, making for true black box testing.

Testing Cognito

We love integration tests here at Lumigo. We see them as a major part of our CI/CD process, and we believe that they play a pivotal role in serverless testing.

When people say #Serverless they think #Lambda#FaaS , but serverless will become much more complicated, involving multiple managed services, just unit testing and mocking is not enough, testing stuff in the real cloud has become more important pic.twitter.com/dnQ8IcGUyp

One of the test scenarios that we have here is creating an event in our system and then executing an API REST query to retrieve the event details. It’s pure black box testing. Our REST interface sits behind API-GW and is authenticated by Cognito.

If you’ve ever tried to create users in Cognito programmatically, you know that it’s hard. This is because setting the initial password is not enough, the developer needs to change it manually 😨, but manual and automation do not go together.

The following article will cover:

Our testing scenario and how we incorporate Cognito into it

Creating a user in Cognito via a python script, including their password 😃

Actual testing code snippets

Testing scenario

So before digging into the details, let’s first define our test scenario:

We need to create a valid Cognito user. At Lumigo the developer uses the same Cognito user to run the integration test and to log into our development dashboard.

We then embed the username and password created into the integration test configuration.

In the test itself, we pull the configuration and authenticate it using amazon-cognito-identity-js

Creating a user

One of the hardest things about using Cognito is to create a user with a predefined password, without the need to change it after first login (FORCE_CHANGE_PASSWORD account status).

Luckily, there is a nice Python package called warrant which gives us the ability to play directly with Cognito in Python. Let’s use it to create our user and define its password.

Line 66 – Create a Cognito user, this initial creation which leaves the user in FORCE_CHANGE_PASSWORD account status

Line 88 – Which changes the user’s password to the one we actually want

Embedding the user’s password and username

After creating the user we need to embed it into a configuration file which our integration tests framework uses. For the integration tests we use NodeJS, therefore our best way to pass configuration is to use dotenv. We’ve created a simple prepare_env.sh script which prepares the .env files.

The trick in the script is to automate everything, i.e.

Line 59 – Generate a random username.

Line 65,66 – Pull the pool and client ID automatically through AWS CLI

Line 73 – Creating virtual env and install requirements.txt

Authenticating with the user

After creating the user and embedding it in a .env file, it’s time to use it. Each test has the following structure:

Authenticate user via Cognito and receive an authentication token

Use the authentication token in the Authorization header

Let’s look at an example:

Important pointers:

We use amazon-cognito-identity-js

Usually, amazon-cognito-identity-js is used in the client, therefore, you need to set global.fetch for it to work, see line 3

Line 34 – at the end we are interested in the token itself which you can use in the Authorization header

To summarize the process:

Each developer prepares their development environment once by running a script

The script creates a Cognito user

The Cognito user is used by the integration tests to receive an authentication token

Which in turn is used in the authorization header

Tell us how you use Cognito in your integration flow! How do you solve the issues covered in this article? Agree or disagree with our approach? Share your thoughts on Twitter 🙂