Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
d80d309
test: point LLM and OCR mobile workflows at ios-cpp-log-capture branch
tobi-legan Apr 20, 2026
60932fd
test: add bare_console.log pullFile to iOS WDIO after hooks
tobi-legan Apr 20, 2026
34da7ca
fix: add 3s pause before pullFile to avoid log flush race condition
tobi-legan Apr 20, 2026
02ea8f9
fix: prevent download step hang from pullFile base64 log bloat
tobi-legan Apr 20, 2026
9fd8247
feat: add iOS bare_console.log capture to all addon mobile workflows
tobi-legan Apr 20, 2026
7b2e608
feat: split Device Farm artifacts into console logs and full logs
tobi-legan Apr 22, 2026
64118d6
fix: extract bare_console.log from Customer_Artifacts.zip in console …
tobi-legan Apr 22, 2026
8cd0055
fix: simplify console logs to only bare_console, logcat, and appium logs
tobi-legan Apr 22, 2026
e5e2399
Merge remote-tracking branch 'origin/main' into test/ios-cpp-log-capture
tobi-legan Apr 22, 2026
0428671
fix: add .github/actions to sparse-checkout in OCR and ONNX on-pr wor…
tobi-legan Apr 22, 2026
36d41be
Revert "fix: add .github/actions to sparse-checkout in OCR and ONNX o…
tobi-legan Apr 22, 2026
4e2ffdf
fix: align TTS console-logs extract path with download path (include …
tobi-legan Apr 22, 2026
aee6209
fix: use find for nested zip extraction in OCR console-logs
tobi-legan Apr 22, 2026
abaa587
fix: use find for nested zip extraction in all 8 remaining workflows
tobi-legan Apr 22, 2026
0c7e863
Merge branch 'main' into test/ios-cpp-log-capture
tobi-legan Apr 23, 2026
5b60805
Merge branch 'main' into test/ios-cpp-log-capture
tobi-legan Apr 23, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,7 @@ jobs:
# iOS wdio config with crash detection (bail:0 = continue on test failures, crash = process.exit)
# usePrebuiltWDA uses Device Farm's pre-built WebDriverAgent
# Increased timeout to 30 minutes (1800000ms) for long-running LLM tests
WDIO_CONFIG='exports.config={runner:"local",hostname:"127.0.0.1",port:4723,path:"/wd/hub",specs:["*.spec.js","*.test.js"],maxInstances:1,bail:0,capabilities:[{platformName:"iOS","appium:automationName":"XCUITest","appium:bundleId":"'${{ env.APP_BUNDLE_ID }}'","appium:newCommandTimeout":300,"appium:noReset":true,"appium:forceAppLaunch":false,"appium:usePrebuiltWDA":true,"appium:wdaLocalPort":8100,"appium:showIOSLog":true,"appium:realDeviceLogger":"/usr/local/lib/node_modules/appium/node_modules/deviceconsole/deviceconsole"}],logLevel:"debug",waitforTimeout:120000,connectionRetryTimeout:30000,connectionRetryCount:3,services:[],framework:"mocha",reporters:["spec"],mochaOpts:{ui:"bdd",timeout:1800000},before:async function(capabilities,specs,browser){const BUNDLE_ID="'${{ env.APP_BUNDLE_ID }}'";global.appCrashed=false;global.checkAppCrash=async(stage)=>{try{const state=await browser.queryAppState(BUNDLE_ID);console.log("["+stage+"] App state: "+state+" (4=foreground,3=background,1=not running)");if(state<3){console.error("\\n🛑 APP CRASHED at "+stage+"! State="+state);console.error("Check device logs for BareKit/native errors.\\n");global.appCrashed=true;process.exit(1);}return state;}catch(e){console.log("["+stage+"] queryAppState error: "+e.message);return-1;}};console.log("Checking initial app state...");await global.checkAppCrash("startup");console.log("Waiting for app to initialize...");await browser.pause(5000);await global.checkAppCrash("after-pause");const initText=await browser.$("-ios predicate string:label CONTAINS \"INITIALIZED\"");await initText.waitForDisplayed({timeout:60000});await global.checkAppCrash("after-init");console.log("App initialized, clicking Run Automated Tests...");const button=await browser.$("-ios predicate string:label CONTAINS \"Run Automated Tests\"");await button.waitForDisplayed({timeout:15000});await button.click();console.log("Button clicked!");await browser.pause(5000);await global.checkAppCrash("after-click");},after:async function(result,capabilities,specs){try{const fs=require("fs");const path=require("path");const artifactDir=path.resolve(process.cwd(),"tests","artifacts");const remoteArtifactDir="@'${{ env.APP_BUNDLE_ID }}':documents/test/generated-images/";const artifactPath=path.join(artifactDir,"ios-generated-images.zip");fs.mkdirSync(artifactDir,{recursive:true});if(typeof browser.pullFolder!=="function"){console.log("No iOS generated image artifacts collected: browser.pullFolder is not available");return;}console.log("Attempting to pull generated images from "+remoteArtifactDir);const folderData=await browser.pullFolder(remoteArtifactDir);fs.writeFileSync(artifactPath,Buffer.from(folderData,"base64"));console.log("Saved generated image artifacts to "+artifactPath);}catch(e){console.log("No iOS generated image artifacts collected: "+e.message);}},afterTest:async function(test,context,{error}){if(global.appCrashed)return;await global.checkAppCrash("after-test:"+test.title);}};'
WDIO_CONFIG='exports.config={runner:"local",hostname:"127.0.0.1",port:4723,path:"/wd/hub",specs:["*.spec.js","*.test.js"],maxInstances:1,bail:0,capabilities:[{platformName:"iOS","appium:automationName":"XCUITest","appium:bundleId":"'${{ env.APP_BUNDLE_ID }}'","appium:newCommandTimeout":300,"appium:noReset":true,"appium:forceAppLaunch":false,"appium:usePrebuiltWDA":true,"appium:wdaLocalPort":8100,"appium:showIOSLog":true,"appium:realDeviceLogger":"/usr/local/lib/node_modules/appium/node_modules/deviceconsole/deviceconsole"}],logLevel:"debug",waitforTimeout:120000,connectionRetryTimeout:30000,connectionRetryCount:3,services:[],framework:"mocha",reporters:["spec"],mochaOpts:{ui:"bdd",timeout:1800000},before:async function(capabilities,specs,browser){const BUNDLE_ID="'${{ env.APP_BUNDLE_ID }}'";global.appCrashed=false;global.checkAppCrash=async(stage)=>{try{const state=await browser.queryAppState(BUNDLE_ID);console.log("["+stage+"] App state: "+state+" (4=foreground,3=background,1=not running)");if(state<3){console.error("\\n🛑 APP CRASHED at "+stage+"! State="+state);console.error("Check device logs for BareKit/native errors.\\n");global.appCrashed=true;process.exit(1);}return state;}catch(e){console.log("["+stage+"] queryAppState error: "+e.message);return-1;}};console.log("Checking initial app state...");await global.checkAppCrash("startup");console.log("Waiting for app to initialize...");await browser.pause(5000);await global.checkAppCrash("after-pause");const initText=await browser.$("-ios predicate string:label CONTAINS \"INITIALIZED\"");await initText.waitForDisplayed({timeout:60000});await global.checkAppCrash("after-init");console.log("App initialized, clicking Run Automated Tests...");const button=await browser.$("-ios predicate string:label CONTAINS \"Run Automated Tests\"");await button.waitForDisplayed({timeout:15000});await button.click();console.log("Button clicked!");await browser.pause(5000);await global.checkAppCrash("after-click");},after:async function(result,capabilities,specs){console.log("[bare-log] Waiting for log flush...");await browser.pause(3000);try{var BID="'${{ env.APP_BUNDLE_ID }}'";var _h=require("http");var lb64=await new Promise(function(ok,fail){var bd=JSON.stringify({path:"@"+BID+":documents/bare_console.log"});var rq=_h.request({hostname:"127.0.0.1",port:4723,path:"/wd/hub/session/"+browser.sessionId+"/appium/device/pull_file",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(bd)}},function(rs){var d="";rs.on("data",function(c){d+=c;});rs.on("end",function(){try{ok(JSON.parse(d).value);}catch(e){fail(e);}});});rq.on("error",fail);rq.write(bd);rq.end();});var logTxt=Buffer.from(lb64,"base64").toString();var logDir=process.env.DEVICEFARM_LOG_DIR||".";require("fs").writeFileSync(logDir+"/bare_console.log",logTxt);console.log("[bare-log] Written bare_console.log ("+logTxt.length+" bytes)");}catch(le){console.log("[bare-log] pull failed: "+le.message);}try{const fs=require("fs");const path=require("path");const artifactDir=path.resolve(process.cwd(),"tests","artifacts");const remoteArtifactDir="@'${{ env.APP_BUNDLE_ID }}':documents/test/generated-images/";const artifactPath=path.join(artifactDir,"ios-generated-images.zip");fs.mkdirSync(artifactDir,{recursive:true});if(typeof browser.pullFolder!=="function"){console.log("No iOS generated image artifacts collected: browser.pullFolder is not available");return;}console.log("Attempting to pull generated images from "+remoteArtifactDir);const folderData=await browser.pullFolder(remoteArtifactDir);fs.writeFileSync(artifactPath,Buffer.from(folderData,"base64"));console.log("Saved generated image artifacts to "+artifactPath);}catch(e){console.log("No iOS generated image artifacts collected: "+e.message);}},afterTest:async function(test,context,{error}){if(global.appCrashed)return;await global.checkAppCrash("after-test:"+test.title);}};'
fi

# Base64 encode the wdio config to safely embed in YAML
Expand Down Expand Up @@ -1366,7 +1366,7 @@ jobs:
SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-')
DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}"

