diff --git a/linux/scripts/test/deb-packaging.tests.sh b/linux/scripts/test/deb-packaging.tests.sh index 134421e0a43..8da8fd8ec8d 100755 --- a/linux/scripts/test/deb-packaging.tests.sh +++ b/linux/scripts/test/deb-packaging.tests.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -eu ## START STANDARD BUILD SCRIPT INCLUDE @@ -7,93 +7,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" . "${THIS_SCRIPT%/*}/../../../resources/build/build-utils.sh" ## END STANDARD BUILD SCRIPT INCLUDE -mockDebPkgTools() { - echo "#!/bin/bash - " > "${tmpDir}/dpkg" - chmod +x "${tmpDir}/dpkg" - cp "${tmpDir}/dpkg" "${tmpDir}/dpkg-gensymbols" - PATH=${tmpDir}:${PATH} -} - -createBase() { - TIER=$1 - remoteDir=$(mktemp -d) - cd "${remoteDir}" - git init --bare --initial-branch=master . - - workDir=$(mktemp -d) - cd "${workDir}" - git init --initial-branch=master . - git remote add origin "${remoteDir}" - mkdir -p linux/debian - echo "libkeymancore.so.1 libkeymancore1 #MINVER# -* Build-Depends-Package: libkeymancore-dev - - km_core_actions_dispose@Base 17.0.197 - km_core_context_clear@Base 17.0.195 - km_core_context_get@Base 17.0.195 - km_core_context_item_list_size@Base 17.0.195 - km_core_context_items_dispose@Base 17.0.195 -" > linux/debian/libkeymancore1.symbols - git add linux/debian/libkeymancore1.symbols - - mkdir -p core - echo "1.0.0" > core/CORE_API_VERSION.md - git add core/CORE_API_VERSION.md - - echo "16.0.145" > VERSION.md - git add VERSION.md - - echo "stable" > TIER.md - git add TIER.md - - mkdir -p linux/scripts - cp -r "${REPO_ROOT}"/linux/scripts/* linux/scripts - git add linux/scripts - - mkdir -p resources/build - cp -r "${REPO_ROOT}"/resources/build/* resources/build - cp "${REPO_ROOT}"/resources/builder.inc.sh resources/ - git add resources - - git commit -m "Initial" - git push origin master - - git branch -c stable-16.0 - git push origin stable-16.0 - git tag -m "16.0.145" release-16.0.145 - git push origin release-16.0.145 - - echo "${TIER}" > TIER.md - git add TIER.md - - echo "17.0.255" > VERSION.md - git add VERSION.md - git commit -m "Commit for Alpha" - git push origin master - - git checkout -b chore - - BINPKG_NAME=${tmpDir}/libkeymancore1_17.0.257-1+noble1_amd64.deb - touch "${BINPKG_NAME}" -} - -setup() { - OLDPATH=${PATH} - tmpDir=$(mktemp -d) - mockDebPkgTools -} - -teardown() { - PATH=${OLDPATH} - rm -rf ${tmpDir} -} - -run_test() { - setup - $1 > /tmp/$1.log 2>&1 && echo -e "${COLOR_GREEN}$1: OK${COLOR_RESET}" || echo -e "${COLOR_RED}$1: FAILED${COLOR_RESET}" - teardown -} +. "${THIS_SCRIPT%/*}/test.inc.sh" test_check_updated_version_number__NoChange_OK() { createBase alpha @@ -120,6 +34,7 @@ test_check_updated_version_number__LineAdded_OK() { } test_check_updated_version_number__LineAddedWithoutVerUpd_ERROR() { + local output createBase alpha sed -i 's/ km_core_actions_dispose@Base 17.0.197/ km_core_actions_dispose@Base 17.0.197\n km_core_added@Base 17.0.197/' linux/debian/libkeymancore1.symbols @@ -150,6 +65,7 @@ test_check_updated_version_number__LineRemovedWithAPIUpd_OK() { } test_check_updated_version_number__LineRemoved_OnlyCoreApiUpd_ERROR() { + local output createBase alpha echo "2.0.0" > core/CORE_API_VERSION.md git add core/CORE_API_VERSION.md @@ -165,6 +81,7 @@ test_check_updated_version_number__LineRemoved_OnlyCoreApiUpd_ERROR() { } test_check_updated_version_number__LineRemoved_OnlySymbolsFileUpd_ERROR() { + local output createBase alpha git mv linux/debian/libkeymancore{1,2}.symbols sed -i 's/libkeymancore1/libkeymancore2/' linux/debian/libkeymancore2.symbols @@ -181,6 +98,7 @@ test_check_updated_version_number__LineRemoved_OnlySymbolsFileUpd_ERROR() { } test_check_updated_version_number__LineRemovedWithAPIUpd_NotMetadataUpd_ERROR() { + local output createBase alpha echo "2.0.0" > core/CORE_API_VERSION.md git add core/CORE_API_VERSION.md @@ -247,6 +165,7 @@ test_check_updated_version_number__LineRemoved_InAlpha_FileMissingInStable_ApiVe } test_check_updated_version_number__LineRemoved_InAlpha_FileMissingInStable_ApiVerUnchanged_ERROR() { + local output createBase alpha git checkout master # simulate a commit that renamed the .symbols file @@ -271,6 +190,7 @@ test_check_updated_version_number__LineRemoved_InAlpha_FileMissingInStable_ApiVe } test_check_updated_version_number__LineRemoved_InAlpha_ChangeFromStable_ERROR() { + local output createBase alpha sed -i '6d' linux/debian/libkeymancore1.symbols @@ -285,6 +205,7 @@ test_check_updated_version_number__LineRemoved_InAlpha_ChangeFromStable_ERROR() } test_check_updated_version_number__LineRemoved_InBeta_ApiVerUnchanged_ERROR() { + local output createBase beta # simulate a commit that already introduced an API version change in Beta @@ -340,6 +261,7 @@ test_check_updated_version_number__LineRemoved_InBeta_ApiVerChanged_OK() { } test_check_updated_version_number__LineRemoved_InBeta_FileMissingInStable_ApiVerUnchanged_ERROR() { + local output createBase alpha git checkout -b beta # simulate a commit that renamed the .symbols file @@ -363,6 +285,34 @@ test_check_updated_version_number__LineRemoved_InBeta_FileMissingInStable_ApiVer [[ "${output[*]}" == *" ERROR: Major API change without updating API version number in libfoo1.symbols file"* ]] } +test_check_updated_version_number__LineInsertedInBranch_OK() { + createBase alpha + + local base_sha=$(git rev-parse master) + + # Add a line in chore branch + echo " km_core_foo@Base 17.0.200" >> linux/debian/libkeymancore1.symbols + git add linux/debian/libkeymancore1.symbols + git commit -m "API method added in chore branch" + + # Add a line in master branch + git checkout master + echo " km_core_foo@Base 17.0.205" >> linux/debian/libkeymancore1.symbols + git add linux/debian/libkeymancore1.symbols + git commit -m "API method changed in master branch" + echo "readme" > README.md + git add README.md + git commit -m "Some change on master" + git checkout chore + + # merge master into chore + git merge --strategy-option=ours master + + echo "## Calling API verification" + pwd + linux/scripts/deb-packaging.sh --bin-pkg "${BINPKG_NAME}" --git-sha "$(git rev-parse HEAD)" --git-base "${base_sha}" verify +} + echo "(test logs are in /tmp/.log)" run_test test_check_updated_version_number__NoChange_OK run_test test_check_updated_version_number__LineAdded_OK @@ -378,5 +328,6 @@ run_test test_check_updated_version_number__LineRemoved_InAlpha_ChangeFromStable run_test test_check_updated_version_number__LineRemoved_InBeta_ApiVerUnchanged_ERROR run_test test_check_updated_version_number__LineRemoved_InBeta_ApiVerChanged_OK run_test test_check_updated_version_number__LineRemoved_InBeta_FileMissingInStable_ApiVerUnchanged_ERROR +run_test test_check_updated_version_number__LineInsertedInBranch_OK # TODO: still some test cases missing for the different checks diff --git a/linux/scripts/test/test.inc.sh b/linux/scripts/test/test.inc.sh new file mode 100644 index 00000000000..6e21ef2b5d9 --- /dev/null +++ b/linux/scripts/test/test.inc.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash + +setup() { + OLDPATH=${PATH} + tmpDir="$(mktemp -d)" + mockDebPkgTools +} + +teardown() { + PATH=${OLDPATH} + rm -rf "${tmpDir}" +} + +mockDebPkgTools() { + echo "#!/bin/bash + " > "${tmpDir}/dpkg" + chmod +x "${tmpDir}/dpkg" + cp "${tmpDir}/dpkg" "${tmpDir}/dpkg-gensymbols" + PATH=${tmpDir}:${PATH} +} + +createBase() { + TIER=$1 + remoteDir=$(mktemp -d) + cd "${remoteDir}" + git init --bare --initial-branch=master . + + workDir=$(mktemp -d) + cd "${workDir}" + git init --initial-branch=master . + git remote add origin "${remoteDir}" + mkdir -p linux/debian + echo "libkeymancore.so.1 libkeymancore1 #MINVER# +* Build-Depends-Package: libkeymancore-dev + + km_core_actions_dispose@Base 17.0.197 + km_core_context_clear@Base 17.0.195 + km_core_context_get@Base 17.0.198 + km_core_context_item_list_size@Base 17.0.195 + km_core_context_items_dispose@Base 17.0.195 +" > linux/debian/libkeymancore1.symbols + git add linux/debian/libkeymancore1.symbols + + mkdir -p core + echo "1.0.0" > core/CORE_API_VERSION.md + git add core/CORE_API_VERSION.md + + echo "16.0.145" > VERSION.md + git add VERSION.md + + echo "stable" > TIER.md + git add TIER.md + + mkdir -p linux/scripts + cp -r "${REPO_ROOT}"/linux/scripts/* linux/scripts + git add linux/scripts + + mkdir -p resources/build + cp -r "${REPO_ROOT}"/resources/build/* resources/build + cp "${REPO_ROOT}"/resources/builder.inc.sh resources/ + git add resources + + git commit -m "Initial" + git push origin master + + git branch -c stable-16.0 + git push origin stable-16.0 + git tag -m "16.0.145" release-16.0.145 + git push origin release-16.0.145 + + echo "${TIER}" > TIER.md + git add TIER.md + + echo "17.0.255" > VERSION.md + git add VERSION.md + git commit -m "Commit for Alpha" + git push origin master + + git checkout -b chore + + BINPKG_NAME=${tmpDir}/libkeymancore1_17.0.257-1+noble1_amd64.deb + touch "${BINPKG_NAME}" +} + +run_test() { + setup + $1 > "/tmp/$1.log" 2>&1 && echo -e "${COLOR_GREEN}$1: OK${COLOR_RESET}" || echo -e "${COLOR_RED}$1: FAILED${COLOR_RESET}" + teardown +} diff --git a/linux/scripts/test/test.sh b/linux/scripts/test/test.sh new file mode 100755 index 00000000000..f0a56655d58 --- /dev/null +++ b/linux/scripts/test/test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -eu + +"$(dirname "$0")/deb-packaging.tests.sh" +"$(dirname "$0")/verify_api.tests.sh" diff --git a/linux/scripts/test/verify_api.tests.sh b/linux/scripts/test/verify_api.tests.sh new file mode 100755 index 00000000000..05f60cea836 --- /dev/null +++ b/linux/scripts/test/verify_api.tests.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# Unit tests for verify_api.inc.sh +set -eu +shopt -s inherit_errexit + +## START STANDARD BUILD SCRIPT INCLUDE +# adjust relative paths as necessary +THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")" +. "${THIS_SCRIPT%/*}/../../../resources/build/build-utils.sh" +## END STANDARD BUILD SCRIPT INCLUDE + +. "${THIS_SCRIPT%/*}/test.inc.sh" +. "${KEYMAN_ROOT}/linux/scripts/verify_api.inc.sh" + + +fixture_setup() { + SONAME=1 + LIB_NAME=libkeymancore + PKG_NAME="${LIB_NAME}${SONAME}" + EXIT_CODE=-1 +} + +test_compare_versions__less_patch() { + [[ $(compare_versions "17.0.197" "17.0.198") == -1 ]] +} + +test_compare_versions__less_minor() { + [[ $(compare_versions "17.0.197" "17.1.197") == -1 ]] +} + +test_compare_versions__less_major() { + [[ $(compare_versions "17.0.197" "18.0.0") == -1 ]] +} + +test_compare_versions__greater() { + [[ $(compare_versions "17.0.198" "17.0.197") == 1 ]] +} + +test_compare_versions__same() { + [[ $(compare_versions "17.0.197" "17.0.197") == 0 ]] +} + +test_compare_versions__greater0() { + [[ $(compare_versions "17.0.197" "0") == 1 ]] +} + +test_get_highest_version_in_symbols_file() { + local output + createBase alpha + echo ' (c++|optional)"typeinfo name for std::codecvt@Base" 17.0.244' >> linux/debian/libkeymancore1.symbols + git add linux/debian/libkeymancore1.symbols + git commit -m "API method added" + + # Execute + output=$(get_highest_version_in_symbols_file "$(git rev-parse HEAD)") + echo "${output[*]}" # for logging + [[ "${output}" == "17.0.244" ]] +} + +test_check_updated_version_number__LineInsertedInBranch_OK() { + local output + createBase alpha + + local base_sha=$(git rev-parse master) + + # Add a line in chore branch + sed -i 's/km_core_actions_dispose@Base 17.0.197/km_core_actions_dispose@Base 17.0.201/' linux/debian/libkeymancore1.symbols + echo " km_core_foo@Base 17.0.200" >> linux/debian/libkeymancore1.symbols + git add linux/debian/libkeymancore1.symbols + git commit -m "API method added in chore branch" + + # Add a line in master branch + git checkout master + sed -i 's/km_core_actions_dispose@Base 17.0.197/km_core_actions_dispose@Base 17.0.199/' linux/debian/libkeymancore1.symbols + git add linux/debian/libkeymancore1.symbols + git commit -m "API method changed in master branch" + echo "readme" > README.md + git add README.md + git commit -m "Some change on master" + git checkout chore + + # merge master into chore + git merge --strategy-option=ours master + + echo "## Calling API verification" + pwd + GIT_SHA="$(git rev-parse HEAD)" + GIT_BASE="${base_sha}" + + output=$(check_updated_version_number) + echo "${output[*]}" # for logging + [[ "${output[*]}" == *"OK: libkeymancore1.symbols file got updated with package version number"* ]] +} + + +fixture_setup +echo "(test logs are in /tmp/.log)" +run_test test_compare_versions__less_patch +run_test test_compare_versions__less_minor +run_test test_compare_versions__less_major +run_test test_compare_versions__greater +run_test test_compare_versions__same +run_test test_compare_versions__greater0 +run_test test_get_highest_version_in_symbols_file +run_test test_check_updated_version_number__LineInsertedInBranch_OK diff --git a/linux/scripts/verify_api.inc.sh b/linux/scripts/verify_api.inc.sh index 63072bc4f7c..adaa9187c27 100644 --- a/linux/scripts/verify_api.inc.sh +++ b/linux/scripts/verify_api.inc.sh @@ -79,17 +79,70 @@ check_updated_version_number() { # If only lines got removed we basically skip this test. A later check will # test that the API version got updated. output_ok "${PKG_NAME}.symbols file did change but only removed lines" - elif ! git log -p -1 -- "debian/${PKG_NAME}.symbols" | grep -q "${VERSION}"; then - output_error "${PKG_NAME}.symbols file got changed without changing the package version number of the symbol" - EXIT_CODE=1 else - output_ok "${PKG_NAME}.symbols file got updated with package version number" + local version_base version_head + version_head=$(get_highest_version_in_symbols_file "${GIT_SHA}") + version_base=$(get_highest_version_in_symbols_file "${GIT_BASE}") + if (( $(compare_versions "${version_head}" "${version_base}") > 0 )); then + output_ok "${PKG_NAME}.symbols file got updated with package version number" + else + output_error "${PKG_NAME}.symbols file got changed without changing the package version number of the symbol" + EXIT_CODE=1 + fi fi else output_ok "${PKG_NAME}.symbols file didn't change" fi } +compare_versions() { + local first_parts second_parts + IFS='.' read -r -a first_parts <<< "$1" + IFS='.' read -r -a second_parts <<< "$2" + if (( first_parts[0] < second_parts[0] )); then + echo -1 + elif (( first_parts[0] > second_parts[0] )); then + echo 1 + elif (( first_parts[1] < second_parts[1] )); then + echo -1 + elif (( first_parts[1] > second_parts[1] )); then + echo 1 + elif (( first_parts[2] < second_parts[2] )); then + echo -1 + elif (( first_parts[2] > second_parts[2] )); then + echo 1 + else + echo 0 + fi +} + +get_highest_version_in_symbols_file() { + local sha="$1" + local symbol_lines line line_version + local max_version=0 + + tmpfile=$(mktemp) + if ! git cat-file blob "${sha}:linux/debian/${PKG_NAME}.symbols" > "${tmpfile}" 2>/dev/null; then + rm "${tmpfile}" + return 1 + fi + + # Start with fourth line which is where symbols start + mapfile -s 3 symbol_lines < "${tmpfile}" + for line in "${symbol_lines[@]}"; do + # km_core_actions_dispose@Base 17.0.197 + line_version=${line##* } + if (( $(compare_versions "${line_version}" "${max_version}") > 0 )); then + max_version="${line_version}" + fi + done + + echo "${max_version}" + + rm "${tmpfile}" + return 0 +} + get_api_version_in_symbols_file() { # Retrieve symbols file at commit $1 and extract "1" from # "libkeymancore.so.1 libkeymancore1 #MINVER#"