From 05d60ab0780de5a16036bfe57a60333266864efd Mon Sep 17 00:00:00 2001 From: Jack Green Date: Tue, 5 Nov 2024 12:43:36 +0000 Subject: [PATCH 1/2] Test JDK version as part of PR builder [DI-317] (#816) Adds additional assertion to the PR builder smoke test that the JDK is the version expected for the image. This is currently a _manual, post release_ check, moving earlier in the cycle to catch defects earlier. Fixes: [DI-317](https://hazelcast.atlassian.net/browse/DI-317) Post merge actions: - [ ] backport - [ ] _Discuss_ if we remove the manual, post-release check? [DI-317]: https://hazelcast.atlassian.net/browse/DI-317?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- .github/scripts/simple-smoke-test.sh | 53 ++++++++++++++----- .github/workflows/build-pr.yml | 12 +++-- .github/workflows/ee-nlc-snapshot-push.yml | 2 +- .github/workflows/ee-nlc-tag-push.yml | 2 +- .github/workflows/ee_latest_snapshot_push.yml | 2 +- .../workflows/oss_latest_snapshot_push.yml | 2 +- .github/workflows/tag_image_push.yml | 4 +- 7 files changed, 53 insertions(+), 24 deletions(-) diff --git a/.github/scripts/simple-smoke-test.sh b/.github/scripts/simple-smoke-test.sh index 73c9a5ce..4cfa0a2d 100755 --- a/.github/scripts/simple-smoke-test.sh +++ b/.github/scripts/simple-smoke-test.sh @@ -88,21 +88,48 @@ function test_map_read_write() { fi } -function install_clc() { - while ! curl https://hazelcast.com/clc/install.sh | bash - do - echo "Retrying clc installation..." - sleep 3 - done - export PATH=${PATH}:${HOME}/.hazelcast/bin - clc config add default cluster.name=dev cluster.address=localhost +function check_java_version() { + local expected_major_version=$1 + local actual_major_version + actual_major_version=$(docker run --rm "${image}" sh -c 'java -version 2>&1 | head -n 1 | awk -F "\"" "{print \$2}" | awk -F "." "{print \$1}"') + + if [[ "${expected_major_version}" == "${actual_major_version}" ]]; then + echo "Expected Java version (${expected_distribution_type}) identified." + else + echoerr "Expected Java version '${expected_major_version}' but got '${actual_major_version}'" + exit 1; + fi } -# Prints the given message to stderr -function echoerr() { - echo "ERROR - $*" 1>&2; +function derive_expected_distribution_type() { + local input_distribution_type=$1 + + case "${input_distribution_type}" in + "oss") + echo "Hazelcast Platform" + ;; + "ee") + echo "Hazelcast Enterprise" + ;; + *) + echoerr "Unrecognized distribution type ${input_distribution_type}" + exit 1 + ;; + esac } +image=$1 +container_name=$2 +input_distribution_type=$3 +expected_version=$4 +expected_java_major_version=$5 + + +remove_container_if_exists +start_container + +trap stop_container EXIT -install_clc -test_docker_image "$@" +expected_distribution_type=$(derive_expected_distribution_type "${input_distribution_type}") +test_package "${expected_distribution_type}" "${expected_version}" +check_java_version "${expected_java_major_version}" diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 67bc5815..64289444 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -85,8 +85,9 @@ jobs: - name: Run smoke test against OSS image timeout-minutes: 2 - run: | - .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${{ needs.prepare.outputs.HZ_VERSION_OSS }} + run: | + . .github/scripts/docker.functions.sh + .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${{ needs.prepare.outputs.HZ_VERSION_OSS }} "$(get_default_jdk hazelcast-oss)" - name: Build Test EE image run: | @@ -102,8 +103,9 @@ jobs: - name: Run smoke test against EE image timeout-minutes: 2 run: | + . .github/scripts/docker.functions.sh export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} - .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${{ needs.prepare.outputs.HZ_VERSION_EE }} + .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${{ needs.prepare.outputs.HZ_VERSION_EE }} "$(get_default_jdk hazelcast-enterprise)" - name: Get docker logs if: ${{ always() }} @@ -162,7 +164,7 @@ jobs: - name: Run smoke test against OSS image timeout-minutes: 2 run: | - .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${{ needs.prepare.outputs.HZ_VERSION_OSS }} + .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${{ needs.prepare.outputs.HZ_VERSION_OSS }} ${{ matrix.jdk }} - name: Build Test EE image run: | @@ -180,7 +182,7 @@ jobs: timeout-minutes: 2 run: | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} - .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${{ needs.prepare.outputs.HZ_VERSION_EE }} + .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${{ needs.prepare.outputs.HZ_VERSION_EE }} ${{ matrix.jdk }} - name: Get docker logs if: ${{ always() }} diff --git a/.github/workflows/ee-nlc-snapshot-push.yml b/.github/workflows/ee-nlc-snapshot-push.yml index d4357af2..8942938d 100644 --- a/.github/workflows/ee-nlc-snapshot-push.yml +++ b/.github/workflows/ee-nlc-snapshot-push.yml @@ -73,7 +73,7 @@ jobs: timeout-minutes: 2 run: | export HZ_INSTANCETRACKING_FILENAME=instance-tracking.txt - .github/scripts/simple-smoke-test.sh hazelcast-nlc:test ${{ env.test_container_name_ee }} ee ${HZ_VERSION} + .github/scripts/simple-smoke-test.sh hazelcast-nlc:test ${{ env.test_container_name_ee }} ee ${HZ_VERSION} ${{ matrix.jdk }} - name: Get docker logs if: ${{ always() }} diff --git a/.github/workflows/ee-nlc-tag-push.yml b/.github/workflows/ee-nlc-tag-push.yml index 147c6591..7f16c5b8 100644 --- a/.github/workflows/ee-nlc-tag-push.yml +++ b/.github/workflows/ee-nlc-tag-push.yml @@ -87,7 +87,7 @@ jobs: timeout-minutes: 2 run: | export HZ_INSTANCETRACKING_FILENAME=instance-tracking.txt - .github/scripts/simple-smoke-test.sh hazelcast-nlc:test ${{ env.test_container_name_ee }} ee ${HZ_VERSION} + .github/scripts/simple-smoke-test.sh hazelcast-nlc:test ${{ env.test_container_name_ee }} ee ${HZ_VERSION} ${{ matrix.jdk }} - name: Get docker logs if: ${{ always() }} diff --git a/.github/workflows/ee_latest_snapshot_push.yml b/.github/workflows/ee_latest_snapshot_push.yml index 63ffb3ed..393d3159 100644 --- a/.github/workflows/ee_latest_snapshot_push.yml +++ b/.github/workflows/ee_latest_snapshot_push.yml @@ -75,7 +75,7 @@ jobs: timeout-minutes: 2 run: | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} - .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${HZ_VERSION} + .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${HZ_VERSION} ${{ matrix.jdk }} - name: Get docker logs if: ${{ always() }} diff --git a/.github/workflows/oss_latest_snapshot_push.yml b/.github/workflows/oss_latest_snapshot_push.yml index f79cddf7..befa48ba 100644 --- a/.github/workflows/oss_latest_snapshot_push.yml +++ b/.github/workflows/oss_latest_snapshot_push.yml @@ -83,7 +83,7 @@ jobs: - name: Run smoke test against OSS image timeout-minutes: 2 run: | - .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${HZ_VERSION} + .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${HZ_VERSION} ${{ matrix.jdk }} - name: Get docker logs if: ${{ always() }} diff --git a/.github/workflows/tag_image_push.yml b/.github/workflows/tag_image_push.yml index 368c0895..99cba73e 100644 --- a/.github/workflows/tag_image_push.yml +++ b/.github/workflows/tag_image_push.yml @@ -147,7 +147,7 @@ jobs: if: needs.prepare.outputs.should_build_oss == 'yes' timeout-minutes: 2 run: | - .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${{ env.HZ_VERSION }} + .github/scripts/simple-smoke-test.sh hazelcast-oss:test ${{ env.test_container_name_oss }} oss ${{ env.HZ_VERSION }} ${{ matrix.jdk }} - name: Get EE dist ZIP URL run: | @@ -170,7 +170,7 @@ jobs: timeout-minutes: 2 run: | export HZ_LICENSEKEY=${{ secrets.HZ_ENTERPRISE_LICENSE }} - .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${{ env.HZ_VERSION }} + .github/scripts/simple-smoke-test.sh hazelcast-ee:test ${{ env.test_container_name_ee }} ee ${{ env.HZ_VERSION }} ${{ matrix.jdk }} - name: Get docker logs if: ${{ always() }} From a4826affa357dfbc1e27caa8b561126a4486f807 Mon Sep 17 00:00:00 2001 From: Jack Green Date: Thu, 1 Aug 2024 12:13:57 +0100 Subject: [PATCH 2/2] Split `simple-smoke-test.sh` to be used elsewhere [DI-215] (#790) `simple-smoke-test.sh` is a useful suite of tests to validate a packaged Hazelcast instance - but is Docker-centric. - Refactored to split the script into two halves: - `abstract-simple-smoke-test` that tests against an abstract Hazelcast instance - `simple-smoke-test` a Docker-specific implementation - Refactored the metadata checks to search the instance's logs for the variant and version (i.e. OSS/EE, `5.5.0` etc) rather than inspecting the containers' filesystem - an existing test elsewhere in the codebase already does this so we already have some dependency on keeping the output consistent, although I can't currently find the test in question - Added extra coverage from [`hazelcast-packaging`'s `check-hazelcast-health.sh`](https://github.com/hazelcast/hazelcast-packaging/blob/bd417d0604b57ae2f72234d8781929fdf86b0687/check-hazelcast-health.sh) Required for [DI-215](https://hazelcast.atlassian.net/browse/DI-215) [DI-215]: https://hazelcast.atlassian.net/browse/DI-215?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- .github/scripts/abstract-simple-smoke-test.sh | 87 ++++++++++++++++++ .github/scripts/simple-smoke-test.sh | 92 ++----------------- 2 files changed, 96 insertions(+), 83 deletions(-) create mode 100755 .github/scripts/abstract-simple-smoke-test.sh diff --git a/.github/scripts/abstract-simple-smoke-test.sh b/.github/scripts/abstract-simple-smoke-test.sh new file mode 100755 index 00000000..0765e9d4 --- /dev/null +++ b/.github/scripts/abstract-simple-smoke-test.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o pipefail + +# Performs simple validation tests on an already-running Hazelcast instance +# Abstract as could be from Docker, Homebrew, local binary etc +# Because abstract, expects callers to implement required, but absent functions +function test_package() { + local expected_distribution_type=$1 + local expected_version=$2 + + test_health + test_map_read_write + + # Deliberately last step as it doesn't block-and-wait until the instance is initialized + # Otherwise would have false positives if instance still starting and logs empty + check_metadata "${expected_distribution_type}" "${expected_version}" +} + +# Search logs for entries _like_: +# Hazelcast Platform 5.5.0 (20240725) starting at [172.17.0.2]:5701 +# To validate the version and distribution is correct +function check_metadata() { + local expected_distribution_type=$1 + local expected_version=$2 + + logs=$(get_hz_logs) + + if [[ -z "${logs}" ]]; then + echoerr "Failed to read logs" + exit 1; + fi + + if grep -q "${expected_distribution_type} ${expected_version}" <<< "${logs}"; then + echo "Expected contents (${expected_distribution_type}) and version (${expected_version}) identified." + else + echoerr "Failed to find ${expected_distribution_type} ${expected_version} in logs:" + echoerr "${logs}" + exit 1; + fi +} + +function test_health() { + local attempts=0 + local max_attempts=30 + until curl --silent --fail "127.0.0.1:5701/hazelcast/health/ready"; do + if [[ ${attempts} -eq ${max_attempts} ]];then + echoerr "Hazelcast not responding" + exit 1; + fi + printf '.' + attempts=$((attempts+1)) + sleep 2 + done +} + +function test_map_read_write() { + install_clc + + local key="some-key" + local expected="some-value" + echo "Putting value '${expected}' for key '${key}'" + clc --timeout 5s map set -n some-map "${key}" "${expected}" --log.path stderr + echo "Getting value for key '${key}'" + local actual + actual=$(clc map get --format delimited -n some-map "${key}" --log.path stderr) + + if [[ "${expected}" != "${actual}" ]]; then + echoerr "Expected to read '${expected}' but got '${actual}'" + exit 1; + fi +} + +function install_clc() { + while ! curl https://hazelcast.com/clc/install.sh | bash + do + echo "Retrying clc installation..." + sleep 3 + done + export PATH=${PATH}:${HOME}/.hazelcast/bin + clc config add default cluster.name=dev cluster.address=localhost +} + +# Prints the given message to stderr +function echoerr() { + echo "ERROR - $*" 1>&2; +} diff --git a/.github/scripts/simple-smoke-test.sh b/.github/scripts/simple-smoke-test.sh index 4cfa0a2d..ca143ac0 100755 --- a/.github/scripts/simple-smoke-test.sh +++ b/.github/scripts/simple-smoke-test.sh @@ -1,24 +1,11 @@ #!/usr/bin/env bash -set -o errexit -o nounset -o pipefail +set -o errexit -function test_docker_image() { - local image=$1 - local container_name=$2 - local expected_distribution_type=$3 - local expected_version=$4 - - remove_container_if_exists "${container_name}" - - check_distribution_type "${image}" "${expected_distribution_type}" - check_image_hz_version "${image}" "${expected_version}" - - test_map_read_write "${image}" "${container_name}" -} +# shellcheck source=../.github/scripts/abstract-simple-smoke-test.sh +. .github/scripts/abstract-simple-smoke-test.sh function remove_container_if_exists() { - local container_name=$1 - local containers containers=$(docker ps --all --quiet --filter name="${container_name}") @@ -28,77 +15,18 @@ function remove_container_if_exists() { fi } -function check_distribution_type() { - local image=$1 - local expected_distribution_type=$2 - - echo "Checking ${image} distribution type" - if docker run --rm "${image}" bash -c 'compgen -G lib/*enterprise*'; then - echo "EE contents identified" - distribution_type="ee" - else - echo "No EE contents identified - assuming OSS" - distribution_type="oss" - fi - - if [[ "${distribution_type}" != "${expected_distribution_type}" ]]; then - echoerr "Image ${image} should contain ${expected_distribution_type} distribution but ${distribution_type} was detected" - exit 1 - fi +function start_container() { + echo "Starting container '${container_name}' from image '${image}'" + docker run -it --name "${container_name}" -e HZ_LICENSEKEY -e HZ_INSTANCETRACKING_FILENAME -d -p5701:5701 "${image}" } -function check_image_hz_version() { - local image=$1 - local expected_version=$2 - - echo "Checking ${image} version" - local version - version=$(docker run --rm "${image}" bin/hz-cli --version | awk '/Hazelcast/ {print $2}') - if [[ "${version}" == "${expected_version}" ]]; then - echo "${image} version identified as ${version}" - else - echoerr "${image} version was ${version}, not ${expected_version} as expected" - exit 1 - fi +function get_hz_logs() { + docker logs "${container_name}" } -function test_map_read_write() { - local image=$1 - local expected_distribution_type=$2 - - echo "Starting container '${container_name}' from image '${image}'" - docker run -it --name "${container_name}" -e HZ_LICENSEKEY -e HZ_INSTANCETRACKING_FILENAME -d -p5701:5701 "${image}" - local key="some-key" - local expected="some-value" - echo "Putting value '${expected}' for key '${key}'" - while ! clc --timeout 5s map set -n some-map "${key}" "${expected}" --log.path stderr - do - echo "Retrying..." - sleep 3 - done - echo "Getting value for key '${key}'" - local actual - actual=$(clc map get --format delimited -n some-map "${key}" --log.path stderr) +function stop_container() { echo "Stopping container ${container_name}" docker stop "${container_name}" - - if [[ "${expected}" != "${actual}" ]]; then - echoerr "Expected to read '${expected}' but got '${actual}'" - exit 1; - fi -} - -function check_java_version() { - local expected_major_version=$1 - local actual_major_version - actual_major_version=$(docker run --rm "${image}" sh -c 'java -version 2>&1 | head -n 1 | awk -F "\"" "{print \$2}" | awk -F "." "{print \$1}"') - - if [[ "${expected_major_version}" == "${actual_major_version}" ]]; then - echo "Expected Java version (${expected_distribution_type}) identified." - else - echoerr "Expected Java version '${expected_major_version}' but got '${actual_major_version}'" - exit 1; - fi } function derive_expected_distribution_type() { @@ -122,7 +50,6 @@ image=$1 container_name=$2 input_distribution_type=$3 expected_version=$4 -expected_java_major_version=$5 remove_container_if_exists @@ -132,4 +59,3 @@ trap stop_container EXIT expected_distribution_type=$(derive_expected_distribution_type "${input_distribution_type}") test_package "${expected_distribution_type}" "${expected_version}" -check_java_version "${expected_java_major_version}"