if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then
if curl -fsSL --max-time 300 -o "$DEST" "$ART_URL" 2>/dev/null; then
echo " Downloaded: $SUITE_NAME / $ART_NAME"

if echo "$ART_NAME" | grep -qiE "test.spec|testspec"; then
Expand All @@ -1389,7 +1389,7 @@ jobs:
SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-')
DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_${SAFE_SUITE}_${SAFE_ART}.${ART_EXT}"

if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then
if curl -fsSL --max-time 300 -o "$DEST" "$ART_URL" 2>/dev/null; then
echo " Downloaded: $SUITE_NAME / $ART_NAME (LOG)"
fi
done
Expand All @@ -1412,7 +1412,7 @@ jobs:
SAFE_ART=$(echo "$ART_NAME" | tr ' /' '__' | tr -cd '[:alnum:]_-')
DEST="$LOG_DIR/${SAFE_RUN}_${SAFE_NAME}_job_${SAFE_ART}.${ART_EXT}"

if curl -fsSL -o "$DEST" "$ART_URL" 2>/dev/null; then
if curl -fsSL --max-time 300 -o "$DEST" "$ART_URL" 2>/dev/null; then
echo " Downloaded (job-level): $ART_NAME"
fi
done
Expand All @@ -1424,7 +1424,53 @@ jobs:
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
find "$LOG_DIR" -type f -exec ls -lh {} \; 2>/dev/null || echo " (no logs downloaded)"

