Skip to content

Layer5 Cloud Tests #310

Layer5 Cloud Tests

Layer5 Cloud Tests #310

name: Layer5 Cloud Tests
on:
workflow_call:
inputs:
pr_commit_sha:
description: "Git commit SHA to checkout for testing"
required: true
type: string
pr_number:
description: "PR number for comment updates (empty for push events)"
default: ""
required: false
type: string
run_integration_tests:
description: "Whether to run integration tests"
default: false
required: false
type: boolean
node_version:
description: "Node.js version for UI tests"
required: false
default: '20.x'
type: string
secrets:
GH_ACCESS_TOKEN:
required: true
workflow_dispatch:
inputs:
pr_commit_sha:
description: "Git commit SHA to checkout for testing"
required: true
type: string
pr_number:
description: "PR number for comment updates (leave empty for master/qa runs)"
required: false
default: ""
run_integration_tests:
description: "Whether to run integration tests"
required: false
default: false
type: boolean
node_version:
description: "Node.js version for UI tests"
required: false
default: '20.x'
type: string
jobs:
server-tests:
name: Server Tests
runs-on: ubuntu-24.04
timeout-minutes: 15
env:
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
PR_NUMBER: ${{ inputs.pr_number }}
steps:
- name: Checkout for composite action
uses: actions/checkout@v6
with:
fetch-depth: 1
sparse-checkout: |
.github/actions/cloud-comment
sparse-checkout-cone-mode: false
- name: Comment starting
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: "Starting Cloud Server tests ([takes approximately 8 min end-to-end](https://github.com/layer5labs/meshery-extensions-packages/actions/runs/${{ github.run_id }}))..."
append: false
recreate: true
#------------------------------------------
- name: Checkout Cloud code
uses: actions/checkout@v6
with:
repository: layer5io/meshery-cloud
ref: ${{ inputs.pr_number != '' && format('refs/pull/{0}/head', inputs.pr_number) || inputs.pr_commit_sha }}
token: ${{ secrets.GH_ACCESS_TOKEN }}
fetch-depth: 1
path: meshery-cloud
- name: Comment checkout success
if: success()
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":heavy_check_mark: Checked out meshery-cloud repo."
- name: Comment checkout failure
if: failure()
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":x: Failed to clone meshery-cloud repo."
#------------------------------------------
#------------------------------------------
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: "1.25"
check-latest: true
cache: true
- name: Download dependencies
working-directory: meshery-cloud
run: |
go mod download
go mod verify
- name: Comment Go setup success
if: success()
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":heavy_check_mark: Setup Golang environment. Running unit tests... (takes approximately 3 min)"
- name: Comment Go setup failure
if: failure()
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":x: Failed to setup Golang environment."
#------------------------------------------
#------------------------------------------
- name: Run unit tests
id: unit-tests
continue-on-error: true
working-directory: meshery-cloud
run: make server-tests-unit
- name: Comment unit tests success
if: steps.unit-tests.outcome == 'success'
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":heavy_check_mark: Unit tests passed. Running integration tests..."
- name: Comment unit tests failure
if: steps.unit-tests.outcome == 'failure'
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":x: Unit tests failed. Running integration tests..."
#------------------------------------------
#------------------------------------------
- name: Run integration tests
id: integration-tests
continue-on-error: true
if: ${{ inputs.run_integration_tests }}
working-directory: meshery-cloud
run: make ENVIRONMENT=staging server-tests-integration
- name: Comment integration tests success
if: steps.integration-tests.outcome == 'success'
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":heavy_check_mark: Golang integration tests passed."
- name: Comment integration tests failure
if: steps.integration-tests.outcome == 'failure'
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":x: Golang integration tests failed."
- name: Comment integration tests skipped
if: steps.integration-tests.outcome == 'skipped'
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":fast_forward: Integration tests skipped (not requested)."
#------------------------------------------
#------------------------------------------
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: server-test-results
path: meshery-cloud/allure-results/
if-no-files-found: ignore
retention-days: 14
#------------------------------------------
#------------------------------------------
# Publish server test results (pass or fail) to qa.meshery.io. PR runs
# route under pr-reports/<N>/ so they stay out of the master dashboard.
# The sync is intentionally ungated on test outcome — failing runs must
# land so the dashboard reflects every CI run.
- name: Checkout QA
if: ${{ !cancelled() }}
uses: actions/checkout@v6
with:
repository: meshery-extensions/qa
path: qa
token: ${{ secrets.GH_ACCESS_TOKEN }}
- name: Sync server test results to qa
if: ${{ !cancelled() }}
run: |
set -euo pipefail
if [ -n "${{ inputs.pr_number }}" ]; then
BASE="qa/pr-reports/${{ inputs.pr_number }}"
else
BASE="qa"
fi
SERVER_DEST="$BASE/meshery-server-results"
rm -rf "$SERVER_DEST"
mkdir -p "$SERVER_DEST"
for dir in \
meshery-cloud/allure-results \
meshery-cloud/server/*/allure-results; do
[ -d "$dir" ] || continue
cp -R "$dir/." "$SERVER_DEST/" 2>/dev/null || true
done
echo "meshery-server-results: $(find "$SERVER_DEST" -type f | wc -l) file(s)"
- name: Commit & push server results to qa
if: ${{ !cancelled() }}
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: "[Cloud] Sync server test results - ${GITHUB_SHA}"
commit_options: --signoff
repository: qa
file_pattern: ${{ inputs.pr_number != '' && format('pr-reports/{0}', inputs.pr_number) || 'meshery-server-results' }}
commit_user_name: meshery-ci
commit_user_email: ci@meshery.io
env:
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
- name: Comment QA sync success
if: ${{ success() && !cancelled() }}
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":heavy_check_mark: Synced server test results to QA dashboard."
- name: Comment QA sync failure
if: ${{ failure() }}
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":x: Failed to sync server test results to QA dashboard."
#------------------------------------------
#------------------------------------------
- name: Comment final success
if: ${{ steps.unit-tests.outcome == 'success' && (steps.integration-tests.outcome == 'success' || steps.integration-tests.outcome == 'skipped') }}
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":white_check_mark: All Layer5 Cloud Server tests completed successfully."
- name: Comment final failure
if: ${{ steps.unit-tests.outcome == 'failure' || steps.integration-tests.outcome == 'failure' }}
uses: ./.github/actions/cloud-comment
with:
id: cloud-tests
message: ":x: Layer5 Cloud Server tests completed with failures. See [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})."
- name: Fail if any tests failed
if: ${{ steps.unit-tests.outcome == 'failure' || steps.integration-tests.outcome == 'failure' }}
run: |
echo "::error::Test failures detected"
[ "${{ steps.unit-tests.outcome }}" = "failure" ] && echo " - Unit tests failed"
[ "${{ steps.integration-tests.outcome }}" = "failure" ] && echo " - Integration tests failed"
exit 1
#------------------------------------------
ui-tests:
name: UI Tests
runs-on: ubuntu-24.04
timeout-minutes: 10
env:
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
PR_NUMBER: ${{ inputs.pr_number }}
steps:
- name: Checkout for composite action
uses: actions/checkout@v6
with:
fetch-depth: 1
sparse-checkout: |
.github/actions/cloud-comment
sparse-checkout-cone-mode: false
- name: Comment starting
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: "Starting Cloud UI tests ([workflow run](https://github.com/layer5labs/meshery-extensions-packages/actions/runs/${{ github.run_id }}))..."
append: false
recreate: true
#------------------------------------------
- name: Checkout Cloud code
uses: actions/checkout@v6
with:
repository: layer5io/meshery-cloud
ref: ${{ inputs.pr_number != '' && format('refs/pull/{0}/head', inputs.pr_number) || inputs.pr_commit_sha }}
token: ${{ secrets.GH_ACCESS_TOKEN }}
fetch-depth: 1
path: meshery-cloud
- name: Comment checkout success
if: success()
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":heavy_check_mark: Checked out meshery-cloud repo."
- name: Comment checkout failure
if: failure()
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":x: Failed to clone meshery-cloud repo."
#------------------------------------------
#------------------------------------------
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node_version }}
cache: "npm"
cache-dependency-path: meshery-cloud/ui/package-lock.json
- name: Comment Node setup success
if: steps.setup-node.outcome == 'success'
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":heavy_check_mark: Setup Node.js. Installing dependencies..."
- name: Comment Node setup failure
if: steps.setup-node.outcome == 'failure'
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":x: Failed to setup Node.js."
#------------------------------------------
#------------------------------------------
- name: Install UI dependencies
id: install-deps
working-directory: meshery-cloud
run: make ui-setup
- name: Comment deps success
if: steps.install-deps.outcome == 'success'
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":heavy_check_mark: Installed UI dependencies. Running UI tests..."
- name: Comment deps failure
if: steps.install-deps.outcome == 'failure'
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":x: Failed to install UI dependencies."
#------------------------------------------
#------------------------------------------
- name: Run UI tests
id: ui-tests
working-directory: meshery-cloud
run: make ui-tests
- name: Upload UI test results
if: always()
uses: actions/upload-artifact@v4
with:
name: ui-test-results
path: meshery-cloud/ui/coverage/
if-no-files-found: ignore
retention-days: 14
- name: Comment UI tests success
if: steps.ui-tests.outcome == 'success'
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":white_check_mark: All Cloud UI tests passed."
- name: Comment UI tests failure
if: steps.ui-tests.outcome == 'failure'
uses: ./.github/actions/cloud-comment
with:
id: cloud-ui-tests
message: ":x: Cloud UI tests failed. See [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})."
#------------------------------------------
#------------------------------------------
# Publish UI (Jest) results to qa.meshery.io. Runs on pass or fail.
# Until meshery-cloud wires an allure-jest reporter into the ui target,
# meshery-cloud/ui/allure-results will be empty and this step no-ops.
- name: Checkout QA
if: ${{ !cancelled() }}
uses: actions/checkout@v6
with:
repository: meshery-extensions/qa
path: qa
token: ${{ secrets.GH_ACCESS_TOKEN }}
- name: Sync UI test results to qa
if: ${{ !cancelled() }}
run: |
set -euo pipefail
if [ -n "${{ inputs.pr_number }}" ]; then
BASE="qa/pr-reports/${{ inputs.pr_number }}"
else
BASE="qa"
fi
UI_DEST="$BASE/remote-provider-results"
mkdir -p "$UI_DEST"
for dir in meshery-cloud/ui/allure-results; do
[ -d "$dir" ] || continue
cp -R "$dir/." "$UI_DEST/" 2>/dev/null || true
done
echo "remote-provider-results (UI): $(find "$UI_DEST" -type f | wc -l) file(s)"
- name: Commit & push UI results to qa
if: ${{ !cancelled() }}
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: "[Cloud] Sync UI test results - ${GITHUB_SHA}"
commit_options: --signoff
repository: qa
file_pattern: ${{ inputs.pr_number != '' && format('pr-reports/{0}', inputs.pr_number) || 'remote-provider-results' }}
commit_user_name: meshery-ci
commit_user_email: ci@meshery.io
env:
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
#------------------------------------------
e2e-tests:
name: Playwright e2e
runs-on: ubuntu-24.04
timeout-minutes: 30
env:
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
PR_NUMBER: ${{ inputs.pr_number }}
steps:
- name: Checkout for composite action
uses: actions/checkout@v6
with:
fetch-depth: 1
sparse-checkout: |
.github/actions/cloud-comment
sparse-checkout-cone-mode: false
- name: Comment starting
uses: ./.github/actions/cloud-comment
with:
id: cloud-e2e-tests
message: "Starting Cloud Playwright e2e ([workflow run](https://github.com/layer5labs/meshery-extensions-packages/actions/runs/${{ github.run_id }}))..."
append: false
recreate: true
- name: Checkout Cloud code
uses: actions/checkout@v6
with:
repository: layer5io/meshery-cloud
ref: ${{ inputs.pr_number != '' && format('refs/pull/{0}/head', inputs.pr_number) || inputs.pr_commit_sha }}
token: ${{ secrets.GH_ACCESS_TOKEN }}
fetch-depth: 1
path: meshery-cloud
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node_version }}
cache: 'npm'
cache-dependency-path: meshery-cloud/ui/package-lock.json
- name: Install Cloud UI dependencies
working-directory: meshery-cloud
run: make ui-setup
- name: Cache Playwright browsers
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: playwright-${{ hashFiles('meshery-cloud/ui/package-lock.json') }}
- name: Install Playwright browsers
working-directory: meshery-cloud/ui
run: npx playwright install --with-deps
# ALLURE_RESULTS_DIR routes allure-playwright (when wired in
# meshery-cloud) to a path the sync-to-qa step collects. Until that
# reporter is added, the directory stays empty and sync no-ops.
# Step timeout is set below the job timeout so a hung test fails
# with room left for the QA sync + gating step to run. Current
# observed e2e runtime is ~22 min; 25 min gives a small buffer.
- name: Run Cloud UI e2e tests
id: e2e
timeout-minutes: 25
continue-on-error: true
working-directory: meshery-cloud/ui
env:
ALLURE_RESULTS_DIR: ${{ github.workspace }}/meshery-cloud/ui/allure-results
run: npm run e2e
- name: Comment e2e success
if: steps.e2e.outcome == 'success'
uses: ./.github/actions/cloud-comment
with:
id: cloud-e2e-tests
message: ":white_check_mark: Cloud Playwright e2e tests passed."
- name: Comment e2e failure
if: steps.e2e.outcome == 'failure'
uses: ./.github/actions/cloud-comment
with:
id: cloud-e2e-tests
message: ":x: Cloud Playwright e2e tests failed. See [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})."
- name: Upload e2e test results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-test-results
path: meshery-cloud/ui/allure-results/
if-no-files-found: ignore
retention-days: 14
#------------------------------------------
# Publish Playwright e2e results to qa.meshery.io. Runs on pass or
# fail. PR runs route under pr-reports/<N>/.
- name: Checkout QA
if: ${{ !cancelled() }}
uses: actions/checkout@v6
with:
repository: meshery-extensions/qa
path: qa
token: ${{ secrets.GH_ACCESS_TOKEN }}
# Clear the destination before copying so removed/renamed result
# files don't linger as stale entries on the QA dashboard. Safe in
# this job because no other parallel job writes to the same subtree
# within this run (the ui-tests Jest sync is currently a no-op).
- name: Sync e2e results to qa
if: ${{ !cancelled() }}
run: |
set -euo pipefail
if [ -n "${{ inputs.pr_number }}" ]; then
BASE="qa/pr-reports/${{ inputs.pr_number }}"
else
BASE="qa"
fi
E2E_DEST="$BASE/remote-provider-results"
rm -rf "$E2E_DEST"
mkdir -p "$E2E_DEST"
for dir in meshery-cloud/ui/allure-results; do
[ -d "$dir" ] || continue
cp -R "$dir/." "$E2E_DEST/" 2>/dev/null || true
done
echo "remote-provider-results (e2e): $(find "$E2E_DEST" -type f | wc -l) file(s)"
- name: Commit & push e2e results to qa
if: ${{ !cancelled() }}
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: "[Cloud] Sync e2e results - ${GITHUB_SHA}"
commit_options: --signoff
repository: qa
file_pattern: ${{ inputs.pr_number != '' && format('pr-reports/{0}', inputs.pr_number) || 'remote-provider-results' }}
commit_user_name: meshery-ci
commit_user_email: ci@meshery.io
env:
GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }}
# Gate after the sync so failing e2e results still publish to QA
# while the job correctly surfaces as failed in PR checks.
- name: Fail job if e2e failed
if: steps.e2e.outcome == 'failure'
run: |
echo "::error::Playwright e2e tests failed"
exit 1
#------------------------------------------