Skip to content

Commit 5fcfbb0

Browse files
committed
Add iOS hang diagnostics
1 parent afea0e2 commit 5fcfbb0

File tree

2 files changed

+124
-13
lines changed

2 files changed

+124
-13
lines changed

TestRunner/app/tests/Marshalling/ReferenceTests.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,15 +844,23 @@ describe(module.id, function () {
844844
let stringToHash = "bla";
845845

846846
const bytesToAlloc = 32;
847+
console.log("[diag][ReferenceAccessor] start");
847848
const result = interop.alloc(bytesToAlloc);
849+
console.log("[diag][ReferenceAccessor] allocated", result.toString());
848850
CC_SHA256(interop.handleof(NSString.stringWithString(stringToHash).UTF8String), stringToHash.length, result);
851+
console.log("[diag][ReferenceAccessor] sha complete");
849852
let buffer = new interop.Reference(interop.types.uint8, result);
853+
console.log("[diag][ReferenceAccessor] buffer ready");
850854

851855
let actual = "";
852856
for (let i = 0; i < bytesToAlloc; i++) {
853857
actual += buffer[i].toString(16).padStart(2, "0");
858+
if ((i + 1) % 8 === 0) {
859+
console.log("[diag][ReferenceAccessor] bytes", i + 1, actual);
860+
}
854861
}
855862

863+
console.log("[diag][ReferenceAccessor] final", actual);
856864
expect(actual).toBe("4df3c3f68fcc83b27e9d42c90431a72499f17875c81a599b566c9889b9696703");
857865
});
858866
});

scripts/run-tests-ios.js

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,10 @@ function wireLogStreamOutput(logStreamProcess, state) {
709709
}
710710

