obsidian-integration-testing 11.0.0 → 12.1.0
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/dist/lib/cjs/adb-device-list.cjs +54 -0
- package/dist/lib/cjs/adb-device-list.d.cts +72 -0
- package/dist/lib/cjs/android-sdk.cjs +52 -0
- package/dist/lib/cjs/android-sdk.d.cts +29 -0
- package/dist/lib/cjs/app-startup-progress.cjs +87 -0
- package/dist/lib/cjs/app-startup-progress.d.cts +128 -0
- package/dist/lib/cjs/appium-server-marker.cjs +112 -0
- package/dist/lib/cjs/appium-server-marker.d.cts +103 -0
- package/dist/lib/cjs/avd-probe-verdict.cjs +90 -0
- package/dist/lib/cjs/avd-probe-verdict.d.cts +175 -0
- package/dist/lib/cjs/cli.cjs +104 -19
- package/dist/lib/cjs/cli.d.cts +16 -8
- package/dist/lib/cjs/community-plugin-registry.cjs +52 -0
- package/dist/lib/cjs/community-plugin-registry.d.cts +116 -0
- package/dist/lib/cjs/config-directory-fallback-error.cjs +57 -0
- package/dist/lib/cjs/config-directory-fallback-error.d.cts +64 -0
- package/dist/lib/cjs/config-directory.cjs +46 -0
- package/dist/lib/cjs/config-directory.d.cts +45 -0
- package/dist/lib/cjs/connect-to-cdp.cjs +13 -7
- package/dist/lib/cjs/connect-to-cdp.d.cts +19 -0
- package/dist/lib/cjs/context-provider.cjs +12 -1
- package/dist/lib/cjs/context-provider.d.cts +26 -3
- package/dist/lib/cjs/demo-vault-bootstrap.cjs +148 -0
- package/dist/lib/cjs/demo-vault-bootstrap.d.cts +114 -0
- package/dist/lib/cjs/demo-vault-populate.cjs +38 -10
- package/dist/lib/cjs/demo-vault-populate.d.cts +70 -0
- package/dist/lib/cjs/device-readiness.cjs +38 -3
- package/dist/lib/cjs/device-readiness.d.cts +83 -9
- package/dist/lib/cjs/emulator-arguments.cjs +6 -2
- package/dist/lib/cjs/emulator-arguments.d.cts +26 -0
- package/dist/lib/cjs/emulator-backend.cjs +71 -0
- package/dist/lib/cjs/emulator-backend.d.cts +76 -0
- package/dist/lib/cjs/emulator-liveness.cjs +72 -0
- package/dist/lib/cjs/emulator-liveness.d.cts +158 -0
- package/dist/lib/cjs/emulator-snapshot.cjs +57 -0
- package/dist/lib/cjs/emulator-snapshot.d.cts +68 -0
- package/dist/lib/cjs/eval-in-obsidian.cjs +1 -1
- package/dist/lib/cjs/eval-in-obsidian.d.cts +42 -13
- package/dist/lib/cjs/global-setup-core.cjs +30 -30
- package/dist/lib/cjs/global-setup-core.d.cts +27 -2
- package/dist/lib/cjs/headless-vault-config.cjs +51 -0
- package/dist/lib/cjs/headless-vault-config.d.cts +67 -0
- package/dist/lib/cjs/index.cjs +24 -1
- package/dist/lib/cjs/index.d.cts +14 -5
- package/dist/lib/cjs/installer-asset.cjs +1 -1
- package/dist/lib/cjs/installer-asset.d.cts +1 -1
- package/dist/lib/cjs/integration-setup-failed-error.cjs +62 -0
- package/dist/lib/cjs/integration-setup-failed-error.d.cts +66 -0
- package/dist/lib/cjs/jest/global-setup.cjs +2 -2
- package/dist/lib/cjs/jest/global-setup.d.cts +5 -1
- package/dist/lib/cjs/kill-process-tree.cjs +18 -7
- package/dist/lib/cjs/kill-process-tree.d.cts +10 -2
- package/dist/lib/cjs/library.cjs +1 -1
- package/dist/lib/cjs/mobile-input.cjs +173 -0
- package/dist/lib/cjs/mobile-input.d.cts +156 -0
- package/dist/lib/cjs/namespace-bootstrap.cjs +92 -9
- package/dist/lib/cjs/obsidian-installer.cjs +1 -1
- package/dist/lib/cjs/obsidian-instance.cjs +52 -3
- package/dist/lib/cjs/obsidian-instance.d.cts +12 -0
- package/dist/lib/cjs/obsidian-metadata.cjs +123 -17
- package/dist/lib/cjs/obsidian-metadata.d.cts +17 -6
- package/dist/lib/cjs/obsidian-version-switch.cjs +3 -3
- package/dist/lib/cjs/open-obsidian-settings-tab.cjs +1 -1
- package/dist/lib/cjs/open-obsidian-settings-tab.d.cts +3 -2
- package/dist/lib/cjs/owned-instance-exit-marker.cjs +99 -0
- package/dist/lib/cjs/owned-instance-exit-marker.d.cts +106 -0
- package/dist/lib/cjs/owned-instance-exited-error.cjs +106 -0
- package/dist/lib/cjs/owned-instance-exited-error.d.cts +98 -0
- package/dist/lib/cjs/owned-vault-seed.cjs +9 -5
- package/dist/lib/cjs/owned-vault-seed.d.cts +24 -3
- package/dist/lib/cjs/parent-liveness.cjs +42 -5
- package/dist/lib/cjs/parent-liveness.d.cts +37 -5
- package/dist/lib/cjs/port-owner.cjs +61 -0
- package/dist/lib/cjs/port-owner.d.cts +47 -0
- package/dist/lib/cjs/process-capture.cjs +62 -0
- package/dist/lib/cjs/process-capture.d.cts +83 -0
- package/dist/lib/cjs/process-exit-message.cjs +14 -8
- package/dist/lib/cjs/process-exit-message.d.cts +37 -3
- package/dist/lib/cjs/process-liveness.cjs +51 -0
- package/dist/lib/cjs/process-liveness.d.cts +18 -0
- package/dist/lib/cjs/release-catalog.cjs +73 -0
- package/dist/lib/cjs/release-catalog.d.cts +125 -0
- package/dist/lib/cjs/run-version-matrix.cjs +1 -1
- package/dist/lib/cjs/run-version-matrix.d.cts +1 -1
- package/dist/lib/cjs/teardown-verdict.cjs +53 -0
- package/dist/lib/cjs/teardown-verdict.d.cts +69 -0
- package/dist/lib/cjs/temporary-vault.cjs +43 -8
- package/dist/lib/cjs/temporary-vault.d.cts +47 -5
- package/dist/lib/cjs/transport-appium.cjs +223 -17
- package/dist/lib/cjs/transport-appium.d.cts +104 -3
- package/dist/lib/cjs/transport-desktop-cdp.cjs +201 -6
- package/dist/lib/cjs/transport-desktop-cdp.d.cts +100 -0
- package/dist/lib/cjs/transport-factory.cjs +1165 -142
- package/dist/lib/cjs/transport-factory.d.cts +10 -1
- package/dist/lib/cjs/transport-options.cjs +11 -3
- package/dist/lib/cjs/transport-options.d.cts +131 -12
- package/dist/lib/cjs/transport.cjs +1 -1
- package/dist/lib/cjs/transport.d.cts +7 -1
- package/dist/lib/cjs/vault-plugin-install.cjs +40 -0
- package/dist/lib/cjs/vault-plugin-install.d.cts +64 -0
- package/dist/lib/cjs/vault-teardown-verdict.cjs +42 -0
- package/dist/lib/cjs/vault-teardown-verdict.d.cts +57 -0
- package/dist/lib/cjs/version-matrix.cjs +1 -1
- package/dist/lib/cjs/version-matrix.d.cts +2 -2
- package/dist/lib/cjs/vitest/global-setup.cjs +13 -7
- package/dist/lib/cjs/vitest/global-setup.d.cts +5 -1
- package/dist/lib/cjs/vitest/setup.cjs +2 -1
- package/dist/lib/cjs/vitest/setup.d.cts +5 -0
- package/dist/lib/cjs/vitest/typings.d.cts +6 -4
- package/dist/lib/cjs/webview-cdp.cjs +263 -0
- package/dist/lib/cjs/webview-cdp.d.cts +156 -0
- package/dist/lib/cjs/wedged-appium-server.cjs +113 -0
- package/dist/lib/cjs/wedged-appium-server.d.cts +187 -0
- package/dist/lib/esm/adb-device-list.d.mts +72 -0
- package/dist/lib/esm/adb-device-list.mjs +28 -0
- package/dist/lib/esm/android-sdk.d.mts +29 -0
- package/dist/lib/esm/android-sdk.mjs +18 -0
- package/dist/lib/esm/app-startup-progress.d.mts +128 -0
- package/dist/lib/esm/app-startup-progress.mjs +59 -0
- package/dist/lib/esm/appium-server-marker.d.mts +103 -0
- package/dist/lib/esm/appium-server-marker.mjs +89 -0
- package/dist/lib/esm/avd-probe-verdict.d.mts +175 -0
- package/dist/lib/esm/avd-probe-verdict.mjs +62 -0
- package/dist/lib/esm/cli.d.mts +16 -8
- package/dist/lib/esm/cli.mjs +110 -19
- package/dist/lib/esm/community-plugin-registry.d.mts +116 -0
- package/dist/lib/esm/community-plugin-registry.mjs +23 -0
- package/dist/lib/esm/config-directory-fallback-error.d.mts +64 -0
- package/dist/lib/esm/config-directory-fallback-error.mjs +33 -0
- package/dist/lib/esm/config-directory.d.mts +45 -0
- package/dist/lib/esm/config-directory.mjs +21 -0
- package/dist/lib/esm/connect-to-cdp.d.mts +19 -0
- package/dist/lib/esm/connect-to-cdp.mjs +13 -7
- package/dist/lib/esm/context-provider.d.mts +26 -3
- package/dist/lib/esm/context-provider.mjs +10 -1
- package/dist/lib/esm/demo-vault-bootstrap.d.mts +114 -0
- package/dist/lib/esm/demo-vault-bootstrap.mjs +127 -0
- package/dist/lib/esm/demo-vault-populate.d.mts +70 -0
- package/dist/lib/esm/demo-vault-populate.mjs +35 -9
- package/dist/lib/esm/device-readiness.d.mts +83 -9
- package/dist/lib/esm/device-readiness.mjs +34 -2
- package/dist/lib/esm/emulator-arguments.d.mts +26 -0
- package/dist/lib/esm/emulator-arguments.mjs +6 -2
- package/dist/lib/esm/emulator-backend.d.mts +76 -0
- package/dist/lib/esm/emulator-backend.mjs +45 -0
- package/dist/lib/esm/emulator-liveness.d.mts +158 -0
- package/dist/lib/esm/emulator-liveness.mjs +47 -0
- package/dist/lib/esm/emulator-snapshot.d.mts +68 -0
- package/dist/lib/esm/emulator-snapshot.mjs +32 -0
- package/dist/lib/esm/eval-in-obsidian.d.mts +42 -13
- package/dist/lib/esm/eval-in-obsidian.mjs +1 -1
- package/dist/lib/esm/global-setup-core.d.mts +27 -2
- package/dist/lib/esm/global-setup-core.mjs +34 -35
- package/dist/lib/esm/headless-vault-config.d.mts +67 -0
- package/dist/lib/esm/headless-vault-config.mjs +31 -0
- package/dist/lib/esm/index.d.mts +14 -5
- package/dist/lib/esm/index.mjs +26 -2
- package/dist/lib/esm/installer-asset.d.mts +1 -1
- package/dist/lib/esm/installer-asset.mjs +1 -1
- package/dist/lib/esm/integration-setup-failed-error.d.mts +66 -0
- package/dist/lib/esm/integration-setup-failed-error.mjs +38 -0
- package/dist/lib/esm/jest/global-setup.d.mts +5 -1
- package/dist/lib/esm/jest/global-setup.mjs +2 -2
- package/dist/lib/esm/kill-process-tree.d.mts +10 -2
- package/dist/lib/esm/kill-process-tree.mjs +16 -6
- package/dist/lib/esm/library.mjs +1 -1
- package/dist/lib/esm/mobile-input.d.mts +156 -0
- package/dist/lib/esm/mobile-input.mjs +144 -0
- package/dist/lib/esm/namespace-bootstrap.mjs +95 -9
- package/dist/lib/esm/obsidian-installer.mjs +1 -1
- package/dist/lib/esm/obsidian-instance.d.mts +12 -0
- package/dist/lib/esm/obsidian-instance.mjs +55 -3
- package/dist/lib/esm/obsidian-metadata.d.mts +17 -6
- package/dist/lib/esm/obsidian-metadata.mjs +123 -17
- package/dist/lib/esm/obsidian-version-switch.mjs +3 -3
- package/dist/lib/esm/open-obsidian-settings-tab.d.mts +3 -2
- package/dist/lib/esm/open-obsidian-settings-tab.mjs +1 -1
- package/dist/lib/esm/owned-instance-exit-marker.d.mts +106 -0
- package/dist/lib/esm/owned-instance-exit-marker.mjs +78 -0
- package/dist/lib/esm/owned-instance-exited-error.d.mts +98 -0
- package/dist/lib/esm/owned-instance-exited-error.mjs +81 -0
- package/dist/lib/esm/owned-vault-seed.d.mts +24 -3
- package/dist/lib/esm/owned-vault-seed.mjs +9 -5
- package/dist/lib/esm/parent-liveness.d.mts +37 -5
- package/dist/lib/esm/parent-liveness.mjs +42 -5
- package/dist/lib/esm/port-owner.d.mts +47 -0
- package/dist/lib/esm/port-owner.mjs +36 -0
- package/dist/lib/esm/process-capture.d.mts +83 -0
- package/dist/lib/esm/process-capture.mjs +38 -0
- package/dist/lib/esm/process-exit-message.d.mts +37 -3
- package/dist/lib/esm/process-exit-message.mjs +13 -8
- package/dist/lib/esm/process-liveness.d.mts +18 -0
- package/dist/lib/esm/process-liveness.mjs +17 -0
- package/dist/lib/esm/release-catalog.d.mts +125 -0
- package/dist/lib/esm/release-catalog.mjs +46 -0
- package/dist/lib/esm/run-version-matrix.d.mts +1 -1
- package/dist/lib/esm/run-version-matrix.mjs +1 -1
- package/dist/lib/esm/teardown-verdict.d.mts +69 -0
- package/dist/lib/esm/teardown-verdict.mjs +28 -0
- package/dist/lib/esm/temporary-vault.d.mts +47 -5
- package/dist/lib/esm/temporary-vault.mjs +43 -8
- package/dist/lib/esm/transport-appium.d.mts +104 -3
- package/dist/lib/esm/transport-appium.mjs +233 -17
- package/dist/lib/esm/transport-desktop-cdp.d.mts +100 -0
- package/dist/lib/esm/transport-desktop-cdp.mjs +208 -7
- package/dist/lib/esm/transport-factory.d.mts +10 -1
- package/dist/lib/esm/transport-factory.mjs +1220 -149
- package/dist/lib/esm/transport-options.d.mts +131 -12
- package/dist/lib/esm/transport-options.mjs +9 -2
- package/dist/lib/esm/transport.d.mts +7 -1
- package/dist/lib/esm/vault-plugin-install.d.mts +64 -0
- package/dist/lib/esm/vault-plugin-install.mjs +20 -0
- package/dist/lib/esm/vault-teardown-verdict.d.mts +57 -0
- package/dist/lib/esm/vault-teardown-verdict.mjs +18 -0
- package/dist/lib/esm/version-matrix.d.mts +2 -2
- package/dist/lib/esm/version-matrix.mjs +1 -1
- package/dist/lib/esm/vitest/global-setup.d.mts +5 -1
- package/dist/lib/esm/vitest/global-setup.mjs +14 -7
- package/dist/lib/esm/vitest/setup.d.mts +5 -0
- package/dist/lib/esm/vitest/setup.mjs +3 -1
- package/dist/lib/esm/vitest/typings.d.mts +6 -4
- package/dist/lib/esm/webview-cdp.d.mts +156 -0
- package/dist/lib/esm/webview-cdp.mjs +235 -0
- package/dist/lib/esm/wedged-appium-server.d.mts +187 -0
- package/dist/lib/esm/wedged-appium-server.mjs +86 -0
- package/package.json +25 -23
- package/dist/lib/cjs/native-dialog-monitor.cjs +0 -192
- package/dist/lib/cjs/native-dialog-monitor.d.cts +0 -66
- package/dist/lib/cjs/obsidian-namespace.cjs +0 -17
- package/dist/lib/cjs/obsidian-namespace.d.cts +0 -128
- package/dist/lib/esm/native-dialog-monitor.d.mts +0 -66
- package/dist/lib/esm/native-dialog-monitor.mjs +0 -158
- package/dist/lib/esm/obsidian-namespace.d.mts +0 -128
- package/dist/lib/esm/obsidian-namespace.mjs +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers for recognizing a **wedged** Appium server and deciding what to
|
|
5
|
+
* do about it. Kept separate from the integration-only `transport-factory` so
|
|
6
|
+
* the classification, the remedy decision and the message stay unit-testable
|
|
7
|
+
* (the factory itself needs a real device and is excluded from unit tests).
|
|
8
|
+
*
|
|
9
|
+
* A wedged server is one that is still **live** — it listens on its port and
|
|
10
|
+
* answers `/status` with `ready: true` — but is no longer **usable**: its
|
|
11
|
+
* `appium-adb` can no longer enumerate devices, so every session creation dies
|
|
12
|
+
* with `Could not find a connected Android device in <n>ms` while the host's own
|
|
13
|
+
* `adb devices` lists the device instantly. Liveness is not readiness, and the
|
|
14
|
+
* error names the wrong subject: it blames a device that is demonstrably
|
|
15
|
+
* present, which sends whoever reads it to `adb devices` — the one diagnostic
|
|
16
|
+
* that actively misleads here.
|
|
17
|
+
*
|
|
18
|
+
* The wedge develops over time in a long-lived server (one auto-started by an
|
|
19
|
+
* earlier run and left listening), so the preflight cannot see it coming: it can
|
|
20
|
+
* only be recognized from the failed session, cross-checked against the host's
|
|
21
|
+
* adb.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Parameters for {@link buildWedgedAppiumServerMessage}.
|
|
25
|
+
*/
|
|
26
|
+
export interface BuildWedgedAppiumServerMessageParams {
|
|
27
|
+
/**
|
|
28
|
+
Origin of the Appium server that could not see the device (e.g. `http://localhost:4723`).
|
|
29
|
+
*/
|
|
30
|
+
readonly appiumOrigin: string;
|
|
31
|
+
/**
|
|
32
|
+
The device the host's adb can see but Appium cannot.
|
|
33
|
+
*/
|
|
34
|
+
readonly deviceId: string;
|
|
35
|
+
/**
|
|
36
|
+
Why this run is reporting rather than restarting.
|
|
37
|
+
*/
|
|
38
|
+
readonly reason: WedgedAppiumServerReportReason;
|
|
39
|
+
/**
|
|
40
|
+
How long the server has been running, when known from its marker.
|
|
41
|
+
*/
|
|
42
|
+
readonly serverAgeInMilliseconds?: number | undefined;
|
|
43
|
+
/**
|
|
44
|
+
PID of the server, when known from its marker.
|
|
45
|
+
*/
|
|
46
|
+
readonly serverPid?: number | undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The server is not to blame: either the failure was a different error, or the
|
|
50
|
+
* host's adb cannot see the device either. The original error is rethrown.
|
|
51
|
+
*/
|
|
52
|
+
export interface NotWedgedVerdict {
|
|
53
|
+
/**
|
|
54
|
+
Which of the two honest-failure cases this is.
|
|
55
|
+
*/
|
|
56
|
+
readonly reason: 'device-absent' | 'other-error';
|
|
57
|
+
/**
|
|
58
|
+
Discriminant.
|
|
59
|
+
*/
|
|
60
|
+
readonly remedy: 'not-wedged';
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The server is wedged but must not be touched by this run.
|
|
64
|
+
*/
|
|
65
|
+
export interface ReportServerVerdict {
|
|
66
|
+
/**
|
|
67
|
+
Why this run is reporting rather than restarting.
|
|
68
|
+
*/
|
|
69
|
+
readonly reason: WedgedAppiumServerReportReason;
|
|
70
|
+
/**
|
|
71
|
+
Discriminant.
|
|
72
|
+
*/
|
|
73
|
+
readonly remedy: 'report';
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Parameters for {@link resolveWedgedAppiumServerRemedy}.
|
|
77
|
+
*/
|
|
78
|
+
export interface ResolveWedgedAppiumServerRemedyParams {
|
|
79
|
+
/**
|
|
80
|
+
Device IDs the **host's** adb currently lists (the cross-check that convicts the server).
|
|
81
|
+
*/
|
|
82
|
+
readonly connectedDeviceIds: readonly string[];
|
|
83
|
+
/**
|
|
84
|
+
The device the session was requested against.
|
|
85
|
+
*/
|
|
86
|
+
readonly deviceId: string;
|
|
87
|
+
/**
|
|
88
|
+
The error the session attempt failed with.
|
|
89
|
+
*/
|
|
90
|
+
readonly error: unknown;
|
|
91
|
+
/**
|
|
92
|
+
Whether the server was already listening and was adopted, rather than started by this run.
|
|
93
|
+
*/
|
|
94
|
+
readonly isAdoptedServer: boolean;
|
|
95
|
+
/**
|
|
96
|
+
Whether this run may start an Appium server (`shouldAutoStartAppium` is not `false`).
|
|
97
|
+
*/
|
|
98
|
+
readonly isAutoStartAllowed: boolean;
|
|
99
|
+
/**
|
|
100
|
+
Whether the adopted server's marker proves an earlier run of this harness started it.
|
|
101
|
+
*/
|
|
102
|
+
readonly isHarnessOwnedServer: boolean;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The server is wedged and an earlier run of this harness started it, so this
|
|
106
|
+
* run may replace it.
|
|
107
|
+
*/
|
|
108
|
+
export interface RestartServerVerdict {
|
|
109
|
+
/**
|
|
110
|
+
Always the harness-owned case.
|
|
111
|
+
*/
|
|
112
|
+
readonly reason: 'harness-owned';
|
|
113
|
+
/**
|
|
114
|
+
Discriminant.
|
|
115
|
+
*/
|
|
116
|
+
readonly remedy: 'restart';
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The classification of a failed session attempt.
|
|
120
|
+
*
|
|
121
|
+
* `'device-absent'` and `'other-error'` are the not-wedged verdicts: the
|
|
122
|
+
* original error was honest and is rethrown untouched.
|
|
123
|
+
*/
|
|
124
|
+
export type WedgedAppiumServerReason = 'device-absent' | 'harness-owned' | 'other-error' | WedgedAppiumServerReportReason;
|
|
125
|
+
/**
|
|
126
|
+
* What the factory should do with a failed session attempt.
|
|
127
|
+
*/
|
|
128
|
+
export type WedgedAppiumServerRemedy = 'not-wedged' | 'report' | 'restart';
|
|
129
|
+
/**
|
|
130
|
+
* Why a wedged server is only reported rather than restarted. Each maps to its
|
|
131
|
+
* own remedy sentence — the whole point of the rewrite is that the message says
|
|
132
|
+
* what *this* run can and cannot do about the server it found.
|
|
133
|
+
*/
|
|
134
|
+
export type WedgedAppiumServerReportReason = 'auto-start-disabled' | 'foreign-server' | 'freshly-started' | 'restart-did-not-help';
|
|
135
|
+
/**
|
|
136
|
+
* The verdict on a failed session attempt, discriminated by `remedy` so a
|
|
137
|
+
* `'report'` verdict carries a reason {@link buildWedgedAppiumServerMessage} can
|
|
138
|
+
* turn into advice.
|
|
139
|
+
*/
|
|
140
|
+
export type WedgedAppiumServerVerdict = NotWedgedVerdict | ReportServerVerdict | RestartServerVerdict;
|
|
141
|
+
/**
|
|
142
|
+
* Builds the error message that replaces `Could not find a connected Android
|
|
143
|
+
* device`, naming the **server** and stating the evidence — the host's adb can
|
|
144
|
+
* see the device, so the server is the thing that is stale.
|
|
145
|
+
*
|
|
146
|
+
* @param params - The server, the device, and why this run is not restarting it.
|
|
147
|
+
* @returns The message.
|
|
148
|
+
*/
|
|
149
|
+
export declare function buildWedgedAppiumServerMessage(params: BuildWedgedAppiumServerMessageParams): string;
|
|
150
|
+
/**
|
|
151
|
+
* Checks whether a failed session attempt is `appium-adb`'s device-enumeration
|
|
152
|
+
* failure. The whole `cause` chain is searched, so WebdriverIO's wrapping of the
|
|
153
|
+
* server's error does not hide it.
|
|
154
|
+
*
|
|
155
|
+
* @param error - The error the session attempt failed with.
|
|
156
|
+
* @returns `true` when it is the device-not-found failure.
|
|
157
|
+
*/
|
|
158
|
+
export declare function checkIsAppiumDeviceNotFoundError(error: unknown): boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Checks whether an Appium `/status` body reports a server that is accepting new
|
|
161
|
+
* sessions.
|
|
162
|
+
*
|
|
163
|
+
* Deliberately **tolerant**: only an explicit `ready: false` (Appium sets it
|
|
164
|
+
* while shutting down) is treated as not-ready. A body that cannot be parsed, or
|
|
165
|
+
* that omits the flag, reads as ready — an unrecognized shape must not make a
|
|
166
|
+
* healthy server look unreachable.
|
|
167
|
+
*
|
|
168
|
+
* This does not catch the wedge (a wedged server still answers `ready: true`);
|
|
169
|
+
* it closes the adjacent hole of adopting a server that is on its way down.
|
|
170
|
+
*
|
|
171
|
+
* @param statusBody - The raw `/status` response body.
|
|
172
|
+
* @returns `false` only when the server explicitly reports itself not ready.
|
|
173
|
+
*/
|
|
174
|
+
export declare function checkIsAppiumStatusReady(statusBody: string): boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Decides what to do with a failed session attempt.
|
|
177
|
+
*
|
|
178
|
+
* The device-not-found error is only evidence against the server when the host's
|
|
179
|
+
* adb *can* still see the device; otherwise the error was honest and is left
|
|
180
|
+
* alone. A server this harness started in an earlier run is restarted (the
|
|
181
|
+
* confirmed remedy); every other wedged server is reported rather than killed,
|
|
182
|
+
* because terminating a process this run does not own is not its call to make.
|
|
183
|
+
*
|
|
184
|
+
* @param params - The failed attempt and what is known about the server.
|
|
185
|
+
* @returns The verdict.
|
|
186
|
+
*/
|
|
187
|
+
export declare function resolveWedgedAppiumServerRemedy(params: ResolveWedgedAppiumServerRemedyParams): WedgedAppiumServerVerdict;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers for parsing `adb devices` output.
|
|
5
|
+
*
|
|
6
|
+
* Kept separate from the integration-only `transport-factory` (excluded from
|
|
7
|
+
* unit tests) so the parsing stays unit-testable — the factory itself shells out
|
|
8
|
+
* to `adb`.
|
|
9
|
+
*
|
|
10
|
+
* The listing answers two **different** questions, and conflating them is a
|
|
11
|
+
* defect rather than a nicety:
|
|
12
|
+
*
|
|
13
|
+
* - *Is the device usable?* — only a device in the `device` state is, which is
|
|
14
|
+
* what the session preflight asks ({@link listOnlineDeviceIds}).
|
|
15
|
+
* - *Is the device gone?* — a dying emulator drops to `offline` while it still
|
|
16
|
+
* holds the AVD's `multiinstance.lock` and its console port, so teardown must
|
|
17
|
+
* treat **any** listed state as "still here" ({@link checkIsDeviceListed}).
|
|
18
|
+
* Reading `offline` as gone is what lets the next run collide with a leftover.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* One row of `adb devices`.
|
|
22
|
+
*/
|
|
23
|
+
export interface AdbDeviceEntry {
|
|
24
|
+
/**
|
|
25
|
+
The device UDID, e.g. `emulator-5554`.
|
|
26
|
+
*/
|
|
27
|
+
readonly deviceId: string;
|
|
28
|
+
/**
|
|
29
|
+
The device state adb reports, e.g. `device`, `offline`, `unauthorized`.
|
|
30
|
+
*/
|
|
31
|
+
readonly state: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parameters for {@link checkIsDeviceListed}.
|
|
35
|
+
*/
|
|
36
|
+
export interface CheckIsDeviceListedParams {
|
|
37
|
+
/**
|
|
38
|
+
The device UDID to look for.
|
|
39
|
+
*/
|
|
40
|
+
readonly deviceId: string;
|
|
41
|
+
/**
|
|
42
|
+
Raw stdout of `adb devices`.
|
|
43
|
+
*/
|
|
44
|
+
readonly devicesOutput: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Decides whether a device is still listed at all, **in any state**.
|
|
48
|
+
*
|
|
49
|
+
* This is teardown's question, not the preflight's: an emulator that answers
|
|
50
|
+
* `offline` has not released the AVD.
|
|
51
|
+
*
|
|
52
|
+
* @param params - The listing output and the device to look for.
|
|
53
|
+
* @returns `true` when the device appears in the listing, whatever its state.
|
|
54
|
+
*/
|
|
55
|
+
export declare function checkIsDeviceListed(params: CheckIsDeviceListedParams): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Lists the devices that are actually usable — those in the `device` state.
|
|
58
|
+
*
|
|
59
|
+
* @param devicesOutput - Raw stdout of `adb devices`.
|
|
60
|
+
* @returns The online device IDs, in listed order.
|
|
61
|
+
*/
|
|
62
|
+
export declare function listOnlineDeviceIds(devicesOutput: string): string[];
|
|
63
|
+
/**
|
|
64
|
+
* Parses the rows of `adb devices` into device IDs and states.
|
|
65
|
+
*
|
|
66
|
+
* Every row is `<id>\t<state>`; the `List of devices attached` header and the
|
|
67
|
+
* `* daemon … *` banner carry no tab, which is what distinguishes them.
|
|
68
|
+
*
|
|
69
|
+
* @param devicesOutput - Raw stdout of `adb devices`.
|
|
70
|
+
* @returns One entry per listed device, in listed order.
|
|
71
|
+
*/
|
|
72
|
+
export declare function parseAdbDevices(devicesOutput: string): AdbDeviceEntry[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ONLINE_DEVICE_STATE = "device";
|
|
2
|
+
function checkIsDeviceListed(params) {
|
|
3
|
+
return parseAdbDevices(params.devicesOutput).some((entry) => entry.deviceId === params.deviceId);
|
|
4
|
+
}
|
|
5
|
+
function listOnlineDeviceIds(devicesOutput) {
|
|
6
|
+
return parseAdbDevices(devicesOutput).filter((entry) => entry.state === ONLINE_DEVICE_STATE).map((entry) => entry.deviceId);
|
|
7
|
+
}
|
|
8
|
+
function parseAdbDevices(devicesOutput) {
|
|
9
|
+
const entries = [];
|
|
10
|
+
for (const rawLine of devicesOutput.split("\n")) {
|
|
11
|
+
const line = rawLine.trim();
|
|
12
|
+
const separatorIndex = line.indexOf(" ");
|
|
13
|
+
if (separatorIndex === -1) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
entries.push({
|
|
17
|
+
deviceId: line.slice(0, separatorIndex).trim(),
|
|
18
|
+
state: line.slice(separatorIndex + 1).trim()
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return entries;
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
checkIsDeviceListed,
|
|
25
|
+
listOnlineDeviceIds,
|
|
26
|
+
parseAdbDevices
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2FkYi1kZXZpY2UtbGlzdC50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiLyoqXG4gKiBAZmlsZVxuICpcbiAqIFB1cmUgaGVscGVycyBmb3IgcGFyc2luZyBgYWRiIGRldmljZXNgIG91dHB1dC5cbiAqXG4gKiBLZXB0IHNlcGFyYXRlIGZyb20gdGhlIGludGVncmF0aW9uLW9ubHkgYHRyYW5zcG9ydC1mYWN0b3J5YCAoZXhjbHVkZWQgZnJvbVxuICogdW5pdCB0ZXN0cykgc28gdGhlIHBhcnNpbmcgc3RheXMgdW5pdC10ZXN0YWJsZSBcdTIwMTQgdGhlIGZhY3RvcnkgaXRzZWxmIHNoZWxscyBvdXRcbiAqIHRvIGBhZGJgLlxuICpcbiAqIFRoZSBsaXN0aW5nIGFuc3dlcnMgdHdvICoqZGlmZmVyZW50KiogcXVlc3Rpb25zLCBhbmQgY29uZmxhdGluZyB0aGVtIGlzIGFcbiAqIGRlZmVjdCByYXRoZXIgdGhhbiBhIG5pY2V0eTpcbiAqXG4gKiAtICpJcyB0aGUgZGV2aWNlIHVzYWJsZT8qIFx1MjAxNCBvbmx5IGEgZGV2aWNlIGluIHRoZSBgZGV2aWNlYCBzdGF0ZSBpcywgd2hpY2ggaXNcbiAqICAgd2hhdCB0aGUgc2Vzc2lvbiBwcmVmbGlnaHQgYXNrcyAoe0BsaW5rIGxpc3RPbmxpbmVEZXZpY2VJZHN9KS5cbiAqIC0gKklzIHRoZSBkZXZpY2UgZ29uZT8qIFx1MjAxNCBhIGR5aW5nIGVtdWxhdG9yIGRyb3BzIHRvIGBvZmZsaW5lYCB3aGlsZSBpdCBzdGlsbFxuICogICBob2xkcyB0aGUgQVZEJ3MgYG11bHRpaW5zdGFuY2UubG9ja2AgYW5kIGl0cyBjb25zb2xlIHBvcnQsIHNvIHRlYXJkb3duIG11c3RcbiAqICAgdHJlYXQgKiphbnkqKiBsaXN0ZWQgc3RhdGUgYXMgXCJzdGlsbCBoZXJlXCIgKHtAbGluayBjaGVja0lzRGV2aWNlTGlzdGVkfSkuXG4gKiAgIFJlYWRpbmcgYG9mZmxpbmVgIGFzIGdvbmUgaXMgd2hhdCBsZXRzIHRoZSBuZXh0IHJ1biBjb2xsaWRlIHdpdGggYSBsZWZ0b3Zlci5cbiAqL1xuXG4vKipcbiAqIE9uZSByb3cgb2YgYGFkYiBkZXZpY2VzYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBZGJEZXZpY2VFbnRyeSB7XG4gIC8qKlxuICBUaGUgZGV2aWNlIFVESUQsIGUuZy4gYGVtdWxhdG9yLTU1NTRgLlxuICAgKi9cbiAgcmVhZG9ubHkgZGV2aWNlSWQ6IHN0cmluZztcblxuICAvKipcbiAgVGhlIGRldmljZSBzdGF0ZSBhZGIgcmVwb3J0cywgZS5nLiBgZGV2aWNlYCwgYG9mZmxpbmVgLCBgdW5hdXRob3JpemVkYC5cbiAgICovXG4gIHJlYWRvbmx5IHN0YXRlOiBzdHJpbmc7XG59XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3Ige0BsaW5rIGNoZWNrSXNEZXZpY2VMaXN0ZWR9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENoZWNrSXNEZXZpY2VMaXN0ZWRQYXJhbXMge1xuICAvKipcbiAgVGhlIGRldmljZSBVRElEIHRvIGxvb2sgZm9yLlxuICAgKi9cbiAgcmVhZG9ubHkgZGV2aWNlSWQ6IHN0cmluZztcblxuICAvKipcbiAgUmF3IHN0ZG91dCBvZiBgYWRiIGRldmljZXNgLlxuICAgKi9cbiAgcmVhZG9ubHkgZGV2aWNlc091dHB1dDogc3RyaW5nO1xufVxuXG5jb25zdCBPTkxJTkVfREVWSUNFX1NUQVRFID0gJ2RldmljZSc7XG5cbi8qKlxuICogRGVjaWRlcyB3aGV0aGVyIGEgZGV2aWNlIGlzIHN0aWxsIGxpc3RlZCBhdCBhbGwsICoqaW4gYW55IHN0YXRlKiouXG4gKlxuICogVGhpcyBpcyB0ZWFyZG93bidzIHF1ZXN0aW9uLCBub3QgdGhlIHByZWZsaWdodCdzOiBhbiBlbXVsYXRvciB0aGF0IGFuc3dlcnNcbiAqIGBvZmZsaW5lYCBoYXMgbm90IHJlbGVhc2VkIHRoZSBBVkQuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRoZSBsaXN0aW5nIG91dHB1dCBhbmQgdGhlIGRldmljZSB0byBsb29rIGZvci5cbiAqIEByZXR1cm5zIGB0cnVlYCB3aGVuIHRoZSBkZXZpY2UgYXBwZWFycyBpbiB0aGUgbGlzdGluZywgd2hhdGV2ZXIgaXRzIHN0YXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tJc0RldmljZUxpc3RlZChwYXJhbXM6IENoZWNrSXNEZXZpY2VMaXN0ZWRQYXJhbXMpOiBib29sZWFuIHtcbiAgcmV0dXJuIHBhcnNlQWRiRGV2aWNlcyhwYXJhbXMuZGV2aWNlc091dHB1dCkuc29tZSgoZW50cnkpID0+IGVudHJ5LmRldmljZUlkID09PSBwYXJhbXMuZGV2aWNlSWQpO1xufVxuXG4vKipcbiAqIExpc3RzIHRoZSBkZXZpY2VzIHRoYXQgYXJlIGFjdHVhbGx5IHVzYWJsZSBcdTIwMTQgdGhvc2UgaW4gdGhlIGBkZXZpY2VgIHN0YXRlLlxuICpcbiAqIEBwYXJhbSBkZXZpY2VzT3V0cHV0IC0gUmF3IHN0ZG91dCBvZiBgYWRiIGRldmljZXNgLlxuICogQHJldHVybnMgVGhlIG9ubGluZSBkZXZpY2UgSURzLCBpbiBsaXN0ZWQgb3JkZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsaXN0T25saW5lRGV2aWNlSWRzKGRldmljZXNPdXRwdXQ6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgcmV0dXJuIHBhcnNlQWRiRGV2aWNlcyhkZXZpY2VzT3V0cHV0KVxuICAgIC5maWx0ZXIoKGVudHJ5KSA9PiBlbnRyeS5zdGF0ZSA9PT0gT05MSU5FX0RFVklDRV9TVEFURSlcbiAgICAubWFwKChlbnRyeSkgPT4gZW50cnkuZGV2aWNlSWQpO1xufVxuXG4vKipcbiAqIFBhcnNlcyB0aGUgcm93cyBvZiBgYWRiIGRldmljZXNgIGludG8gZGV2aWNlIElEcyBhbmQgc3RhdGVzLlxuICpcbiAqIEV2ZXJ5IHJvdyBpcyBgPGlkPlxcdDxzdGF0ZT5gOyB0aGUgYExpc3Qgb2YgZGV2aWNlcyBhdHRhY2hlZGAgaGVhZGVyIGFuZCB0aGVcbiAqIGAqIGRhZW1vbiBcdTIwMjYgKmAgYmFubmVyIGNhcnJ5IG5vIHRhYiwgd2hpY2ggaXMgd2hhdCBkaXN0aW5ndWlzaGVzIHRoZW0uXG4gKlxuICogQHBhcmFtIGRldmljZXNPdXRwdXQgLSBSYXcgc3Rkb3V0IG9mIGBhZGIgZGV2aWNlc2AuXG4gKiBAcmV0dXJucyBPbmUgZW50cnkgcGVyIGxpc3RlZCBkZXZpY2UsIGluIGxpc3RlZCBvcmRlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQWRiRGV2aWNlcyhkZXZpY2VzT3V0cHV0OiBzdHJpbmcpOiBBZGJEZXZpY2VFbnRyeVtdIHtcbiAgY29uc3QgZW50cmllczogQWRiRGV2aWNlRW50cnlbXSA9IFtdO1xuXG4gIGZvciAoY29uc3QgcmF3TGluZSBvZiBkZXZpY2VzT3V0cHV0LnNwbGl0KCdcXG4nKSkge1xuICAgIGNvbnN0IGxpbmUgPSByYXdMaW5lLnRyaW0oKTtcbiAgICBjb25zdCBzZXBhcmF0b3JJbmRleCA9IGxpbmUuaW5kZXhPZignXFx0Jyk7XG4gICAgaWYgKHNlcGFyYXRvckluZGV4ID09PSAtMSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgZW50cmllcy5wdXNoKHtcbiAgICAgIGRldmljZUlkOiBsaW5lLnNsaWNlKDAsIHNlcGFyYXRvckluZGV4KS50cmltKCksXG4gICAgICBzdGF0ZTogbGluZS5zbGljZShzZXBhcmF0b3JJbmRleCArIDEpLnRyaW0oKVxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIGVudHJpZXM7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiQUFrREEsTUFBTSxzQkFBc0I7QUFXckIsU0FBUyxvQkFBb0IsUUFBNEM7QUFDOUUsU0FBTyxnQkFBZ0IsT0FBTyxhQUFhLEVBQUUsS0FBSyxDQUFDLFVBQVUsTUFBTSxhQUFhLE9BQU8sUUFBUTtBQUNqRztBQVFPLFNBQVMsb0JBQW9CLGVBQWlDO0FBQ25FLFNBQU8sZ0JBQWdCLGFBQWEsRUFDakMsT0FBTyxDQUFDLFVBQVUsTUFBTSxVQUFVLG1CQUFtQixFQUNyRCxJQUFJLENBQUMsVUFBVSxNQUFNLFFBQVE7QUFDbEM7QUFXTyxTQUFTLGdCQUFnQixlQUF5QztBQUN2RSxRQUFNLFVBQTRCLENBQUM7QUFFbkMsYUFBVyxXQUFXLGNBQWMsTUFBTSxJQUFJLEdBQUc7QUFDL0MsVUFBTSxPQUFPLFFBQVEsS0FBSztBQUMxQixVQUFNLGlCQUFpQixLQUFLLFFBQVEsR0FBSTtBQUN4QyxRQUFJLG1CQUFtQixJQUFJO0FBQ3pCO0FBQUEsSUFDRjtBQUVBLFlBQVEsS0FBSztBQUFBLE1BQ1gsVUFBVSxLQUFLLE1BQU0sR0FBRyxjQUFjLEVBQUUsS0FBSztBQUFBLE1BQzdDLE9BQU8sS0FBSyxNQUFNLGlCQUFpQixDQUFDLEVBQUUsS0FBSztBQUFBLElBQzdDLENBQUM7QUFBQSxFQUNIO0FBRUEsU0FBTztBQUNUOyIsCiAgIm5hbWVzIjogW10KfQo=
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Resolves the Android SDK binaries the harness shells out to.
|
|
5
|
+
*
|
|
6
|
+
* Lives here rather than as a private method on the integration-only
|
|
7
|
+
* `transport-factory` because it is an **agreement**, not an implementation
|
|
8
|
+
* detail: `scripts/emulator-wedge-probe.ts` exists to reproduce a host fault by
|
|
9
|
+
* booting the emulator exactly as a run would, and a probe that resolved a
|
|
10
|
+
* different binary than the harness would quietly measure something else. One
|
|
11
|
+
* function, one answer, both callers.
|
|
12
|
+
*
|
|
13
|
+
* The lookup itself is the SDK's own convention — `ANDROID_HOME` first, then the
|
|
14
|
+
* older `ANDROID_SDK_ROOT` — and it deliberately does **not** fall back to a
|
|
15
|
+
* platform-default install path. A wrong guess would boot some other SDK's
|
|
16
|
+
* emulator and report on it as though it were the configured one; an error that
|
|
17
|
+
* names both variables is the shorter route to a working setup.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the `emulator` binary from the Android SDK root.
|
|
21
|
+
*
|
|
22
|
+
* No extension is appended: Node's process spawning resolves `emulator.exe` on
|
|
23
|
+
* Windows on its own, and the same path string is what the SDK's own tooling
|
|
24
|
+
* documents.
|
|
25
|
+
*
|
|
26
|
+
* @returns The absolute path to the `emulator` binary.
|
|
27
|
+
* @throws When neither `ANDROID_HOME` nor `ANDROID_SDK_ROOT` is set.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveEmulatorBinaryPath(): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
function resolveEmulatorBinaryPath() {
|
|
4
|
+
return join(resolveAndroidSdkRoot(), "emulator", "emulator");
|
|
5
|
+
}
|
|
6
|
+
function resolveAndroidSdkRoot() {
|
|
7
|
+
const sdkRoot = process.env["ANDROID_HOME"] ?? process.env["ANDROID_SDK_ROOT"];
|
|
8
|
+
if (!sdkRoot) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
"Cannot find Android emulator: neither ANDROID_HOME nor ANDROID_SDK_ROOT environment variable is set."
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
return sdkRoot;
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
resolveEmulatorBinaryPath
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2FuZHJvaWQtc2RrLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogUmVzb2x2ZXMgdGhlIEFuZHJvaWQgU0RLIGJpbmFyaWVzIHRoZSBoYXJuZXNzIHNoZWxscyBvdXQgdG8uXG4gKlxuICogTGl2ZXMgaGVyZSByYXRoZXIgdGhhbiBhcyBhIHByaXZhdGUgbWV0aG9kIG9uIHRoZSBpbnRlZ3JhdGlvbi1vbmx5XG4gKiBgdHJhbnNwb3J0LWZhY3RvcnlgIGJlY2F1c2UgaXQgaXMgYW4gKiphZ3JlZW1lbnQqKiwgbm90IGFuIGltcGxlbWVudGF0aW9uXG4gKiBkZXRhaWw6IGBzY3JpcHRzL2VtdWxhdG9yLXdlZGdlLXByb2JlLnRzYCBleGlzdHMgdG8gcmVwcm9kdWNlIGEgaG9zdCBmYXVsdCBieVxuICogYm9vdGluZyB0aGUgZW11bGF0b3IgZXhhY3RseSBhcyBhIHJ1biB3b3VsZCwgYW5kIGEgcHJvYmUgdGhhdCByZXNvbHZlZCBhXG4gKiBkaWZmZXJlbnQgYmluYXJ5IHRoYW4gdGhlIGhhcm5lc3Mgd291bGQgcXVpZXRseSBtZWFzdXJlIHNvbWV0aGluZyBlbHNlLiBPbmVcbiAqIGZ1bmN0aW9uLCBvbmUgYW5zd2VyLCBib3RoIGNhbGxlcnMuXG4gKlxuICogVGhlIGxvb2t1cCBpdHNlbGYgaXMgdGhlIFNESydzIG93biBjb252ZW50aW9uIFx1MjAxNCBgQU5EUk9JRF9IT01FYCBmaXJzdCwgdGhlbiB0aGVcbiAqIG9sZGVyIGBBTkRST0lEX1NES19ST09UYCBcdTIwMTQgYW5kIGl0IGRlbGliZXJhdGVseSBkb2VzICoqbm90KiogZmFsbCBiYWNrIHRvIGFcbiAqIHBsYXRmb3JtLWRlZmF1bHQgaW5zdGFsbCBwYXRoLiBBIHdyb25nIGd1ZXNzIHdvdWxkIGJvb3Qgc29tZSBvdGhlciBTREsnc1xuICogZW11bGF0b3IgYW5kIHJlcG9ydCBvbiBpdCBhcyB0aG91Z2ggaXQgd2VyZSB0aGUgY29uZmlndXJlZCBvbmU7IGFuIGVycm9yIHRoYXRcbiAqIG5hbWVzIGJvdGggdmFyaWFibGVzIGlzIHRoZSBzaG9ydGVyIHJvdXRlIHRvIGEgd29ya2luZyBzZXR1cC5cbiAqL1xuXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5cbi8qKlxuICogUmVzb2x2ZXMgdGhlIGBlbXVsYXRvcmAgYmluYXJ5IGZyb20gdGhlIEFuZHJvaWQgU0RLIHJvb3QuXG4gKlxuICogTm8gZXh0ZW5zaW9uIGlzIGFwcGVuZGVkOiBOb2RlJ3MgcHJvY2VzcyBzcGF3bmluZyByZXNvbHZlcyBgZW11bGF0b3IuZXhlYCBvblxuICogV2luZG93cyBvbiBpdHMgb3duLCBhbmQgdGhlIHNhbWUgcGF0aCBzdHJpbmcgaXMgd2hhdCB0aGUgU0RLJ3Mgb3duIHRvb2xpbmdcbiAqIGRvY3VtZW50cy5cbiAqXG4gKiBAcmV0dXJucyBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgYGVtdWxhdG9yYCBiaW5hcnkuXG4gKiBAdGhyb3dzIFdoZW4gbmVpdGhlciBgQU5EUk9JRF9IT01FYCBub3IgYEFORFJPSURfU0RLX1JPT1RgIGlzIHNldC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVFbXVsYXRvckJpbmFyeVBhdGgoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGpvaW4ocmVzb2x2ZUFuZHJvaWRTZGtSb290KCksICdlbXVsYXRvcicsICdlbXVsYXRvcicpO1xufVxuXG5mdW5jdGlvbiByZXNvbHZlQW5kcm9pZFNka1Jvb3QoKTogc3RyaW5nIHtcbiAgY29uc3Qgc2RrUm9vdCA9IHByb2Nlc3MuZW52WydBTkRST0lEX0hPTUUnXSA/PyBwcm9jZXNzLmVudlsnQU5EUk9JRF9TREtfUk9PVCddO1xuICBpZiAoIXNka1Jvb3QpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnQ2Fubm90IGZpbmQgQW5kcm9pZCBlbXVsYXRvcjogbmVpdGhlciBBTkRST0lEX0hPTUUgbm9yIEFORFJPSURfU0RLX1JPT1QgZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgc2V0LidcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIHNka1Jvb3Q7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiQUFtQkEsU0FBUyxZQUFZO0FBQ3JCLE9BQU8sYUFBYTtBQVliLFNBQVMsNEJBQW9DO0FBQ2xELFNBQU8sS0FBSyxzQkFBc0IsR0FBRyxZQUFZLFVBQVU7QUFDN0Q7QUFFQSxTQUFTLHdCQUFnQztBQUN2QyxRQUFNLFVBQVUsUUFBUSxJQUFJLGNBQWMsS0FBSyxRQUFRLElBQUksa0JBQWtCO0FBQzdFLE1BQUksQ0FBQyxTQUFTO0FBQ1osVUFBTSxJQUFJO0FBQUEsTUFDUjtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBRUEsU0FBTztBQUNUOyIsCiAgIm5hbWVzIjogW10KfQo=
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers for tracking how far Obsidian Mobile has got through its startup
|
|
5
|
+
* after `location.reload()`, and for describing where it stalled when a budget
|
|
6
|
+
* runs out.
|
|
7
|
+
*
|
|
8
|
+
* Startup is watched as a **ladder of milestones**, not a single boolean,
|
|
9
|
+
* because the two halves of it cost wildly different amounts of time and only
|
|
10
|
+
* one of them is Obsidian's fault. Reaching `globalThis.app` is the app cold
|
|
11
|
+
* start — the WebView reloading, the guest still churning — and on a cold or
|
|
12
|
+
* contended emulator it can take minutes. Everything after it is Obsidian
|
|
13
|
+
* opening the vault and loading plugins, which **L19** measured at ~1s (≤8.4s
|
|
14
|
+
* under 12-core + disk + memory stress). Charging both to one 90s wall clock is
|
|
15
|
+
* what made a first run after a machine restart fail by design, so the transport
|
|
16
|
+
* runs them as two budgets and uses these helpers to tell them apart.
|
|
17
|
+
*
|
|
18
|
+
* Kept separate from the integration-only `transport-appium` (excluded from unit
|
|
19
|
+
* tests) so the classification and message formatting stay unit-testable — the
|
|
20
|
+
* polling itself needs a real device.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* How far Obsidian has got through its startup, as seen from one WebView probe.
|
|
24
|
+
*
|
|
25
|
+
* Ordered from least to most advanced; {@link compareAppStartupMilestones}
|
|
26
|
+
* relies on that order.
|
|
27
|
+
*/
|
|
28
|
+
export type AppStartupMilestone = 'layout-ready' | 'no-app' | 'no-webview' | 'no-workspace' | 'workspace-not-ready';
|
|
29
|
+
/**
|
|
30
|
+
* Which of the two startup budgets was being spent when it ran out.
|
|
31
|
+
*/
|
|
32
|
+
export type AppStartupPhase = 'app-start' | 'layout-ready';
|
|
33
|
+
/**
|
|
34
|
+
* Parameters for {@link buildStartupTimeoutMessage}.
|
|
35
|
+
*/
|
|
36
|
+
export interface BuildStartupTimeoutMessageParams {
|
|
37
|
+
/**
|
|
38
|
+
How long this phase's budget had been spent when it ran out.
|
|
39
|
+
*/
|
|
40
|
+
readonly elapsedInMilliseconds: number;
|
|
41
|
+
/**
|
|
42
|
+
The furthest milestone reached before the budget ran out.
|
|
43
|
+
*/
|
|
44
|
+
readonly milestone: AppStartupMilestone;
|
|
45
|
+
/**
|
|
46
|
+
The phase whose budget ran out.
|
|
47
|
+
*/
|
|
48
|
+
readonly phase: AppStartupPhase;
|
|
49
|
+
/**
|
|
50
|
+
How many probes were made during the phase.
|
|
51
|
+
*/
|
|
52
|
+
readonly pollCount: number;
|
|
53
|
+
/**
|
|
54
|
+
The slowest single probe round-trip observed during the phase.
|
|
55
|
+
*/
|
|
56
|
+
readonly slowestRoundTripInMilliseconds: number;
|
|
57
|
+
/**
|
|
58
|
+
The budget that ran out.
|
|
59
|
+
*/
|
|
60
|
+
readonly timeoutInMilliseconds: number;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The raw shape a WebView startup probe reports back.
|
|
64
|
+
*
|
|
65
|
+
* Mirrors what the injected probe function can observe without importing
|
|
66
|
+
* anything: whether the global `app` object exists yet, whether its `workspace`
|
|
67
|
+
* does, and whether that workspace has finished laying out.
|
|
68
|
+
*/
|
|
69
|
+
export interface StartupProbeResult {
|
|
70
|
+
/**
|
|
71
|
+
Whether `globalThis.app` is defined.
|
|
72
|
+
*/
|
|
73
|
+
readonly hasApp: boolean;
|
|
74
|
+
/**
|
|
75
|
+
Whether `app.workspace` is defined.
|
|
76
|
+
*/
|
|
77
|
+
readonly hasWorkspace: boolean;
|
|
78
|
+
/**
|
|
79
|
+
Whether `app.workspace.layoutReady` is truthy.
|
|
80
|
+
*/
|
|
81
|
+
readonly isLayoutReady: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Builds the diagnostic message for a startup budget that ran out.
|
|
85
|
+
*
|
|
86
|
+
* It names the milestone actually reached, the poll count and the slowest probe
|
|
87
|
+
* round-trip, because those three together separate the failure modes **L19**
|
|
88
|
+
* could not tell apart from the old message: a genuine Obsidian slowdown shows
|
|
89
|
+
* many fast polls stalled at one milestone, whereas a contended guest shows a
|
|
90
|
+
* handful of polls each taking tens of seconds.
|
|
91
|
+
*
|
|
92
|
+
* @param params - The phase, the milestone reached, and the timing evidence.
|
|
93
|
+
* @returns A human-readable error message.
|
|
94
|
+
*/
|
|
95
|
+
export declare function buildStartupTimeoutMessage(params: BuildStartupTimeoutMessageParams): string;
|
|
96
|
+
/**
|
|
97
|
+
* Reports whether the app-start phase is satisfied at this milestone.
|
|
98
|
+
*
|
|
99
|
+
* @param milestone - The milestone the latest probe reported.
|
|
100
|
+
* @returns `true` once `globalThis.app` exists, so the layout-ready budget may start.
|
|
101
|
+
*/
|
|
102
|
+
export declare function checkAppStarted(milestone: AppStartupMilestone): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Reports whether the layout-ready phase is satisfied at this milestone.
|
|
105
|
+
*
|
|
106
|
+
* @param milestone - The milestone the latest probe reported.
|
|
107
|
+
* @returns `true` once the workspace has finished laying out.
|
|
108
|
+
*/
|
|
109
|
+
export declare function checkLayoutReady(milestone: AppStartupMilestone): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Turns a WebView probe into a milestone.
|
|
112
|
+
*
|
|
113
|
+
* A probe that could not run at all — `undefined`, because `browser.execute()`
|
|
114
|
+
* threw while the page was mid-reload — is the least advanced milestone rather
|
|
115
|
+
* than an error: during a reload it is the expected reading.
|
|
116
|
+
*
|
|
117
|
+
* @param probeResult - What the probe reported, or `undefined` when it threw.
|
|
118
|
+
* @returns The milestone that reading represents.
|
|
119
|
+
*/
|
|
120
|
+
export declare function classifyAppStartupProbe(probeResult: StartupProbeResult | undefined): AppStartupMilestone;
|
|
121
|
+
/**
|
|
122
|
+
* Orders two milestones on the startup ladder.
|
|
123
|
+
*
|
|
124
|
+
* @param left - The first milestone.
|
|
125
|
+
* @param right - The second milestone.
|
|
126
|
+
* @returns A negative number when `left` is less advanced, `0` when equal, a positive number when more advanced.
|
|
127
|
+
*/
|
|
128
|
+
export declare function compareAppStartupMilestones(left: AppStartupMilestone, right: AppStartupMilestone): number;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const MILESTONE_ORDER = [
|
|
2
|
+
"no-webview",
|
|
3
|
+
"no-app",
|
|
4
|
+
"no-workspace",
|
|
5
|
+
"workspace-not-ready",
|
|
6
|
+
"layout-ready"
|
|
7
|
+
];
|
|
8
|
+
const APP_STARTED_MILESTONE = "no-workspace";
|
|
9
|
+
const MILESTONE_DESCRIPTIONS = {
|
|
10
|
+
"layout-ready": "the workspace finished laying out",
|
|
11
|
+
"no-app": "the WebView answered, but `globalThis.app` never appeared",
|
|
12
|
+
"no-webview": "the WebView never answered a single probe",
|
|
13
|
+
"no-workspace": "`globalThis.app` appeared, but `app.workspace` never did",
|
|
14
|
+
"workspace-not-ready": "`app.workspace` exists, but `layoutReady` never became true"
|
|
15
|
+
};
|
|
16
|
+
const PHASE_DESCRIPTIONS = {
|
|
17
|
+
"app-start": "Obsidian Mobile did not finish starting",
|
|
18
|
+
"layout-ready": "Obsidian layout did not become ready"
|
|
19
|
+
};
|
|
20
|
+
function buildStartupTimeoutMessage(params) {
|
|
21
|
+
const {
|
|
22
|
+
elapsedInMilliseconds,
|
|
23
|
+
milestone,
|
|
24
|
+
phase,
|
|
25
|
+
pollCount,
|
|
26
|
+
slowestRoundTripInMilliseconds,
|
|
27
|
+
timeoutInMilliseconds
|
|
28
|
+
} = params;
|
|
29
|
+
return `${PHASE_DESCRIPTIONS[phase]} within ${String(timeoutInMilliseconds)}ms (elapsed ${String(elapsedInMilliseconds)}ms). Furthest progress: ${MILESTONE_DESCRIPTIONS[milestone]}. Probed ${String(pollCount)} time(s), slowest round-trip ${String(slowestRoundTripInMilliseconds)}ms. A handful of probes each taking tens of seconds means a contended guest, not a slow Obsidian \u2014 let the emulator go idle before the run, or raise \`deviceIdleTimeoutInMilliseconds\`.`;
|
|
30
|
+
}
|
|
31
|
+
function checkAppStarted(milestone) {
|
|
32
|
+
return compareAppStartupMilestones(milestone, APP_STARTED_MILESTONE) >= 0;
|
|
33
|
+
}
|
|
34
|
+
function checkLayoutReady(milestone) {
|
|
35
|
+
return milestone === "layout-ready";
|
|
36
|
+
}
|
|
37
|
+
function classifyAppStartupProbe(probeResult) {
|
|
38
|
+
if (!probeResult) {
|
|
39
|
+
return "no-webview";
|
|
40
|
+
}
|
|
41
|
+
if (!probeResult.hasApp) {
|
|
42
|
+
return "no-app";
|
|
43
|
+
}
|
|
44
|
+
if (!probeResult.hasWorkspace) {
|
|
45
|
+
return "no-workspace";
|
|
46
|
+
}
|
|
47
|
+
return probeResult.isLayoutReady ? "layout-ready" : "workspace-not-ready";
|
|
48
|
+
}
|
|
49
|
+
function compareAppStartupMilestones(left, right) {
|
|
50
|
+
return MILESTONE_ORDER.indexOf(left) - MILESTONE_ORDER.indexOf(right);
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
buildStartupTimeoutMessage,
|
|
54
|
+
checkAppStarted,
|
|
55
|
+
checkLayoutReady,
|
|
56
|
+
classifyAppStartupProbe,
|
|
57
|
+
compareAppStartupMilestones
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2FwcC1zdGFydHVwLXByb2dyZXNzLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogUHVyZSBoZWxwZXJzIGZvciB0cmFja2luZyBob3cgZmFyIE9ic2lkaWFuIE1vYmlsZSBoYXMgZ290IHRocm91Z2ggaXRzIHN0YXJ0dXBcbiAqIGFmdGVyIGBsb2NhdGlvbi5yZWxvYWQoKWAsIGFuZCBmb3IgZGVzY3JpYmluZyB3aGVyZSBpdCBzdGFsbGVkIHdoZW4gYSBidWRnZXRcbiAqIHJ1bnMgb3V0LlxuICpcbiAqIFN0YXJ0dXAgaXMgd2F0Y2hlZCBhcyBhICoqbGFkZGVyIG9mIG1pbGVzdG9uZXMqKiwgbm90IGEgc2luZ2xlIGJvb2xlYW4sXG4gKiBiZWNhdXNlIHRoZSB0d28gaGFsdmVzIG9mIGl0IGNvc3Qgd2lsZGx5IGRpZmZlcmVudCBhbW91bnRzIG9mIHRpbWUgYW5kIG9ubHlcbiAqIG9uZSBvZiB0aGVtIGlzIE9ic2lkaWFuJ3MgZmF1bHQuIFJlYWNoaW5nIGBnbG9iYWxUaGlzLmFwcGAgaXMgdGhlIGFwcCBjb2xkXG4gKiBzdGFydCBcdTIwMTQgdGhlIFdlYlZpZXcgcmVsb2FkaW5nLCB0aGUgZ3Vlc3Qgc3RpbGwgY2h1cm5pbmcgXHUyMDE0IGFuZCBvbiBhIGNvbGQgb3JcbiAqIGNvbnRlbmRlZCBlbXVsYXRvciBpdCBjYW4gdGFrZSBtaW51dGVzLiBFdmVyeXRoaW5nIGFmdGVyIGl0IGlzIE9ic2lkaWFuXG4gKiBvcGVuaW5nIHRoZSB2YXVsdCBhbmQgbG9hZGluZyBwbHVnaW5zLCB3aGljaCAqKkwxOSoqIG1lYXN1cmVkIGF0IH4xcyAoXHUyMjY0OC40c1xuICogdW5kZXIgMTItY29yZSArIGRpc2sgKyBtZW1vcnkgc3RyZXNzKS4gQ2hhcmdpbmcgYm90aCB0byBvbmUgOTBzIHdhbGwgY2xvY2sgaXNcbiAqIHdoYXQgbWFkZSBhIGZpcnN0IHJ1biBhZnRlciBhIG1hY2hpbmUgcmVzdGFydCBmYWlsIGJ5IGRlc2lnbiwgc28gdGhlIHRyYW5zcG9ydFxuICogcnVucyB0aGVtIGFzIHR3byBidWRnZXRzIGFuZCB1c2VzIHRoZXNlIGhlbHBlcnMgdG8gdGVsbCB0aGVtIGFwYXJ0LlxuICpcbiAqIEtlcHQgc2VwYXJhdGUgZnJvbSB0aGUgaW50ZWdyYXRpb24tb25seSBgdHJhbnNwb3J0LWFwcGl1bWAgKGV4Y2x1ZGVkIGZyb20gdW5pdFxuICogdGVzdHMpIHNvIHRoZSBjbGFzc2lmaWNhdGlvbiBhbmQgbWVzc2FnZSBmb3JtYXR0aW5nIHN0YXkgdW5pdC10ZXN0YWJsZSBcdTIwMTQgdGhlXG4gKiBwb2xsaW5nIGl0c2VsZiBuZWVkcyBhIHJlYWwgZGV2aWNlLlxuICovXG5cbi8qKlxuICogSG93IGZhciBPYnNpZGlhbiBoYXMgZ290IHRocm91Z2ggaXRzIHN0YXJ0dXAsIGFzIHNlZW4gZnJvbSBvbmUgV2ViVmlldyBwcm9iZS5cbiAqXG4gKiBPcmRlcmVkIGZyb20gbGVhc3QgdG8gbW9zdCBhZHZhbmNlZDsge0BsaW5rIGNvbXBhcmVBcHBTdGFydHVwTWlsZXN0b25lc31cbiAqIHJlbGllcyBvbiB0aGF0IG9yZGVyLlxuICovXG5leHBvcnQgdHlwZSBBcHBTdGFydHVwTWlsZXN0b25lID1cbiAgfCAnbGF5b3V0LXJlYWR5J1xuICB8ICduby1hcHAnXG4gIHwgJ25vLXdlYnZpZXcnXG4gIHwgJ25vLXdvcmtzcGFjZSdcbiAgfCAnd29ya3NwYWNlLW5vdC1yZWFkeSc7XG5cbi8qKlxuICogV2hpY2ggb2YgdGhlIHR3byBzdGFydHVwIGJ1ZGdldHMgd2FzIGJlaW5nIHNwZW50IHdoZW4gaXQgcmFuIG91dC5cbiAqL1xuZXhwb3J0IHR5cGUgQXBwU3RhcnR1cFBoYXNlID0gJ2FwcC1zdGFydCcgfCAnbGF5b3V0LXJlYWR5JztcblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciB7QGxpbmsgYnVpbGRTdGFydHVwVGltZW91dE1lc3NhZ2V9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJ1aWxkU3RhcnR1cFRpbWVvdXRNZXNzYWdlUGFyYW1zIHtcbiAgLyoqXG4gIEhvdyBsb25nIHRoaXMgcGhhc2UncyBidWRnZXQgaGFkIGJlZW4gc3BlbnQgd2hlbiBpdCByYW4gb3V0LlxuICAgKi9cbiAgcmVhZG9ubHkgZWxhcHNlZEluTWlsbGlzZWNvbmRzOiBudW1iZXI7XG5cbiAgLyoqXG4gIFRoZSBmdXJ0aGVzdCBtaWxlc3RvbmUgcmVhY2hlZCBiZWZvcmUgdGhlIGJ1ZGdldCByYW4gb3V0LlxuICAgKi9cbiAgcmVhZG9ubHkgbWlsZXN0b25lOiBBcHBTdGFydHVwTWlsZXN0b25lO1xuXG4gIC8qKlxuICBUaGUgcGhhc2Ugd2hvc2UgYnVkZ2V0IHJhbiBvdXQuXG4gICAqL1xuICByZWFkb25seSBwaGFzZTogQXBwU3RhcnR1cFBoYXNlO1xuXG4gIC8qKlxuICBIb3cgbWFueSBwcm9iZXMgd2VyZSBtYWRlIGR1cmluZyB0aGUgcGhhc2UuXG4gICAqL1xuICByZWFkb25seSBwb2xsQ291bnQ6IG51bWJlcjtcblxuICAvKipcbiAgVGhlIHNsb3dlc3Qgc2luZ2xlIHByb2JlIHJvdW5kLXRyaXAgb2JzZXJ2ZWQgZHVyaW5nIHRoZSBwaGFzZS5cbiAgICovXG4gIHJlYWRvbmx5IHNsb3dlc3RSb3VuZFRyaXBJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xuXG4gIC8qKlxuICBUaGUgYnVkZ2V0IHRoYXQgcmFuIG91dC5cbiAgICovXG4gIHJlYWRvbmx5IHRpbWVvdXRJbk1pbGxpc2Vjb25kczogbnVtYmVyO1xufVxuXG4vKipcbiAqIFRoZSByYXcgc2hhcGUgYSBXZWJWaWV3IHN0YXJ0dXAgcHJvYmUgcmVwb3J0cyBiYWNrLlxuICpcbiAqIE1pcnJvcnMgd2hhdCB0aGUgaW5qZWN0ZWQgcHJvYmUgZnVuY3Rpb24gY2FuIG9ic2VydmUgd2l0aG91dCBpbXBvcnRpbmdcbiAqIGFueXRoaW5nOiB3aGV0aGVyIHRoZSBnbG9iYWwgYGFwcGAgb2JqZWN0IGV4aXN0cyB5ZXQsIHdoZXRoZXIgaXRzIGB3b3Jrc3BhY2VgXG4gKiBkb2VzLCBhbmQgd2hldGhlciB0aGF0IHdvcmtzcGFjZSBoYXMgZmluaXNoZWQgbGF5aW5nIG91dC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdGFydHVwUHJvYmVSZXN1bHQge1xuICAvKipcbiAgV2hldGhlciBgZ2xvYmFsVGhpcy5hcHBgIGlzIGRlZmluZWQuXG4gICAqL1xuICByZWFkb25seSBoYXNBcHA6IGJvb2xlYW47XG5cbiAgLyoqXG4gIFdoZXRoZXIgYGFwcC53b3Jrc3BhY2VgIGlzIGRlZmluZWQuXG4gICAqL1xuICByZWFkb25seSBoYXNXb3Jrc3BhY2U6IGJvb2xlYW47XG5cbiAgLyoqXG4gIFdoZXRoZXIgYGFwcC53b3Jrc3BhY2UubGF5b3V0UmVhZHlgIGlzIHRydXRoeS5cbiAgICovXG4gIHJlYWRvbmx5IGlzTGF5b3V0UmVhZHk6IGJvb2xlYW47XG59XG5cbi8qKlxuICogVGhlIG1pbGVzdG9uZSBsYWRkZXIsIGxlYXN0IHRvIG1vc3QgYWR2YW5jZWQuIFRoZSBpbmRleCBpbiB0aGlzIGFycmF5ICppcypcbiAqIHRoZSBvcmRlcmluZyB1c2VkIGJ5IHtAbGluayBjb21wYXJlQXBwU3RhcnR1cE1pbGVzdG9uZXN9LlxuICovXG5jb25zdCBNSUxFU1RPTkVfT1JERVI6IHJlYWRvbmx5IEFwcFN0YXJ0dXBNaWxlc3RvbmVbXSA9IFtcbiAgJ25vLXdlYnZpZXcnLFxuICAnbm8tYXBwJyxcbiAgJ25vLXdvcmtzcGFjZScsXG4gICd3b3Jrc3BhY2Utbm90LXJlYWR5JyxcbiAgJ2xheW91dC1yZWFkeSdcbl07XG5cbi8qKlxuICogVGhlIG1pbGVzdG9uZSBhdCB3aGljaCB0aGUgYXBwLXN0YXJ0IHBoYXNlIGlzIHNhdGlzZmllZDogYGdsb2JhbFRoaXMuYXBwYFxuICogZXhpc3RzLCBzbyB0aGUgV2ViVmlldyBoYXMgcmVsb2FkZWQgYW5kIE9ic2lkaWFuJ3Mgb3duIGJvb3QgaGFzIGJlZ3VuLiBXaGF0XG4gKiByZW1haW5zIGZyb20gaGVyZSBpcyBPYnNpZGlhbiB3b3JrLCB3aGljaCB0aGUgdGlnaHQgbGF5b3V0LXJlYWR5IGJ1ZGdldFxuICogY292ZXJzLlxuICovXG5jb25zdCBBUFBfU1RBUlRFRF9NSUxFU1RPTkU6IEFwcFN0YXJ0dXBNaWxlc3RvbmUgPSAnbm8td29ya3NwYWNlJztcblxuLyoqXG4gKiBIdW1hbi1yZWFkYWJsZSBkZXNjcmlwdGlvbnMgb2YgZWFjaCBtaWxlc3RvbmUsIHVzZWQgaW4gdGhlIHRpbWVvdXQgbWVzc2FnZSBzb1xuICogdGhlIGZhaWx1cmUgbmFtZXMgd2hhdCBuZXZlciBoYXBwZW5lZCBpbnN0ZWFkIG9mIG9ubHkgd2hhdCB3YXMgaG9wZWQgZm9yLlxuICovXG5jb25zdCBNSUxFU1RPTkVfREVTQ1JJUFRJT05TOiBSZWNvcmQ8QXBwU3RhcnR1cE1pbGVzdG9uZSwgc3RyaW5nPiA9IHtcbiAgJ2xheW91dC1yZWFkeSc6ICd0aGUgd29ya3NwYWNlIGZpbmlzaGVkIGxheWluZyBvdXQnLFxuICAnbm8tYXBwJzogJ3RoZSBXZWJWaWV3IGFuc3dlcmVkLCBidXQgYGdsb2JhbFRoaXMuYXBwYCBuZXZlciBhcHBlYXJlZCcsXG4gICduby13ZWJ2aWV3JzogJ3RoZSBXZWJWaWV3IG5ldmVyIGFuc3dlcmVkIGEgc2luZ2xlIHByb2JlJyxcbiAgJ25vLXdvcmtzcGFjZSc6ICdgZ2xvYmFsVGhpcy5hcHBgIGFwcGVhcmVkLCBidXQgYGFwcC53b3Jrc3BhY2VgIG5ldmVyIGRpZCcsXG4gICd3b3Jrc3BhY2Utbm90LXJlYWR5JzogJ2BhcHAud29ya3NwYWNlYCBleGlzdHMsIGJ1dCBgbGF5b3V0UmVhZHlgIG5ldmVyIGJlY2FtZSB0cnVlJ1xufTtcblxuLyoqXG4gKiBXaGF0IGVhY2ggcGhhc2Ugd2FzIHdhaXRpbmcgZm9yLCB1c2VkIGluIHRoZSB0aW1lb3V0IG1lc3NhZ2UuXG4gKi9cbmNvbnN0IFBIQVNFX0RFU0NSSVBUSU9OUzogUmVjb3JkPEFwcFN0YXJ0dXBQaGFzZSwgc3RyaW5nPiA9IHtcbiAgJ2FwcC1zdGFydCc6ICdPYnNpZGlhbiBNb2JpbGUgZGlkIG5vdCBmaW5pc2ggc3RhcnRpbmcnLFxuICAnbGF5b3V0LXJlYWR5JzogJ09ic2lkaWFuIGxheW91dCBkaWQgbm90IGJlY29tZSByZWFkeSdcbn07XG5cbi8qKlxuICogQnVpbGRzIHRoZSBkaWFnbm9zdGljIG1lc3NhZ2UgZm9yIGEgc3RhcnR1cCBidWRnZXQgdGhhdCByYW4gb3V0LlxuICpcbiAqIEl0IG5hbWVzIHRoZSBtaWxlc3RvbmUgYWN0dWFsbHkgcmVhY2hlZCwgdGhlIHBvbGwgY291bnQgYW5kIHRoZSBzbG93ZXN0IHByb2JlXG4gKiByb3VuZC10cmlwLCBiZWNhdXNlIHRob3NlIHRocmVlIHRvZ2V0aGVyIHNlcGFyYXRlIHRoZSBmYWlsdXJlIG1vZGVzICoqTDE5KipcbiAqIGNvdWxkIG5vdCB0ZWxsIGFwYXJ0IGZyb20gdGhlIG9sZCBtZXNzYWdlOiBhIGdlbnVpbmUgT2JzaWRpYW4gc2xvd2Rvd24gc2hvd3NcbiAqIG1hbnkgZmFzdCBwb2xscyBzdGFsbGVkIGF0IG9uZSBtaWxlc3RvbmUsIHdoZXJlYXMgYSBjb250ZW5kZWQgZ3Vlc3Qgc2hvd3MgYVxuICogaGFuZGZ1bCBvZiBwb2xscyBlYWNoIHRha2luZyB0ZW5zIG9mIHNlY29uZHMuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIFRoZSBwaGFzZSwgdGhlIG1pbGVzdG9uZSByZWFjaGVkLCBhbmQgdGhlIHRpbWluZyBldmlkZW5jZS5cbiAqIEByZXR1cm5zIEEgaHVtYW4tcmVhZGFibGUgZXJyb3IgbWVzc2FnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkU3RhcnR1cFRpbWVvdXRNZXNzYWdlKHBhcmFtczogQnVpbGRTdGFydHVwVGltZW91dE1lc3NhZ2VQYXJhbXMpOiBzdHJpbmcge1xuICBjb25zdCB7XG4gICAgZWxhcHNlZEluTWlsbGlzZWNvbmRzLFxuICAgIG1pbGVzdG9uZSxcbiAgICBwaGFzZSxcbiAgICBwb2xsQ291bnQsXG4gICAgc2xvd2VzdFJvdW5kVHJpcEluTWlsbGlzZWNvbmRzLFxuICAgIHRpbWVvdXRJbk1pbGxpc2Vjb25kc1xuICB9ID0gcGFyYW1zO1xuXG4gIHJldHVybiBgJHtQSEFTRV9ERVNDUklQVElPTlNbcGhhc2VdfSB3aXRoaW4gJHtTdHJpbmcodGltZW91dEluTWlsbGlzZWNvbmRzKX1tcyBgXG4gICAgKyBgKGVsYXBzZWQgJHtTdHJpbmcoZWxhcHNlZEluTWlsbGlzZWNvbmRzKX1tcykuIEZ1cnRoZXN0IHByb2dyZXNzOiAke01JTEVTVE9ORV9ERVNDUklQVElPTlNbbWlsZXN0b25lXX0uIGBcbiAgICArIGBQcm9iZWQgJHtTdHJpbmcocG9sbENvdW50KX0gdGltZShzKSwgc2xvd2VzdCByb3VuZC10cmlwICR7U3RyaW5nKHNsb3dlc3RSb3VuZFRyaXBJbk1pbGxpc2Vjb25kcyl9bXMuIGBcbiAgICArICdBIGhhbmRmdWwgb2YgcHJvYmVzIGVhY2ggdGFraW5nIHRlbnMgb2Ygc2Vjb25kcyBtZWFucyBhIGNvbnRlbmRlZCBndWVzdCwgbm90IGEgc2xvdyBPYnNpZGlhbiBcdTIwMTQgJ1xuICAgICsgJ2xldCB0aGUgZW11bGF0b3IgZ28gaWRsZSBiZWZvcmUgdGhlIHJ1biwgb3IgcmFpc2UgYGRldmljZUlkbGVUaW1lb3V0SW5NaWxsaXNlY29uZHNgLic7XG59XG5cbi8qKlxuICogUmVwb3J0cyB3aGV0aGVyIHRoZSBhcHAtc3RhcnQgcGhhc2UgaXMgc2F0aXNmaWVkIGF0IHRoaXMgbWlsZXN0b25lLlxuICpcbiAqIEBwYXJhbSBtaWxlc3RvbmUgLSBUaGUgbWlsZXN0b25lIHRoZSBsYXRlc3QgcHJvYmUgcmVwb3J0ZWQuXG4gKiBAcmV0dXJucyBgdHJ1ZWAgb25jZSBgZ2xvYmFsVGhpcy5hcHBgIGV4aXN0cywgc28gdGhlIGxheW91dC1yZWFkeSBidWRnZXQgbWF5IHN0YXJ0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tBcHBTdGFydGVkKG1pbGVzdG9uZTogQXBwU3RhcnR1cE1pbGVzdG9uZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gY29tcGFyZUFwcFN0YXJ0dXBNaWxlc3RvbmVzKG1pbGVzdG9uZSwgQVBQX1NUQVJURURfTUlMRVNUT05FKSA+PSAwO1xufVxuXG4vKipcbiAqIFJlcG9ydHMgd2hldGhlciB0aGUgbGF5b3V0LXJlYWR5IHBoYXNlIGlzIHNhdGlzZmllZCBhdCB0aGlzIG1pbGVzdG9uZS5cbiAqXG4gKiBAcGFyYW0gbWlsZXN0b25lIC0gVGhlIG1pbGVzdG9uZSB0aGUgbGF0ZXN0IHByb2JlIHJlcG9ydGVkLlxuICogQHJldHVybnMgYHRydWVgIG9uY2UgdGhlIHdvcmtzcGFjZSBoYXMgZmluaXNoZWQgbGF5aW5nIG91dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNoZWNrTGF5b3V0UmVhZHkobWlsZXN0b25lOiBBcHBTdGFydHVwTWlsZXN0b25lKTogYm9vbGVhbiB7XG4gIHJldHVybiBtaWxlc3RvbmUgPT09ICdsYXlvdXQtcmVhZHknO1xufVxuXG4vKipcbiAqIFR1cm5zIGEgV2ViVmlldyBwcm9iZSBpbnRvIGEgbWlsZXN0b25lLlxuICpcbiAqIEEgcHJvYmUgdGhhdCBjb3VsZCBub3QgcnVuIGF0IGFsbCBcdTIwMTQgYHVuZGVmaW5lZGAsIGJlY2F1c2UgYGJyb3dzZXIuZXhlY3V0ZSgpYFxuICogdGhyZXcgd2hpbGUgdGhlIHBhZ2Ugd2FzIG1pZC1yZWxvYWQgXHUyMDE0IGlzIHRoZSBsZWFzdCBhZHZhbmNlZCBtaWxlc3RvbmUgcmF0aGVyXG4gKiB0aGFuIGFuIGVycm9yOiBkdXJpbmcgYSByZWxvYWQgaXQgaXMgdGhlIGV4cGVjdGVkIHJlYWRpbmcuXG4gKlxuICogQHBhcmFtIHByb2JlUmVzdWx0IC0gV2hhdCB0aGUgcHJvYmUgcmVwb3J0ZWQsIG9yIGB1bmRlZmluZWRgIHdoZW4gaXQgdGhyZXcuXG4gKiBAcmV0dXJucyBUaGUgbWlsZXN0b25lIHRoYXQgcmVhZGluZyByZXByZXNlbnRzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2xhc3NpZnlBcHBTdGFydHVwUHJvYmUocHJvYmVSZXN1bHQ6IFN0YXJ0dXBQcm9iZVJlc3VsdCB8IHVuZGVmaW5lZCk6IEFwcFN0YXJ0dXBNaWxlc3RvbmUge1xuICBpZiAoIXByb2JlUmVzdWx0KSB7XG4gICAgcmV0dXJuICduby13ZWJ2aWV3JztcbiAgfVxuICBpZiAoIXByb2JlUmVzdWx0Lmhhc0FwcCkge1xuICAgIHJldHVybiAnbm8tYXBwJztcbiAgfVxuICBpZiAoIXByb2JlUmVzdWx0Lmhhc1dvcmtzcGFjZSkge1xuICAgIHJldHVybiAnbm8td29ya3NwYWNlJztcbiAgfVxuICByZXR1cm4gcHJvYmVSZXN1bHQuaXNMYXlvdXRSZWFkeSA/ICdsYXlvdXQtcmVhZHknIDogJ3dvcmtzcGFjZS1ub3QtcmVhZHknO1xufVxuXG4vKipcbiAqIE9yZGVycyB0d28gbWlsZXN0b25lcyBvbiB0aGUgc3RhcnR1cCBsYWRkZXIuXG4gKlxuICogQHBhcmFtIGxlZnQgLSBUaGUgZmlyc3QgbWlsZXN0b25lLlxuICogQHBhcmFtIHJpZ2h0IC0gVGhlIHNlY29uZCBtaWxlc3RvbmUuXG4gKiBAcmV0dXJucyBBIG5lZ2F0aXZlIG51bWJlciB3aGVuIGBsZWZ0YCBpcyBsZXNzIGFkdmFuY2VkLCBgMGAgd2hlbiBlcXVhbCwgYSBwb3NpdGl2ZSBudW1iZXIgd2hlbiBtb3JlIGFkdmFuY2VkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcGFyZUFwcFN0YXJ0dXBNaWxlc3RvbmVzKGxlZnQ6IEFwcFN0YXJ0dXBNaWxlc3RvbmUsIHJpZ2h0OiBBcHBTdGFydHVwTWlsZXN0b25lKTogbnVtYmVyIHtcbiAgcmV0dXJuIE1JTEVTVE9ORV9PUkRFUi5pbmRleE9mKGxlZnQpIC0gTUlMRVNUT05FX09SREVSLmluZGV4T2YocmlnaHQpO1xufVxuIl0sCiAgIm1hcHBpbmdzIjogIkFBdUdBLE1BQU0sa0JBQWtEO0FBQUEsRUFDdEQ7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQ0Y7QUFRQSxNQUFNLHdCQUE2QztBQU1uRCxNQUFNLHlCQUE4RDtBQUFBLEVBQ2xFLGdCQUFnQjtBQUFBLEVBQ2hCLFVBQVU7QUFBQSxFQUNWLGNBQWM7QUFBQSxFQUNkLGdCQUFnQjtBQUFBLEVBQ2hCLHVCQUF1QjtBQUN6QjtBQUtBLE1BQU0scUJBQXNEO0FBQUEsRUFDMUQsYUFBYTtBQUFBLEVBQ2IsZ0JBQWdCO0FBQ2xCO0FBY08sU0FBUywyQkFBMkIsUUFBa0Q7QUFDM0YsUUFBTTtBQUFBLElBQ0o7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0YsSUFBSTtBQUVKLFNBQU8sR0FBRyxtQkFBbUIsS0FBSyxDQUFDLFdBQVcsT0FBTyxxQkFBcUIsQ0FBQyxlQUMzRCxPQUFPLHFCQUFxQixDQUFDLDJCQUEyQix1QkFBdUIsU0FBUyxDQUFDLFlBQzNGLE9BQU8sU0FBUyxDQUFDLGdDQUFnQyxPQUFPLDhCQUE4QixDQUFDO0FBR3ZHO0FBUU8sU0FBUyxnQkFBZ0IsV0FBeUM7QUFDdkUsU0FBTyw0QkFBNEIsV0FBVyxxQkFBcUIsS0FBSztBQUMxRTtBQVFPLFNBQVMsaUJBQWlCLFdBQXlDO0FBQ3hFLFNBQU8sY0FBYztBQUN2QjtBQVlPLFNBQVMsd0JBQXdCLGFBQWtFO0FBQ3hHLE1BQUksQ0FBQyxhQUFhO0FBQ2hCLFdBQU87QUFBQSxFQUNUO0FBQ0EsTUFBSSxDQUFDLFlBQVksUUFBUTtBQUN2QixXQUFPO0FBQUEsRUFDVDtBQUNBLE1BQUksQ0FBQyxZQUFZLGNBQWM7QUFDN0IsV0FBTztBQUFBLEVBQ1Q7QUFDQSxTQUFPLFlBQVksZ0JBQWdCLGlCQUFpQjtBQUN0RDtBQVNPLFNBQVMsNEJBQTRCLE1BQTJCLE9BQW9DO0FBQ3pHLFNBQU8sZ0JBQWdCLFFBQVEsSUFBSSxJQUFJLGdCQUFnQixRQUFRLEtBQUs7QUFDdEU7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Records which Appium server on a port this harness started, so a later run
|
|
5
|
+
* that finds a server already listening can tell **provenance**: one of our own
|
|
6
|
+
* servers left over from an earlier run, or a foreign one the user manages.
|
|
7
|
+
*
|
|
8
|
+
* The preflight adopts any server that answers `/status`, and adoption is the
|
|
9
|
+
* right default — starting a second server on an occupied port cannot work. But
|
|
10
|
+
* adopting silently means a wedged leftover (see `wedged-appium-server.ts`) is
|
|
11
|
+
* indistinguishable from a healthy server, and the harness has no basis on which
|
|
12
|
+
* to decide whether restarting it is its call to make. The marker supplies that
|
|
13
|
+
* basis: a server we started may be restarted, a foreign one is only ever
|
|
14
|
+
* reported.
|
|
15
|
+
*
|
|
16
|
+
* The marker is a small JSON sentinel next to the setup lock (`setup-lock.ts`),
|
|
17
|
+
* keyed by port, and is deliberately tolerant — a missing, unreadable, or
|
|
18
|
+
* mismatched marker simply reads as "not ours".
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Identifies the Appium server this harness started on a port.
|
|
22
|
+
*/
|
|
23
|
+
export interface AppiumServerMarker {
|
|
24
|
+
/**
|
|
25
|
+
PID of the spawned server process (the shell wrapper that owns the server's process tree).
|
|
26
|
+
*/
|
|
27
|
+
readonly pid: number;
|
|
28
|
+
/**
|
|
29
|
+
The port the server was started on.
|
|
30
|
+
*/
|
|
31
|
+
readonly port: number;
|
|
32
|
+
/**
|
|
33
|
+
When the server was started (`Date.now()` epoch milliseconds).
|
|
34
|
+
*/
|
|
35
|
+
readonly startedAtInMilliseconds: number;
|
|
36
|
+
/**
|
|
37
|
+
* When a run tried to stop this server and could not verify it exited
|
|
38
|
+
* (`Date.now()` epoch milliseconds), or `undefined` when no stop has failed.
|
|
39
|
+
*
|
|
40
|
+
* Its presence means the server is a **known-doomed leftover**: it was ours,
|
|
41
|
+
* we asked it to die, and it did not. See {@link recordAppiumServerStopAttempt}.
|
|
42
|
+
*/
|
|
43
|
+
readonly stopAttemptedAtInMilliseconds?: number | undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Parameters for {@link writeAppiumServerMarker}.
|
|
47
|
+
*/
|
|
48
|
+
export interface WriteAppiumServerMarkerParams {
|
|
49
|
+
/**
|
|
50
|
+
PID of the spawned server process.
|
|
51
|
+
*/
|
|
52
|
+
readonly pid: number;
|
|
53
|
+
/**
|
|
54
|
+
The port the server was started on.
|
|
55
|
+
*/
|
|
56
|
+
readonly port: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Checks whether the marked server is still running, which is what makes an
|
|
60
|
+
* adopted server ours to restart.
|
|
61
|
+
*
|
|
62
|
+
* A dead PID means the marker outlived its server, so whatever answers on that
|
|
63
|
+
* port now is somebody else's — the marker proves nothing about it.
|
|
64
|
+
*
|
|
65
|
+
* @param marker - The marker read for the port, or `undefined` when there is none.
|
|
66
|
+
* @returns `true` when an earlier run of this harness started the server now listening.
|
|
67
|
+
*/
|
|
68
|
+
export declare function checkIsHarnessOwnedAppiumServer(marker: AppiumServerMarker | undefined): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Removes the marker for a port. Called once the marked server has been stopped,
|
|
71
|
+
* so a later run does not mistake a recycled PID for our server.
|
|
72
|
+
*
|
|
73
|
+
* @param port - The Appium server port.
|
|
74
|
+
*/
|
|
75
|
+
export declare function clearAppiumServerMarker(port: number): void;
|
|
76
|
+
/**
|
|
77
|
+
* Reads the marker for a port.
|
|
78
|
+
*
|
|
79
|
+
* @param port - The Appium server port.
|
|
80
|
+
* @returns The marker, or `undefined` when there is none, it is unreadable, or it does not describe this port.
|
|
81
|
+
*/
|
|
82
|
+
export declare function readAppiumServerMarker(port: number): AppiumServerMarker | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Records that a run tried to stop the marked server and could not verify it
|
|
85
|
+
* exited — **instead of** clearing the marker.
|
|
86
|
+
*
|
|
87
|
+
* Clearing it would be the worst of both worlds: the leftover keeps serving, and
|
|
88
|
+
* the next run reads it as a foreign, user-managed server it must never touch
|
|
89
|
+
* (`checkIsHarnessOwnedAppiumServer` needs the marker to convict it). Keeping
|
|
90
|
+
* the marker, stamped, says exactly what is true — this is ours, and it outlived
|
|
91
|
+
* our teardown — which is what lets the next run refuse to adopt it and replace
|
|
92
|
+
* it instead.
|
|
93
|
+
*
|
|
94
|
+
* @param port - The Appium server port.
|
|
95
|
+
*/
|
|
96
|
+
export declare function recordAppiumServerStopAttempt(port: number): void;
|
|
97
|
+
/**
|
|
98
|
+
* Records the server this run just started, stamping it with the current time so
|
|
99
|
+
* a later run can report how long it has been up.
|
|
100
|
+
*
|
|
101
|
+
* @param params - The started server's PID and port.
|
|
102
|
+
*/
|
|
103
|
+
export declare function writeAppiumServerMarker(params: WriteAppiumServerMarkerParams): void;
|