@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
|
@@ -49,7 +49,7 @@ require("reflect-metadata");
|
|
|
49
49
|
const chai_1 = require("chai");
|
|
50
50
|
const sinon_1 = __importDefault(require("sinon"));
|
|
51
51
|
const express_1 = __importDefault(require("express"));
|
|
52
|
-
const
|
|
52
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
53
53
|
const typedi_1 = require("typedi");
|
|
54
54
|
const control_1 = __importStar(require("../../src/app/routers/control"));
|
|
55
55
|
const device_store_1 = require("../../src/data-service/device-store");
|
|
@@ -60,6 +60,8 @@ const IOSStreamService_1 = __importDefault(require("../../src/device-managers/io
|
|
|
60
60
|
const AndroidStreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidStreamService"));
|
|
61
61
|
const AndroidH264StreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidH264StreamService"));
|
|
62
62
|
const authMiddleware_1 = require("../../src/middleware/authMiddleware");
|
|
63
|
+
const container_registration_1 = require("../helpers/container-registration");
|
|
64
|
+
const loopbackServer_1 = require("../helpers/loopbackServer");
|
|
63
65
|
const UDID = 'DEV-1';
|
|
64
66
|
const ALICE = 'usr_alice';
|
|
65
67
|
const BOB = 'usr_bob';
|
|
@@ -90,7 +92,12 @@ describe('POST /control/:udid/stream/leave', () => {
|
|
|
90
92
|
let h264Clients;
|
|
91
93
|
let mjpegViewers;
|
|
92
94
|
let iosViewers;
|
|
95
|
+
let restoreContainer;
|
|
96
|
+
// Served on 127.0.0.1: request(app) listens on every address and connects
|
|
97
|
+
// to 127.0.0.1, where another process's listener on that port can answer.
|
|
98
|
+
const loopback = (0, loopbackServer_1.loopbackServers)();
|
|
93
99
|
beforeEach(() => {
|
|
100
|
+
restoreContainer = (0, container_registration_1.saveRegistrations)(ApiKeyService_1.ApiKeyService, AndroidStreamService_1.default, AndroidH264StreamService_1.default, IOSStreamService_1.default, recording_store_1.RecordingStore);
|
|
94
101
|
deviceRow = {
|
|
95
102
|
udid: UDID,
|
|
96
103
|
host: '127.0.0.1',
|
|
@@ -126,14 +133,15 @@ describe('POST /control/:udid/stream/leave', () => {
|
|
|
126
133
|
isRecording: () => __awaiter(void 0, void 0, void 0, function* () { return false; }),
|
|
127
134
|
});
|
|
128
135
|
});
|
|
129
|
-
afterEach(() => {
|
|
136
|
+
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
130
137
|
sinon_1.default.restore();
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
restoreContainer();
|
|
139
|
+
yield loopback.closeAll();
|
|
140
|
+
}));
|
|
133
141
|
describe('the route', () => {
|
|
134
142
|
it('schedules the leave for the holder and answers at once', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
135
143
|
const leave = sinon_1.default.stub(control_1.previewLeaves, 'leave');
|
|
136
|
-
const res = yield (0,
|
|
144
|
+
const res = yield (0, loopbackRequest_1.default)(yield loopback.serve(buildApp(ALICE))).post(`/xenon/api/control/${UDID}/stream/leave`);
|
|
137
145
|
(0, chai_1.expect)(res.status, JSON.stringify(res.body)).to.equal(202);
|
|
138
146
|
(0, chai_1.expect)(leave.calledOnceWith(UDID)).to.equal(true);
|
|
139
147
|
// Nothing is stopped yet: that waits for the grace and the viewer count.
|
|
@@ -141,14 +149,14 @@ describe('POST /control/:udid/stream/leave', () => {
|
|
|
141
149
|
}));
|
|
142
150
|
it('refuses someone else’s hold', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
143
151
|
const leave = sinon_1.default.stub(control_1.previewLeaves, 'leave');
|
|
144
|
-
const res = yield (0,
|
|
152
|
+
const res = yield (0, loopbackRequest_1.default)(yield loopback.serve(buildApp(BOB))).post(`/xenon/api/control/${UDID}/stream/leave`);
|
|
145
153
|
(0, chai_1.expect)(res.status).to.equal(403);
|
|
146
154
|
(0, chai_1.expect)(leave.called).to.equal(false);
|
|
147
155
|
}));
|
|
148
156
|
// A reload leaves and then starts again; the start must win.
|
|
149
157
|
it('stream/start cancels a pending leave', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
150
158
|
const cancel = sinon_1.default.stub(control_1.previewLeaves, 'cancel');
|
|
151
|
-
yield (0,
|
|
159
|
+
yield (0, loopbackRequest_1.default)(yield loopback.serve(buildApp(ALICE))).post(`/xenon/api/control/${UDID}/stream/start`);
|
|
152
160
|
(0, chai_1.expect)(cancel.calledWith(UDID)).to.equal(true);
|
|
153
161
|
}));
|
|
154
162
|
});
|
|
@@ -0,0 +1,164 @@
|
|
|
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 sinon_1 = __importDefault(require("sinon"));
|
|
51
|
+
const typedi_1 = require("typedi");
|
|
52
|
+
const IOSStreamService_1 = __importDefault(require("../../src/device-managers/ios/IOSStreamService"));
|
|
53
|
+
const AndroidStreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidStreamService"));
|
|
54
|
+
const AndroidH264StreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidH264StreamService"));
|
|
55
|
+
const previewHold_1 = require("../../src/device-managers/android/previewHold");
|
|
56
|
+
const singleFlight_1 = require("../../src/helpers/singleFlight");
|
|
57
|
+
const device_store_1 = require("../../src/data-service/device-store");
|
|
58
|
+
const deviceService = __importStar(require("../../src/data-service/device-service"));
|
|
59
|
+
const PluginContext_1 = require("../../src/PluginContext");
|
|
60
|
+
const PortAllocator_1 = require("../../src/services/PortAllocator");
|
|
61
|
+
const recording_store_1 = require("../../src/services/recording/recording-store");
|
|
62
|
+
const IPluginArgs_1 = require("../../src/interfaces/IPluginArgs");
|
|
63
|
+
/**
|
|
64
|
+
* A hub's table holds its nodes' rows too, and a node on the same machine
|
|
65
|
+
* sees the same phones (an iPhone, emulator-5554). The stream services
|
|
66
|
+
* looked a phone up by udid alone, so on such a hub they could act on the
|
|
67
|
+
* node's row: release the node's preview hold, or judge "an Appium session
|
|
68
|
+
* holds this phone" from the node's session. A phone's own row is the one
|
|
69
|
+
* filed under a host this server's discovery writes (localDeviceHosts).
|
|
70
|
+
*
|
|
71
|
+
* The store fake matches every key of the filter, as Prisma's findFirst does.
|
|
72
|
+
*/
|
|
73
|
+
const IP = '192.168.0.104';
|
|
74
|
+
const HUB = `http://${IP}:4724`;
|
|
75
|
+
const NODE = `http://${IP}:4725`;
|
|
76
|
+
const UDID = 'shared-phone-1';
|
|
77
|
+
/** A live-preview hold on the phone, as formatManualLock writes it. */
|
|
78
|
+
const hold = (userId) => `manual_${userId}_${UDID}`;
|
|
79
|
+
describe("stream services act on this server's own row for a udid", () => {
|
|
80
|
+
let rows;
|
|
81
|
+
let unblock;
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
rows = [];
|
|
84
|
+
sinon_1.default.stub(device_store_1.DeviceStoreFactory, 'getStore').returns({
|
|
85
|
+
findDevice: (filter) => __awaiter(void 0, void 0, void 0, function* () {
|
|
86
|
+
var _a;
|
|
87
|
+
return ((_a = rows.find((r) => Object.entries(filter).every(([k, v]) => r[k] === v))) !== null && _a !== void 0 ? _a : null);
|
|
88
|
+
}),
|
|
89
|
+
updateDevice: () => __awaiter(void 0, void 0, void 0, function* () { return undefined; }),
|
|
90
|
+
});
|
|
91
|
+
const hub = new PluginContext_1.PluginContext();
|
|
92
|
+
hub.setContext(Object.assign({}, IPluginArgs_1.DefaultPluginArgs, { bindHostOrIp: IP }), 4724, 'hub', '');
|
|
93
|
+
const real = typedi_1.Container.get.bind(typedi_1.Container);
|
|
94
|
+
sinon_1.default.stub(typedi_1.Container, 'get').callsFake((token) => {
|
|
95
|
+
if (token === PluginContext_1.PluginContext)
|
|
96
|
+
return hub;
|
|
97
|
+
if (token === PortAllocator_1.PortAllocator)
|
|
98
|
+
return { release: () => __awaiter(void 0, void 0, void 0, function* () { return undefined; }) };
|
|
99
|
+
if (token === recording_store_1.RecordingStore)
|
|
100
|
+
return { isRecording: () => __awaiter(void 0, void 0, void 0, function* () { return false; }) };
|
|
101
|
+
if (token === AndroidH264StreamService_1.default)
|
|
102
|
+
return { getMultiplexer: () => undefined };
|
|
103
|
+
if (token === AndroidStreamService_1.default)
|
|
104
|
+
return { getStreamStatus: () => undefined };
|
|
105
|
+
return real(token);
|
|
106
|
+
});
|
|
107
|
+
unblock = sinon_1.default.stub(deviceService, 'unblockDevice').resolves();
|
|
108
|
+
sinon_1.default.stub(process, 'kill');
|
|
109
|
+
});
|
|
110
|
+
afterEach(() => sinon_1.default.restore());
|
|
111
|
+
function iosService() {
|
|
112
|
+
// Bypass the constructor: it starts watchdog intervals.
|
|
113
|
+
const svc = Object.create(IOSStreamService_1.default.prototype);
|
|
114
|
+
svc.sessions = new Map();
|
|
115
|
+
svc.startFlight = new singleFlight_1.SingleFlight();
|
|
116
|
+
svc.recoveryCooldowns = new Map();
|
|
117
|
+
svc.cleanupOrphanTunnels = () => __awaiter(this, void 0, void 0, function* () { return undefined; });
|
|
118
|
+
return svc;
|
|
119
|
+
}
|
|
120
|
+
it("iOS: stopping the hub's stream never releases the node's preview hold", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
121
|
+
rows = [
|
|
122
|
+
{ udid: UDID, host: NODE, platform: 'ios', busy: true, session_id: `manual_usr_bob_${UDID}` },
|
|
123
|
+
{ udid: UDID, host: HUB, platform: 'ios', busy: false, session_id: undefined },
|
|
124
|
+
];
|
|
125
|
+
const svc = iosService();
|
|
126
|
+
svc.sessions.set(UDID, {
|
|
127
|
+
udid: UDID,
|
|
128
|
+
wdaProcess: null,
|
|
129
|
+
forwardWDAProcess: null,
|
|
130
|
+
forwardMJPEGProcess: null,
|
|
131
|
+
tunnelProcess: null,
|
|
132
|
+
wdaPort: 28101,
|
|
133
|
+
mjpegPort: 29101,
|
|
134
|
+
status: 'running',
|
|
135
|
+
lastViewerAt: Date.now(),
|
|
136
|
+
viewerCount: 0,
|
|
137
|
+
});
|
|
138
|
+
yield svc.stopStream(UDID);
|
|
139
|
+
(0, chai_1.expect)(unblock.called, `unblocked ${JSON.stringify(unblock.args)}`).to.equal(false);
|
|
140
|
+
}));
|
|
141
|
+
it("iOS: whether an Appium session holds the phone is read from the hub's own row", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
142
|
+
rows = [
|
|
143
|
+
{ udid: UDID, host: NODE, platform: 'ios', busy: false, session_id: undefined },
|
|
144
|
+
{ udid: UDID, host: HUB, platform: 'ios', busy: true, session_id: 'hub-appium-session' },
|
|
145
|
+
];
|
|
146
|
+
(0, chai_1.expect)(yield iosService().appiumSessionMayUse(UDID, 'go-ios tunnels')).to.equal(true);
|
|
147
|
+
}));
|
|
148
|
+
it("Android: a stopping preview never releases the node's preview hold", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
149
|
+
rows = [
|
|
150
|
+
{ udid: UDID, host: NODE, platform: 'android', busy: true, session_id: hold('usr_bob') },
|
|
151
|
+
{ udid: UDID, host: HUB, platform: 'android', busy: false, session_id: undefined },
|
|
152
|
+
];
|
|
153
|
+
(0, chai_1.expect)(yield (0, previewHold_1.releaseIdlePreviewHold)(UDID)).to.equal(false);
|
|
154
|
+
(0, chai_1.expect)(unblock.called).to.equal(false);
|
|
155
|
+
}));
|
|
156
|
+
it("Android: the hub's own preview hold is still released", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
157
|
+
rows = [
|
|
158
|
+
{ udid: UDID, host: NODE, platform: 'android', busy: false, session_id: undefined },
|
|
159
|
+
{ udid: UDID, host: HUB, platform: 'android', busy: true, session_id: hold('usr_al') },
|
|
160
|
+
];
|
|
161
|
+
(0, chai_1.expect)(yield (0, previewHold_1.releaseIdlePreviewHold)(UDID)).to.equal(true);
|
|
162
|
+
(0, chai_1.expect)(unblock.calledOnceWith(UDID, HUB)).to.equal(true);
|
|
163
|
+
}));
|
|
164
|
+
});
|
|
@@ -49,7 +49,7 @@ require("reflect-metadata");
|
|
|
49
49
|
const chai_1 = require("chai");
|
|
50
50
|
const sinon_1 = __importDefault(require("sinon"));
|
|
51
51
|
const express_1 = __importDefault(require("express"));
|
|
52
|
-
const
|
|
52
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
53
53
|
const typedi_1 = require("typedi");
|
|
54
54
|
const control_1 = __importDefault(require("../../src/app/routers/control"));
|
|
55
55
|
const device_store_1 = require("../../src/data-service/device-store");
|
|
@@ -60,6 +60,8 @@ const IOSStreamService_1 = __importDefault(require("../../src/device-managers/io
|
|
|
60
60
|
const AndroidStreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidStreamService"));
|
|
61
61
|
const AndroidH264StreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidH264StreamService"));
|
|
62
62
|
const authMiddleware_1 = require("../../src/middleware/authMiddleware");
|
|
63
|
+
const container_registration_1 = require("../helpers/container-registration");
|
|
64
|
+
const loopbackServer_1 = require("../helpers/loopbackServer");
|
|
63
65
|
/**
|
|
64
66
|
* Round-trip guard for POST /control/:udid/stream/stop.
|
|
65
67
|
*
|
|
@@ -121,6 +123,10 @@ describe('POST /control/:udid/stream/stop — lock ownership round-trip', () =>
|
|
|
121
123
|
let androidStop;
|
|
122
124
|
let h264Stop;
|
|
123
125
|
let deviceRow;
|
|
126
|
+
let restoreContainer;
|
|
127
|
+
// Served on 127.0.0.1: request(app) listens on every address and connects
|
|
128
|
+
// to 127.0.0.1, where another process's listener on that port can answer.
|
|
129
|
+
const loopback = (0, loopbackServer_1.loopbackServers)();
|
|
124
130
|
function setLock(sessionId) {
|
|
125
131
|
deviceRow = {
|
|
126
132
|
udid: UDID,
|
|
@@ -131,6 +137,7 @@ describe('POST /control/:udid/stream/stop — lock ownership round-trip', () =>
|
|
|
131
137
|
};
|
|
132
138
|
}
|
|
133
139
|
beforeEach(() => {
|
|
140
|
+
restoreContainer = (0, container_registration_1.saveRegistrations)(ApiKeyService_1.ApiKeyService, AndroidStreamService_1.default, AndroidH264StreamService_1.default, IOSStreamService_1.default, recording_store_1.RecordingStore);
|
|
134
141
|
setLock(`manual_${ALICE}_${UDID}`);
|
|
135
142
|
sinon_1.default.stub(device_store_1.DeviceStoreFactory, 'getStore').returns({
|
|
136
143
|
findDevice: () => __awaiter(void 0, void 0, void 0, function* () { return deviceRow; }),
|
|
@@ -145,11 +152,12 @@ describe('POST /control/:udid/stream/stop — lock ownership round-trip', () =>
|
|
|
145
152
|
// Nothing is being recorded here (see stream-stop-recording.spec.ts).
|
|
146
153
|
typedi_1.Container.set(recording_store_1.RecordingStore, { activeRecordingFor: () => __awaiter(void 0, void 0, void 0, function* () { return null; }) });
|
|
147
154
|
});
|
|
148
|
-
afterEach(() => {
|
|
155
|
+
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
149
156
|
sinon_1.default.restore();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
157
|
+
restoreContainer();
|
|
158
|
+
yield loopback.closeAll();
|
|
159
|
+
}));
|
|
160
|
+
const stop = (caller) => __awaiter(void 0, void 0, void 0, function* () { return (0, loopbackRequest_1.default)(yield loopback.serve(buildApp(caller))).post(`/xenon/api/control/${UDID}/stream/stop`); });
|
|
153
161
|
it('CRITICAL: the header-pair caller who started the stream can stop it', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
154
162
|
// Exactly what stream/start wrote for this caller: manual_<userId>_<udid>.
|
|
155
163
|
// req.apiKey.id is set and DIFFERENT — the pre-fix reader picked it and 403'd.
|
|
@@ -49,7 +49,7 @@ require("reflect-metadata");
|
|
|
49
49
|
const chai_1 = require("chai");
|
|
50
50
|
const sinon_1 = __importDefault(require("sinon"));
|
|
51
51
|
const express_1 = __importDefault(require("express"));
|
|
52
|
-
const
|
|
52
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
53
53
|
const typedi_1 = require("typedi");
|
|
54
54
|
const control_1 = __importDefault(require("../../src/app/routers/control"));
|
|
55
55
|
const device_store_1 = require("../../src/data-service/device-store");
|
|
@@ -60,6 +60,8 @@ const IOSStreamService_1 = __importDefault(require("../../src/device-managers/io
|
|
|
60
60
|
const AndroidStreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidStreamService"));
|
|
61
61
|
const AndroidH264StreamService_1 = __importDefault(require("../../src/device-managers/android/AndroidH264StreamService"));
|
|
62
62
|
const authMiddleware_1 = require("../../src/middleware/authMiddleware");
|
|
63
|
+
const container_registration_1 = require("../helpers/container-registration");
|
|
64
|
+
const loopbackServer_1 = require("../helpers/loopbackServer");
|
|
63
65
|
/**
|
|
64
66
|
* POST /control/:udid/stream/stop must not stop the stream under a live
|
|
65
67
|
* recording. The recording reads from that stream: measured 2026-09-26 on a
|
|
@@ -96,7 +98,12 @@ describe('POST /control/:udid/stream/stop — a device being recorded', () => {
|
|
|
96
98
|
let androidStop;
|
|
97
99
|
let h264Stop;
|
|
98
100
|
let active;
|
|
101
|
+
let restoreContainer;
|
|
102
|
+
// Served on 127.0.0.1: request(app) listens on every address and connects
|
|
103
|
+
// to 127.0.0.1, where another process's listener on that port can answer.
|
|
104
|
+
const loopback = (0, loopbackServer_1.loopbackServers)();
|
|
99
105
|
beforeEach(() => {
|
|
106
|
+
restoreContainer = (0, container_registration_1.saveRegistrations)(ApiKeyService_1.ApiKeyService, AndroidStreamService_1.default, AndroidH264StreamService_1.default, IOSStreamService_1.default, recording_store_1.RecordingStore);
|
|
100
107
|
active = { id: 'rec-1', groupId: 'grp-1' };
|
|
101
108
|
sinon_1.default.stub(device_store_1.DeviceStoreFactory, 'getStore').returns({
|
|
102
109
|
findDevice: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -118,11 +125,12 @@ describe('POST /control/:udid/stream/stop — a device being recorded', () => {
|
|
|
118
125
|
typedi_1.Container.set(IOSStreamService_1.default, { stopStream: sinon_1.default.stub().resolves() });
|
|
119
126
|
typedi_1.Container.set(recording_store_1.RecordingStore, { activeRecordingFor: () => __awaiter(void 0, void 0, void 0, function* () { return active; }) });
|
|
120
127
|
});
|
|
121
|
-
afterEach(() => {
|
|
128
|
+
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
122
129
|
sinon_1.default.restore();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
restoreContainer();
|
|
131
|
+
yield loopback.closeAll();
|
|
132
|
+
}));
|
|
133
|
+
const stop = (caller) => __awaiter(void 0, void 0, void 0, function* () { return (0, loopbackRequest_1.default)(yield loopback.serve(buildApp(caller))).post(`/xenon/api/control/${UDID}/stream/stop`); });
|
|
126
134
|
it('refuses the owner with 409 and names the recording to stop instead', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
127
135
|
const res = yield stop({ userId: ALICE });
|
|
128
136
|
(0, chai_1.expect)(res.status, JSON.stringify(res.body)).to.equal(409);
|
|
@@ -16,7 +16,7 @@ require("reflect-metadata");
|
|
|
16
16
|
const chai_1 = require("chai");
|
|
17
17
|
const sinon_1 = __importDefault(require("sinon"));
|
|
18
18
|
const express_1 = __importDefault(require("express"));
|
|
19
|
-
const
|
|
19
|
+
const loopbackRequest_1 = __importDefault(require("../helpers/loopbackRequest"));
|
|
20
20
|
const typedi_1 = require("typedi");
|
|
21
21
|
const fs_1 = __importDefault(require("fs"));
|
|
22
22
|
const os_1 = __importDefault(require("os"));
|
|
@@ -29,6 +29,8 @@ const UserService_1 = require("../../src/services/UserService");
|
|
|
29
29
|
const ApiKeyService_1 = require("../../src/services/ApiKeyService");
|
|
30
30
|
const UserSessionService_1 = require("../../src/services/UserSessionService");
|
|
31
31
|
const device_store_1 = require("../../src/data-service/device-store");
|
|
32
|
+
const container_registration_1 = require("../helpers/container-registration");
|
|
33
|
+
const loopbackServer_1 = require("../helpers/loopbackServer");
|
|
32
34
|
/**
|
|
33
35
|
* `req.auth.userId` must always hold a User id.
|
|
34
36
|
*
|
|
@@ -78,7 +80,12 @@ describe('stream/ticket carries the user identity, not the credential', () => {
|
|
|
78
80
|
app.use('/xenon/api', apiRouter);
|
|
79
81
|
return app;
|
|
80
82
|
}
|
|
83
|
+
let restoreContainer;
|
|
84
|
+
// Served on 127.0.0.1: request(app) listens on every address and connects
|
|
85
|
+
// to 127.0.0.1, where another process's listener on that port can answer.
|
|
86
|
+
const loopback = (0, loopbackServer_1.loopbackServers)();
|
|
81
87
|
beforeEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
+
restoreContainer = (0, container_registration_1.saveRegistrations)(JwtKeyService_1.JwtKeyService, StreamTicketService_1.StreamTicketService, UserService_1.UserService, ApiKeyService_1.ApiKeyService, UserSessionService_1.UserSessionService);
|
|
82
89
|
dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'xenon-ticket-identity-'));
|
|
83
90
|
const keySvc = new JwtKeyService_1.JwtKeyService();
|
|
84
91
|
yield keySvc.init(dir);
|
|
@@ -101,12 +108,15 @@ describe('stream/ticket carries the user identity, not the credential', () => {
|
|
|
101
108
|
}),
|
|
102
109
|
});
|
|
103
110
|
}));
|
|
104
|
-
afterEach(() => {
|
|
111
|
+
afterEach(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
112
|
sinon_1.default.restore();
|
|
106
|
-
|
|
113
|
+
restoreContainer();
|
|
114
|
+
yield loopback.closeAll();
|
|
107
115
|
fs_1.default.rmSync(dir, { recursive: true, force: true });
|
|
116
|
+
}));
|
|
117
|
+
const mint = (caller) => __awaiter(void 0, void 0, void 0, function* () {
|
|
118
|
+
return (0, loopbackRequest_1.default)(yield loopback.serve(buildApp(caller))).post(`/xenon/api/control/${UDID}/stream/ticket`);
|
|
108
119
|
});
|
|
109
|
-
const mint = (caller) => (0, supertest_1.default)(buildApp(caller)).post(`/xenon/api/control/${UDID}/stream/ticket`);
|
|
110
120
|
it('mints with the userId even when a different apiKey id is present', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
121
|
const res = yield mint({ userId: ALICE_USER, apiKeyId: ALICE_KEY });
|
|
112
122
|
(0, chai_1.expect)(res.status, JSON.stringify(res.body)).to.equal(200);
|
|
@@ -150,7 +160,7 @@ describe('stream/ticket carries the user identity, not the credential', () => {
|
|
|
150
160
|
// two must match: minting for any udid would mark the ones that 404 as
|
|
151
161
|
// phones another team owns.
|
|
152
162
|
it("404s a udid that isn't a device, and mints nothing", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
153
|
-
const res = yield (0,
|
|
163
|
+
const res = yield (0, loopbackRequest_1.default)(yield loopback.serve(buildApp({ userId: ALICE_USER }))).post('/xenon/api/control/NO-SUCH-DEVICE/stream/ticket');
|
|
154
164
|
(0, chai_1.expect)(res.status).to.equal(404);
|
|
155
165
|
(0, chai_1.expect)(res.text).to.equal('Device not found');
|
|
156
166
|
}));
|