711711
const normalized = stripAnsi(line);
712+
state.recentRawLines.push(normalized);
713+
if (state.recentRawLines.length > 400) {
714+
state.recentRawLines.splice(0, state.recentRawLines.length - 400);
715+
}
712716
if (!includeLine(normalized)) {
713717
return;
714718
}
@@ -864,13 +868,7 @@ function collectRecentSimulatorLogs(udid, pid) {
864868
const text = result.stdout || "";
865869
let lines = text
866870
.split(/\r?\n/)
867-
.filter((line) =>
868-
line.includes("CONSOLE LOG:") ||
869-
line.includes("NativeScriptException") ||
870-
line.includes("Uncaught") ||
871-
line.includes("EXC_BAD_ACCESS") ||
872-
line.includes("heap")
873-
);
871+
.filter(Boolean);
874872

875873
// Keep only the most recent app run in this log window.
876874
const startIndex = (() => {
@@ -895,6 +893,106 @@ function collectRecentSimulatorLogs(udid, pid) {
895893
return lines.join("\n");
896894
}
897895

896+
function getRecentRawLogTail(state, maxLines = 80) {
897+
if (!state.recentRawLines || state.recentRawLines.length === 0) {
898+
return "";
899+
}
900+
901+
return state.recentRawLines.slice(-maxLines).join("\n");
902+
}
903+
904+
function readJunitFileState(udid) {
905+
const dataContainer = getAppDataContainerPath(udid);
906+
if (!dataContainer) {
907+
return {
908+
dataContainer: null,
909+
junitPath: null,
910+
exists: false,
911+
complete: false,
912+
sizeBytes: 0,
913+
tail: "",
914+
documentsEntries: []
915+
};
916+
}
917+
918+
const documentsPath = path.join(dataContainer, "Documents");
919+
const junitPath = path.join(documentsPath, "junit-result.xml");
920+
const documentsEntries = fs.existsSync(documentsPath)
921+
? fs.readdirSync(documentsPath).sort()
922+
: [];
923+
924+
if (!fs.existsSync(junitPath)) {
925+
return {
926+
dataContainer,
927+
junitPath,
928+
exists: false,
929+
complete: false,
930+
sizeBytes: 0,
931+
tail: "",
932+
documentsEntries
933+
};
934+
}
935+
936+
const xml = fs.readFileSync(junitPath, "utf8");
937+
return {
938+
dataContainer,
939+
junitPath,
940+
exists: true,
941+
complete: xml.includes("</testsuites>"),
942+
sizeBytes: Buffer.byteLength(xml, "utf8"),
943+
tail: xml.slice(-2000),
944+
documentsEntries
945+
};
946+
}
947+
948+
function collectSimulatorProcessSnapshot(udid) {
949+
const result = run("xcrun", ["simctl", "spawn", udid, "ps", "-axo", "pid,ppid,stat,etime,command"]);
950+
if (result.status !== 0) {
951+
return "";
952+
}
953+
954+
const lines = (result.stdout || "")
955+
.split(/\r?\n/)
956+
.filter((line) => /PID|TestRunner|launchd_sim|UIKitApplication/i.test(line));
957+
958+
return lines.join("\n");
959+
}
960+
961+
function formatInactivityDiagnostics(udid, state, pid) {
962+
const sections = [];
963+
const rawTail = getRecentRawLogTail(state);
964+
if (rawTail) {
965+
sections.push(`--- Recent raw simulator log lines ---\n${rawTail}`);
966+
}
967+
968+
const simulatorLogs = collectRecentSimulatorLogs(udid, pid);
969+
if (simulatorLogs) {
970+
sections.push(`--- Recent TestRunner simulator logs ---\n${simulatorLogs}`);
971+
}
972+
973+
const junitState = readJunitFileState(udid);
974+
const junitSummaryLines = [
975+
`data container: ${junitState.dataContainer || "<missing>"}`,
976+
`junit path: ${junitState.junitPath || "<missing>"}`,
977+
`junit exists: ${junitState.exists}`,
978+
`junit complete: ${junitState.complete}`,
979+
`junit size bytes: ${junitState.sizeBytes}`,
980+
`documents entries: ${junitState.documentsEntries.length > 0 ? junitState.documentsEntries.join(", ") : "<empty>"}`
981+
];
982+
if (junitState.tail) {
983+
junitSummaryLines.push("junit tail:");
984+
junitSummaryLines.push(junitState.tail);
985+
}
986+
sections.push(`--- App container state ---\n${junitSummaryLines.join("\n")}`);
987+
988+
const processSnapshot = collectSimulatorProcessSnapshot(udid);
989+
if (processSnapshot) {
990+
sections.push(`--- Simulator process snapshot ---\n${processSnapshot}`);
991+
}
992+
993+
return sections.join("\n\n");
994+
}
995+
898996
function parseJasmineSummary(logText) {
899997
const re = /(SUCCESS|FAILURE):\s+(\d+)\s+specs,\s+(\d+)\s+failure(?:s)?\,\s+(\d+)\s+skipped,\s+(\d+)\s+disabled/i;
900998
const match = logText.match(re);
@@ -990,7 +1088,13 @@ async function main() {
9901088
let launchProcess;
9911089
let logStreamProcess;
9921090
let exitCode = 0;
993-
const launchState = { logs: "", jasmineSummary: null, fatalDetected: false, lastActivityAt: Date.now() };
1091+
const launchState = {
1092+
logs: "",
1093+
jasmineSummary: null,
1094+
fatalDetected: false,
1095+
lastActivityAt: Date.now(),
1096+
recentRawLines: []
1097+
};
9941098

9951099
try {
9961100
if (enableLiveLogStream) {
@@ -1043,11 +1147,10 @@ async function main() {
10431147
} else {
10441148
const closeResult = launchResult || { code: 0, signal: null };
10451149
const launchPid = extractLaunchPid(launchState.logs);
1046-
const simulatorLogs = collectRecentSimulatorLogs(udid, launchPid);
1047-
if (simulatorLogs) {
1048-
launchState.logs += `\n${simulatorLogs}`;
1049-
console.log("\n--- TestRunner Logs (simulator) ---");
1050-
console.log(simulatorLogs);
1150+
const inactivityDiagnostics = formatInactivityDiagnostics(udid, launchState, launchPid);
1151+
if (inactivityDiagnostics) {
1152+
launchState.logs += `\n${inactivityDiagnostics}`;
1153+
console.log(`\n${inactivityDiagnostics}`);
10511154
}
10521155

10531156
const jasmineSummary = launchState.jasmineSummary || parseJasmineSummary(launchState.logs);

0 commit comments

Comments
 (0)