diff --git a/docs/development/testing.md b/docs/development/testing.md index 2b9db0a37..5b4d23c67 100644 --- a/docs/development/testing.md +++ b/docs/development/testing.md @@ -46,3 +46,39 @@ make deploy-test-nodejs-express ``` For a full list of test make targets check out `tests.mk` in the root of the Dokku repository. + +## Executing a single test suite + +When working on a particular plugin, it may be useful to run _only_ a particular test suite. This can be done by specifying the test suite path: + +```shell +bats tests/unit/10_apps.bats +``` + +It is also possible to target multiple test suites at a time. + +```shell +bats tests/unit/10_apps.bats tests/unit/10_certs.bats +``` + +## Executing a single test + +In order to increase testing velocity, a wrapper script around bats is available that can be used to run a single testcase within a suite. + +Tests within a suite may be listed by specifying the suite as a parameter to the `tests/bats-exec-test-single` script. + +```shell +tests/bats-exec-test-single tests/unit/10_apps.bats +``` + +A single test can be specified as a second parameter. The test is selected by fuzzy-match, and only the first match is executed. + +```shell +tests/bats-exec-test-single tests/unit/10_apps.bats clone +``` + +Some special characters are translated in the test listing - specifically the characters `( ) :` - while others are not. The fuzzy matching happens on the test names listed when no second character is invoked, so executing a test with a more specific name will work as expected. + +```shell +tests/bats-exec-test-single tests/unit/10_apps.bats clone_-2d-2dskip-2ddeploy +``` diff --git a/tests/bats-exec-test-single b/tests/bats-exec-test-single new file mode 100755 index 000000000..8012ca47c --- /dev/null +++ b/tests/bats-exec-test-single @@ -0,0 +1,68 @@ +#!/bin/bash + +fn-available-tests() { + declare PROCESSED_TEST_FILE="$1" + AVAILABLE_TESTS="$(grep -o -E '^test_[^ ]+' "$PROCESSED_TEST_FILE")" + AVAILABLE_TESTS=${AVAILABLE_TESTS//-28/(} + AVAILABLE_TESTS=${AVAILABLE_TESTS//-29/)} + AVAILABLE_TESTS=${AVAILABLE_TESTS//-3a/:} + echo "$AVAILABLE_TESTS" +} + +fn-matched-test() { + declare TEST_NAME="$1" AVAILABLE_TESTS="$2" + + if [[ -z "$TEST_NAME" ]]; then + return + fi + + echo "$AVAILABLE_TESTS" | grep "$TEST_NAME" | head -1 +} + +fn-real-test-name() { + declare TEST_NAME="$1" + + REAL_TEST_NAME=${TEST_NAME::-2} + REAL_TEST_NAME=${REAL_TEST_NAME//(/-28} + REAL_TEST_NAME=${REAL_TEST_NAME//)/-29} + REAL_TEST_NAME=${REAL_TEST_NAME//:/-3a} + echo "$REAL_TEST_NAME" +} + +main() { + declare TEST_FILE="$1" TEST_NAME="$2" + local AVAILABLE_TESTS + + if [[ -z "$TEST_FILE" ]]; then + echo "No test file specified" + exit 1 + fi + + if [[ ! -e "$TEST_FILE" ]]; then + echo "not found: '$TEST_FILE'" + exit 1 + fi + + TMP_OUTPUT=$(mktemp "/tmp/${FUNCNAME[0]}.XXXX") + trap 'rm -rf "$TMP_OUTPUT" > /dev/null' RETURN INT TERM EXIT + + /usr/local/libexec/bats-preprocess < "$TEST_FILE" > "$TMP_OUTPUT" + AVAILABLE_TESTS="$(fn-available-tests "$TMP_OUTPUT")" + MATCHED_TEST=$(fn-matched-test "$TEST_NAME" "$AVAILABLE_TESTS") + + if [[ -z "$MATCHED_TEST" ]]; then + if [[ -n "$TEST_NAME" ]]; then + echo "test '$TEST_NAME' not found in ${TEST_FILE}" + fi + + echo "available test are:" + echo "$AVAILABLE_TESTS" + exit 1 + fi + + echo "Running test: ${MATCHED_TEST}" + export BATS_TEST_SOURCE="$TMP_OUTPUT" + /usr/local/libexec/bats-exec-test "$TEST_FILE" "$(fn-real-test-name "$MATCHED_TEST")" +} + +main "$@"