@xenon-device-management/xenon 2.0.0 → 2.2.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 +3 -4
- package/lib/public/assets/{AnnotationOverlay-BmTPCAds.js → AnnotationOverlay-XpewX5nn.js} +1 -1
- package/lib/public/assets/{ApiKeyGate-B5eB7f8B.js → ApiKeyGate-BQDv3ZCC.js} +1 -1
- package/lib/public/assets/BugReportButton-C7OmS61B.js +10 -0
- package/lib/public/assets/{DeviceMosaicView-9DUoZnQi.js → DeviceMosaicView-wl3l2Zlt.js} +1 -1
- package/lib/public/assets/{EmptyState-lvyNiXev.js → EmptyState-fPxujqqE.js} +1 -1
- package/lib/public/assets/{FieldGroup-BduMPM9K.js → FieldGroup-5bCutWrs.js} +1 -1
- package/lib/public/assets/{FilterMenu-BSqX6I94.js → FilterMenu-owsBiDT1.js} +1 -1
- package/lib/public/assets/{Menu-Ba5cT7jZ.js → Menu-DFhqzPSt.js} +1 -1
- package/lib/public/assets/{Modal-CceoMY7D.js → Modal-Bw-a-E-e.js} +1 -1
- package/lib/public/assets/{RecordingPage-6T9dOidc.js → RecordingPage-WtByf5bC.js} +1 -1
- package/lib/public/assets/{RecordingsPage-qj6FdZXR.js → RecordingsPage-FpWWFNgT.js} +1 -1
- package/lib/public/assets/{SegmentedControl-CSRuZ8TR.js → SegmentedControl-Jzn9c7o8.js} +1 -1
- package/lib/public/assets/{SettingCard-Bp1kz4By.js → SettingCard-BR7nOhpT.js} +1 -1
- package/lib/public/assets/{Table-LV7zFyZg.js → Table-B_Va3V05.js} +1 -1
- package/lib/public/assets/{activity-D17TUloi.js → activity-DxRFWvkN.js} +1 -1
- package/lib/public/assets/{ai-settings-qvbhY89P.js → ai-settings-CQf-9_V6.js} +1 -1
- package/lib/public/assets/{api-keys-BfpvdG7G.js → api-keys-SoE1Kd7N.js} +1 -1
- package/lib/public/assets/{apps-Dbnzd0fW.js → apps-CgGXTlgn.js} +1 -1
- package/lib/public/assets/{arrow-left-DD1VjtC7.js → arrow-left-uQ6WIwiC.js} +1 -1
- package/lib/public/assets/{arrow-right-D0pnM3ma.js → arrow-right-C9RyfzXS.js} +1 -1
- package/lib/public/assets/{arrow-up-right-BIC8JOV6.js → arrow-up-right-DFHi_8yG.js} +1 -1
- package/lib/public/assets/{auth-shell-DWHPXSnI.js → auth-shell-Bii1t4qc.js} +2 -2
- package/lib/public/assets/{builds-page-ClCNBUv_.js → builds-page-Bnv8Z9hi.js} +1 -1
- package/lib/public/assets/{button-xtAhYR-f.js → button-_Y78wXiP.js} +1 -1
- package/lib/public/assets/{calendar-CupwJ7Bm.js → calendar-D4MqSOc2.js} +1 -1
- package/lib/public/assets/{check-CyuEoKkd.js → check-uGHCXe-L.js} +1 -1
- package/lib/public/assets/{chevron-left-DgX-F9xK.js → chevron-left-Dy1OqpzB.js} +1 -1
- package/lib/public/assets/{chevron-right-BKJgJnU9.js → chevron-right-BUsldEli.js} +1 -1
- package/lib/public/assets/{circle-check-CZdg8mMa.js → circle-check-D3Qq0tKp.js} +1 -1
- package/lib/public/assets/{circle-x-CZH6t9z-.js → circle-x-B4IOD1DE.js} +1 -1
- package/lib/public/assets/{clock-Cd-t7xpe.js → clock-BfYfzvSg.js} +1 -1
- package/lib/public/assets/{copy-C6zerX3I.js → copy-DZwYE5Va.js} +1 -1
- package/lib/public/assets/{device-explorer-B1pI6b_M.js → device-explorer-CRG4Utt5.js} +3 -3
- package/lib/public/assets/device-explorer-D2AqrrLN.css +1 -0
- package/lib/public/assets/{download-x9WP7mcL.js → download-CCDYo_TN.js} +1 -1
- package/lib/public/assets/{forgot-password-B0TEH4N-.js → forgot-password-DuLCmVFb.js} +1 -1
- package/lib/public/assets/{funnel-Cb40MfFN.js → funnel-CtKNPqzb.js} +1 -1
- package/lib/public/assets/{index-BR1wTIPC.js → index-3uxl3o7K.js} +43 -43
- package/lib/public/assets/{index-BvH_ekRy.js → index-Zy1Op5C1.js} +1 -1
- package/lib/public/assets/{input-DejcCiTI.js → input-CzTWvUXZ.js} +1 -1
- package/lib/public/assets/{keycodes-Mavx5iGg.js → keycodes-CI-nYDFM.js} +1 -1
- package/lib/public/assets/{layers-BKqYLiHE.js → layers-YZZGFyTX.js} +1 -1
- package/lib/public/assets/{lock-LFsFhc17.js → lock-L8tzWgDo.js} +1 -1
- package/lib/public/assets/{login-x2pkzt-t.js → login-DBbX-fu8.js} +1 -1
- package/lib/public/assets/{maintenance-settings-CYafcoV-.js → maintenance-settings-AJwkOIsE.js} +1 -1
- package/lib/public/assets/{monitor-_7_uJ8d9.js → monitor-Di_66F2m.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-BfLuURKN.js → mouse-pointer-2-Cnab2zdg.js} +1 -1
- package/lib/public/assets/{network-Z_zBhpsD.js → network-DiSumY-1.js} +1 -1
- package/lib/public/assets/{overview-BY5uv08S.js → overview-CwE4gXl5.js} +1 -1
- package/lib/public/assets/{page-header-CP2UkykG.js → page-header-CfR4Sm9V.js} +1 -1
- package/lib/public/assets/{plus-BTD0dnQ0.js → plus-DOS8P9CQ.js} +1 -1
- package/lib/public/assets/{profile-page-BhJZuCS7.js → profile-page-BYpHwQIH.js} +1 -1
- package/lib/public/assets/{reset-password-CMN0SO81.js → reset-password-BRVJU_qV.js} +1 -1
- package/lib/public/assets/{runbook-page-CBpPX9_5.js → runbook-page-Bi3JvAFZ.js} +1 -1
- package/lib/public/assets/{select-Uc9E5pye.js → select-Cqx7pEou.js} +1 -1
- package/lib/public/assets/{selector-detail-page-BSyBnRuU.js → selector-detail-page-C0DsncKj.js} +1 -1
- package/lib/public/assets/{selector-health-DzqxNkzm.js → selector-health-CAhpdilF.js} +1 -1
- package/lib/public/assets/{selector-health-page-CyPLjoD1.js → selector-health-page-CrCVeW2m.js} +1 -1
- package/lib/public/assets/{session-detail-page-BZQZN1P-.js → session-detail-page-F_hwYqEt.js} +1 -1
- package/lib/public/assets/{settings-CkSWiZq8.js → settings-C-s5pypL.js} +1 -1
- package/lib/public/assets/{status-pill-outline-BFYni2qo.js → status-pill-outline-DY5uzv6A.js} +1 -1
- package/lib/public/assets/{tablet-BSd-xSZK.js → tablet-Dli7gwyg.js} +1 -1
- package/lib/public/assets/{teams-PpoEQz31.js → teams-ui4IhHNC.js} +1 -1
- package/lib/public/assets/{trash-2-BorJv5_u.js → trash-2-BV4hSmXJ.js} +1 -1
- package/lib/public/assets/{upload-C3i7sAZl.js → upload-DkGy_J-L.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-CeZQ3EsH.js → use-password-reset-mode-BFtMqQOh.js} +1 -1
- package/lib/public/assets/{users-Drd7ifJx.js → users-BU0nXIVe.js} +1 -1
- package/lib/public/assets/{users-CEJ3fC78.js → users-Nb_rzRmF.js} +1 -1
- package/lib/public/assets/{video-off-CNzn6bPE.js → video-off-CUNzD2kH.js} +1 -1
- package/lib/public/assets/{webhook-settings-BFqX6QXV.js → webhook-settings-Ca3UFXZe.js} +1 -1
- package/lib/public/assets/{zap-4yN8Jdfw.js → zap-B2bH2vKX.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 +11 -104
- package/lib/src/app/routers/grid.js +28 -8
- package/lib/src/app/routers/nodePhoneControl.js +301 -0
- package/lib/src/app/ws/h264StreamWs.js +43 -12
- package/lib/src/app/ws/logcatWs.js +48 -14
- package/lib/src/app/ws/nodeSocketRelay.js +167 -0
- 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 +92 -10
- package/lib/src/data-service/deviceClaims.js +116 -0
- package/lib/src/data-service/deviceFieldOwners.js +32 -10
- package/lib/src/data-service/prisma-store.js +102 -31
- package/lib/src/device-managers/AndroidDeviceManager.js +40 -42
- 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 +13 -5
- package/lib/src/device-managers/android/AndroidStreamService.js +9 -6
- 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 +162 -40
- 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/deviceAccessGuard.js +4 -1
- 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 +63 -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/device-access/ticketActorAccess.js +3 -1
- package/lib/src/services/lease/LeaseOrphanSweeper.js +34 -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/own-node-id.js +29 -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/setup/scratch-default-database.js +32 -0
- package/lib/test/unit/AndroidDeviceManager.spec.js +56 -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 +24 -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 +22 -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 +66 -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 +608 -0
- package/lib/test/unit/hub-node-gateway-appium-server.spec.js +594 -0
- package/lib/test/unit/hub-node-race.spec.js +426 -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 +6 -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 +107 -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 +12 -1
- package/lib/test/unit/loopback-request.spec.js +81 -0
- package/lib/test/unit/mark-node-busy-loki.spec.js +53 -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/node-phone-control.spec.js +131 -0
- package/lib/test/unit/node-socket-relay.spec.js +357 -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 +19 -7
- package/lib/test/unit/stream-own-device-row.spec.js +164 -0
- package/lib/test/unit/stream-stop-ownership.spec.js +17 -5
- package/lib/test/unit/stream-stop-recording.spec.js +17 -5
- package/lib/test/unit/stream-ticket-identity.spec.js +26 -6
- package/lib/test/unit/stream-watchdog-timers.spec.js +46 -0
- 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 +3 -4
- 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,500 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
require("reflect-metadata");
|
|
49
|
+
const chai_1 = require("chai");
|
|
50
|
+
const http_1 = __importDefault(require("http"));
|
|
51
|
+
const path_1 = __importDefault(require("path"));
|
|
52
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
53
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
54
|
+
const ws_1 = __importStar(require("ws"));
|
|
55
|
+
const socket_io_client_1 = require("socket.io-client");
|
|
56
|
+
const commandCaller_1 = require("../../src/middleware/commandCaller");
|
|
57
|
+
const registerCommandAuth_1 = require("../../src/app/registerCommandAuth");
|
|
58
|
+
const h264StreamWs_1 = require("../../src/app/ws/h264StreamWs");
|
|
59
|
+
const logcatWs_1 = require("../../src/app/ws/logcatWs");
|
|
60
|
+
const H264Multiplexer_1 = require("../../src/device-managers/android/H264Multiplexer");
|
|
61
|
+
const LogcatMultiplexer_1 = require("../../src/device-managers/android/LogcatMultiplexer");
|
|
62
|
+
const SocketServer_1 = require("../../src/services/SocketServer");
|
|
63
|
+
const config_1 = require("../../src/config");
|
|
64
|
+
const LIVE_SESSION = 'live-session';
|
|
65
|
+
const OWNERS = { [LIVE_SESSION]: 'alice' };
|
|
66
|
+
const DRIVER_LOGCAT = `/ws/session/${LIVE_SESSION}/appium/device/logcat`;
|
|
67
|
+
const H264_URL = '/xenon/api/control/DEV-1/stream/h264?ticket=t-h264';
|
|
68
|
+
const LOGCAT_URL = '/xenon/api/control/DEV-1/logcat?ticket=t-logcat';
|
|
69
|
+
/** Longer than engine.io's 1 s destroyUpgradeTimeout, so a hang is told apart from it. */
|
|
70
|
+
const HANG_MS = 2500;
|
|
71
|
+
function nativelyUsesUpgradeListener() {
|
|
72
|
+
return typeof http_1.default.createServer().shouldUpgradeCallback !== 'undefined';
|
|
73
|
+
}
|
|
74
|
+
function appiumBaseDriver() {
|
|
75
|
+
const appiumDir = path_1.default.dirname(require.resolve('appium/package.json'));
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
77
|
+
return require(require.resolve('@appium/base-driver', { paths: [appiumDir] }));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Open a WebSocket and report how the server answered: open (with the first
|
|
81
|
+
* message, if one arrives promptly), an HTTP answer, a close without one (and
|
|
82
|
+
* how long it took), or nothing at all.
|
|
83
|
+
*/
|
|
84
|
+
function connect(port, urlPath, headers = {}) {
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
const started = Date.now();
|
|
87
|
+
const ws = new ws_1.default(`ws://127.0.0.1:${port}${urlPath}`, { headers });
|
|
88
|
+
let settled = false;
|
|
89
|
+
const settle = (outcome) => {
|
|
90
|
+
if (settled)
|
|
91
|
+
return;
|
|
92
|
+
settled = true;
|
|
93
|
+
clearTimeout(hang);
|
|
94
|
+
resolve(outcome);
|
|
95
|
+
ws.terminate();
|
|
96
|
+
};
|
|
97
|
+
const hang = setTimeout(() => settle({ kind: 'hang' }), HANG_MS);
|
|
98
|
+
ws.on('open', () => {
|
|
99
|
+
const wait = setTimeout(() => settle({ kind: 'open' }), 300);
|
|
100
|
+
ws.once('message', (data) => {
|
|
101
|
+
clearTimeout(wait);
|
|
102
|
+
settle({ kind: 'open', firstMessage: data });
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
ws.on('unexpected-response', (req, res) => {
|
|
106
|
+
var _a;
|
|
107
|
+
settle({ kind: 'http', status: (_a = res.statusCode) !== null && _a !== void 0 ? _a : 0 });
|
|
108
|
+
req.destroy();
|
|
109
|
+
});
|
|
110
|
+
ws.on('error', (err) => settle({ kind: 'closed', message: err.message, ms: Date.now() - started }));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
describe("Xenon's and Appium's WebSockets on Appium 3's own server()", () => {
|
|
114
|
+
const quiet = {
|
|
115
|
+
debug: () => undefined,
|
|
116
|
+
info: () => undefined,
|
|
117
|
+
warn: () => undefined,
|
|
118
|
+
error: () => undefined,
|
|
119
|
+
};
|
|
120
|
+
let server;
|
|
121
|
+
let socketServer;
|
|
122
|
+
let sockets;
|
|
123
|
+
let clients;
|
|
124
|
+
let enabled;
|
|
125
|
+
let warnings;
|
|
126
|
+
/** URL of every upgrade each WebSocket server was asked to take, in order. */
|
|
127
|
+
let taken;
|
|
128
|
+
let bidiConnections;
|
|
129
|
+
let driverConnections;
|
|
130
|
+
let h264Redeemed;
|
|
131
|
+
let logcatRedeemed;
|
|
132
|
+
let wssNames;
|
|
133
|
+
function booted() {
|
|
134
|
+
if (!server)
|
|
135
|
+
throw new Error('boot() first');
|
|
136
|
+
return server;
|
|
137
|
+
}
|
|
138
|
+
function port() {
|
|
139
|
+
return booted().address().port;
|
|
140
|
+
}
|
|
141
|
+
function boot(opts) {
|
|
142
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
143
|
+
const baseDriver = appiumBaseDriver();
|
|
144
|
+
const credentials = { 'alice-token': 'alice', 'bob-token': 'bob' };
|
|
145
|
+
const verifier = new commandCaller_1.CommandCallerVerifier({
|
|
146
|
+
verifyKeyPair: sinon_1.default.stub().callsFake((_ak, token) => __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
return credentials[token]
|
|
148
|
+
? {
|
|
149
|
+
row: { id: 'k', userId: credentials[token], scopes: 'sessions', expiresAt: null },
|
|
150
|
+
user: { id: credentials[token], role: 'MEMBER', status: 'ACTIVE' },
|
|
151
|
+
}
|
|
152
|
+
: null;
|
|
153
|
+
})),
|
|
154
|
+
verifyBearer: sinon_1.default.stub().resolves(null),
|
|
155
|
+
});
|
|
156
|
+
const deps = {
|
|
157
|
+
enabled: () => enabled,
|
|
158
|
+
authDisabled: () => false,
|
|
159
|
+
verifier,
|
|
160
|
+
ownerOf: (id) => __awaiter(this, void 0, void 0, function* () { var _a; return (_a = OWNERS[id]) !== null && _a !== void 0 ? _a : null; }),
|
|
161
|
+
ownersOf: (ids) => __awaiter(this, void 0, void 0, function* () { return new Map(ids.map((id) => { var _a; return [id, (_a = OWNERS[id]) !== null && _a !== void 0 ? _a : null]; })); }),
|
|
162
|
+
logger: {
|
|
163
|
+
info: () => undefined,
|
|
164
|
+
warn: (m) => warnings.push(m),
|
|
165
|
+
error: () => undefined,
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
// A fake driver that, like UiAutomator2, registers a per-session WebSocket
|
|
169
|
+
// with the server when its session starts.
|
|
170
|
+
const driverWss = new ws_1.WebSocketServer({ noServer: true });
|
|
171
|
+
wssNames.set(driverWss, 'driver');
|
|
172
|
+
driverWss.on('connection', (ws, req) => {
|
|
173
|
+
driverConnections.push(String(req.url));
|
|
174
|
+
ws.on('error', () => undefined);
|
|
175
|
+
});
|
|
176
|
+
const driver = {
|
|
177
|
+
log: quiet,
|
|
178
|
+
protocol: 'W3C',
|
|
179
|
+
sessionExists: (id) => id === LIVE_SESSION,
|
|
180
|
+
proxyActive: () => false,
|
|
181
|
+
canProxy: () => false,
|
|
182
|
+
proxyRouteIsAvoided: () => false,
|
|
183
|
+
executeCommand: (command) => __awaiter(this, void 0, void 0, function* () {
|
|
184
|
+
if (command === 'createSession') {
|
|
185
|
+
yield booted().addWebSocketHandler(DRIVER_LOGCAT, driverWss);
|
|
186
|
+
return [LIVE_SESSION, {}];
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
const h264Mux = new H264Multiplexer_1.H264Multiplexer();
|
|
192
|
+
h264Mux.setConfig({ type: 'config', data: Buffer.from([0, 0, 0, 1, 0x67]), ptsMs: 0 });
|
|
193
|
+
const logcatMux = new LogcatMultiplexer_1.LogcatMultiplexer();
|
|
194
|
+
logcatMux.push({ ts: 1, pid: 1, tid: 1, level: 'I', tag: 'T', message: 'hello' });
|
|
195
|
+
const createServer = http_1.default.createServer;
|
|
196
|
+
const forced = opts.upgrades === 'listener' ? sinon_1.default.stub(http_1.default, 'createServer') : undefined;
|
|
197
|
+
forced === null || forced === void 0 ? void 0 : forced.callsFake(((app) => {
|
|
198
|
+
const s = createServer(app);
|
|
199
|
+
if (typeof s.shouldUpgradeCallback === 'undefined') {
|
|
200
|
+
s.shouldUpgradeCallback = () => true;
|
|
201
|
+
}
|
|
202
|
+
return s;
|
|
203
|
+
}));
|
|
204
|
+
try {
|
|
205
|
+
server = yield baseDriver.server({
|
|
206
|
+
routeConfiguringFunction: baseDriver.routeConfiguringFunction(driver),
|
|
207
|
+
port: 0,
|
|
208
|
+
hostname: '127.0.0.1',
|
|
209
|
+
basePath: '/wd/hub',
|
|
210
|
+
cliArgs: { basePath: '/wd/hub' },
|
|
211
|
+
serverUpdaters: [
|
|
212
|
+
(app, httpServer, cliArgs) => {
|
|
213
|
+
// ServerManager.updateServer, in its order.
|
|
214
|
+
(0, registerCommandAuth_1.registerCommandAuth)(app, cliArgs, deps);
|
|
215
|
+
(0, registerCommandAuth_1.registerSessionUpgradeGuard)(httpServer, app, cliArgs, deps);
|
|
216
|
+
if (opts.role === 'hub') {
|
|
217
|
+
socketServer = new SocketServer_1.SocketServer();
|
|
218
|
+
socketServer.initialize(httpServer);
|
|
219
|
+
}
|
|
220
|
+
(0, h264StreamWs_1.attachH264Ws)(httpServer, {
|
|
221
|
+
redeem: (ticket, udid) => __awaiter(this, void 0, void 0, function* () {
|
|
222
|
+
h264Redeemed.push(`${udid}:${ticket}`);
|
|
223
|
+
return { actorId: 'alice' };
|
|
224
|
+
}),
|
|
225
|
+
startStream: () => __awaiter(this, void 0, void 0, function* () { return h264Mux; }),
|
|
226
|
+
});
|
|
227
|
+
(0, logcatWs_1.attachLogcatWs)(httpServer, {
|
|
228
|
+
redeem: (ticket, udid) => __awaiter(this, void 0, void 0, function* () {
|
|
229
|
+
logcatRedeemed.push(`${udid}:${ticket}`);
|
|
230
|
+
return { actorId: 'alice' };
|
|
231
|
+
}),
|
|
232
|
+
authorize: () => __awaiter(this, void 0, void 0, function* () { return true; }),
|
|
233
|
+
startStream: () => __awaiter(this, void 0, void 0, function* () { return ({ mux: logcatMux }); }),
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
forced === null || forced === void 0 ? void 0 : forced.restore();
|
|
241
|
+
}
|
|
242
|
+
booted().on('connection', (socket) => {
|
|
243
|
+
sockets.add(socket);
|
|
244
|
+
socket.on('close', () => sockets.delete(socket));
|
|
245
|
+
});
|
|
246
|
+
// Appium's main adds its BiDi handler right after server() resolves.
|
|
247
|
+
const bidi = new ws_1.WebSocketServer({ noServer: true });
|
|
248
|
+
wssNames.set(bidi, 'bidi');
|
|
249
|
+
bidi.on('connection', (ws, req) => {
|
|
250
|
+
bidiConnections.push(String(req.url));
|
|
251
|
+
ws.on('error', () => undefined);
|
|
252
|
+
});
|
|
253
|
+
yield booted().addWebSocketHandler('/wd/hub/bidi', bidi);
|
|
254
|
+
yield booted().addWebSocketHandler('/wd/hub/bidi/:sessionId', bidi);
|
|
255
|
+
if (socketServer) {
|
|
256
|
+
const engine = socketServer.io.engine;
|
|
257
|
+
const handleUpgrade = engine.handleUpgrade;
|
|
258
|
+
sinon_1.default.stub(engine, 'handleUpgrade').callsFake(function (...args) {
|
|
259
|
+
var _a;
|
|
260
|
+
taken.push({ by: 'socket.io', url: String((_a = args[0]) === null || _a === void 0 ? void 0 : _a.url) });
|
|
261
|
+
return handleUpgrade.apply(this, args);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function createSession() {
|
|
267
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
268
|
+
yield (0, loopbackRequest_1.default)(booted())
|
|
269
|
+
.post('/wd/hub/session')
|
|
270
|
+
.send({ capabilities: { alwaysMatch: { platformName: 'Fake' } } })
|
|
271
|
+
.expect(200);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
function connectSocketIo(transports) {
|
|
275
|
+
const client = (0, socket_io_client_1.io)(`http://127.0.0.1:${port()}`, {
|
|
276
|
+
path: '/socket.io',
|
|
277
|
+
transports,
|
|
278
|
+
reconnection: false,
|
|
279
|
+
forceNew: true,
|
|
280
|
+
});
|
|
281
|
+
clients.push(client);
|
|
282
|
+
return client;
|
|
283
|
+
}
|
|
284
|
+
// Appium's HTTP logger writes every request to stdout; quiet it here only.
|
|
285
|
+
let appiumLog;
|
|
286
|
+
let appiumLogLevel;
|
|
287
|
+
let authDisabled = false;
|
|
288
|
+
before(() => {
|
|
289
|
+
appiumBaseDriver();
|
|
290
|
+
const support = require.resolve('@appium/support', {
|
|
291
|
+
paths: [path_1.default.dirname(require.resolve('appium/package.json'))],
|
|
292
|
+
});
|
|
293
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
294
|
+
const log = require(require.resolve('@appium/logger', { paths: [support] })).default;
|
|
295
|
+
appiumLog = log;
|
|
296
|
+
appiumLogLevel = log.level;
|
|
297
|
+
log.level = 'silent';
|
|
298
|
+
// socket.io's handshake: an auth-disabled hub admits every dashboard.
|
|
299
|
+
authDisabled = config_1.config.authDisabled;
|
|
300
|
+
config_1.config.authDisabled = true;
|
|
301
|
+
});
|
|
302
|
+
after(() => {
|
|
303
|
+
if (appiumLog && appiumLogLevel)
|
|
304
|
+
appiumLog.level = appiumLogLevel;
|
|
305
|
+
config_1.config.authDisabled = authDisabled;
|
|
306
|
+
});
|
|
307
|
+
beforeEach(() => {
|
|
308
|
+
enabled = false;
|
|
309
|
+
warnings = [];
|
|
310
|
+
taken = [];
|
|
311
|
+
bidiConnections = [];
|
|
312
|
+
driverConnections = [];
|
|
313
|
+
h264Redeemed = [];
|
|
314
|
+
logcatRedeemed = [];
|
|
315
|
+
sockets = new Set();
|
|
316
|
+
clients = [];
|
|
317
|
+
wssNames = new Map();
|
|
318
|
+
// Record which WebSocket server each upgrade is handed to. The h264 and
|
|
319
|
+
// logcat servers are created inside attach*Ws, so they are named by the
|
|
320
|
+
// path they are asked to take.
|
|
321
|
+
const handleUpgrade = ws_1.WebSocketServer.prototype.handleUpgrade;
|
|
322
|
+
sinon_1.default.stub(ws_1.WebSocketServer.prototype, 'handleUpgrade').callsFake(function (...args) {
|
|
323
|
+
var _a, _b;
|
|
324
|
+
const url = String((_a = args[0]) === null || _a === void 0 ? void 0 : _a.url);
|
|
325
|
+
const by = (_b = wssNames.get(this)) !== null && _b !== void 0 ? _b : (/\/stream\/h264/.test(url) ? 'h264' : /\/logcat\?/.test(url) ? 'logcat' : 'unknown');
|
|
326
|
+
taken.push({ by, url });
|
|
327
|
+
return handleUpgrade.apply(this, args);
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
331
|
+
for (const c of clients)
|
|
332
|
+
c.close();
|
|
333
|
+
sinon_1.default.restore();
|
|
334
|
+
const s = server;
|
|
335
|
+
server = undefined;
|
|
336
|
+
const io = socketServer === null || socketServer === void 0 ? void 0 : socketServer.io;
|
|
337
|
+
socketServer = undefined;
|
|
338
|
+
if (!s)
|
|
339
|
+
return;
|
|
340
|
+
for (const socket of sockets)
|
|
341
|
+
socket.destroy();
|
|
342
|
+
s.closeAllConnections();
|
|
343
|
+
if (io) {
|
|
344
|
+
// socket.io's close() also closes the http.Server, and Appium's close()
|
|
345
|
+
// calls process.exit() when its shutdown timer runs out. Close only
|
|
346
|
+
// socket.io's own side here.
|
|
347
|
+
io.httpServer = undefined;
|
|
348
|
+
yield new Promise((resolve) => io.close(() => resolve()));
|
|
349
|
+
}
|
|
350
|
+
// Appium replaces close() with a graceful one that calls process.exit()
|
|
351
|
+
// if connections outlive its shutdown timeout. Use http.Server's own.
|
|
352
|
+
yield new Promise((resolve) => http_1.default.Server.prototype.close.call(s, () => resolve()));
|
|
353
|
+
}));
|
|
354
|
+
for (const upgrades of ['native', 'listener']) {
|
|
355
|
+
const how = upgrades === 'listener' || nativelyUsesUpgradeListener()
|
|
356
|
+
? 'its upgrade listener (Node >= 22.21 / 24.9)'
|
|
357
|
+
: 'its Express upgrade middleware (Node < 22.21)';
|
|
358
|
+
describe(`Appium taking upgrades with ${how} [${upgrades}]`, () => {
|
|
359
|
+
describe('on a hub (socket.io attached)', () => {
|
|
360
|
+
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
361
|
+
yield boot({ upgrades, role: 'hub' });
|
|
362
|
+
}));
|
|
363
|
+
it("hands an H.264 upgrade with a ticket to Xenon's H.264 handler, which streams", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
364
|
+
var _a;
|
|
365
|
+
const outcome = yield connect(port(), H264_URL);
|
|
366
|
+
(0, chai_1.expect)(outcome.kind).to.equal('open');
|
|
367
|
+
(0, chai_1.expect)((_a = outcome.firstMessage) === null || _a === void 0 ? void 0 : _a[0], 'the config frame').to.equal(0);
|
|
368
|
+
(0, chai_1.expect)(h264Redeemed).to.deep.equal(['DEV-1:t-h264']);
|
|
369
|
+
(0, chai_1.expect)(taken).to.deep.equal([{ by: 'h264', url: H264_URL }]);
|
|
370
|
+
}));
|
|
371
|
+
it("hands a logcat upgrade with a ticket to Xenon's logcat handler, which streams", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
372
|
+
const outcome = yield connect(port(), LOGCAT_URL);
|
|
373
|
+
(0, chai_1.expect)(outcome.kind).to.equal('open');
|
|
374
|
+
(0, chai_1.expect)(JSON.parse(String(outcome.firstMessage)).message).to.equal('hello');
|
|
375
|
+
(0, chai_1.expect)(logcatRedeemed).to.deep.equal(['DEV-1:t-logcat']);
|
|
376
|
+
(0, chai_1.expect)(taken).to.deep.equal([{ by: 'logcat', url: LOGCAT_URL }]);
|
|
377
|
+
}));
|
|
378
|
+
it('connects socket.io over the websocket transport, with no polling fallback', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
379
|
+
const client = connectSocketIo(['websocket']);
|
|
380
|
+
yield new Promise((resolve, reject) => {
|
|
381
|
+
client.once('connect', () => resolve());
|
|
382
|
+
client.once('connect_error', (err) => reject(err));
|
|
383
|
+
});
|
|
384
|
+
(0, chai_1.expect)(client.io.engine.transport.name).to.equal('websocket');
|
|
385
|
+
(0, chai_1.expect)(taken.map((t) => t.by)).to.deep.equal(['socket.io']);
|
|
386
|
+
}));
|
|
387
|
+
it("upgrades the dashboard's default socket.io client from polling to websocket", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
388
|
+
const client = connectSocketIo(['polling', 'websocket']);
|
|
389
|
+
yield new Promise((resolve, reject) => {
|
|
390
|
+
client.once('connect_error', (err) => reject(err));
|
|
391
|
+
client.io.engine.once('upgrade', () => resolve());
|
|
392
|
+
setTimeout(() => { var _a, _b; return reject(new Error(`still on ${(_b = (_a = client.io.engine) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.name}`)); }, HANG_MS);
|
|
393
|
+
});
|
|
394
|
+
(0, chai_1.expect)(client.io.engine.transport.name).to.equal('websocket');
|
|
395
|
+
(0, chai_1.expect)(taken.map((t) => t.by)).to.deep.equal(['socket.io']);
|
|
396
|
+
}));
|
|
397
|
+
it("hands a BiDi upgrade to Appium's BiDi handler", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
398
|
+
(0, chai_1.expect)((yield connect(port(), `/wd/hub/bidi/${LIVE_SESSION}`)).kind).to.equal('open');
|
|
399
|
+
(0, chai_1.expect)(bidiConnections).to.deep.equal([`/wd/hub/bidi/${LIVE_SESSION}`]);
|
|
400
|
+
(0, chai_1.expect)(taken).to.deep.equal([{ by: 'bidi', url: `/wd/hub/bidi/${LIVE_SESSION}` }]);
|
|
401
|
+
}));
|
|
402
|
+
it("hands a driver's session socket, added in createSession, to the driver", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
403
|
+
yield createSession();
|
|
404
|
+
(0, chai_1.expect)((yield connect(port(), DRIVER_LOGCAT)).kind).to.equal('open');
|
|
405
|
+
(0, chai_1.expect)(driverConnections).to.deep.equal([DRIVER_LOGCAT]);
|
|
406
|
+
(0, chai_1.expect)(taken).to.deep.equal([{ by: 'driver', url: DRIVER_LOGCAT }]);
|
|
407
|
+
}));
|
|
408
|
+
it('gives an unknown session socket to Appium, which closes it at once', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
409
|
+
const outcome = yield connect(port(), '/wd/hub/ws/session/x/appium/device/logcat');
|
|
410
|
+
(0, chai_1.expect)(outcome.kind).to.equal('closed');
|
|
411
|
+
// At once, not after engine.io's 1 s timer for upgrades it doesn't own.
|
|
412
|
+
(0, chai_1.expect)(outcome.ms).to.be.below(800);
|
|
413
|
+
(0, chai_1.expect)(taken).to.deep.equal([]);
|
|
414
|
+
}));
|
|
415
|
+
it('gives exactly one handler each socket, all on one server', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
416
|
+
yield createSession();
|
|
417
|
+
const client = connectSocketIo(['websocket']);
|
|
418
|
+
yield new Promise((resolve, reject) => {
|
|
419
|
+
client.once('connect', () => resolve());
|
|
420
|
+
client.once('connect_error', (err) => reject(err));
|
|
421
|
+
});
|
|
422
|
+
for (const url of [H264_URL, LOGCAT_URL, `/wd/hub/bidi/${LIVE_SESSION}`, DRIVER_LOGCAT]) {
|
|
423
|
+
(0, chai_1.expect)((yield connect(port(), url)).kind, url).to.equal('open');
|
|
424
|
+
}
|
|
425
|
+
(0, chai_1.expect)(taken.map((t) => t.by)).to.deep.equal([
|
|
426
|
+
'socket.io',
|
|
427
|
+
'h264',
|
|
428
|
+
'logcat',
|
|
429
|
+
'bidi',
|
|
430
|
+
'driver',
|
|
431
|
+
]);
|
|
432
|
+
}));
|
|
433
|
+
describe('with XENON_REQUIRE_COMMAND_AUTH on', () => {
|
|
434
|
+
beforeEach(() => {
|
|
435
|
+
enabled = true;
|
|
436
|
+
});
|
|
437
|
+
it('refuses a BiDi upgrade without credentials with 404, before Appium sees it', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
438
|
+
(0, chai_1.expect)(yield connect(port(), `/wd/hub/bidi/${LIVE_SESSION}`)).to.deep.equal({
|
|
439
|
+
kind: 'http',
|
|
440
|
+
status: 404,
|
|
441
|
+
});
|
|
442
|
+
(0, chai_1.expect)(taken).to.deep.equal([]);
|
|
443
|
+
(0, chai_1.expect)(warnings).to.have.length(1);
|
|
444
|
+
}));
|
|
445
|
+
it("lets the owner's BiDi and driver sockets through to Appium", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
446
|
+
yield createSession();
|
|
447
|
+
const alice = { 'x-xenon-access-key': 'ak', 'x-xenon-token': 'alice-token' };
|
|
448
|
+
(0, chai_1.expect)((yield connect(port(), `/wd/hub/bidi/${LIVE_SESSION}`, alice)).kind).to.equal('open');
|
|
449
|
+
(0, chai_1.expect)((yield connect(port(), DRIVER_LOGCAT, alice)).kind).to.equal('open');
|
|
450
|
+
(0, chai_1.expect)(taken.map((t) => t.by)).to.deep.equal(['bidi', 'driver']);
|
|
451
|
+
}));
|
|
452
|
+
it("refuses another user's driver socket with 404", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
453
|
+
yield createSession();
|
|
454
|
+
const bob = { 'x-xenon-access-key': 'ak', 'x-xenon-token': 'bob-token' };
|
|
455
|
+
(0, chai_1.expect)(yield connect(port(), DRIVER_LOGCAT, bob)).to.deep.equal({
|
|
456
|
+
kind: 'http',
|
|
457
|
+
status: 404,
|
|
458
|
+
});
|
|
459
|
+
(0, chai_1.expect)(driverConnections).to.deep.equal([]);
|
|
460
|
+
}));
|
|
461
|
+
it('answers an unknown session socket 404, as for any session the caller does not own', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
462
|
+
(0, chai_1.expect)(yield connect(port(), '/wd/hub/ws/session/x/appium/device/logcat')).to.deep.equal({ kind: 'http', status: 404 });
|
|
463
|
+
}));
|
|
464
|
+
it("leaves Xenon's ticketed sockets and socket.io alone", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
465
|
+
(0, chai_1.expect)((yield connect(port(), H264_URL)).kind).to.equal('open');
|
|
466
|
+
(0, chai_1.expect)((yield connect(port(), LOGCAT_URL)).kind).to.equal('open');
|
|
467
|
+
const client = connectSocketIo(['websocket']);
|
|
468
|
+
yield new Promise((resolve, reject) => {
|
|
469
|
+
client.once('connect', () => resolve());
|
|
470
|
+
client.once('connect_error', (err) => reject(err));
|
|
471
|
+
});
|
|
472
|
+
(0, chai_1.expect)(taken.map((t) => t.by)).to.deep.equal(['h264', 'logcat', 'socket.io']);
|
|
473
|
+
(0, chai_1.expect)(warnings).to.deep.equal([]);
|
|
474
|
+
}));
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
describe('on a node (no socket.io)', () => {
|
|
478
|
+
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
479
|
+
yield boot({ upgrades, role: 'node' });
|
|
480
|
+
}));
|
|
481
|
+
it("hands H.264 and logcat upgrades to Xenon's handlers", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
482
|
+
(0, chai_1.expect)((yield connect(port(), H264_URL)).kind).to.equal('open');
|
|
483
|
+
(0, chai_1.expect)((yield connect(port(), LOGCAT_URL)).kind).to.equal('open');
|
|
484
|
+
(0, chai_1.expect)(taken.map((t) => t.by)).to.deep.equal(['h264', 'logcat']);
|
|
485
|
+
}));
|
|
486
|
+
it("hands BiDi and a driver's session socket to Appium", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
487
|
+
yield createSession();
|
|
488
|
+
(0, chai_1.expect)((yield connect(port(), `/wd/hub/bidi/${LIVE_SESSION}`)).kind).to.equal('open');
|
|
489
|
+
(0, chai_1.expect)((yield connect(port(), DRIVER_LOGCAT)).kind).to.equal('open');
|
|
490
|
+
(0, chai_1.expect)(taken.map((t) => t.by)).to.deep.equal(['bidi', 'driver']);
|
|
491
|
+
}));
|
|
492
|
+
it('gives an unknown upgrade to Appium, which closes it at once', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
493
|
+
const outcome = yield connect(port(), '/nowhere');
|
|
494
|
+
(0, chai_1.expect)(outcome.kind).to.equal('closed');
|
|
495
|
+
(0, chai_1.expect)(outcome.ms).to.be.below(800);
|
|
496
|
+
}));
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
});
|