appium-webdriveragent
Version:
Package bundling WebDriverAgent
132 lines • 4.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.killAppUsingPattern = killAppUsingPattern;
exports.resetTestProcesses = resetTestProcesses;
exports.getPIDsListeningOnPort = getPIDsListeningOnPort;
const asyncbox_1 = require("asyncbox");
const teen_process_1 = require("teen_process");
const logger_1 = require("../logger");
/**
* Find and terminate all processes matching the given pgrep pattern.
*/
async function killAppUsingPattern(pgrepPattern) {
const signals = [2, 15, 9];
for (const signal of signals) {
const matchedPids = await getPIDsUsingPattern(pgrepPattern);
if (matchedPids.length === 0) {
return;
}
const args = [`-${signal}`, ...matchedPids];
try {
await (0, teen_process_1.exec)('kill', args);
}
catch (err) {
logger_1.log.debug(`kill ${args.join(' ')} -> ${err.message}`);
}
if (signal === signals[signals.length - 1]) {
// there is no need to wait after SIGKILL
return;
}
try {
await (0, asyncbox_1.waitForCondition)(async () => {
const pidCheckPromises = matchedPids.map(async (pid) => {
try {
await (0, teen_process_1.exec)('kill', ['-0', pid]);
// the process is still alive
return false;
}
catch {
// the process is dead
return true;
}
});
return (await Promise.all(pidCheckPromises)).every((x) => x === true);
}, {
waitMs: 1000,
intervalMs: 100,
});
return;
}
catch {
// try the next signal
}
}
}
/**
* Kills running XCTest processes for the particular device.
*/
async function resetTestProcesses(udid, isSimulator) {
const processPatterns = [`xcodebuild.*${udid}`];
if (isSimulator) {
processPatterns.push(`${udid}.*XCTRunner`);
// Some XCTest launches might not include xcodebuild in their command line
processPatterns.push(`xctest.*${udid}`);
}
logger_1.log.debug(`Killing running processes '${processPatterns.join(', ')}' for the device ${udid}...`);
await Promise.all(processPatterns.map(killAppUsingPattern));
}
/**
* Get the IDs of processes listening on the particular system port.
* It is also possible to apply additional filtering based on the
* process command line.
*
* @param port - The port number.
* @param filteringFunc - Optional lambda function, which
* receives command line string of the particular process
* listening on given port, and is expected to return
* either true or false to include/exclude the corresponding PID
* from the resulting array.
* @returns - the list of matched process ids.
*/
async function getPIDsListeningOnPort(port, filteringFunc = null) {
const result = [];
try {
// This only works since Mac OS X El Capitan
const { stdout } = await (0, teen_process_1.exec)('lsof', ['-ti', `tcp:${port}`]);
result.push(...stdout.trim().split(/\n+/));
}
catch (e) {
if (e.code !== 1) {
// code 1 means no processes. Other errors need reporting
logger_1.log.debug(`Error getting processes listening on port '${port}': ${e.stderr || e.message}`);
}
return result;
}
if (typeof filteringFunc !== 'function') {
return result;
}
const filtered = await Promise.all(result.map(async (pid) => {
let stdout;
try {
({ stdout } = await (0, teen_process_1.exec)('ps', ['-p', pid, '-o', 'command']));
}
catch (e) {
if (e.code === 1) {
// The process does not exist anymore, there's nothing to filter
return null;
}
throw e;
}
return (await filteringFunc(stdout)) ? pid : null;
}));
return filtered.filter((pid) => Boolean(pid));
}
async function getPIDsUsingPattern(pattern) {
const args = [
'-if', // case insensitive, full cmdline match
pattern,
];
try {
const { stdout } = await (0, teen_process_1.exec)('pgrep', args);
return stdout
.split(/\s+/)
.map((x) => parseInt(x, 10))
.filter(Number.isInteger)
.map((x) => `${x}`);
}
catch (err) {
logger_1.log.debug(`'pgrep ${args.join(' ')}' didn't detect any matching processes. Return code: ${err.code}`);
return [];
}
}
//# sourceMappingURL=processes.js.map