diff --git a/test/helpers b/test/helpers index fb2129b2..d68d3e00 100644 --- a/test/helpers +++ b/test/helpers @@ -2,32 +2,77 @@ ### Helpers functions -test::helpers::get_php_version() { - local old_home +test::helpers::test_deploy() { + # Deploy a PHP app in a Scalingo runtime and test that everything is as + # expected. The different fixtures allow us to test different setup and + # conditions. - old_home="${HOME}" + local fixture_name="${1}" + local detect_expectation="${2}" + local version="${3}" - HOME="/app" - export HOME + # Setup the fixture: + test::utils::setupFixture "${fixture_name}" - pushd "${HOME}" > /dev/null + # Test that bin/detect works as expected: + test::utils::detect + test::utils::assertCapturedSuccess + test::utils::assertCapturedEquals "${detect_expectation}" - cp --archive --recursive "${BUILD_DIR}"/* "${HOME}/" + # Test that bin/compile works as expected: + test::utils::compile + # We can't use assertCapturedSuccess here: + # With an empty composer.json file, composer will use stderr to warn us + # that nothing had to be installed, causing the test to fail for no + # reason -_- + test::utils::assertSuccess - test::utils::capture ./vendor/php/bin/php --version + # Switch environment: + test::helpers::enter_prod + + # Test that PHP has the awaited version: + test::helpers::get_php_version + test::utils::assertCapturedStartswith "PHP ${version}" - popd > /dev/null + # Test that all default PHP modules are available: + test::helpers::list_php_modules + for module in "${default_modules[@]}"; do + test::utils::assertFileContains "${module}" "${STD_OUT}" + done +} - rm -Rf "${HOME}"/* +test::helpers::get_php_version() { + # Captures the output of `php --version` so we can check that the version + # installed is the expected one. - HOME="${old_home}" - export HOME + test::utils::capture ./vendor/php/bin/php --version } test::helpers::list_php_modules() { - local old_home + # Captures the output of `php --modules` so we can check that all default + # modules are indeed available. + + test::utils::capture ./vendor/php/bin/php --modules +} - old_home="${HOME}" +test::helpers::enter_prod() { + # Helper to switch to a production-like environment: + # - $HOME is set to /app + # - Working directory is set to $HOME + # - The result of the `compile` script is copied to $HOME + # + # This environment is automatically reverted back, thanks to the `tearDown` + # function override in `test/run`. + # It would have been nice to put that in a `setUp` override. Unfortunately, + # we can't because the switch of environment should only happen **during** + # the test (after several steps have been reached), not before. + # + # /!\ This function is meant to be called after a successful call to + # to `test::utils::compile` to further test the result of the + # bin/compile call. It makes no sense to call it in another context. + + PREV_HOME="${HOME}" + export PREV_HOME HOME="/app" export HOME @@ -35,43 +80,4 @@ test::helpers::list_php_modules() { pushd "${HOME}" > /dev/null cp --archive --recursive "${BUILD_DIR}"/* "${HOME}/" - - test::utils::capture ./vendor/php/bin/php --modules - - popd > /dev/null - - rm -Rf "${HOME}"/* - - HOME="${old_home}" - export HOME -} - - -test::helpers::test_compile() { - local fixture="${1}" - local php_version="${2}" - - # PHP 8.0 is only available on stack `scalingo-20`: - [[ "${STACK}" != "scalingo-20" && "${php_version}" == "8.0." ]] \ - && echo "[skipping] PHP 8.0 is not available on scalingo-22" \ - && startSkipping - - # Test that buildpack compiles: - test::utils::compile "${fixture}" - # We can't use assertCapturedSuccess here: - # Even with an empty composer.json file, composer will use stderr to warn - # us that nothing had to be installed, causing the test to fail for no - # reason -_- - test::utils::assertSuccess - - # Test that we have the appropriate PHP version: - test::helpers::get_php_version - test::utils::assertCapturedStartswith "PHP ${php_version}" - - # Test that all default PHP modules are present: - test::helpers::list_php_modules - - for module in "${default_modules[@]}"; do - test::utils::assertFileContains "${module}" "${STD_OUT}" - done } diff --git a/test/run b/test/run index 1ef5d586..a54e8bc4 100755 --- a/test/run +++ b/test/run @@ -16,20 +16,35 @@ oneTimeTearDown() { } setUp() { - export OUTPUT_DIR="$( mktemp --directory "${SHUNIT_TMPDIR}/output.XXXX" )" + OUTPUT_DIR="$( mktemp --directory "${SHUNIT_TMPDIR}/output.XXXX" )" STD_OUT="${OUTPUT_DIR}/stdout" STD_ERR="${OUTPUT_DIR}/stderr" - export BUILD_DIR="${OUTPUT_DIR}/build" - export CACHE_DIR="${OUTPUT_DIR}/cache" - export HOME="${BUILD_DIR}" + BUILD_DIR="${OUTPUT_DIR}/build" + CACHE_DIR="${OUTPUT_DIR}/cache" + HOME="${BUILD_DIR}" + BUILDPACK_DIR="$( mktemp --directory "/tmp/test-XXXXXX" )" mkdir -p "${OUTPUT_DIR}" "${BUILD_DIR}" "${CACHE_DIR}" + export OUTPUT_DIR STD_OUT STD_ERR BUILD_DIR CACHE_DIR HOME BUILDPACK_DIR + + # Copy the buildpack code into BUILDPACK_DIR: + cp --archive "$( pwd )"/* "${BUILDPACK_DIR}/" } tearDown() { + # Empty OUTPUT_DIR and BUILDPACK_DIR rm -rf "${OUTPUT_DIR}" + rm -rf "${BUILDPACK_DIR}" + + unset BUILDPACK_DIR BUILD_DIR CACHE_DIR PHP_VERSION + + # We may have changed working dir, let's switch back to the initial one: + popd > /dev/null 2>&1 + + # Make sure /app is empty: + rm -rf "/app"/* } # Load shUnit2, which also run the tests: diff --git a/test/tests b/test/tests index d3691409..f92f55bc 100755 --- a/test/tests +++ b/test/tests @@ -3,6 +3,9 @@ source "$( pwd )/test/utils" source "$( pwd )/test/helpers" +# List of modules that we want to ship with every PHP setup. +# For now, users can't specify a version for these modules, we just ship +# what we have. Hence no specific versions constraints here. readonly default_modules=( "apcu" "bcmath" "bz2" "Core" "ctype" "curl" "date" "dom" "exif" "fileinfo" "filter" "gd" "hash" "iconv" "intl" "json" "libxml" "mbstring" "mongodb" @@ -12,50 +15,112 @@ readonly default_modules=( "tokenizer" "xml" "xmlreader" "xmlwriter" "xsl" "Zend OPcache" "zip" "zlib" ) -test::detect_legacy_default() { - # Test the buildpack detect script with a single simple .php file - test::utils::detect "legacy_default" - test::utils::assertCapturedSuccess - test::utils::assertCapturedEquals "PHP (classic)" + +test::legacy::defaults() { + # Test a deployment of a legacy app (not using Composer) + # With default settings + + test::helpers::test_deploy "legacy_default" "PHP (classic)" "8.1." } -test::detect_composer_default() { - test::utils::detect "composer_default" - test::utils::assertCapturedSuccess - test::utils::assertCapturedEquals "PHP (composer.json)" +test::legacy::php80() { + # Test a deployment of a legacy app (not using Composer) + # Specifying we want PHP 8.0.x via environment + + PHP_VERSION="8.0" + export PHP_VERSION + + # PHP 8.0 is only available on stack `scalingo-20`: + if [[ "${STACK}" != "scalingo-20" ]]; then + echo "[skipping] PHP 8.0 is not available on scalingo-22" + startSkipping + fi + + test::helpers::test_deploy "legacy_default" "PHP (classic)" "8.0." } -test::compile_legacy_default() { - test::helpers::test_compile "legacy_default" "8.1." +test::legacy::php81() { + # Test a deployment of a legacy app (not using Composer) + # Specifying we want PHP 8.1.x via environment + + PHP_VERSION="8.1" + export PHP_VERSION + + test::helpers::test_deploy "legacy_default" "PHP (classic)" "8.1." } -test::compile_composer_default() { - test::helpers::test_compile "composer_default" "8.1." +test::legacy::php82() { + # Test a deployment of a legacy app (not using Composer) + # Specifying we want PHP 8.2.x via environment + + PHP_VERSION="8.2" + export PHP_VERSION + + test::helpers::test_deploy "legacy_default" "PHP (classic)" "8.2." } -test::compile_composer_php80() { - test::helpers::test_compile "composer_php80" "8.0." +test::legacy::php83() { + # Test a deployment of a legacy app (not using Composer) + # Specifying we want PHP 8.3.x via environment + + PHP_VERSION="8.3" + export PHP_VERSION + + test::helpers::test_deploy "legacy_default" "PHP (classic)" "8.3." } -test::compile_composer_php81() { - test::helpers::test_compile "composer_php81" "8.1." +test::composer::defaults() { + # Test a deployment of a PHP app using Composer + # With default settings + + test::helpers::test_deploy "composer_default" "PHP (composer.json)" "8.1." } -test::compile_composer_php82() { - test::helpers::test_compile "composer_php82" "8.2." +test::composer::php80() { + # Test a deployment of a PHP app using Composer + # Specifying we want PHP 8.0.x in composer.json + + # PHP 8.0 is only available on stack `scalingo-20`: + if [[ "${STACK}" != "scalingo-20" ]]; then + echo "[skipping] PHP 8.0 is not available on scalingo-22" + startSkipping + fi + + test::helpers::test_deploy "composer_php80" "PHP (composer.json)" "8.0." +} + +test::composer::php81() { + # Test a deployment of a PHP app using Composer + # Specifying we want PHP 8.1.x in composer.json + + test::helpers::test_deploy "composer_php81" "PHP (composer.json)" "8.1." } -test::compile_composer_php83() { - test::helpers::test_compile "composer_php83" "8.3." +test::composer::php82() { + # Test a deployment of a PHP app using Composer + # Specifying we want PHP 8.2.x in composer.json + + test::helpers::test_deploy "composer_php82" "PHP (composer.json)" "8.2." } +test::composer::php83() { + # Test a deployment of a PHP app using Composer + # Specifying we want PHP 8.3.x in composer.json + + test::helpers::test_deploy "composer_php83" "PHP (composer.json)" "8.3." +} + + # Add these functions to the test suite: -suite_addTest test::detect_legacy_default -suite_addTest test::compile_legacy_default -suite_addTest test::detect_composer_default -suite_addTest test::compile_composer_default -suite_addTest test::compile_composer_php80 -suite_addTest test::compile_composer_php81 -suite_addTest test::compile_composer_php82 -suite_addTest test::compile_composer_php83 +suite_addTest test::legacy::defaults +suite_addTest test::legacy::php80 +suite_addTest test::legacy::php81 +suite_addTest test::legacy::php82 +suite_addTest test::legacy::php83 + +suite_addTest test::composer::defaults +suite_addTest test::composer::php80 +suite_addTest test::composer::php81 +suite_addTest test::composer::php82 +suite_addTest test::composer::php83 diff --git a/test/utils b/test/utils index 79a6324a..425dd9f5 100644 --- a/test/utils +++ b/test/utils @@ -3,38 +3,26 @@ # taken from # https://github.com/ryanbrainard/heroku-buildpack-testrunner/blob/master/lib/test_utils.sh -test::utils::detect() { - local buildpack_dir - - export buildpack_dir="$( mktemp --directory "/tmp/test-detect-XXXXXX" )" - - cp -a "$( pwd )"/* "${buildpack_dir}/" - cp -a "$( pwd )/test/fixtures/${1}"/* "${BUILD_DIR}/" +test::utils::setupFixture() { + local fixture="${1}" - pushd "${buildpack_dir}" > /dev/null - - test::utils::capture "${buildpack_dir}/bin/detect" "${BUILD_DIR}" + cp --archive "${BUILDPACK_DIR}/test/fixtures/${fixture}"/* "${BUILD_DIR}/" +} - popd > /dev/null +test::utils::detect() { + test::utils::capture "${BUILDPACK_DIR}/bin/detect" "${BUILD_DIR}" } test::utils::compile() { - local buildpack_dir - - buildpack_dir="$( mktemp --directory "/tmp/test-compile-XXXXXX" )" - - cp -a "$( pwd )"/* "${buildpack_dir}/" - cp -a "$( pwd )/test/fixtures/${1}"/* "${BUILD_DIR}/" - - pushd "${buildpack_dir}" > /dev/null - - test::utils::capture "${buildpack_dir}/bin/compile" "${BUILD_DIR}" \ + test::utils::capture "${BUILDPACK_DIR}/bin/compile" "${BUILD_DIR}" \ "${CACHE_DIR}" - - popd > /dev/null } test::utils::capture() { + # Redirects stdout to $STD_OUT and stderr to $STD_ERR so we can + # analyze/test/grep these outputs after. + # It also set a few variables ($LAST_COMMAND, $RETURN) for further use. + test::utils::resetCapture LAST_COMMAND="$@" @@ -158,15 +146,10 @@ test::utils::_assertMatches() { fail "Expected 4 or 5 parameters; Receieved $# parameters" fi - local needle - local haystack - local expectation - local haystack_type - - needle="${1}" - haystack="${2}" - expectation="${3}" - haystack_type="${4}" + local needle="${1}" + local haystack="${2}" + local expectation="${3}" + local haystack_type="${4}" case "${haystack_type}" in "file") @@ -259,8 +242,8 @@ test::utils::command_exists () { } test::utils::assertFileMD5() { - expectedHash="${1}" - filename="${2}" + local expectedHash="${1}" + local filename="${2}" if test::utils::command_exists "md5sum"; then md5_cmd="md5sum ${filename}" @@ -286,11 +269,13 @@ test::utils::assertDirectoryExists() { } test::utils::assertFileExists() { - filename="${1}" - assertTrue "${filename} doesn't exist" "[[ -e "${filename}" ]]" + local filename="${1}" + + assertTrue "${filename} doesn't exist" "[[ -e "${filename}" ]]" } test::utils::assertFileDoesNotExist() { - filename="${1}" - assertTrue "${filename} exists" "[[ ! -e "${filename}" ]]" + local filename="${1}" + + assertTrue "${filename} exists" "[[ ! -e "${filename}" ]]" }