This repository contains code written to run load testing for the MilMove application. Load testing is accomplished via the Locust framework.
Works created by U.S. Federal employees as part of their jobs typically are not eligible for copyright in the United States. In places where the contributions of U.S. Federal employees are not eligible for copyright, this work is in the public domain. In places where it is eligible for copyright, such as some foreign jurisdictions, the remainder of this work is licensed under the MIT License, the full text of which is included in the LICENSE.txt file in this repository.
- Overview
- Project Directories
- Getting Started
- Updating Python Version
- Updating Pipenv Version
- OpenAPI Generator
- Running Locust Locally
- Running Tests
- Reports
MilMove is a system to help service members (and other authorized personnel) move their gear and possessions from one place to another.
This codebase has been written to perform load tests on the MilMove app for the purpose of gathering data about responses times, finding breakpoints, and assessing the overall health of the system.
The documentation in this README is focused on the repo structure, setting up your local environment,
and running unit tests. Documentation on locust
, how we use it, and running the load tests can be
found in the mymove locust docs.
This section covers some high-level notes for some directories included in this repo.
This directory contains a representation of the task definition for running the docker container in
AWS. To make changes to the task definition will require changing the terraform in
transcom/transcom-infrasec-gov-nonato/transcom-gov-dev/app-dev/loadtesting.tf
. This file is
updated manually to reflect the current state.
Locust uses a python file called a "locustfile" as the base for
running a load test. This directory contains all locustfiles for this repo. This file must contain
at least one class definition that inherits from a locust User
class (or more likely a subclass).
Locust will dynamically create instances of these User
classes to simulate the request load
desired.
Each of these files can be thought of as a different test case for the system, although locust also provides a number of config options to allow you to manipulate which users and/or tasks run from any given locustfile.
As of 2022-05-25, the locustfiles/queue.py
is the recommended way to
run the load tests.
aws-session-port-forward.py
- This is the script used to access the deployed locust load testing
container and forward to your local port 4000 accessible
at http://localhost:4000.
codebuild
- This script is invoked when making a new build/deployment using the AWS CodeBuild
service. It builds a new docker image and publishes it to ECR so the service can pull down the new
image. It also controls updating the service if there is a new task definition from updating the
Terraform code.
install_tools
- This script is used in the local set up for this repository if you aren't using
nix
.
regenerate-swagger-client
- We are using
openapi-generator
to generate python code that uses the milmove API. See the OpenAPI
Generator section below for more information
This folder is for static files (certificates, PDFs, etc.) that will be used during load testing.
Each User
class needs a set of tasks to complete to be able to run a load test. All tasks are
callables that can be manually set into the tasks
attribute of the user, or they can be organized
into instances of the locust class TaskSet
and then associated with a user. This directory
contains all the tasks used in our load tests.
To read more about users and tasks and how they interact, refer to Writing a locustfile.
This directory contains python code and utilities that help us run our load tests. For example, the code we use to manage authenticating to the Prime API. Mixin classes, helper functions, and constants are located here.
This directory contains different move "flows" that exercise a move end to end through the system through the different roles (service member, service counselor, TOO, prime).
You can run a flow outside of locust when developing/testing. For example, try
PYTHONPATH=$PWD python utils/flows/simple_hhg.py
This directory contains steps to support each flow.
Note: These instructions include the relevant commands for MacOS only. Please keep this in mind and be prepared to search for alternatives if you are running a different OS.
We have two supported installation methods, pyenv
and nix
. Pick which you prefer and proceed to
that section.
-
When setting up for the first time, before you run
direnv allow
, runmake install_tools
- This will install
pyenv
andpipenv
along with other tools likepre-commit
.
- This will install
-
Restart your terminal.
- If you see something similar to the following
direnv: loading ~/Projects/milmove_load_testing/.envrc direnv: Want to load secrets from chamber? 'ln -s .envrc.chamber.template .envrc.chamber' /bin/bash:979: pipenv: command not found /bin/bash:980: pipenv: command not found
Then please run
install_tools
again. -
Now run
direnv allow
- This should install the dependencies via
pipenv
automatically.
- This should install the dependencies via
-
Install
pre-commit
hooks:make ensure_pre_commit
If you need help with this setup, you can ask for help in the Truss slack #code-nix channel.
-
First read the overview in the Truss Engineering Playbook .
-
Follow the installation instructions in the playbook.
-
Ensure you have
direnv
and a modernbash
installed. To install globally with nix, run:nix-env -i direnv bash
-
To set up the appropriate nix environment variables run:
direnv allow
-
Run
./nix/update.sh
-
Install
pre-commit
hooks:make ensure_pre_commit
If the nix dependencies change, you should see a warning from direnv:
direnv: WARNING: nix packages out of date. Run nix/update.sh
If the python version changes, you may need to do pipenv --rm
and
then something like cd / && cd -
Note that if you would like to disable nix
for this repo, you can do so by creating
a .nix-disable
file at the top level of this repo and reload your shell.
-
If the python dependencies get updated (
Pipfile
and/orPipfile.lock
files change), you can update your local environment by running:make install_python_deps
Maintaining many ways to set up locally can be time-consuming, which is why we removed the asdf
and docker setups.
The asdf
end set-up was similar to the pyenv
setup, but required many commands to have tweaks to
work the same as the pyenv
commands which made them harder to maintain.
As for docker, we had a few reasons for dropping support:
- Locust is a tool that needs to reach the target host and running it from inside docker makes it harder to reach a server that is managed outside of docker.
- Docker adds yet another layer for possible issues. We've experienced some problems in the past with docker network problems that were masked as locust errors. Errors like this are a pain to debug.
- Our current setup using
direnv
andpipenv
is fairly quick to set up using eithernix
or themake install_tools
command, decreasing the "quick setup" case for using docker.
Setups were removed in the following PRs:
If you encounter compiler issues while installing the required Python version, try:
brew unlink binutils
To update python to a new version, you need to modify multiple files:
.circleci/config.yml
Update thecimg/python
versionDockerfile
Update theFROM
at the topPipfile
Update thepython_full_version
near the bottomfrew-brew.local
Update thepython_version
near the topnix/default.nix
Update the python stanza from nix package search- Update the
load_tester
image in themymove/.circleci/config.yml
to the right version
NOTE: nix installs pipenv with its own bundled version of python, but pipenv can create virtual envs for other versions of python.
We want to lock our pipenv version to ensure consistent behavior
Dockerfile
Update theRUN pip install
linenix/default.nix
Update the pipenv stanza from nix package search
We are using openapi-generator to generate python client code for interacting with the milmove API.
Run ./scripts/regenerate-swagger-client
to build the newest version
of the files. They will be saved to ./openapi_client
.
One of the biggest challenges with this approach is that the swagger definitions on milmove frequently do not match what is actually returned my milmove. This is very definitely buggy behavior by the milmove app, and so we try to work around it where we can.
To run locust on your local machine against a milmove instance running
on your local machine, use make server_run
in the milmove directory
and then in another shell in this repo, run
locust -f locustfiles/queue.py --host local -u 10
Or, to run headless for 30 seconds and print the results, do
locust -f locustfiles/queue.py --host local -u 10 -t 30s --headless
You should always see 0% failures.
There are two types of tests in this repository:
- Load tests which run against the mymove server, whether local or deployed. For more info on these, see Running Load Tests.
- Unit tests which test the helper code we have in this repository. For more info on these, see Running Unit Tests.
These are located is tests/
directories within the corresponding python package, e.g.
utils/tests/
. They are mainly here to ensure our setup code is doing what we expect, e.g. testing
that our Prime auth code is setting up certs the way we expect.
This project uses pytest
as its testing framework. To run
the tests use the command:
pytest
To see verbose output and any print statements in the tests, use:
pytest -v -s
To run a specific test, use:
pytest utils/tests/test_parsers.py
For more instructions and examples, please read pytest's documentation.
We store reports from running against the loadtest environment in confluence.