@xenon-device-management/xenon 2.0.0 → 2.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/README.md +2 -1
- package/lib/package.json +1 -2
- package/lib/public/assets/{AnnotationOverlay-BmTPCAds.js → AnnotationOverlay-C-Pw_hvw.js} +1 -1
- package/lib/public/assets/{ApiKeyGate-B5eB7f8B.js → ApiKeyGate-DmYQ0oSk.js} +1 -1
- package/lib/public/assets/BugReportButton-n8T1dFUp.js +10 -0
- package/lib/public/assets/{DeviceMosaicView-9DUoZnQi.js → DeviceMosaicView-D-rGOBbJ.js} +1 -1
- package/lib/public/assets/{EmptyState-lvyNiXev.js → EmptyState-DExETevp.js} +1 -1
- package/lib/public/assets/{FieldGroup-BduMPM9K.js → FieldGroup-CCdFlZm6.js} +1 -1
- package/lib/public/assets/{FilterMenu-BSqX6I94.js → FilterMenu-DiUSOSL-.js} +1 -1
- package/lib/public/assets/{Menu-Ba5cT7jZ.js → Menu-ZOfpH6gh.js} +1 -1
- package/lib/public/assets/{Modal-CceoMY7D.js → Modal-CZNtoB-1.js} +1 -1
- package/lib/public/assets/{RecordingPage-6T9dOidc.js → RecordingPage-BKp6h8Jl.js} +1 -1
- package/lib/public/assets/{RecordingsPage-qj6FdZXR.js → RecordingsPage-Bf881FX4.js} +1 -1
- package/lib/public/assets/{SegmentedControl-CSRuZ8TR.js → SegmentedControl-EUoyizvW.js} +1 -1
- package/lib/public/assets/{SettingCard-Bp1kz4By.js → SettingCard-ClT4hf4_.js} +1 -1
- package/lib/public/assets/{Table-LV7zFyZg.js → Table-ucR4bnmc.js} +1 -1
- package/lib/public/assets/{activity-D17TUloi.js → activity-K-hdylwq.js} +1 -1
- package/lib/public/assets/{ai-settings-qvbhY89P.js → ai-settings-BLhdwI3c.js} +1 -1
- package/lib/public/assets/{api-keys-BfpvdG7G.js → api-keys-BbiN7rBI.js} +1 -1
- package/lib/public/assets/{apps-Dbnzd0fW.js → apps-Dez1petz.js} +1 -1
- package/lib/public/assets/{arrow-left-DD1VjtC7.js → arrow-left-UjmFHLAJ.js} +1 -1
- package/lib/public/assets/{arrow-right-D0pnM3ma.js → arrow-right-BVyEigbu.js} +1 -1
- package/lib/public/assets/{arrow-up-right-BIC8JOV6.js → arrow-up-right-B-ZlBof3.js} +1 -1
- package/lib/public/assets/{auth-shell-DWHPXSnI.js → auth-shell-DAQjAgUv.js} +2 -2
- package/lib/public/assets/{builds-page-ClCNBUv_.js → builds-page-CmIPa5JK.js} +1 -1
- package/lib/public/assets/{button-xtAhYR-f.js → button-Dd-IhMC1.js} +1 -1
- package/lib/public/assets/{calendar-CupwJ7Bm.js → calendar-CAIeJwa5.js} +1 -1
- package/lib/public/assets/{check-CyuEoKkd.js → check-C4Jrjg8f.js} +1 -1
- package/lib/public/assets/{chevron-left-DgX-F9xK.js → chevron-left-BGzlf-4i.js} +1 -1
- package/lib/public/assets/{chevron-right-BKJgJnU9.js → chevron-right-_wYqDjDC.js} +1 -1
- package/lib/public/assets/{circle-check-CZdg8mMa.js → circle-check-Ckn00yMB.js} +1 -1
- package/lib/public/assets/{circle-x-CZH6t9z-.js → circle-x-pdVkomLa.js} +1 -1
- package/lib/public/assets/{clock-Cd-t7xpe.js → clock-B8vmwkHj.js} +1 -1
- package/lib/public/assets/{copy-C6zerX3I.js → copy-BAqnFI-F.js} +1 -1
- package/lib/public/assets/{device-explorer-B1pI6b_M.js → device-explorer-CYq_4F_N.js} +3 -3
- package/lib/public/assets/device-explorer-D2AqrrLN.css +1 -0
- package/lib/public/assets/{download-x9WP7mcL.js → download-B6UEAp_1.js} +1 -1
- package/lib/public/assets/{forgot-password-B0TEH4N-.js → forgot-password-CLqNvmrN.js} +1 -1
- package/lib/public/assets/{funnel-Cb40MfFN.js → funnel-Da90BBbT.js} +1 -1
- package/lib/public/assets/{index-BR1wTIPC.js → index-BuIIcmGp.js} +2 -2
- package/lib/public/assets/{index-BvH_ekRy.js → index-MX7IzqyW.js} +1 -1
- package/lib/public/assets/{input-DejcCiTI.js → input-Bq9aY-We.js} +1 -1
- package/lib/public/assets/{keycodes-Mavx5iGg.js → keycodes-CIhXIJyP.js} +1 -1
- package/lib/public/assets/{layers-BKqYLiHE.js → layers-bXjpswQI.js} +1 -1
- package/lib/public/assets/{lock-LFsFhc17.js → lock-pJ72y5Fy.js} +1 -1
- package/lib/public/assets/{login-x2pkzt-t.js → login-UOcHALV2.js} +1 -1
- package/lib/public/assets/{maintenance-settings-CYafcoV-.js → maintenance-settings-XnJgp5yb.js} +1 -1
- package/lib/public/assets/{monitor-_7_uJ8d9.js → monitor-QkAhI1Jx.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-BfLuURKN.js → mouse-pointer-2-B42Da0m4.js} +1 -1
- package/lib/public/assets/{network-Z_zBhpsD.js → network-CKVqcyp6.js} +1 -1
- package/lib/public/assets/{overview-BY5uv08S.js → overview-BORGkN3N.js} +1 -1
- package/lib/public/assets/{page-header-CP2UkykG.js → page-header-CKWFOjOI.js} +1 -1
- package/lib/public/assets/{plus-BTD0dnQ0.js → plus-BpFKVdC8.js} +1 -1
- package/lib/public/assets/{profile-page-BhJZuCS7.js → profile-page-CcbKBicY.js} +1 -1
- package/lib/public/assets/{reset-password-CMN0SO81.js → reset-password-BA0W9bxl.js} +1 -1
- package/lib/public/assets/{runbook-page-CBpPX9_5.js → runbook-page-Cp7ZBq3s.js} +1 -1
- package/lib/public/assets/{select-Uc9E5pye.js → select-DIZWIoVR.js} +1 -1
- package/lib/public/assets/{selector-detail-page-BSyBnRuU.js → selector-detail-page-C_4YuvAp.js} +1 -1
- package/lib/public/assets/{selector-health-DzqxNkzm.js → selector-health-CXjD_Xth.js} +1 -1
- package/lib/public/assets/{selector-health-page-CyPLjoD1.js → selector-health-page-CTqIHeoG.js} +1 -1
- package/lib/public/assets/{session-detail-page-BZQZN1P-.js → session-detail-page-B0KYkk8z.js} +1 -1
- package/lib/public/assets/{settings-CkSWiZq8.js → settings-BcRBKUXd.js} +1 -1
- package/lib/public/assets/{status-pill-outline-BFYni2qo.js → status-pill-outline-Dh2PXSf_.js} +1 -1
- package/lib/public/assets/{tablet-BSd-xSZK.js → tablet-_sXqZztt.js} +1 -1
- package/lib/public/assets/{teams-PpoEQz31.js → teams-DGHT8MKm.js} +1 -1
- package/lib/public/assets/{trash-2-BorJv5_u.js → trash-2-BV88cV3Z.js} +1 -1
- package/lib/public/assets/{upload-C3i7sAZl.js → upload-CIDH9wkj.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-CeZQ3EsH.js → use-password-reset-mode-DYGuSNwl.js} +1 -1
- package/lib/public/assets/{users-CEJ3fC78.js → users-7yviqflc.js} +1 -1
- package/lib/public/assets/{users-Drd7ifJx.js → users-BUE7MoTq.js} +1 -1
- package/lib/public/assets/{video-off-CNzn6bPE.js → video-off-BTRxtlGo.js} +1 -1
- package/lib/public/assets/{webhook-settings-BFqX6QXV.js → webhook-settings-DMKD9Pgm.js} +1 -1
- package/lib/public/assets/{zap-4yN8Jdfw.js → zap-CWE94qcK.js} +1 -1
- package/lib/public/index.html +1 -1
- package/lib/src/InternalHttpClient.js +5 -1
- package/lib/src/XenonCapabilityManager.js +15 -1
- package/lib/src/app/appiumBasePath.js +32 -0
- package/lib/src/app/index.js +12 -0
- package/lib/src/app/insertBeforeRoutes.js +24 -4
- package/lib/src/app/registerCommandAuth.js +152 -33
- package/lib/src/app/routers/control.js +57 -13
- package/lib/src/app/routers/grid.js +28 -8
- package/lib/src/app/ws/h264StreamWs.js +13 -8
- package/lib/src/app/ws/logcatWs.js +12 -7
- package/lib/src/app/ws/upgradeRouter.js +215 -0
- package/lib/src/dashboard/event-manager.js +7 -6
- package/lib/src/data-service/device-service.js +152 -49
- package/lib/src/data-service/device-store.js +81 -10
- package/lib/src/data-service/deviceClaims.js +98 -0
- package/lib/src/data-service/deviceFieldOwners.js +32 -10
- package/lib/src/data-service/prisma-store.js +94 -31
- package/lib/src/device-managers/AndroidDeviceManager.js +13 -15
- package/lib/src/device-managers/HealthMonitorService.js +17 -2
- package/lib/src/device-managers/IOSDeviceManager.js +5 -1
- package/lib/src/device-managers/NodeDevices.js +7 -2
- package/lib/src/device-managers/android/AndroidH264StreamService.js +3 -3
- package/lib/src/device-managers/android/AndroidStreamService.js +6 -5
- package/lib/src/device-managers/android/previewHold.js +2 -2
- package/lib/src/device-managers/ios/IOSDiscoveryService.js +19 -8
- package/lib/src/device-managers/ios/IOSStreamService.js +158 -38
- package/lib/src/device-managers/localDeviceHosts.js +86 -0
- package/lib/src/device-managers/ownDeviceRow.js +38 -0
- package/lib/src/device-utils.js +78 -24
- package/lib/src/gateway/createHandoff.js +73 -0
- package/lib/src/gateway/defaultGateway.js +80 -0
- package/lib/src/gateway/forwardToNode.js +147 -0
- package/lib/src/gateway/hubSessionToken.js +356 -0
- package/lib/src/gateway/internalCall.js +90 -0
- package/lib/src/gateway/nodeSessionStatus.js +140 -0
- package/lib/src/gateway/nodeWebDriverUrl.js +139 -0
- package/lib/src/gateway/sessionCreate.js +136 -0
- package/lib/src/gateway/sessionGateway.js +201 -0
- package/lib/src/gateway/sessionLocator.js +100 -0
- package/lib/src/generated/client/edge.js +7 -4
- package/lib/src/generated/client/index-browser.js +4 -1
- package/lib/src/generated/client/index.d.ts +112 -1
- package/lib/src/generated/client/index.js +7 -4
- package/lib/src/generated/client/package.json +1 -1
- package/lib/src/generated/client/schema.prisma +9 -0
- package/lib/src/generated/client/wasm.js +4 -1
- package/lib/src/helpers/index.js +5 -1
- package/lib/src/logger.js +5 -0
- package/lib/src/middleware/authMiddleware.js +80 -0
- package/lib/src/middleware/commandAuth.js +31 -17
- package/lib/src/middleware/csrfMiddleware.js +3 -2
- package/lib/src/middleware/sessionListingFilter.js +153 -0
- package/lib/src/middleware/sessionUpgradeGuard.js +203 -0
- package/lib/src/plugin.js +27 -1
- package/lib/src/prisma.js +2 -1
- package/lib/src/services/DeviceReconciler.js +5 -2
- package/lib/src/services/OrphanSweeper.js +12 -19
- package/lib/src/services/PortAllocator.js +75 -16
- package/lib/src/services/ServerManager.js +50 -30
- package/lib/src/services/SessionLifecycleService.js +335 -76
- package/lib/src/services/ShutdownCoordinator.js +7 -1
- package/lib/src/services/SocketServer.js +11 -2
- package/lib/src/services/device-access/LiveSessionOwners.js +53 -0
- package/lib/src/services/device-access/SessionOwnerResolver.js +74 -0
- package/lib/src/services/lease/LeaseOrphanSweeper.js +32 -6
- package/lib/src/services/lease/LeaseService.js +19 -5
- package/lib/src/services/session/nodeCreateCaps.js +55 -0
- package/lib/src/services/session/sessionCredentials.js +7 -59
- package/lib/src/sessions/CloudSession.js +12 -0
- package/lib/src/sessions/LocalSession.js +52 -26
- package/lib/src/sessions/RemoteSession.js +116 -9
- package/lib/src/sessions/SessionManager.js +49 -6
- package/lib/src/sessions/appiumUmbrella.js +32 -0
- package/lib/test/helpers/appium-umbrella.js +84 -0
- package/lib/test/helpers/fake-device-table.js +97 -0
- package/lib/test/helpers/loki-stores.js +41 -0
- package/lib/test/helpers/loopbackRequest.js +77 -0
- package/lib/test/helpers/scratch-database.js +100 -0
- package/lib/test/helpers/scratch-port-leases.js +119 -0
- package/lib/test/helpers/test-container.js +35 -27
- package/lib/test/integration/androidDevices.spec.js +5 -4
- package/lib/test/integration/ios/01iOSSimulator.spec.js +6 -5
- package/lib/test/integration/ios/02iOSDevices.spec.js +3 -2
- package/lib/test/integration/prisma-device-store-add-devices.spec.js +14 -4
- package/lib/test/unit/AndroidDeviceManager.spec.js +8 -1
- package/lib/test/unit/DeviceModel.spec.js +9 -9
- package/lib/test/unit/HealingCascade.test.js +5 -1
- package/lib/test/unit/OrphanSweeper.test.js +17 -13
- package/lib/test/unit/SessionHeartbeatWrite.test.js +6 -7
- package/lib/test/unit/StreamTicketService.spec.js +4 -1
- package/lib/test/unit/TokenEndpoint.spec.js +17 -3
- package/lib/test/unit/aggregate-hotspots-session-scope.spec.js +5 -5
- package/lib/test/unit/android-h264-service.spec.js +6 -0
- package/lib/test/unit/android-stream-stall-eof.spec.js +10 -0
- package/lib/test/unit/apps-team-visibility.spec.js +16 -16
- package/lib/test/unit/auth-me-auth-disabled.test.js +7 -4
- package/lib/test/unit/authMiddleware.appTicket.spec.js +5 -5
- package/lib/test/unit/authMiddleware.bearer.spec.js +4 -1
- package/lib/test/unit/authMiddleware.mcpAudience.spec.js +4 -1
- package/lib/test/unit/authMiddleware.streamTicket.spec.js +19 -7
- package/lib/test/unit/authMiddleware.test.js +3 -0
- package/lib/test/unit/bug-report/route.spec.js +9 -9
- package/lib/test/unit/cliargs-admin-only.spec.js +3 -3
- package/lib/test/unit/clipboard-route.spec.js +18 -8
- package/lib/test/unit/command-auth-appium-server.spec.js +187 -32
- package/lib/test/unit/command-auth.spec.js +31 -31
- package/lib/test/unit/control-device-lookup.spec.js +9 -9
- package/lib/test/unit/control-forward-decision.spec.js +115 -0
- package/lib/test/unit/control-lookup-failure.spec.js +3 -3
- package/lib/test/unit/create-error-message.spec.js +43 -0
- package/lib/test/unit/create-handoff.spec.js +86 -0
- package/lib/test/unit/dashboard-events-team-scope.spec.js +6 -3
- package/lib/test/unit/device-access-guard.spec.js +28 -28
- package/lib/test/unit/device-service.spec.js +4 -0
- package/lib/test/unit/device-store-clear-at-boot.spec.js +48 -0
- package/lib/test/unit/device-sync-lost-update.spec.js +17 -89
- package/lib/test/unit/device-team-guard.spec.js +20 -20
- package/lib/test/unit/device-utils.spec.js +8 -0
- package/lib/test/unit/extract-team-cap.spec.js +65 -0
- package/lib/test/unit/grid-admin-only.spec.js +3 -3
- package/lib/test/unit/healing-tier-gate.spec.js +5 -1
- package/lib/test/unit/health-monitor-own-phones.spec.js +102 -0
- package/lib/test/unit/health-monitor-stream-lookup.spec.js +11 -1
- package/lib/test/unit/helpers.spec.js +27 -0
- package/lib/test/unit/hub-boot-sweep-recovery.spec.js +192 -0
- package/lib/test/unit/hub-create-once.spec.js +190 -0
- package/lib/test/unit/hub-create-session-umbrella.spec.js +160 -0
- package/lib/test/unit/hub-gateway-create-appium-server.spec.js +591 -0
- package/lib/test/unit/hub-node-control-forward.spec.js +291 -0
- package/lib/test/unit/hub-node-gateway-appium-server.spec.js +594 -0
- package/lib/test/unit/hub-node-race.spec.js +401 -0
- package/lib/test/unit/hub-node-same-host.spec.js +356 -0
- package/lib/test/unit/hub-register-removal.spec.js +165 -0
- package/lib/test/unit/hub-remote-session-heartbeat.spec.js +277 -0
- package/lib/test/unit/hub-routed-session-recovery.spec.js +151 -0
- package/lib/test/unit/hub-session-token.spec.js +265 -0
- package/lib/test/unit/insert-before-routes.spec.js +5 -5
- package/lib/test/unit/install-repository-app-team.spec.js +2 -2
- package/lib/test/unit/interceptor/MitmProxyHost.spec.js +23 -10
- package/lib/test/unit/internal-call.spec.js +181 -0
- package/lib/test/unit/ios-discovery-same-host.spec.js +193 -0
- package/lib/test/unit/ios-stream-appium-tunnel.spec.js +317 -0
- package/lib/test/unit/ios-stream-port-leases.spec.js +299 -0
- package/lib/test/unit/ios-wda-status-identity.spec.js +84 -0
- package/lib/test/unit/is-xenon-running.spec.js +69 -0
- package/lib/test/unit/lease/LeaseOrphanSweeper.spec.js +2 -2
- package/lib/test/unit/lease/LeaseService.spec.js +28 -1
- package/lib/test/unit/lease/lease-reap-held-phone.spec.js +154 -0
- package/lib/test/unit/lease/lease-sweeper-expiry.spec.js +92 -0
- package/lib/test/unit/lease/lease-team-visibility.spec.js +2 -2
- package/lib/test/unit/lease/lease-token-log-filter.spec.js +242 -64
- package/lib/test/unit/lease/lease-token-oracle.spec.js +20 -7
- package/lib/test/unit/lease/session-lease-proof.spec.js +8 -3
- package/lib/test/unit/logcat-ws.spec.js +4 -1
- package/lib/test/unit/loopback-request.spec.js +81 -0
- package/lib/test/unit/node-create-caps.spec.js +54 -0
- package/lib/test/unit/node-gateway-create-appium-server.spec.js +354 -0
- package/lib/test/unit/node-hub-session-owner.spec.js +223 -0
- package/lib/test/unit/omni-vision.spec.js +7 -3
- package/lib/test/unit/plugin.spec.js +45 -4
- package/lib/test/unit/port-allocator-os-probe.spec.js +151 -0
- package/lib/test/unit/profile-router.test.js +11 -11
- package/lib/test/unit/queue-requester.spec.js +5 -0
- package/lib/test/unit/queue-team-scope-routes.spec.js +17 -16
- package/lib/test/unit/queue-visibility.spec.js +1 -1
- package/lib/test/unit/recording-downloads-visibility.spec.js +2 -2
- package/lib/test/unit/recording-instrumentation.spec.js +5 -0
- package/lib/test/unit/recording-source-ended.spec.js +5 -0
- package/lib/test/unit/recording-store.spec.js +9 -3
- package/lib/test/unit/recordings-library-routes.spec.js +51 -51
- package/lib/test/unit/recordings-write-visibility.spec.js +2 -2
- package/lib/test/unit/remote-session-create.spec.js +130 -0
- package/lib/test/unit/reservation-team-visibility.spec.js +5 -5
- package/lib/test/unit/reset-link.test.js +14 -14
- package/lib/test/unit/session-app-resolution.spec.js +14 -10
- package/lib/test/unit/session-assets.spec.js +9 -9
- package/lib/test/unit/session-attribution-wiring.spec.js +29 -2
- package/lib/test/unit/session-create-layer.spec.js +255 -0
- package/lib/test/unit/session-credential-strip.spec.js +25 -9
- package/lib/test/unit/session-credentials.spec.js +0 -47
- package/lib/test/unit/session-listing-auth.spec.js +345 -0
- package/lib/test/unit/session-locator.spec.js +250 -0
- package/lib/test/unit/session-node-calls.spec.js +174 -0
- package/lib/test/unit/session-owner-resolver.spec.js +107 -0
- package/lib/test/unit/session-recovery-routing.spec.js +118 -0
- package/lib/test/unit/session-upgrade-guard.spec.js +571 -0
- package/lib/test/unit/shutdown-drain-remote.spec.js +58 -0
- package/lib/test/unit/socketServer.bearer.spec.js +3 -1
- package/lib/test/unit/stream-leave-route.spec.js +15 -7
- package/lib/test/unit/stream-own-device-row.spec.js +164 -0
- package/lib/test/unit/stream-stop-ownership.spec.js +13 -5
- package/lib/test/unit/stream-stop-recording.spec.js +13 -5
- package/lib/test/unit/stream-ticket-identity.spec.js +15 -5
- package/lib/test/unit/upgrade-router.spec.js +446 -0
- package/lib/test/unit/users-router.test.js +11 -8
- package/lib/test/unit/verify-credential.spec.js +4 -1
- package/lib/test/unit/webdriver-info-route.spec.js +64 -0
- package/lib/test/unit/ws-upgrade-routing-appium-server.spec.js +500 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -2
- package/prisma/migrations/20260929120000_device_claims/migration.sql +8 -0
- package/prisma/schema.prisma +9 -0
- package/lib/public/assets/BugReportButton-DKYsOdGV.js +0 -10
- package/lib/public/assets/device-explorer-DV8rWRxL.css +0 -1
- package/lib/src/proxy/wd-command-proxy.js +0 -221
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.useScratchDatabase = useScratchDatabase;
|
|
16
|
+
const child_process_1 = require("child_process");
|
|
17
|
+
const fs_1 = __importDefault(require("fs"));
|
|
18
|
+
const os_1 = __importDefault(require("os"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
21
|
+
const client_1 = require("../../src/generated/client");
|
|
22
|
+
const prisma_1 = require("../../src/prisma");
|
|
23
|
+
// Every model the `prisma` wrapper exposes (src/prisma.ts MODEL_DELEGATES).
|
|
24
|
+
const MODELS = [
|
|
25
|
+
'build',
|
|
26
|
+
'session',
|
|
27
|
+
'sessionLog',
|
|
28
|
+
'log',
|
|
29
|
+
'profiling',
|
|
30
|
+
'app',
|
|
31
|
+
'device',
|
|
32
|
+
'pendingSession',
|
|
33
|
+
'cLIArgs',
|
|
34
|
+
'webhookConfig',
|
|
35
|
+
'webConfig',
|
|
36
|
+
'locatorEtalon',
|
|
37
|
+
'lease',
|
|
38
|
+
'portLease',
|
|
39
|
+
'apiKey',
|
|
40
|
+
'selectorState',
|
|
41
|
+
'user',
|
|
42
|
+
'userSession',
|
|
43
|
+
'passwordResetToken',
|
|
44
|
+
'team',
|
|
45
|
+
'teamMember',
|
|
46
|
+
'eventLog',
|
|
47
|
+
'project',
|
|
48
|
+
'recording',
|
|
49
|
+
'bookmark',
|
|
50
|
+
'annotation',
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Back the whole `prisma` wrapper with a scratch SQLite file for the enclosing
|
|
54
|
+
* `describe`, so the real queries (the device store, the session lifecycle,
|
|
55
|
+
* SessionOwnerResolver) run against a real database that is not the server's.
|
|
56
|
+
* Like useScratchPortLeases, for every model.
|
|
57
|
+
*
|
|
58
|
+
* Call it inside a `describe`, never at the top of a file. The database is
|
|
59
|
+
* migrated once per suite; the stubs are made before each test and removed
|
|
60
|
+
* after it, so a spec's own `sinon.restore()` can't leave the next test on
|
|
61
|
+
* the real database. Tests empty the tables they use.
|
|
62
|
+
*/
|
|
63
|
+
function useScratchDatabase() {
|
|
64
|
+
const ctx = {};
|
|
65
|
+
const sandbox = sinon_1.default.createSandbox();
|
|
66
|
+
let dbPath = '';
|
|
67
|
+
before(function () {
|
|
68
|
+
this.timeout(90000);
|
|
69
|
+
dbPath = path_1.default.join(os_1.default.tmpdir(), `xenon-scratch-${process.pid}-${Date.now()}.db`);
|
|
70
|
+
const url = `file:${dbPath}`;
|
|
71
|
+
(0, child_process_1.execSync)('npx prisma migrate deploy', {
|
|
72
|
+
cwd: path_1.default.resolve(__dirname, '../..'),
|
|
73
|
+
env: Object.assign(Object.assign({}, process.env), { DATABASE_URL: url }),
|
|
74
|
+
stdio: 'pipe',
|
|
75
|
+
});
|
|
76
|
+
ctx.db = new client_1.PrismaClient({ datasources: { db: { url } } });
|
|
77
|
+
});
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
for (const model of MODELS) {
|
|
80
|
+
const wrapper = prisma_1.prisma[model];
|
|
81
|
+
const delegate = ctx.db[model];
|
|
82
|
+
for (const [name, value] of Object.entries(wrapper)) {
|
|
83
|
+
if (typeof value !== 'function' || typeof delegate[name] !== 'function')
|
|
84
|
+
continue;
|
|
85
|
+
sandbox.stub(wrapper, name).callsFake((...args) => delegate[name](...args));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
afterEach(() => sandbox.restore());
|
|
90
|
+
after(() => __awaiter(this, void 0, void 0, function* () {
|
|
91
|
+
sandbox.restore();
|
|
92
|
+
if (ctx.db)
|
|
93
|
+
yield ctx.db.$disconnect();
|
|
94
|
+
for (const f of [dbPath, `${dbPath}-journal`]) {
|
|
95
|
+
if (f && fs_1.default.existsSync(f))
|
|
96
|
+
fs_1.default.unlinkSync(f);
|
|
97
|
+
}
|
|
98
|
+
}));
|
|
99
|
+
return ctx;
|
|
100
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.useScratchPortLeases = useScratchPortLeases;
|
|
16
|
+
const child_process_1 = require("child_process");
|
|
17
|
+
const fs_1 = __importDefault(require("fs"));
|
|
18
|
+
const net_1 = __importDefault(require("net"));
|
|
19
|
+
const os_1 = __importDefault(require("os"));
|
|
20
|
+
const path_1 = __importDefault(require("path"));
|
|
21
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
22
|
+
const client_1 = require("../../src/generated/client");
|
|
23
|
+
const prisma_1 = require("../../src/prisma");
|
|
24
|
+
const METHODS = [
|
|
25
|
+
'findUnique',
|
|
26
|
+
'findFirst',
|
|
27
|
+
'findMany',
|
|
28
|
+
'create',
|
|
29
|
+
'update',
|
|
30
|
+
'upsert',
|
|
31
|
+
'delete',
|
|
32
|
+
'deleteMany',
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Below every OS's ephemeral range (macOS 49152-65535, Linux 32768-60999).
|
|
36
|
+
* The blocks used to come from 40000-60000, half of it inside macOS's range,
|
|
37
|
+
* where the suite's own outgoing connections take ports: now and then one
|
|
38
|
+
* held base+1 while a two-port range needed it, and PortAllocator answered
|
|
39
|
+
* "range exhausted" in the full run only.
|
|
40
|
+
*/
|
|
41
|
+
const FIRST_BASE = 20000;
|
|
42
|
+
const BLOCKS = 128;
|
|
43
|
+
const USED_OFFSETS = [...Array(10).keys(), ...Array.from({ length: 10 }, (_, i) => 50 + i)];
|
|
44
|
+
function bindable(port, host) {
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
const server = net_1.default.createServer();
|
|
47
|
+
server.once('error', (err) =>
|
|
48
|
+
// A host without IPv6 can't have a listener there either.
|
|
49
|
+
resolve(err.code === 'EADDRNOTAVAIL' || err.code === 'EAFNOSUPPORT'));
|
|
50
|
+
server.listen(port, host, () => server.close(() => resolve(true)));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function blockIsFree(base) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
for (const offset of USED_OFFSETS) {
|
|
56
|
+
if (!(yield bindable(base + offset, '0.0.0.0')))
|
|
57
|
+
return false;
|
|
58
|
+
if (!(yield bindable(base + offset, '::')))
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function freeBlock() {
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
let base = FIRST_BASE;
|
|
67
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
68
|
+
base = FIRST_BASE + Math.floor(Math.random() * BLOCKS) * 100;
|
|
69
|
+
if (yield blockIsFree(base))
|
|
70
|
+
return base;
|
|
71
|
+
}
|
|
72
|
+
return base;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Back `prisma.portLease` with a scratch SQLite file for the enclosing
|
|
77
|
+
* `describe`, so PortAllocator runs its real queries (unique constraint on
|
|
78
|
+
* `port` included) without touching the server's database.
|
|
79
|
+
*
|
|
80
|
+
* Call it inside a `describe`, never at the top of a file. The database is
|
|
81
|
+
* created once per suite; the table is emptied and the stubs are re-made
|
|
82
|
+
* before each test, so a spec's own `sinon.restore()` can't leave the next
|
|
83
|
+
* test pointed at the real database.
|
|
84
|
+
*/
|
|
85
|
+
function useScratchPortLeases() {
|
|
86
|
+
const ctx = {};
|
|
87
|
+
const sandbox = sinon_1.default.createSandbox();
|
|
88
|
+
let dbPath = '';
|
|
89
|
+
before(function () {
|
|
90
|
+
this.timeout(60000);
|
|
91
|
+
dbPath = path_1.default.join(os_1.default.tmpdir(), `xenon-port-leases-${process.pid}-${Date.now()}.db`);
|
|
92
|
+
const url = `file:${dbPath}`;
|
|
93
|
+
(0, child_process_1.execSync)('npx prisma migrate deploy', {
|
|
94
|
+
cwd: path_1.default.resolve(__dirname, '../..'),
|
|
95
|
+
env: Object.assign(Object.assign({}, process.env), { DATABASE_URL: url }),
|
|
96
|
+
stdio: 'pipe',
|
|
97
|
+
});
|
|
98
|
+
ctx.db = new client_1.PrismaClient({ datasources: { db: { url } } });
|
|
99
|
+
});
|
|
100
|
+
beforeEach(() => __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
yield ctx.db.portLease.deleteMany({});
|
|
102
|
+
ctx.base = yield freeBlock();
|
|
103
|
+
const wrapper = prisma_1.prisma.portLease;
|
|
104
|
+
for (const m of METHODS) {
|
|
105
|
+
sandbox.stub(wrapper, m).callsFake((...args) => ctx.db.portLease[m](...args));
|
|
106
|
+
}
|
|
107
|
+
}));
|
|
108
|
+
afterEach(() => sandbox.restore());
|
|
109
|
+
after(() => __awaiter(this, void 0, void 0, function* () {
|
|
110
|
+
sandbox.restore();
|
|
111
|
+
if (ctx.db)
|
|
112
|
+
yield ctx.db.$disconnect();
|
|
113
|
+
for (const f of [dbPath, `${dbPath}-journal`]) {
|
|
114
|
+
if (f && fs_1.default.existsSync(f))
|
|
115
|
+
fs_1.default.unlinkSync(f);
|
|
116
|
+
}
|
|
117
|
+
}));
|
|
118
|
+
return ctx;
|
|
119
|
+
}
|
|
@@ -23,20 +23,38 @@ const PluginContext_1 = require("../../src/PluginContext");
|
|
|
23
23
|
const IPluginArgs_1 = require("../../src/interfaces/IPluginArgs");
|
|
24
24
|
const uuid_1 = require("uuid");
|
|
25
25
|
const db_1 = require("../../src/data-service/db");
|
|
26
|
-
const device_store_1 = require("../../src/data-service/device-store");
|
|
27
26
|
const AndroidDeviceManager_1 = __importDefault(require("../../src/device-managers/AndroidDeviceManager"));
|
|
28
27
|
const IOSDeviceManager_1 = __importDefault(require("../../src/device-managers/IOSDeviceManager"));
|
|
29
28
|
const device_managers_1 = require("../../src/device-managers");
|
|
30
|
-
const sinon_1 = __importDefault(require("sinon"));
|
|
31
29
|
const IOSDiscoveryService_1 = require("../../src/device-managers/ios/IOSDiscoveryService");
|
|
32
|
-
const
|
|
30
|
+
const container_registration_1 = require("./container-registration");
|
|
33
31
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* The classes setupTestContainer() builds. Each call makes new ones, with its
|
|
33
|
+
* own PluginContext; the ones already registered are put back by
|
|
34
|
+
* resetTestContainer().
|
|
35
|
+
*/
|
|
36
|
+
const BUILT = [
|
|
37
|
+
PluginContext_1.PluginContext,
|
|
38
|
+
IOSDiscoveryService_1.IOSDiscoveryService,
|
|
39
|
+
AndroidDeviceManager_1.default,
|
|
40
|
+
IOSDeviceManager_1.default,
|
|
41
|
+
device_managers_1.XenonManager,
|
|
42
|
+
];
|
|
43
|
+
/** What each setupTestContainer() call not yet undone replaced, newest last. */
|
|
44
|
+
const undo = [];
|
|
45
|
+
/**
|
|
46
|
+
* Registers a PluginContext configured for testing, and the device managers
|
|
47
|
+
* built with it. Undo it with resetTestContainer() in the same `describe`.
|
|
48
|
+
*
|
|
49
|
+
* Only the ids it builds are replaced. It used to Container.reset(), which
|
|
50
|
+
* discarded every singleton in the process, including the ones other specs
|
|
51
|
+
* and the server's own modules had built and still held.
|
|
36
52
|
*/
|
|
37
53
|
function setupTestContainer(overrides) {
|
|
38
|
-
|
|
39
|
-
|
|
54
|
+
undo.push((0, container_registration_1.saveRegistrations)('LocalStorage', ...BUILT));
|
|
55
|
+
// Unbuilt again, so the Container.get() calls below make new instances.
|
|
56
|
+
for (const id of BUILT)
|
|
57
|
+
typedi_1.Container.set({ id, type: id });
|
|
40
58
|
const nodeId = (0, uuid_1.v4)();
|
|
41
59
|
const port = 4723;
|
|
42
60
|
const pluginArgs = Object.assign({}, IPluginArgs_1.DefaultPluginArgs, overrides || {});
|
|
@@ -85,28 +103,18 @@ function createTestXenonManager(pluginArgs) {
|
|
|
85
103
|
xenonManager.init();
|
|
86
104
|
return xenonManager;
|
|
87
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Puts back every registration the setupTestContainer() calls since the last
|
|
108
|
+
* reset replaced, newest first, and empties the in-memory device database.
|
|
109
|
+
*
|
|
110
|
+
* It changes nothing else. It used to stub device discovery on the
|
|
111
|
+
* AndroidDeviceManager and IOSDiscoveryService prototypes and never restore
|
|
112
|
+
* the stubs, so every spec that ran later got no devices from discovery.
|
|
113
|
+
*/
|
|
88
114
|
function resetTestContainer() {
|
|
89
115
|
return __awaiter(this, void 0, void 0, function* () {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// Stub discovery methods to prevent background pollution
|
|
93
|
-
sandbox.stub(AndroidDeviceManager_1.default.prototype, 'getDevices').resolves([]);
|
|
94
|
-
sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'getDevices').resolves([]);
|
|
95
|
-
// @ts-ignore - Stubbing internal methods to be extra safe
|
|
96
|
-
sandbox.stub(AndroidDeviceManager_1.default.prototype, 'fetchAndroidDevices').resolves([]);
|
|
97
|
-
// @ts-ignore
|
|
98
|
-
sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'fetchLocalIOSDevices').resolves([]);
|
|
99
|
-
// @ts-ignore
|
|
100
|
-
sandbox.stub(IOSDiscoveryService_1.IOSDiscoveryService.prototype, 'fetchLocalSimulators').resolves([]);
|
|
101
|
-
// Clear DeviceStoreFactory static caches to prevent cross-test pollution
|
|
102
|
-
// @ts-ignore - Accessing private static members for test cleanup
|
|
103
|
-
device_store_1.DeviceStoreFactory._deviceStore = undefined;
|
|
104
|
-
// @ts-ignore
|
|
105
|
-
device_store_1.DeviceStoreFactory._pendingSessionStore = undefined;
|
|
106
|
-
// @ts-ignore
|
|
107
|
-
device_store_1.DeviceStoreFactory._cliArgsStore = undefined;
|
|
108
|
-
// @ts-ignore
|
|
109
|
-
device_store_1.DeviceStoreFactory._healEtalonStore = undefined;
|
|
116
|
+
for (const restore of undo.splice(0).reverse())
|
|
117
|
+
restore();
|
|
110
118
|
yield db_1.XenonDatabase.reset();
|
|
111
119
|
});
|
|
112
120
|
}
|
|
@@ -49,6 +49,7 @@ require("reflect-metadata");
|
|
|
49
49
|
const chai_1 = __importStar(require("chai"));
|
|
50
50
|
const db_1 = require("../../src/data-service/db");
|
|
51
51
|
const device_utils_1 = require("../../src/device-utils");
|
|
52
|
+
const localDeviceHosts_1 = require("../../src/device-managers/localDeviceHosts");
|
|
52
53
|
const IPluginArgs_1 = require("../../src/interfaces/IPluginArgs");
|
|
53
54
|
const ip_1 = __importDefault(require("ip"));
|
|
54
55
|
const async_wait_until_1 = __importDefault(require("async-wait-until"));
|
|
@@ -73,7 +74,7 @@ describe('Android Test', () => {
|
|
|
73
74
|
yield (0, device_utils_1.initializeStorage)();
|
|
74
75
|
yield deviceManager.getDevices();
|
|
75
76
|
const hub = pluginArgs.hub;
|
|
76
|
-
yield (0, device_utils_1.updateDeviceList)(pluginArgs
|
|
77
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723), hub);
|
|
77
78
|
yield (0, device_utils_1.cleanPendingSessions)(0);
|
|
78
79
|
yield (0, device_service_1.unblockDeviceMatchingFilter)({});
|
|
79
80
|
const capabilities = {
|
|
@@ -95,7 +96,7 @@ describe('Android Test', () => {
|
|
|
95
96
|
it.skip('Allocate second free device and verify both the device state is busy in db', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
96
97
|
yield (0, device_utils_1.initializeStorage)();
|
|
97
98
|
deviceManager = (0, test_container_1.createTestXenonManager)(Object.assign({}, pluginArgs, { platform: 'android' }));
|
|
98
|
-
yield (0, device_utils_1.updateDeviceList)(
|
|
99
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723));
|
|
99
100
|
const capabilities = {
|
|
100
101
|
alwaysMatch: {
|
|
101
102
|
platformName: 'android',
|
|
@@ -108,7 +109,7 @@ describe('Android Test', () => {
|
|
|
108
109
|
// wait until there are two devices and both are not offline
|
|
109
110
|
let devices;
|
|
110
111
|
(0, async_wait_until_1.default)(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
|
-
yield (0, device_utils_1.updateDeviceList)(
|
|
112
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723));
|
|
112
113
|
devices = yield deviceManager.getDevices();
|
|
113
114
|
return devices.length === 2 && devices.every((device) => !device.offline);
|
|
114
115
|
}));
|
|
@@ -120,7 +121,7 @@ describe('Android Test', () => {
|
|
|
120
121
|
yield (0, device_utils_1.initializeStorage)();
|
|
121
122
|
deviceManager = (0, test_container_1.createTestXenonManager)(pluginArgs);
|
|
122
123
|
const hub = pluginArgs.hub;
|
|
123
|
-
yield (0, device_utils_1.updateDeviceList)(pluginArgs
|
|
124
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723), hub);
|
|
124
125
|
const capabilities = {
|
|
125
126
|
alwaysMatch: {
|
|
126
127
|
platformName: 'android',
|
|
@@ -22,6 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
22
22
|
require("reflect-metadata");
|
|
23
23
|
const chai_1 = require("chai");
|
|
24
24
|
const device_utils_1 = require("../../../src/device-utils");
|
|
25
|
+
const localDeviceHosts_1 = require("../../../src/device-managers/localDeviceHosts");
|
|
25
26
|
const db_1 = require("../../../src/data-service/db");
|
|
26
27
|
const node_simctl_1 = __importDefault(require("node-simctl"));
|
|
27
28
|
const pluginArgs_1 = require("../../../src/data-service/pluginArgs");
|
|
@@ -56,7 +57,7 @@ function initDeviceFarm(iosDeviceType) {
|
|
|
56
57
|
}));
|
|
57
58
|
(0, chai_1.expect)(deviceManager.getMaxSessionCount()).to.be.eql(1);
|
|
58
59
|
const hub = pluginArgs.hub;
|
|
59
|
-
yield (0, device_utils_1.updateDeviceList)(pluginArgs
|
|
60
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723), hub);
|
|
60
61
|
yield markSimulatorsAsBooted();
|
|
61
62
|
yield (0, device_service_1.unblockDeviceMatchingFilter)({});
|
|
62
63
|
yield (0, device_utils_1.cleanPendingSessions)(0);
|
|
@@ -155,7 +156,7 @@ describe('IOS Simulator Test', () => {
|
|
|
155
156
|
yield (0, device_utils_1.initializeStorage)();
|
|
156
157
|
const deviceManager = (0, test_container_1.createTestXenonManager)(pluginArgs);
|
|
157
158
|
const hub = pluginArgs.hub;
|
|
158
|
-
yield (0, device_utils_1.updateDeviceList)(pluginArgs
|
|
159
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723), hub);
|
|
159
160
|
yield markSimulatorsAsBooted();
|
|
160
161
|
yield (0, device_service_1.unblockDeviceMatchingFilter)({});
|
|
161
162
|
yield (0, device_utils_1.cleanPendingSessions)(0);
|
|
@@ -184,7 +185,7 @@ describe('IOS Simulator Test', () => {
|
|
|
184
185
|
yield (0, device_utils_1.initializeStorage)();
|
|
185
186
|
const deviceManager = (0, test_container_1.createTestXenonManager)(pluginArgs);
|
|
186
187
|
const hub = pluginArgs.hub;
|
|
187
|
-
yield (0, device_utils_1.updateDeviceList)(pluginArgs
|
|
188
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723), hub);
|
|
188
189
|
yield markSimulatorsAsBooted();
|
|
189
190
|
yield (0, device_service_1.unblockDeviceMatchingFilter)({});
|
|
190
191
|
yield (0, device_utils_1.cleanPendingSessions)(0);
|
|
@@ -215,7 +216,7 @@ describe('IOS Simulator Test', () => {
|
|
|
215
216
|
yield (0, device_utils_1.initializeStorage)();
|
|
216
217
|
const deviceManager = (0, test_container_1.createTestXenonManager)(pluginArgs);
|
|
217
218
|
const hub = pluginArgs.hub;
|
|
218
|
-
yield (0, device_utils_1.updateDeviceList)(pluginArgs
|
|
219
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723), hub);
|
|
219
220
|
yield markSimulatorsAsBooted();
|
|
220
221
|
yield (0, device_service_1.unblockDeviceMatchingFilter)({});
|
|
221
222
|
yield (0, device_utils_1.cleanPendingSessions)(0);
|
|
@@ -265,7 +266,7 @@ describe('Boot simulator test', () => __awaiter(void 0, void 0, void 0, function
|
|
|
265
266
|
yield (0, device_utils_1.initializeStorage)();
|
|
266
267
|
const deviceManager = (0, test_container_1.createTestXenonManager)(pluginArgs);
|
|
267
268
|
const hub = pluginArgs.hub;
|
|
268
|
-
yield (0, device_utils_1.updateDeviceList)(pluginArgs
|
|
269
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723), hub);
|
|
269
270
|
const capabilities = {
|
|
270
271
|
alwaysMatch: {
|
|
271
272
|
platformName: 'iOS',
|
|
@@ -16,6 +16,7 @@ require("reflect-metadata");
|
|
|
16
16
|
const chai_1 = require("chai");
|
|
17
17
|
const ip_1 = __importDefault(require("ip"));
|
|
18
18
|
const device_utils_1 = require("../../../src/device-utils");
|
|
19
|
+
const localDeviceHosts_1 = require("../../../src/device-managers/localDeviceHosts");
|
|
19
20
|
const db_1 = require("../../../src/data-service/db");
|
|
20
21
|
const IPluginArgs_1 = require("../../../src/interfaces/IPluginArgs");
|
|
21
22
|
const device_service_1 = require("../../../src/data-service/device-service");
|
|
@@ -39,7 +40,7 @@ describe('IOS Test', () => {
|
|
|
39
40
|
d.plugin['xenon'].iosDeviceType = 'real';
|
|
40
41
|
});
|
|
41
42
|
const deviceManager = (0, test_container_1.createTestXenonManager)(pluginArgs);
|
|
42
|
-
yield (0, device_utils_1.updateDeviceList)(
|
|
43
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723));
|
|
43
44
|
const capabilities = {
|
|
44
45
|
alwaysMatch: {
|
|
45
46
|
platformName: 'iOS',
|
|
@@ -57,7 +58,7 @@ describe('IOS Test', () => {
|
|
|
57
58
|
it('Should throw error if the IPA does not match with device type real', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
59
|
yield (0, device_utils_1.initializeStorage)();
|
|
59
60
|
const deviceManager = (0, test_container_1.createTestXenonManager)(pluginArgs);
|
|
60
|
-
yield (0, device_utils_1.updateDeviceList)(
|
|
61
|
+
yield (0, device_utils_1.updateDeviceList)((0, localDeviceHosts_1.localDeviceHosts)(pluginArgs, 4723));
|
|
61
62
|
const capabilities = {
|
|
62
63
|
alwaysMatch: {
|
|
63
64
|
platformName: 'iOS',
|
|
@@ -65,10 +65,20 @@ describe('PrismaDeviceStore.addDevices (integration)', function () {
|
|
|
65
65
|
(0, chai_1.expect)(yield row(NEW)).to.include({ name: 'Pixel 8', busy: false });
|
|
66
66
|
(0, chai_1.expect)(yield row(KNOWN)).to.include({ busy: true });
|
|
67
67
|
}));
|
|
68
|
-
it('
|
|
69
|
-
yield
|
|
70
|
-
|
|
68
|
+
it("as a node's report, records the node's busy apart and never writes the session", () => __awaiter(this, void 0, void 0, function* () {
|
|
69
|
+
yield prisma_1.prisma.device.updateMany({
|
|
70
|
+
where: { udid: KNOWN, host: HOST },
|
|
71
|
+
data: { claimSessionId: 'sess-1', claimedAt: 41 },
|
|
72
|
+
});
|
|
73
|
+
yield store.addDevices([phone(KNOWN, { busy: false, session_id: 'node-sess', sdk: '11' })], {
|
|
74
|
+
nodeReport: true,
|
|
75
|
+
});
|
|
76
|
+
(0, chai_1.expect)(yield row(KNOWN)).to.include({
|
|
77
|
+
sdk: '11',
|
|
78
|
+
nodeBusy: false,
|
|
79
|
+
busy: true,
|
|
80
|
+
session_id: 'sess-1',
|
|
81
|
+
claimSessionId: 'sess-1',
|
|
71
82
|
});
|
|
72
|
-
(0, chai_1.expect)(yield row(KNOWN)).to.include({ busy: false, session_id: 'node-sess' });
|
|
73
83
|
}));
|
|
74
84
|
});
|
|
@@ -18,9 +18,13 @@ const adbkit_1 = __importDefault(require("@devicefarmer/adbkit"));
|
|
|
18
18
|
const appium_adb_1 = require("appium-adb");
|
|
19
19
|
const chai_1 = require("chai");
|
|
20
20
|
const test_container_1 = require("../helpers/test-container");
|
|
21
|
+
const scratch_database_1 = require("../helpers/scratch-database");
|
|
21
22
|
const GetAdbOriginal_1 = require("./GetAdbOriginal");
|
|
22
23
|
const sandbox = sinon_1.default.createSandbox();
|
|
23
24
|
describe('Android Device Manager', () => {
|
|
25
|
+
// deviceInfo() leases the phone's ports through Prisma. Without a database
|
|
26
|
+
// of its own that was the developer's ~/.cache/xenon/xenon.db.
|
|
27
|
+
(0, scratch_database_1.useScratchDatabase)();
|
|
24
28
|
let adb;
|
|
25
29
|
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
26
30
|
sandbox.restore();
|
|
@@ -37,7 +41,10 @@ describe('Android Device Manager', () => {
|
|
|
37
41
|
});
|
|
38
42
|
}));
|
|
39
43
|
afterEach(function () {
|
|
40
|
-
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
sandbox.restore();
|
|
46
|
+
yield (0, test_container_1.resetTestContainer)();
|
|
47
|
+
});
|
|
41
48
|
});
|
|
42
49
|
it('Android Device List to have added state', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
50
|
const androidDevices = (0, test_container_1.createTestAndroidManager)({ platform: 'android' });
|
|
@@ -19,18 +19,20 @@ const device_service_1 = require("../../src/data-service/device-service");
|
|
|
19
19
|
const devices_1 = require("./fixtures/devices");
|
|
20
20
|
const chai_2 = require("chai");
|
|
21
21
|
const device_service_2 = require("../../src/data-service/device-service");
|
|
22
|
-
const sinon_1 = __importDefault(require("sinon"));
|
|
23
|
-
chai_1.default.should();
|
|
24
|
-
const sandbox = sinon_1.default.createSandbox();
|
|
25
22
|
const test_container_1 = require("../helpers/test-container");
|
|
26
|
-
|
|
23
|
+
const loki_stores_1 = require("../helpers/loki-stores");
|
|
24
|
+
chai_1.default.should();
|
|
25
|
+
describe('Model Test', () => {
|
|
26
|
+
// The in-memory store this spec is about. Run on its own, without the
|
|
27
|
+
// NODE_ENV=test that test:all sets, it used the Prisma store instead: the
|
|
28
|
+
// developer's own database, whose tables it wrote to.
|
|
29
|
+
(0, loki_stores_1.useLokiStores)();
|
|
27
30
|
before('Add device collection', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
31
|
yield (0, test_container_1.resetTestContainer)();
|
|
29
32
|
(0, chai_2.expect)((yield db_1.XenonDatabase.DeviceModel).chain().find().data().length).to.be.equal(0);
|
|
30
33
|
(0, chai_2.expect)(devices_1.deviceMock.length).to.be.greaterThanOrEqual(1);
|
|
31
34
|
// console.log(`deviceMock length: ${deviceMock.length}`);
|
|
32
35
|
(yield db_1.XenonDatabase.DeviceModel).insert(devices_1.deviceMock);
|
|
33
|
-
(yield db_1.XenonDatabase.db).saveDatabase();
|
|
34
36
|
// console.log(`result: ${result}`);
|
|
35
37
|
// console.log(`device model length: ${deviceModel.find().length}`);
|
|
36
38
|
(yield db_1.XenonDatabase.DeviceModel)
|
|
@@ -39,9 +41,7 @@ describe('Model Test', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
39
41
|
.data()
|
|
40
42
|
.length.should.be.equal(devices_1.deviceMock.length);
|
|
41
43
|
}));
|
|
42
|
-
after('clean', () =>
|
|
43
|
-
sandbox.restore();
|
|
44
|
-
});
|
|
44
|
+
after('clean', () => (0, test_container_1.resetTestContainer)());
|
|
45
45
|
it('Should remove device from old pool when new poll call does not have the device', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
46
46
|
const findDevice = (yield db_1.XenonDatabase.DeviceModel)
|
|
47
47
|
.chain()
|
|
@@ -157,4 +157,4 @@ describe('Model Test', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
157
157
|
const updatedDeviceUdids = updatedDeviceList.map((device) => device.udid);
|
|
158
158
|
addedDeviceUdids.forEach((udid) => updatedDeviceUdids.includes(udid).should.be.true);
|
|
159
159
|
}));
|
|
160
|
-
})
|
|
160
|
+
});
|
|
@@ -9,12 +9,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
require("reflect-metadata");
|
|
12
13
|
const chai_1 = require("chai");
|
|
13
14
|
const HealingOrchestrator_1 = require("../../src/services/healing/HealingOrchestrator");
|
|
14
15
|
const types_1 = require("../../src/services/healing/types");
|
|
15
16
|
const typedi_1 = require("typedi");
|
|
16
17
|
const HealEtalonService_1 = require("../../src/services/healing/HealEtalonService");
|
|
17
18
|
const HealedLocatorGenerator_1 = require("../../src/services/healing/HealedLocatorGenerator");
|
|
19
|
+
const container_registration_1 = require("../helpers/container-registration");
|
|
18
20
|
// Mock Tesseract
|
|
19
21
|
const TesseractMock = {
|
|
20
22
|
recognize: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -38,8 +40,9 @@ describe('Healing Orchestrator - Cascade Strategy', () => {
|
|
|
38
40
|
let orchestrator;
|
|
39
41
|
let mockEtalonService;
|
|
40
42
|
let mockGenerator;
|
|
43
|
+
let restoreContainer;
|
|
41
44
|
beforeEach(() => {
|
|
42
|
-
|
|
45
|
+
restoreContainer = (0, container_registration_1.saveRegistrations)(HealEtalonService_1.HealEtalonService, HealedLocatorGenerator_1.HealedLocatorGenerator);
|
|
43
46
|
mockEtalonService = {
|
|
44
47
|
getSignature: () => __awaiter(void 0, void 0, void 0, function* () { return null; }),
|
|
45
48
|
saveSignature: () => __awaiter(void 0, void 0, void 0, function* () { }),
|
|
@@ -49,6 +52,7 @@ describe('Healing Orchestrator - Cascade Strategy', () => {
|
|
|
49
52
|
typedi_1.Container.set(HealedLocatorGenerator_1.HealedLocatorGenerator, mockGenerator);
|
|
50
53
|
orchestrator = new HealingOrchestrator_1.HealingOrchestrator(mockEtalonService);
|
|
51
54
|
});
|
|
55
|
+
afterEach(() => restoreContainer());
|
|
52
56
|
it('should cascade to OCR (Tier 3) when Fuzzy XML (Tier 2) fails to find a high-confidence match', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
53
57
|
// 1. Setup a page source that has NO matching text or buttons for "Login"
|
|
54
58
|
// This will cause Fuzzy XML Provider to return null (or score below 0.5 threshold)
|
|
@@ -48,22 +48,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
48
48
|
require("reflect-metadata");
|
|
49
49
|
const chai_1 = require("chai");
|
|
50
50
|
const sinon_1 = __importDefault(require("sinon"));
|
|
51
|
-
const prisma_1 = require("../../src/prisma");
|
|
52
51
|
const test_container_1 = require("../helpers/test-container");
|
|
52
|
+
const scratch_database_1 = require("../helpers/scratch-database");
|
|
53
|
+
const device_store_1 = require("../../src/data-service/device-store");
|
|
54
|
+
const prisma_store_1 = require("../../src/data-service/prisma-store");
|
|
53
55
|
const event_manager_1 = require("../../src/dashboard/event-manager");
|
|
54
56
|
const SessionStatus_1 = require("../../src/types/SessionStatus");
|
|
55
57
|
describe('OrphanSweeper', () => {
|
|
56
|
-
|
|
58
|
+
// Its own migrated database, never the developer's ~/.cache/xenon/xenon.db:
|
|
59
|
+
// that file's schema is whatever the last local migrate left, so a new
|
|
60
|
+
// column failed this spec there and nowhere else.
|
|
61
|
+
const scratch = (0, scratch_database_1.useScratchDatabase)();
|
|
62
|
+
let savedStore;
|
|
57
63
|
const STALE_SESSION_ID = 'orphan-stale-sess-001';
|
|
58
64
|
const STALE_UDID = 'udid-orphan-1';
|
|
59
65
|
const NODE_ID = 'node-a';
|
|
60
66
|
const FRESH_SESSION_ID = 'orphan-fresh-sess-002';
|
|
61
67
|
before(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
62
68
|
(0, test_container_1.setupTestContainer)();
|
|
63
|
-
|
|
69
|
+
savedStore = device_store_1.DeviceStoreFactory._deviceStore;
|
|
70
|
+
device_store_1.DeviceStoreFactory._deviceStore = new prisma_store_1.PrismaDeviceStore();
|
|
64
71
|
// Create a stale session (last_heartbeat_at is old / null with old updatedAt)
|
|
65
72
|
const oldDate = new Date(Date.now() - 5 * 60 * 1000); // 5 minutes ago
|
|
66
|
-
yield
|
|
73
|
+
yield scratch.db.session.upsert({
|
|
67
74
|
where: { id: STALE_SESSION_ID },
|
|
68
75
|
create: {
|
|
69
76
|
id: STALE_SESSION_ID,
|
|
@@ -87,7 +94,7 @@ describe('OrphanSweeper', () => {
|
|
|
87
94
|
},
|
|
88
95
|
});
|
|
89
96
|
// Create a device for the stale session
|
|
90
|
-
yield
|
|
97
|
+
yield scratch.db.device.upsert({
|
|
91
98
|
where: { udid_host: { udid: STALE_UDID, host: 'http://localhost:4723' } },
|
|
92
99
|
create: {
|
|
93
100
|
udid: STALE_UDID,
|
|
@@ -105,10 +112,7 @@ describe('OrphanSweeper', () => {
|
|
|
105
112
|
});
|
|
106
113
|
}));
|
|
107
114
|
after(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
108
|
-
|
|
109
|
-
where: { id: { in: [STALE_SESSION_ID, FRESH_SESSION_ID] } },
|
|
110
|
-
});
|
|
111
|
-
yield prismaClient.device.deleteMany({ where: { udid: STALE_UDID } });
|
|
115
|
+
device_store_1.DeviceStoreFactory._deviceStore = savedStore;
|
|
112
116
|
yield (0, test_container_1.resetTestContainer)();
|
|
113
117
|
}));
|
|
114
118
|
afterEach(() => {
|
|
@@ -122,13 +126,13 @@ describe('OrphanSweeper', () => {
|
|
|
122
126
|
const { OrphanSweeper } = yield Promise.resolve().then(() => __importStar(require('../../src/services/OrphanSweeper')));
|
|
123
127
|
const sweeper = new OrphanSweeper();
|
|
124
128
|
yield sweeper.sweep({ heartbeatIntervalMs: 30000 });
|
|
125
|
-
const session = yield
|
|
129
|
+
const session = yield scratch.db.session.findUnique({
|
|
126
130
|
where: { id: STALE_SESSION_ID },
|
|
127
131
|
select: { status: true, failure_reason: true },
|
|
128
132
|
});
|
|
129
133
|
(0, chai_1.expect)(session.status).to.equal('failed');
|
|
130
134
|
(0, chai_1.expect)(session.failure_reason).to.match(/heartbeat timeout/i);
|
|
131
|
-
const device = yield
|
|
135
|
+
const device = yield scratch.db.device.findFirst({
|
|
132
136
|
where: { udid: STALE_UDID },
|
|
133
137
|
select: { busy: true, owningSessionId: true },
|
|
134
138
|
});
|
|
@@ -138,7 +142,7 @@ describe('OrphanSweeper', () => {
|
|
|
138
142
|
}));
|
|
139
143
|
it('leaves fresh sessions alone', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
140
144
|
// Create a fresh session (heartbeat just now)
|
|
141
|
-
yield
|
|
145
|
+
yield scratch.db.session.upsert({
|
|
142
146
|
where: { id: FRESH_SESSION_ID },
|
|
143
147
|
create: {
|
|
144
148
|
id: FRESH_SESSION_ID,
|
|
@@ -164,7 +168,7 @@ describe('OrphanSweeper', () => {
|
|
|
164
168
|
const { OrphanSweeper } = yield Promise.resolve().then(() => __importStar(require('../../src/services/OrphanSweeper')));
|
|
165
169
|
const sweeper = new OrphanSweeper();
|
|
166
170
|
yield sweeper.sweep({ heartbeatIntervalMs: 30000 });
|
|
167
|
-
const session = yield
|
|
171
|
+
const session = yield scratch.db.session.findUnique({
|
|
168
172
|
where: { id: FRESH_SESSION_ID },
|
|
169
173
|
select: { status: true },
|
|
170
174
|
});
|