Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions .github/workflows/on-pr-test-sdk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# QVAC SDK E2E Tests - PR Trigger
#
# Triggers SDK e2e tests via test-sdk.yml when:
# - "test-e2e-smoke" label applied: runs smoke suite on all platforms
# - "test-e2e-full" label applied: runs full suite on all platforms
# - PR opened/updated targeting release-* branch with packages/sdk/ changes: runs full suite
#
# On success, applies "e2e-tested" label to the PR.
#
# Uses pull_request_target for secrets access (Device Farm, MQTT).
# Authorization gate prevents untrusted fork PRs from running.

name: QVAC Tests (sdk) - PR

on:
pull_request_target:
types: [labeled, opened, synchronize]
paths:
- "packages/sdk/**"

permissions:
contents: read
pull-requests: write
packages: read

jobs:
resolve-config:
runs-on: ubuntu-latest
outputs:
should-run: ${{ steps.check.outputs.should-run }}
suite: ${{ steps.check.outputs.suite }}
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
with:
fetch-depth: 0

- name: Authorize PR
id: auth
uses: ./.github/actions/authorize-pr
with:
label: safe-to-test
github-token: ${{ github.token }}

- name: Determine test config
if: steps.auth.outputs.allowed == 'true'
id: check
shell: bash
run: |
EVENT="${{ github.event.action }}"
LABEL="${{ github.event.label.name }}"
TARGET="${{ github.base_ref }}"

if [ "$EVENT" = "labeled" ]; then
if [ "$LABEL" = "test-e2e-smoke" ]; then
echo "should-run=true" >> "$GITHUB_OUTPUT"
echo "suite=smoke" >> "$GITHUB_OUTPUT"
elif [ "$LABEL" = "test-e2e-full" ]; then
echo "should-run=true" >> "$GITHUB_OUTPUT"
echo "suite=" >> "$GITHUB_OUTPUT"
else
echo "::notice::Ignoring unrelated label: $LABEL"
echo "should-run=false" >> "$GITHUB_OUTPUT"
fi
elif echo "$TARGET" | grep -q '^release-'; then
git fetch origin "refs/pull/${{ github.event.pull_request.number }}/head"
CHANGED=$(git diff --name-only "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" -- packages/sdk/)
if [ -n "$CHANGED" ]; then
echo "::notice::Release branch PR with SDK changes — running full suite"
echo "should-run=true" >> "$GITHUB_OUTPUT"
echo "suite=" >> "$GITHUB_OUTPUT"
else
echo "::notice::Release branch PR but no changes in packages/sdk/ — skipping"
echo "should-run=false" >> "$GITHUB_OUTPUT"
fi
else
echo "should-run=false" >> "$GITHUB_OUTPUT"
fi

run-tests:

Check failure

Code scanning / CodeQL

Checkout of untrusted code in trusted context High

Potential execution of untrusted code on a privileged workflow (
pull_request_target
)
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
needs: resolve-config
if: needs.resolve-config.outputs.should-run == 'true'
uses: ./.github/workflows/test-sdk.yml
with:
targets: all
suite: ${{ needs.resolve-config.outputs.suite }}
secrets: inherit

apply-label:
needs: run-tests
if: success()
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Apply e2e-tested label
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # 7.0.1
with:
script: |
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: ['e2e-tested']
});
80 changes: 78 additions & 2 deletions .github/workflows/test-android-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ on:
description: "Filter tests by category or testId prefix (comma-separated)"
required: false
type: string
suite:
description: "Suite filter (e.g. 'smoke'). Empty = all tests."
required: false
type: string
exclude-suite:
description: "Exclude suites (comma-separated)"
required: false
type: string
device-farm-timeout:
description: "Maximum time in minutes to keep Device Farm session alive."
required: false
Expand Down Expand Up @@ -517,17 +525,31 @@ jobs:
echo " Run ID: ${{ needs.build.outputs.runId }}"
echo " Consumer timeout: ${{ inputs.consumer-timeout }}s"
echo " Filter: ${{ inputs.filter || '(none)' }}"
echo " Suite: ${{ inputs.suite || '(all)' }}"
echo " Exclude suite: ${{ inputs.exclude-suite || '(none)' }}"

FILTER_ARG=""
if [ -n "${{ inputs.filter }}" ]; then
FILTER_ARG="--filter=${{ inputs.filter }}"
fi

SUITE_ARG=""
if [ -n "${{ inputs.suite }}" ]; then
SUITE_ARG="--suite=${{ inputs.suite }}"
fi

EXCLUDE_SUITE_ARG=""
if [ -n "${{ inputs.exclude-suite }}" ]; then
EXCLUDE_SUITE_ARG="--exclude-suite=${{ inputs.exclude-suite }}"
fi

npx qvac-test run:producer \
--runId "${{ needs.build.outputs.runId }}" \
--consumer-timeout "${{ inputs.consumer-timeout }}" \
--config . \
$FILTER_ARG
$FILTER_ARG \
$SUITE_ARG \
$EXCLUDE_SUITE_ARG

- name: Upload results
if: always()
Expand All @@ -551,7 +573,7 @@ jobs:
if: always()
runs-on: ubuntu-latest
environment: release
timeout-minutes: 5
timeout-minutes: 10
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # 6.0.0
Expand Down Expand Up @@ -587,6 +609,60 @@ jobs:
fi
done

- name: Download Device Farm artifacts
run: |
mkdir -p ./device-farm-logs

