Skip to content

Commit f92fc9e

Browse files
committed
Android: replace fixed 10s teardown delay with polling
endRunningApplication force-stopped the app and then unconditionally waited a fixed 10 seconds before continuing, regardless of how quickly the process actually died - paying the full worst-case delay on every single test's beforeEach hook, even though the app almost always tears down in well under a second. Poll "adb shell pidof" every 200ms until the process is gone instead, keeping the 10s cap as a safety net for the rare case where teardown doesn't complete.
1 parent 987a044 commit f92fc9e

1 file changed

Lines changed: 37 additions & 1 deletion

File tree

code-push-plugin-testing-framework/script/platform.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"use strict";
2+
var child_process = require("child_process");
23
var Q = require("q");
34
var testUtil_1 = require("./testUtil");
45
//////////////////////////////////////////////////////////////////////////////////////////
@@ -97,6 +98,41 @@ exports.IOS = IOS;
9798
// bootEmulatorInternal constants
9899
var emulatorMaxReadyAttempts = 50;
99100
var emulatorReadyCheckDelayMs = 5 * 1000;
101+
102+
/**
103+
* Checks whether an Android app is currently running via "pidof". Exit code 1 means the
104+
* process wasn't found, which is the expected (non-error) outcome most of the time while
105+
* polling for teardown - any other failure (e.g. adb/device unavailable) is a genuine
106+
* problem and must not be silently treated as "the app stopped". Calls child_process
107+
* directly instead of going through TestUtil.getProcessOutput, since that helper treats
108+
* every non-zero exit as an error and logs it - which would spam the console with an
109+
* "error" on every single poll where the app has (expectedly) already stopped.
110+
*/
111+
function isAndroidAppRunning(appId) {
112+
return new Promise(function (resolve, reject) {
113+
child_process.exec("adb shell pidof " + appId, function (error) {
114+
if (!error) {
115+
resolve(true);
116+
} else if (error.code === 1) {
117+
resolve(false);
118+
} else {
119+
reject(error);
120+
}
121+
});
122+
});
123+
}
124+
125+
async function waitForAndroidAppToStop(appId, maxWaitMs) {
126+
var pollIntervalMs = 200;
127+
var start = Date.now();
128+
while (true) {
129+
var isRunning = await isAndroidAppRunning(appId);
130+
if (!isRunning || Date.now() - start >= maxWaitMs) {
131+
return;
132+
}
133+
await new Promise(function (resolve) { setTimeout(resolve, pollIntervalMs); });
134+
}
135+
}
100136
/**
101137
* Helper function for EmulatorManager implementations to use to boot an emulator with a given platformName and check, start, and kill methods.
102138
*/
@@ -241,7 +277,7 @@ var AndroidEmulatorManager = (function () {
241277
var t0 = Date.now();
242278
return testUtil_1.TestUtil.getProcessOutput("adb shell am force-stop " + appId).then(function () {
243279
var waitStart = Date.now();
244-
return Q.delay(10000).then(function () {
280+
return waitForAndroidAppToStop(appId, 10000).then(function () {
245281
console.log("[TIMING] android endRunningApplication: force-stop took " + (Date.now() - t0) + "ms, teardown wait took " + (Date.now() - waitStart) + "ms");
246282
});
247283
});

0 commit comments

Comments
 (0)