From d6c774d5ed194447c359cda91f3031bb95837ed9 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 11 Mar 2026 22:59:25 -0500 Subject: [PATCH 1/7] test(detect): add unit tests for bin/detect Verify that bin/detect correctly identifies Elixir projects by checking for mix.exs presence, returning exit 0 with "Elixir" output when found and exit 1 when absent. --- test/detect.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 test/detect.sh diff --git a/test/detect.sh b/test/detect.sh new file mode 100755 index 0000000..6a170ef --- /dev/null +++ b/test/detect.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +source $SCRIPT_DIR/.test_support.sh + + +# TESTS +###################### +suite "bin/detect" + + test "detects mix.exs exists" + + touch $build_path/mix.exs + output=$($SCRIPT_DIR/../bin/detect $build_path) + + [ "$output" == "Elixir" ] + rm $build_path/mix.exs + + + test "exits 1 when no mix.exs" + + set +e + $SCRIPT_DIR/../bin/detect $build_path > /dev/null 2>&1 + result=$? + set -e + + [ "$result" == "1" ] + + +PASSED_ALL_TESTS=true From 443aa1a95e61f8014b9a124b696e322e0b7aa24c Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 11 Mar 2026 22:59:52 -0500 Subject: [PATCH 2/7] test(path_funcs): add unit tests for path builders Cover all 17 path builder functions: build/runtime platform tools, erlang, elixir, hex home, mix home, plus cache paths (stack-based, deps/build backup, mix/hex backup, erlang/elixir cache). --- test/path_funcs.sh | 142 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100755 test/path_funcs.sh diff --git a/test/path_funcs.sh b/test/path_funcs.sh new file mode 100755 index 0000000..b55cb9d --- /dev/null +++ b/test/path_funcs.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +source $SCRIPT_DIR/.test_support.sh + +# include source file +source $SCRIPT_DIR/../lib/path_funcs.sh + +# set runtime_path to a known value +runtime_path="/app" + + +# TESTS +###################### +suite "path_funcs: build paths" + + test "build_platform_tools_path" + + result=$(build_platform_tools_path) + + [ "$result" == "${build_path}/.platform_tools" ] + + + test "build_erlang_path" + + result=$(build_erlang_path) + + [ "$result" == "${build_path}/.platform_tools/erlang" ] + + + test "build_elixir_path" + + result=$(build_elixir_path) + + [ "$result" == "${build_path}/.platform_tools/elixir" ] + + + test "build_hex_home_path" + + result=$(build_hex_home_path) + + [ "$result" == "${build_path}/.hex" ] + + + test "build_mix_home_path" + + result=$(build_mix_home_path) + + [ "$result" == "${build_path}/.mix" ] + + +suite "path_funcs: runtime paths" + + test "runtime_platform_tools_path" + + result=$(runtime_platform_tools_path) + + [ "$result" == "/app/.platform_tools" ] + + + test "runtime_erlang_path" + + result=$(runtime_erlang_path) + + [ "$result" == "/app/.platform_tools/erlang" ] + + + test "runtime_elixir_path" + + result=$(runtime_elixir_path) + + [ "$result" == "/app/.platform_tools/elixir" ] + + + test "runtime_hex_home_path" + + result=$(runtime_hex_home_path) + + [ "$result" == "/app/.hex" ] + + + test "runtime_mix_home_path" + + result=$(runtime_mix_home_path) + + [ "$result" == "/app/.mix" ] + + +suite "path_funcs: cache paths" + + test "stack_based_cache_path" + + result=$(stack_based_cache_path) + + [ "$result" == "${cache_path}/gigalixir-buildpack-elixir/stack-cache" ] + + + test "deps_backup_path" + + result=$(deps_backup_path) + + [ "$result" == "${cache_path}/gigalixir-buildpack-elixir/stack-cache/deps_backup" ] + + + test "build_backup_path" + + result=$(build_backup_path) + + [ "$result" == "${cache_path}/gigalixir-buildpack-elixir/stack-cache/build_backup" ] + + + test "mix_backup_path" + + result=$(mix_backup_path) + + [ "$result" == "${cache_path}/gigalixir-buildpack-elixir/stack-cache/.mix" ] + + + test "hex_backup_path" + + result=$(hex_backup_path) + + [ "$result" == "${cache_path}/gigalixir-buildpack-elixir/stack-cache/.hex" ] + + + test "erlang_cache_path" + + result=$(erlang_cache_path) + + [ "$result" == "${cache_path}/gigalixir-buildpack-elixir/stack-cache/erlang" ] + + + test "elixir_cache_path" + + result=$(elixir_cache_path) + + [ "$result" == "${cache_path}/gigalixir-buildpack-elixir/stack-cache/elixir" ] + + +PASSED_ALL_TESTS=true From 34fc54775fcc28b0853fe54288f4f0dedd50b2ab Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 12 Mar 2026 07:43:20 -0500 Subject: [PATCH 3/7] test(erlang_funcs): add unit tests for erlang funcs Test erlang_tarball filename generation and erlang_builds_url for all stack variants (heroku-20, heroku-22, heroku-24, and unknown/fallback). --- test/erlang_funcs.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 test/erlang_funcs.sh diff --git a/test/erlang_funcs.sh b/test/erlang_funcs.sh new file mode 100755 index 0000000..001c437 --- /dev/null +++ b/test/erlang_funcs.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +source $SCRIPT_DIR/.test_support.sh + +# include source files +source $SCRIPT_DIR/../lib/path_funcs.sh +source $SCRIPT_DIR/../lib/erlang_funcs.sh +source $SCRIPT_DIR/../lib/canonical_version.sh + + +# TESTS +###################### +suite "erlang_tarball" + + test "generates correct tarball filename" + + erlang_version="26.2.1" + result=$(erlang_tarball) + + [ "$result" == "OTP-26.2.1.tar.gz" ] + + + test "generates tarball for major.minor version" + + erlang_version="25.0" + result=$(erlang_tarball) + + [ "$result" == "OTP-25.0.tar.gz" ] + + +suite "erlang_builds_url" + + test "returns heroku-20 URL" + + STACK="heroku-20" + result=$(erlang_builds_url) + + [ "$result" == "https://builds.hex.pm/builds/otp/ubuntu-20.04" ] + + + test "returns heroku-22 URL" + + STACK="heroku-22" + result=$(erlang_builds_url) + + [ "$result" == "https://builds.hex.pm/builds/otp/ubuntu-22.04" ] + + + test "returns heroku-24 URL" + + STACK="heroku-24" + result=$(erlang_builds_url) + + [ "$result" == "https://builds.hex.pm/builds/otp/ubuntu-24.04" ] + + + test "returns cedar-14 URL for unknown stack" + + STACK="unknown-stack" + result=$(erlang_builds_url) + + [ "$result" == "https://s3.amazonaws.com/heroku-buildpack-elixir/erlang/cedar-14" ] + + +PASSED_ALL_TESTS=true From 7a16256544274451a1056487bf973e700dde09b5 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 12 Mar 2026 07:43:25 -0500 Subject: [PATCH 4/7] test(elixir_funcs): add tests for elixir helpers Test otp_version extraction (full, major.minor, major-only formats) and elixir_download_file filename generation for different version combos. --- test/elixir_funcs.sh | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100755 test/elixir_funcs.sh diff --git a/test/elixir_funcs.sh b/test/elixir_funcs.sh new file mode 100755 index 0000000..83b9142 --- /dev/null +++ b/test/elixir_funcs.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +source $SCRIPT_DIR/.test_support.sh + +# include source file +source $SCRIPT_DIR/../lib/elixir_funcs.sh + + +# TESTS +###################### +suite "otp_version" + + test "extracts major version from full version" + + result=$(otp_version "26.2.1") + + [ "$result" == "26" ] + + + test "extracts major version from major.minor" + + result=$(otp_version "25.0") + + [ "$result" == "25" ] + + + test "extracts major version from major only" + + result=$(otp_version "27") + + [ "$result" == "27" ] + + + test "handles OTP 24" + + result=$(otp_version "24.3.4") + + [ "$result" == "24" ] + + +suite "elixir_download_file" + + test "generates correct download filename" + + erlang_version="26.2.1" + elixir_version="v1.16.2" + result=$(elixir_download_file) + + [ "$result" == "elixir-v1.16.2-otp-26.zip" ] + + + test "generates filename for different versions" + + erlang_version="25.0" + elixir_version="v1.14.5" + result=$(elixir_download_file) + + [ "$result" == "elixir-v1.14.5-otp-25.zip" ] + + +PASSED_ALL_TESTS=true From 1ab211694b2b1f1bcc1304ffb09b3a195d53881d Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 12 Mar 2026 07:43:31 -0500 Subject: [PATCH 5/7] test(misc_funcs): add tests for untested helpers Cover export_mix_env (default, env file, preserve), export_env_vars (export, blacklist, missing dir), check_stack (cedar reject, write file, change), and clean_cache (skip vs force rebuild). --- test/misc_funcs.sh | 153 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100755 test/misc_funcs.sh diff --git a/test/misc_funcs.sh b/test/misc_funcs.sh new file mode 100755 index 0000000..ec311ac --- /dev/null +++ b/test/misc_funcs.sh @@ -0,0 +1,153 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +source $SCRIPT_DIR/.test_support.sh + +# include source files +source $SCRIPT_DIR/../lib/path_funcs.sh +source $SCRIPT_DIR/../lib/misc_funcs.sh + +# override functions +reset_test() { + EXIT_CODE=0 + OUTPUT_LINES=() + unset MIX_ENV + env_path="${TEST_DIR}/env_path" + rm -rf $env_path +} + +exit() { + EXIT_CODE=$1 +} +output_line() { + OUTPUT_LINES+=("$1") +} + + +# TESTS +###################### +suite "export_mix_env" + + test "defaults to prod when no MIX_ENV set" + + export_mix_env + + [ "$MIX_ENV" == "prod" ] + + + test "uses custom default when provided" + + export_mix_env "staging" + + [ "$MIX_ENV" == "staging" ] + + + test "reads MIX_ENV from env dir" + + mkdir -p $env_path + echo -n "test" > $env_path/MIX_ENV + + export_mix_env + + [ "$MIX_ENV" == "test" ] + + + test "preserves existing MIX_ENV" + + export MIX_ENV="dev" + + export_mix_env "prod" + + [ "$MIX_ENV" == "dev" ] + unset MIX_ENV + + +suite "export_env_vars" + + test "exports vars from env dir" + + mkdir -p $env_path + echo -n "bar" > $env_path/FOO + + export_env_vars > /dev/null + + [ "$FOO" == "bar" ] + unset FOO + + + test "does not export blacklisted vars" + + mkdir -p $env_path + echo -n "/custom/path" > $env_path/PATH + + export_env_vars > /dev/null + + [ "$PATH" != "/custom/path" ] + + + test "handles missing env dir gracefully" + + env_path="${TEST_DIR}/nonexistent_env" + + export_env_vars > /dev/null + + +suite "check_stack" + + test "rejects cedar stack" + + STACK="cedar" + check_stack > /dev/null + + [ "$EXIT_CODE" == "1" ] + + + test "writes stack to cache file" + + STACK="heroku-24" + # Ensure no previous stack file + rm -f "${cache_path}/stack" + + check_stack > /dev/null + + [ "$(cat ${cache_path}/stack)" == "heroku-24" ] + + + test "detects stack change and clears cache" + + STACK="heroku-22" + echo "heroku-20" > "${cache_path}/stack" + mkdir -p $(stack_based_cache_path)/marker + + check_stack > /dev/null + + [ ! -d "$(stack_based_cache_path)/marker" ] + [ "$(cat ${cache_path}/stack)" == "heroku-22" ] + + +suite "clean_cache" + + test "does not clean stack cache when always_rebuild is false" + + always_rebuild=false + mkdir -p $(stack_based_cache_path)/test_marker + + clean_cache > /dev/null + + [ -d "$(stack_based_cache_path)/test_marker" ] + rm -rf $(stack_based_cache_path)/test_marker + + + test "cleans stack cache when always_rebuild is true" + + always_rebuild=true + mkdir -p $(stack_based_cache_path)/test_marker + + clean_cache > /dev/null + + [ ! -d "$(stack_based_cache_path)/test_marker" ] + + +PASSED_ALL_TESTS=true From b79b81e767b0c64be7d4f2566d4bff079e25acc4 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 12 Mar 2026 07:44:07 -0500 Subject: [PATCH 6/7] test(app_funcs): add tests for app helper funcs Test export_var, export_default_var, profile/export env var generation, write_profile_d_script creation, and write_export file generation. --- test/app_funcs.sh | 165 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100755 test/app_funcs.sh diff --git a/test/app_funcs.sh b/test/app_funcs.sh new file mode 100755 index 0000000..42a0d09 --- /dev/null +++ b/test/app_funcs.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +source $SCRIPT_DIR/.test_support.sh + +# include source files +source $SCRIPT_DIR/../lib/misc_funcs.sh +source $SCRIPT_DIR/../lib/path_funcs.sh +source $SCRIPT_DIR/../lib/app_funcs.sh + +# set runtime_path to a known value +runtime_path="/app" +env_path="${TEST_DIR}/env_path" +MIX_ENV="prod" + + +# TESTS +###################### +suite "export_var" + + test "outputs export statement" + + result=$(export_var "FOO" "bar") + + [ "$result" == "export FOO=bar" ] + + + test "handles path-like values" + + result=$(export_var "PATH" "/usr/bin:\$PATH") + + [ "$result" == 'export PATH=/usr/bin:$PATH' ] + + +suite "export_default_var" + + test "outputs export when env var file missing" + + rm -rf $env_path + result=$(export_default_var "LC_CTYPE" "en_US.utf8") + + [ "$result" == "export LC_CTYPE=en_US.utf8" ] + + + test "outputs nothing when env var file exists" + + mkdir -p $env_path + echo -n "C" > $env_path/LC_CTYPE + + result=$(export_default_var "LC_CTYPE" "en_US.utf8") + + [ -z "$result" ] + rm -rf $env_path + + +suite "echo_profile_env_vars" + + test "includes PATH with runtime paths" + + result=$(echo_profile_env_vars) + + echo "$result" | grep -q "export PATH=/app/.platform_tools/elixir/bin:/app/.platform_tools/erlang/bin:/app/.platform_tools:" + + + test "includes MIX_ENV" + + rm -rf $env_path + result=$(echo_profile_env_vars) + + echo "$result" | grep -q "export MIX_ENV=prod" + + + test "includes HEX_HOME" + + rm -rf $env_path + result=$(echo_profile_env_vars) + + echo "$result" | grep -q "export HEX_HOME=/app/.hex" + + + test "includes MIX_HOME" + + rm -rf $env_path + result=$(echo_profile_env_vars) + + echo "$result" | grep -q "export MIX_HOME=/app/.mix" + + +suite "echo_export_env_vars" + + test "includes PATH with build paths" + + result=$(echo_export_env_vars) + + echo "$result" | grep -q "export PATH=${build_path}/.platform_tools/elixir/bin:${build_path}/.platform_tools/erlang/bin:${build_path}/.platform_tools:" + + + test "includes build MIX_HOME" + + rm -rf $env_path + result=$(echo_export_env_vars) + + echo "$result" | grep -q "export MIX_HOME=${build_path}/.mix" + + + test "includes build HEX_HOME" + + rm -rf $env_path + result=$(echo_export_env_vars) + + echo "$result" | grep -q "export HEX_HOME=${build_path}/.hex" + + +suite "write_profile_d_script" + + test "creates .profile.d directory" + + write_profile_d_script > /dev/null + + [ -d "$build_path/.profile.d" ] + + + test "creates profile script file" + + write_profile_d_script > /dev/null + + [ -f "$build_path/.profile.d/elixir_buildpack_paths.sh" ] + + + test "profile script contains PATH export" + + # Clean up from previous test runs + rm -rf $build_path/.profile.d + + write_profile_d_script > /dev/null + + grep -q "export PATH=" $build_path/.profile.d/elixir_buildpack_paths.sh + + +suite "write_export" + + test "creates export file" + + rm -f "${build_pack_path}/export" + + write_export > /dev/null + + [ -f "${build_pack_path}/export" ] + + + test "export file contains PATH" + + rm -f "${build_pack_path}/export" + + write_export > /dev/null + + grep -q "export PATH=" "${build_pack_path}/export" + + # Clean up + rm -f "${build_pack_path}/export" + + +PASSED_ALL_TESTS=true From a76a77bee5a3ea6b1b3adfa09e0ce8d58e9b50e2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 12 Mar 2026 07:44:22 -0500 Subject: [PATCH 7/7] test(release): add tests for bin/release output Verify bin/release outputs correct YAML format with document separator, empty addons list, and default web process type (mix run --no-halt). --- test/release.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100755 test/release.sh diff --git a/test/release.sh b/test/release.sh new file mode 100755 index 0000000..007bc01 --- /dev/null +++ b/test/release.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +set -e -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +source $SCRIPT_DIR/.test_support.sh + + +# TESTS +###################### +suite "bin/release" + + test "outputs valid YAML format" + + output=$($SCRIPT_DIR/../bin/release) + + echo "$output" | grep -q "^---" + + + test "contains empty addons list" + + output=$($SCRIPT_DIR/../bin/release) + + echo "$output" | grep -q "addons:" + echo "$output" | grep -q "\[\]" + + + test "sets default web process type" + + output=$($SCRIPT_DIR/../bin/release) + + echo "$output" | grep -q "web: mix run --no-halt" + + + test "contains default_process_types key" + + output=$($SCRIPT_DIR/../bin/release) + + echo "$output" | grep -q "default_process_types:" + + +PASSED_ALL_TESTS=true