@xenon-device-management/xenon 1.17.4 → 1.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenon-device-management/xenon",
3
- "version": "1.17.4",
3
+ "version": "1.17.5",
4
4
  "description": "Xenon - Intelligent Mobile Infrastructure. A self-healing device orchestration platform for Appium.",
5
5
  "main": "./lib/src/index.js",
6
6
  "exports": {
@@ -692,6 +692,12 @@ let IOSStreamService = class IOSStreamService {
692
692
  if (!fs_extra_1.default.existsSync(logDir))
693
693
  fs_extra_1.default.mkdirSync(logDir);
694
694
  const wdaRunLog = path_1.default.join(logDir, `runwda-${udid}.log`);
695
+ // Truncated per run, because this file is also the evidence the failure
696
+ // is classified from. Appending across runs meant a "Did not find test
697
+ // app" line from a day earlier was still matched today, so every later
698
+ // failure of any kind — including one where WDA was demonstrably
699
+ // installed — was reported as "WebDriverAgent is not installed".
700
+ fs_extra_1.default.writeFileSync(wdaRunLog, '');
695
701
  (_a = session.wdaProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (d) => fs_extra_1.default.appendFileSync(wdaRunLog, d));
696
702
  (_b = session.wdaProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (d) => fs_extra_1.default.appendFileSync(wdaRunLog, d));
697
703
  // 4. Wait for WDA to be ready
@@ -770,11 +776,16 @@ let IOSStreamService = class IOSStreamService {
770
776
  }
771
777
  if (((_c = session.wdaProcess) === null || _c === void 0 ? void 0 : _c.exitCode) !== null) {
772
778
  const logContent = fs_extra_1.default.existsSync(wdaRunLog) ? fs_extra_1.default.readFileSync(wdaRunLog, 'utf8') : '';
773
- // Missing WDA is permanent until the app is installed — surface an
774
- // actionable reason instead of a raw exit code + log tail.
779
+ // Both of these are permanent until a human acts, and they call for
780
+ // opposite actions — install the app, versus trust the app that is
781
+ // already installed. Surface which, rather than a raw exit code and
782
+ // a log tail.
775
783
  if ((0, iosStreamDiagnostics_1.isMissingWdaError)(logContent)) {
776
784
  throw new Error((0, iosStreamDiagnostics_1.missingWdaMessage)(udid));
777
785
  }
786
+ if ((0, iosStreamDiagnostics_1.isWdaLaunchFailure)(logContent)) {
787
+ throw new Error((0, iosStreamDiagnostics_1.wdaLaunchFailureMessage)(udid));
788
+ }
778
789
  throw new Error(`WDA process exited with code ${(_d = session.wdaProcess) === null || _d === void 0 ? void 0 : _d.exitCode}. Log: ${logContent.slice(-200)}`);
779
790
  }
780
791
  yield new Promise((resolve) => setTimeout(resolve, 1000));
@@ -9,6 +9,8 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.isMissingWdaError = isMissingWdaError;
11
11
  exports.missingWdaMessage = missingWdaMessage;
12
+ exports.isWdaLaunchFailure = isWdaLaunchFailure;
13
+ exports.wdaLaunchFailureMessage = wdaLaunchFailureMessage;
12
14
  exports.classifyTunnelStderr = classifyTunnelStderr;
13
15
  exports.isOwnStreamProcess = isOwnStreamProcess;
14
16
  /**
@@ -27,6 +29,34 @@ function missingWdaMessage(udid) {
27
29
  return (`WebDriverAgent is not installed on ${udid}. ` +
28
30
  `Live streaming requires the WebDriverAgentRunner app — install WDA on this device to enable the mirror.`);
29
31
  }
32
+ /**
33
+ * True when WDA is installed but the runner could not be *started*.
34
+ *
35
+ * go-ios reports the two conditions quite differently, and conflating them
36
+ * sends people to reinstall an app that is already there:
37
+ *
38
+ * missing: cannot get test app information: Did not find test app for '…'
39
+ * present: cannot start test runner: LaunchAppWithStdIo: failed to launch
40
+ * app: launchApp: failed to get PID
41
+ *
42
+ * The second is nearly always the device refusing to run the binary — an
43
+ * untrusted developer certificate, a locked screen, or a lapsed signature —
44
+ * none of which reinstalling addresses on its own.
45
+ */
46
+ function isWdaLaunchFailure(logContent) {
47
+ if (!logContent)
48
+ return false;
49
+ return (/failed to launch app/i.test(logContent) ||
50
+ /LaunchAppWithStdIo/i.test(logContent) ||
51
+ /cannot start test runner/i.test(logContent));
52
+ }
53
+ /** Human-facing, actionable message for the installed-but-unlaunchable case. */
54
+ function wdaLaunchFailureMessage(udid) {
55
+ return (`WebDriverAgent is installed on ${udid} but would not start. ` +
56
+ `This is usually the device refusing to run it: trust the developer certificate under ` +
57
+ `Settings → General → VPN & Device Management, unlock the screen, and check the signing ` +
58
+ `profile has not expired. Launching WebDriverAgentRunner once by hand confirms it.`);
59
+ }
30
60
  /**
31
61
  * Classify a chunk of go-ios `tunnel start` stderr.
32
62
  *
@@ -2,6 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const chai_1 = require("chai");
4
4
  const iosStreamDiagnostics_1 = require("../../src/device-managers/ios/iosStreamDiagnostics");
5
+ /**
6
+ * Both verbatim from a real go-ios run log, and the whole point is that they
7
+ * mean opposite things: reinstall the app, versus trust the app that is
8
+ * already installed.
9
+ */
10
+ const GO_IOS_MISSING = `{"level":"ERROR","msg":"Failed running WDA","error":"runXUITestWithBundleIdsXcode15Ctx: ` +
11
+ `cannot get test app information: Did not find test app for ` +
12
+ `'com.qasecret.WebDriverAgentRunner.xctrunner' on device. Is it installed?"}`;
13
+ const GO_IOS_WONT_LAUNCH = `{"level":"ERROR","msg":"Failed running WDA","error":"runXUITestWithBundleIdsXcode15Ctx: ` +
14
+ `cannot start test runner: LaunchAppWithStdIo: failed to launch app: launchApp: ` +
15
+ `failed to get PID: pidFromResponse: could not get pid"}`;
5
16
  describe('iosStreamDiagnostics', () => {
6
17
  describe('isMissingWdaError', () => {
7
18
  it('detects the go-ios "Did not find test app" WDA crash', () => {
@@ -25,6 +36,44 @@ describe('iosStreamDiagnostics', () => {
25
36
  (0, chai_1.expect)(msg.toLowerCase()).to.contain('install');
26
37
  });
27
38
  });
39
+ describe('telling "not installed" apart from "would not start"', () => {
40
+ it('reads the real missing-app log as missing', () => {
41
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isMissingWdaError)(GO_IOS_MISSING)).to.equal(true);
42
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isWdaLaunchFailure)(GO_IOS_MISSING)).to.equal(false);
43
+ });
44
+ it('reads the real launch-failure log as a launch failure, not as missing', () => {
45
+ // This is the one that was reported as "WebDriverAgent is not installed"
46
+ // against a device where it demonstrably was installed, sending the
47
+ // reader off to reinstall an app that was already there.
48
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isWdaLaunchFailure)(GO_IOS_WONT_LAUNCH)).to.equal(true);
49
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isMissingWdaError)(GO_IOS_WONT_LAUNCH)).to.equal(false);
50
+ });
51
+ it('gives the two cases opposite advice', () => {
52
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.missingWdaMessage)('udid-1')).to.contain('not installed');
53
+ const launch = (0, iosStreamDiagnostics_1.wdaLaunchFailureMessage)('udid-1');
54
+ (0, chai_1.expect)(launch).to.contain('is installed');
55
+ (0, chai_1.expect)(launch).to.contain('VPN & Device Management');
56
+ (0, chai_1.expect)(launch).to.not.contain('not installed');
57
+ });
58
+ it('is safe on empty input', () => {
59
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isWdaLaunchFailure)('')).to.equal(false);
60
+ });
61
+ it('is why the run log must be truncated per run', () => {
62
+ // These classifiers read a file, and the file used to be appended to
63
+ // across runs. A stale "Did not find test app" from a previous day still
64
+ // wins over today's launch failure — which is exactly how an installed
65
+ // WDA came to be reported as missing. IOSStreamService now empties the
66
+ // log before each spawn; this pins what happens if it stops.
67
+ const stale = `${GO_IOS_MISSING}\n${GO_IOS_WONT_LAUNCH}`;
68
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isMissingWdaError)(stale)).to.equal(true);
69
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isWdaLaunchFailure)(stale)).to.equal(true);
70
+ });
71
+ it('does not flag an unrelated crash as either', () => {
72
+ const crash = 'WDA crashed: signal 11 (SIGSEGV)';
73
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isMissingWdaError)(crash)).to.equal(false);
74
+ (0, chai_1.expect)((0, iosStreamDiagnostics_1.isWdaLaunchFailure)(crash)).to.equal(false);
75
+ });
76
+ });
28
77
  describe('classifyTunnelStderr', () => {
29
78
  it('extracts the real target udid from the go-ios JSON payload', () => {
30
79
  const line = JSON.stringify({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenon-device-management/xenon",
3
- "version": "1.17.4",
3
+ "version": "1.17.5",
4
4
  "description": "Xenon - Intelligent Mobile Infrastructure. A self-healing device orchestration platform for Appium.",
5
5
  "main": "./lib/src/index.js",
6
6
  "exports": {