for arn_file in run-arns/*.txt; do
if [ -f "$arn_file" ]; then
RUN_ARN=$(cat "$arn_file")
DEVICE_NAME=$(basename "$arn_file" .txt)

echo "Waiting for run to finish: $DEVICE_NAME"
for attempt in $(seq 1 30); do
STATUS=$(aws devicefarm get-run --arn "$RUN_ARN" --query 'run.status' --output text 2>/dev/null || echo "UNKNOWN")
if [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "STOPPED" ] || [ "$STATUS" = "ERRORED" ]; then
echo "Run $DEVICE_NAME finished with status: $STATUS"
break
fi
echo "Run $DEVICE_NAME still $STATUS (attempt $attempt/30)..."
sleep 10
done

DEVICE_DIR="./device-farm-logs/$DEVICE_NAME"
mkdir -p "$DEVICE_DIR"

echo "Downloading Customer Artifacts for $DEVICE_NAME..."
JOBS=$(aws devicefarm list-jobs --arn "$RUN_ARN" --query 'jobs[*].arn' --output text 2>/dev/null || echo "")
for JOB_ARN in $JOBS; do
aws devicefarm list-artifacts \
--arn "$JOB_ARN" \
--type FILE \
--query "artifacts[?contains(name,'Customer')].[name,extension,url]" \
--output text 2>/dev/null \
| while IFS=$'\t' read -r NAME EXT URL; do
if [ -z "$URL" ] || [ "$URL" = "None" ]; then
continue
fi
SAFE_NAME=$(echo "$NAME" | tr ' /' '__')
echo " Downloading ${SAFE_NAME}.${EXT}"
curl -sS -o "$DEVICE_DIR/${SAFE_NAME}.${EXT}" "$URL" || echo " Failed: ${SAFE_NAME}.${EXT}"
done
done

echo "Artifacts for $DEVICE_NAME:"
ls -lh "$DEVICE_DIR" 2>/dev/null || echo " (empty)"
fi
done

- name: Upload Device Farm logs
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # 7.0.0
with:
name: device-farm-logs-android-${{ needs.build.outputs.runId }}
path: ./device-farm-logs/
retention-days: 30

compare-results:
needs: [build, run-producer]
if: github.event_name == 'pull_request'
Expand Down
16 changes: 15 additions & 1 deletion .github/workflows/test-desktop-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ on:
description: 'Filter tests by category or testId prefix (comma-separated, e.g., "model,completion")'
required: false
type: string
suite:
description: "Suite filter (e.g. 'smoke'). Empty = all tests."
required: false
type: string
exclude-suite:
description: "Exclude suites (comma-separated)"
required: false
type: string
test-version:
description: "Git ref to checkout (branch, tag, or SHA). Defaults to trigger ref."
required: false
Expand Down Expand Up @@ -261,6 +269,10 @@ jobs:

const filter = '${{ inputs.filter }}';
const filterArgs = filter ? ['--filter=' + filter] : [];
const suite = '${{ inputs.suite }}';
const suiteArgs = suite ? ['--suite=' + suite] : [];
const excludeSuite = '${{ inputs.exclude-suite }}';
const excludeSuiteArgs = excludeSuite ? ['--exclude-suite=' + excludeSuite] : [];

const consumer = spawn('npx', [
'qvac-test', 'run:consumer:desktop',
Expand Down Expand Up @@ -309,7 +321,9 @@ jobs:
'--runId=${{ steps.runid.outputs.runId }}',
'--consumer-timeout=${{ inputs.consumer-timeout }}',
'--config=.',
...filterArgs
...filterArgs,
...suiteArgs,
...excludeSuiteArgs
];
console.log('Producer command: npx ' + producerArgs.join(' '));

Expand Down
24 changes: 23 additions & 1 deletion .github/workflows/test-ios-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ on:
description: "Filter tests by category or testId prefix (comma-separated)"
required: false
type: string
suite:
description: "Suite filter (e.g. 'smoke'). Empty = all tests."
required: false
type: string
exclude-suite:
description: "Exclude suites (comma-separated)"
required: false
type: string
device-farm-timeout:
description: "Maximum time in minutes to keep Device Farm session alive."
required: false
Expand Down Expand Up @@ -633,17 +641,31 @@ jobs:
echo " Run ID: ${{ needs.build.outputs.runId }}"
echo " Consumer timeout: ${{ inputs.consumer-timeout }}s"
echo " Filter: ${{ inputs.filter || '(none)' }}"
echo " Suite: ${{ inputs.suite || '(all)' }}"
echo " Exclude suite: ${{ inputs.exclude-suite || '(none)' }}"

FILTER_ARG=""
if [ -n "${{ inputs.filter }}" ]; then
FILTER_ARG="--filter=${{ inputs.filter }}"
fi

SUITE_ARG=""
if [ -n "${{ inputs.suite }}" ]; then
SUITE_ARG="--suite=${{ inputs.suite }}"
fi

EXCLUDE_SUITE_ARG=""
if [ -n "${{ inputs.exclude-suite }}" ]; then
EXCLUDE_SUITE_ARG="--exclude-suite=${{ inputs.exclude-suite }}"
fi

npx qvac-test run:producer \
--runId "${{ needs.build.outputs.runId }}" \
--consumer-timeout "${{ inputs.consumer-timeout }}" \
--config . \
$FILTER_ARG
$FILTER_ARG \
$SUITE_ARG \
$EXCLUDE_SUITE_ARG

- name: Upload results
if: always()
Expand Down
Loading
Loading