- name: Upload Device Farm Logs
- name: Extract Console Logs
if: always() && steps.schedule_run.outputs.run_arn
run: |
LOG_DIR="devicefarm-logs/${{ matrix.platform }}"
CONSOLE_DIR="console-logs/${{ matrix.platform }}"
mkdir -p "$CONSOLE_DIR"
for f in "$LOG_DIR"/*; do
[ -f "$f" ] || continue
fname=$(basename "$f")
if echo "$fname" | grep -qiE "Logcat\."; then
cp "$f" "$CONSOLE_DIR/"
echo " Console log: $fname"
fi
if echo "$fname" | grep -qiE "Customer_Artifacts\.zip$"; then
prefix=$(echo "$fname" | sed 's/_Customer_Artifacts\.zip$//')
tmpdir=$(mktemp -d)
if unzip -qo "$f" -d "$tmpdir" 2>/dev/null; then
bare_log=$(find "$tmpdir" -name "bare_console.log" -type f 2>/dev/null | head -1)
if [ -n "$bare_log" ]; then
cp "$bare_log" "$CONSOLE_DIR/${prefix}_bare_console.log"
echo " Extracted: ${prefix}_bare_console.log"
fi
appium_log=$(find "$tmpdir" -name "appium.log" -type f 2>/dev/null | head -1)
if [ -n "$appium_log" ]; then
cp "$appium_log" "$CONSOLE_DIR/${prefix}_appium.log"
echo " Extracted: ${prefix}_appium.log"
fi
else
echo " WARNING: Failed to unzip $fname"
fi
rm -rf "$tmpdir"
fi
done
echo ""
echo "📋 Console logs extracted:"
find "$CONSOLE_DIR" -type f -exec ls -lh {} \; 2>/dev/null || echo " (no console logs found)"

- name: Upload Console Logs
if: always() && steps.schedule_run.outputs.run_arn
uses: actions/upload-artifact@v4
with:
name: console-logs-diffusion-${{ matrix.platform }}
path: console-logs/
retention-days: 30
if-no-files-found: ignore

- name: Upload Full Device Farm Logs
if: always() && steps.schedule_run.outputs.run_arn
uses: actions/upload-artifact@v4
with:
Expand Down
Loading
Loading