Skip to content

Latest commit

 

History

History
 
 

integration

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
# A2 Integration Test Framework

The A2 integration test framework allows you to write tests against full A2 
stack under different scenarios, such as A1 migration, upgrades from a 
previous A2, backup/restore, etc.

## Running
To run a test, run the following from the A2 root folder outside the studio: 

```bash
HAB_ORIGIN=yourorigin ./integration/run_test ./integration/tests/testname.sh
```

## Test specifications
Tests are written in bash. All tests will inherit integration/base.sh by default.
The test framework allows certain callbacks to be defined in a test, and certain 
variables may be set to change default behaviors. Below, some of the common ones
are listed. Read base.sh for more details.

Constants:
- test_build_slug: Randomizes your container name
- test_container_name: The name the test framework gave your container

Variables:
- test_name: [required] Set this to the name of your test
- test_upgrades: [optional, default=false] Set this to true if your test requires
                 upgrading from a previous version of A2.
- test_backup_restore: [optional, default=false] Set this to true if your test requires backup/restore.
                       Only one of test_upgrades and test_backup_restore is supported at a time. If you 
                       need more, make it work.
- test_loadbalancer_url: [optional, default="https://localhost"] The A2 https loadbalancer url
- test_deploy_inspec_profiles: [optional, default=()] A list of inspec profiles to run after deploy
- test_upgrade_inspec_profiles: [optional, default=()] A list of inspec profiles to run after upgrade
- test_skip_diagnostics: [optional, default=false] Set to true if you do not wish for the diagnostics
                         tests to be run
- test_config_path: The location of the config
- test_external_services: External services required to run this test. See the External Services section.

Callbacks:
- do_setup(): Do any setup you need prior to having A2 installed
- do_build(): Build the harts for your change. In CI, this step only downloads because the changes are
              built in another build step in the pipeline.
- do_create_config(): Initialize the config. At the end of this step, the config should be written to
                      $test_config_path
- do_prepare_deploy(): This step runs right before deploying A2. For upgrades, the default implementation
                       will lay down the dev deployment manifest and move out the changes, to be put back
                       in place in the upgrade step.
- do_deploy(): Deploys A2
- do_test_deploy(): Runs tests after deploy. Uses the test_deploy_inspec_profiles and test_skip_diagnostics
                    variables. to figure out what to run in the default implementation.
- do_upgrade(): Moves the changes back into place and waits for A2 to finish upgrading.
- do_test_upgrade(): Runs tests after upgrade. Uses the test_upgrade_inspec_profiles and test_skip_diagnostics
                     variables. to figure out what to run in the default implementation.
- do_backup(): Create a backup of A2
- do_prepare_restore(): Prepare A2 for restore. The default implementation brings down A2 and deletes stuff
- do_restore(): Restore A2. The id for the backup is stored in test_backup_id
- do_test_restore(): Runs tests post restore. Default implementation only deals with diagnostics

## External Services
The ability to run external services was introduced in chef#5103.

To add an external service, add a folder with the service name (no spaces) to `integration/services`.
For example, `integration/services/elasticsearch`. In the folder for the service, create a shell 
script called `init` with 2 functions: `service_name_setup` and `service_name_teardown`, where 
`service_name` should be replaced with the service name. For example, in the elasticsearch case,
they would be `elasticsearch_setup` and `elasticsearch_teardown`. This init file will be sourced 
into the `run_test` script and the functions called if a test defines it as a dependency through 
the `test_external_services` array. For example, a test might look like this:

```bash
test_name="product"
test_deploy_inspec_profiles=(a2-deploy-integration)
test_external_services=(
  elasticsearch
)

do_prepare_config() {
...
}
```

The `_setup` function is responsible for setting up containers. There are a few helper functions provided
for that. `service_container_name container_name` appends the `test_build_slug` variable to the container
name, ensuring that multiple tests can run without interfering with each other. The `docker_run` function
wraps `docker run` to setup the correct volumes, environment variables, etc.

The `_setup` function can share config with the test container by writing a file in the service config
path. For convention, services should use the `service_config_path service_name` function which will namespace
the directory. `service_config_path` will create a folder `$SERVICES_CONFIG_PATH/service_name`.
`$SERVICES_CONFIG_PATH` gets mounted at `/services` in the test container. As en example,
the elasticsearch config could write out the toml required to start an external elasticsearch in A2. 
The test container would append this file to its generated toml.

An example init file:

```bash

SERVICE_A_DIR=$(dirname ${BASH_SOURCE[0]})

service_a_container1=$(service_container_name "service_a_1")
service_a_container2=$(service_container_name "service_a_2")
service_a_config=$(service_config_path "service_a")

service_a_setup() {
    mkdir -p $(dirname $service_a_config)
    docker_run $service_a_container1
    docker cp "$SERVICE_A_DIR/setup.sh" "${service_a_container1}:/setup.sh"
    docker exec $service_a_container1 /setup.sh
    log_info "Launched $service_a_container1 with ip $(container_ip $service_a_container1)"
    docker_run $service_a_container2
    log_info "Launched $service_a_container2 with ip $(container_ip $service_a_container2)"
    cat <<DOC > $service_a_config
hello
DOC

}

service_a_teardown() {
    docker stop "$service_a_container1"
    docker stop "$service_a_container2"
}
```