Skip to content

Commit 957c826

Browse files
committed
Add separate SauceLabs test script
1 parent c9079bc commit 957c826

File tree

2 files changed

+603
-184
lines changed

2 files changed

+603
-184
lines changed

.github/workflows/integration-test-android.yml

Lines changed: 18 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
run: |
3131
echo "Downloaded build contents:"
3232
ls -lah sample-build/
33-
echo "Using x64 APK for emulator testing"
33+
echo "Using APK for SauceLabs real device testing"
3434
3535
- name: Install Pester
3636
shell: pwsh
@@ -43,197 +43,31 @@ jobs:
4343
mkdir build
4444
cmake -B build -S .
4545
46-
- name: Upload APK to SauceLabs Storage
47-
id: upload_apk
48-
run: |
49-
sudo apt-get install -y jq
50-
51-
APK=$(ls sample-build/*.apk | head -n1)
52-
echo "Uploading: $APK"
53-
54-
RESPONSE=$(curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
55-
-X POST "https://api.${SAUCE_REGION}.saucelabs.com/v1/storage/upload" \
56-
-F "payload=@${APK}" \
57-
-F "name=$(basename "$APK")")
58-
59-
echo "Upload Response: $RESPONSE"
60-
STORAGE_ID=$(echo "$RESPONSE" | jq -r '.item.id')
61-
62-
echo "storage_id=$STORAGE_ID" >> $GITHUB_OUTPUT
63-
64-
- name: Start UE5 test on real device
65-
id: start_session
46+
- name: Run integration tests
47+
id: run-integration-tests
48+
shell: pwsh
49+
env:
50+
SENTRY_UNREAL_TEST_DSN: ${{ secrets.SENTRY_UNREAL_TEST_DSN }}
51+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_API_TOKEN }}
52+
UNREAL_VERSION: ${{ inputs.unreal-version }}
6653
run: |
67-
REQUEST=$(cat <<EOF
68-
{
69-
"capabilities": {
70-
"alwaysMatch": {
71-
"platformName": "Android",
72-
"appium:app": "storage:${{ steps.upload_apk.outputs.storage_id }}",
73-
"appium:deviceName": "Samsung_Galaxy_S23_FE_free",
74-
"appium:automationName": "UiAutomator2",
75-
"appium:noReset": true,
76-
"appium:autoLaunch": false,
77-
"sauce:options": {
78-
"name": "${{ inputs.unreal-version }} Android Integration Test",
79-
"appiumVersion": "latest"
80-
}
81-
}
82-
}
54+
# Find the APK file
55+
$apkPath = Get-ChildItem -Path "${{ github.workspace }}/sample-build" -Filter "*.apk" | Select-Object -First 1
56+
if (-not $apkPath) {
57+
throw "No APK file found in sample-build directory"
8358
}
84-
EOF
85-
)
86-
87-
echo "Sending Appium session request..."
88-
echo "$REQUEST"
89-
90-
RESPONSE=$(curl -sS -w "\nHTTP_CODE:%{http_code}" \
91-
-u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
92-
-X POST "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session" \
93-
-H "Content-Type: application/json" \
94-
-d "$REQUEST")
95-
96-
echo "Session Response: $RESPONSE"
97-
98-
SESSION_ID=$(echo "$RESPONSE" | grep -v "HTTP_CODE" | jq -r '.value.sessionId // .sessionId')
99-
echo "Extracted session_id: $SESSION_ID"
100-
echo "session_id=$SESSION_ID" >> $GITHUB_OUTPUT
101-
102-
- name: First launch (crash capture)
103-
run: |
104-
SESSION_ID="${{ steps.start_session.outputs.session_id }}"
105-
106-
RESPONSE=$(curl -sSL -w "\nHTTP:%{http_code}" \
107-
-u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
108-
-X POST "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session/$SESSION_ID/appium/device/start_activity" \
109-
-H "Content-Type: application/json" \
110-
-d '{
111-
"appPackage": "io.sentry.unreal.sample",
112-
"appActivity": "com.epicgames.unreal.GameActivity",
113-
"appWaitActivity": "*",
114-
"intentAction": "android.intent.action.MAIN",
115-
"intentCategory": "android.intent.category.LAUNCHER",
116-
"optionalIntentArguments": "-e cmdline '-crash-capture'"
117-
}')
118-
echo "Launch response: $RESPONSE"
119-
120-
- name: Wait for app to finish (first run)
121-
run: |
122-
SESSION_ID="${{ steps.start_session.outputs.session_id }}"
123-
124-
echo "Waiting for app to finish..."
125-
MAX_WAIT=20 # Max wait time in seconds
126-
POLL_INTERVAL=2
127-
ELAPSED=0
128-
129-
while [ $ELAPSED -lt $MAX_WAIT ]; do
130-
STATE=$(curl -sSL \
131-
-u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
132-
-X POST "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session/$SESSION_ID/execute/sync" \
133-
-H "Content-Type: application/json" \
134-
-d '{"script": "mobile: queryAppState", "args": [{"appId": "io.sentry.unreal.sample"}]}' \
135-
| jq -r '.value')
136-
137-
echo "App state: $STATE (elapsed: ${ELAPSED}s)"
138-
139-
# State 1 = not running, 0 = not installed
140-
if [ "$STATE" = "1" ] || [ "$STATE" = "0" ]; then
141-
echo "App finished/crashed"
142-
break
143-
fi
144-
145-
sleep $POLL_INTERVAL
146-
ELAPSED=$((ELAPSED + POLL_INTERVAL))
147-
done
148-
149-
if [ $ELAPSED -ge $MAX_WAIT ]; then
150-
echo "Timeout waiting for app to finish"
151-
fi
152-
153-
- name: Get first run logs
154-
run: |
155-
SESSION_ID="${{ steps.start_session.outputs.session_id }}"
156-
curl -sS -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
157-
-X POST "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session/$SESSION_ID/log" \
158-
-H "Content-Type: application/json" \
159-
-d '{"type": "logcat"}' \
160-
-o first_run_logs.json
161-
162-
- name: Second launch (message capture)
163-
run: |
164-
SESSION_ID="${{ steps.start_session.outputs.session_id }}"
165-
166-
RESPONSE=$(curl -sSL -w "\nHTTP:%{http_code}" \
167-
-u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
168-
-X POST "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session/$SESSION_ID/appium/device/start_activity" \
169-
-H "Content-Type: application/json" \
170-
-d '{
171-
"appPackage": "io.sentry.unreal.sample",
172-
"appActivity": "com.epicgames.unreal.GameActivity",
173-
"appWaitActivity": "*",
174-
"intentAction": "android.intent.action.MAIN",
175-
"intentCategory": "android.intent.category.LAUNCHER",
176-
"optionalIntentArguments": "-e cmdline '-message-capture'"
177-
}')
178-
echo "Launch response: $RESPONSE"
179-
180-
- name: Wait for app to finish (second run)
181-
run: |
182-
SESSION_ID="${{ steps.start_session.outputs.session_id }}"
183-
184-
echo "Waiting for app to finish..."
185-
MAX_WAIT=20 # Max wait time in seconds
186-
POLL_INTERVAL=2
187-
ELAPSED=0
188-
189-
while [ $ELAPSED -lt $MAX_WAIT ]; do
190-
STATE=$(curl -sSL \
191-
-u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
192-
-X POST "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session/$SESSION_ID/execute/sync" \
193-
-H "Content-Type: application/json" \
194-
-d '{"script": "mobile: queryAppState", "args": [{"appId": "io.sentry.unreal.sample"}]}' \
195-
| jq -r '.value')
196-
197-
echo "App state: $STATE (elapsed: ${ELAPSED}s)"
198-
199-
# State 1 = not running, 0 = not installed
200-
if [ "$STATE" = "1" ] || [ "$STATE" = "0" ]; then
201-
echo "App finished/crashed"
202-
break
203-
fi
204-
205-
sleep $POLL_INTERVAL
206-
ELAPSED=$((ELAPSED + POLL_INTERVAL))
207-
done
208-
209-
if [ $ELAPSED -ge $MAX_WAIT ]; then
210-
echo "Timeout waiting for app to finish"
211-
fi
21259
213-
- name: Get second run logs
214-
run: |
215-
SESSION_ID="${{ steps.start_session.outputs.session_id }}"
216-
curl -sS -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
217-
-X POST "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session/$SESSION_ID/log" \
218-
-H "Content-Type: application/json" \
219-
-d '{"type": "logcat"}' \
220-
-o second_run_logs.json
60+
Write-Host "Found APK: $($apkPath.Name)"
61+
$env:SENTRY_UNREAL_TEST_APP_PATH = $apkPath.FullName
22162
222-
- name: End session
223-
if: always()
224-
run: |
225-
SESSION_ID="${{ steps.start_session.outputs.session_id }}"
226-
if [ -n "$SESSION_ID" ] && [ "$SESSION_ID" != "null" ]; then
227-
curl -sS -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" \
228-
-X DELETE "https://ondemand.eu-central-1.saucelabs.com/wd/hub/session/$SESSION_ID"
229-
fi
63+
cd integration-test
64+
Invoke-Pester Integration.Tests.Android.SauceLabs.ps1 -CI
23065
23166
- name: Upload integration test output
23267
if: ${{ always() }}
23368
uses: actions/upload-artifact@v4
23469
with:
235-
name: UE ${{ inputs.unreal-version }} device logs (Android)
70+
name: UE ${{ inputs.unreal-version }} integration test output (Android)
23671
path: |
237-
first_run_logs.json
238-
second_run_logs.json
72+
integration-test/output/
23973
retention-days: 14

0 commit comments

Comments
 (0)