diff --git a/.github/documentation/tests.md b/.github/documentation/tests.md new file mode 100644 index 000000000..e59bf7966 --- /dev/null +++ b/.github/documentation/tests.md @@ -0,0 +1,26 @@ +# Tests + +## Table of Contents +- [Description](#description) +- [Jobs](#jobs) +- [Credentials](#credentials) + +### Description +This workflow is triggered when a pull request is opened on the HyperBEAM main branch. Or manually via the Github Actions UI. It is responsible for installing and running the HyperBEAM rebar3 eunit tests. + +### Jobs + +The workflow consists of 1 main job: + +1. **test**: + - Utilizes actions/checkout@v4 and erlef/setup-beam@v1 to create the Erlang ready environment in the github test runner. + - Iterates over each erlang module in Hyperbeam, running `rebar3 eunit --module modulename` on each, aggregating the results and successes. + - Generates and sends a Slack message if any tests failed, containing number of successes, and each module that failed. + +### Credentials + +There are 2 credentials used by this action, both stored in Github secrets. Settings -> Secrets and variables -> Actions. + +`SLACK_BOT_TOKEN` and `SLACK_CHANNEL_ID` + +Generate the token in Slack, and grab the channel ID you want to send to, add those to the action secrets in Github, and the action will work. \ No newline at end of file diff --git a/.github/documentation/workflows.md b/.github/documentation/workflows.md index 5cc269091..3d962d34b 100644 --- a/.github/documentation/workflows.md +++ b/.github/documentation/workflows.md @@ -6,3 +6,4 @@ These workflows are GitHub Actions workflows that are used for a variety of CI/C ## Table of Contents - [CD](cd.md) +- [Tests](tests.md) \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..ccca4193c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,109 @@ +name: Run hb tests + +on: + workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + +jobs: + test: + runs-on: ubuntu-22.04 + name: Install Deps and Run Tests + strategy: + matrix: + otp: ['27.3.3'] + rebar3: ['3.24.0'] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Erlang & rebar3 + uses: erlef/setup-beam@v1 + with: + otp-version: ${{ matrix.otp }} + rebar3-version: ${{ matrix.rebar3 }} + + - id: run_eunit + name: Run EUnit + shell: bash + run: | + set +e + + failed=() + passed=0 + + for file in $(find src -type f -name '*.erl'); do + module=$(basename "$file" .erl) + echo "=== Testing module: $module ===" + + # Capture output & exit code + output=$(rebar3 eunit --module $module 2>&1) + ret=$? + echo "$output" + + # 1) Look for a summary line: “Failed: X. Skipped: Y. Passed: Z.” + pattern='Failed: [0-9]+\.\s*Skipped: [0-9]+\.\s*Passed: [0-9]+\.' + if summary=$( + grep -E "$pattern" <<< "$output" + ); then + n=$(echo "$summary" | sed -n 's/.*Passed: \([0-9]\+\)\..*/\1/p') + # 2) Or if it's all-pass: “All N tests passed.” + elif echo "$output" | grep -qE 'All [0-9]+ tests passed\.'; then + n=$(echo "$output" | grep -oE 'All [0-9]+' | head -1 | awk '{print $2}') + # 3) Fallback: count lines ending in “ok” + else + n=$(echo "$output" | grep -cE '\.\.\.(\[[0-9. ]+ s\] )?ok$') + fi + + passed=$((passed + n)) + + if [ $ret -ne 0 ]; then + failed+=("$module") + fi + done + + # Export for downstream steps + echo "failed=${failed[*]}" >> $GITHUB_OUTPUT + echo "passed=${passed}" >> $GITHUB_OUTPUT + + # Print a summary in the log + echo + echo "✅ Total passed tests: $passed" + if [ ${#failed[@]} -gt 0 ]; then + echo + echo "❌ Failed modules: ${failed[*]}" + exit 1 + fi + + + - name: Notify Slack on Failure + if: failure() + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_TITLE: ${{ github.event.pull_request.title }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + FAILED_LIST: ${{ steps.run_eunit.outputs.failed }} + PASSED_COUNT: ${{ steps.run_eunit.outputs.passed }} + run: | + if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then + TEXT="HyperBEAM tests failed on PR #${PR_NUMBER} ${PR_TITLE}. " + else + TEXT="HyperBEAM tests failed on main. " + fi + + # append without spaces around = + TEXT="$TEXT❌ Failed modules: ${FAILED_LIST}. ✅ ${PASSED_COUNT} passed." + + curl -X POST https://slack.com/api/chat.postMessage \ + -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ + -d "channel=$SLACK_CHANNEL_ID" \ + -d "text=${TEXT} <${RUN_URL}|View test output>" + + + +