Skip to content

Instantly share code, notes, and snippets.

@saikrishna321
Created January 22, 2024 04:24
Show Gist options
  • Save saikrishna321/acff787231d9b952dade60133aaddce0 to your computer and use it in GitHub Desktop.
Save saikrishna321/acff787231d9b952dade60133aaddce0 to your computer and use it in GitHub Desktop.
"use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,i,r,s){void 0===s&&(s=r);var t=Object.getOwnPropertyDescriptor(i,r);t&&("get"in t?i.__esModule:!t.writable&&!t.configurable)||(t={enumerable:!0,get:function(){return i[r]}}),Object.defineProperty(e,s,t)}:function(e,i,r,s){e[s=void 0===s?r:s]=i[r]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,i){Object.defineProperty(e,"default",{enumerable:!0,value:i})}:function(e,i){e.default=i}),__importStar=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var i={};if(null!=e)for(var r in e)"default"!==r&&Object.prototype.hasOwnProperty.call(e,r)&&__createBinding(i,e,r);return __setModuleDefault(i,e),i},__awaiter=this&&this.__awaiter||function(e,n,a,l){return new(a=a||Promise)(function(r,i){function s(e){try{o(l.next(e))}catch(e){i(e)}}function t(e){try{o(l.throw(e))}catch(e){i(e)}}function o(e){var i;e.done?r(e.value):((i=e.value)instanceof a?i:new a(function(e){e(i)})).then(s,t)}o((l=l.apply(e,n||[])).next())})},__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.DevicePlugin=void 0,require("reflect-metadata");const index_1=__importDefault(require("./commands/index")),base_plugin_1=__importDefault(require("@appium/base-plugin")),app_1=require("./app"),async_lock_1=__importDefault(require("async-lock")),device_service_1=require("./data-service/device-service"),pending_sessions_service_1=require("./data-service/pending-sessions-service"),device_utils_1=require("./device-utils"),device_managers_1=require("./device-managers"),typedi_1=require("typedi"),logger_1=__importDefault(require("./logger")),uuid_1=require("uuid"),axios_1=__importStar(require("axios")),https_proxy_agent_1=require("https-proxy-agent"),http_proxy_agent_1=require("http-proxy-agent"),helpers_1=require("./helpers"),wd_command_proxy_1=require("./proxy/wd-command-proxy"),ChromeDriverManager_1=__importDefault(require("./device-managers/ChromeDriverManager")),pluginArgs_1=require("./data-service/pluginArgs"),Cloud_1=__importDefault(require("./enums/Cloud")),appium_adb_1=require("appium-adb"),IPluginArgs_1=require("./interfaces/IPluginArgs"),NodeDevices_1=__importDefault(require("./device-managers/NodeDevices")),SessionManager_1=require("./sessions/SessionManager"),LocalSession_1=require("./sessions/LocalSession"),CloudSession_1=require("./sessions/CloudSession"),RemoteSession_1=require("./sessions/RemoteSession"),event_manager_1=require("./dashboard/event-manager"),CapabilityManager_1=require("./CapabilityManager"),ip_1=__importDefault(require("ip")),lodash_1=__importDefault(require("lodash")),SessionType_1=__importDefault(require("./enums/SessionType")),db_1=require("./data-service/db"),sample_1=require("../pw-wdio-appium/sample"),commandsQueueGuard=new async_lock_1.default,DEVICE_MANAGER_LOCK_NAME="DeviceManager";let platform,androidDeviceType,iosDeviceType,hasEmulators,proxy;class DevicePlugin extends base_plugin_1.default{constructor(e,i){super(e,i),this.pluginArgs=Object.assign({},IPluginArgs_1.DefaultPluginArgs),logger_1.default.debug("πŸ“± Plugin Args: "+JSON.stringify(i)),this.pluginArgs=Object.assign({},IPluginArgs_1.DefaultPluginArgs,this.cliArgs),void 0===this.pluginArgs.bindHostOrIp&&(this.pluginArgs.bindHostOrIp=ip_1.default.address())}onUnexpectedShutdown(e,i){e={session_id:e.sessionId||void 0,udid:e.caps&&e.caps.udid?e.caps.udid:void 0};void 0!==this.pluginArgs.hub?new NodeDevices_1.default(this.pluginArgs.hub).unblockDevice(e):(0,device_service_1.unblockDeviceMatchingFilter)(e),logger_1.default.info(`Unblocking device mapped with filter ${JSON.stringify(e)} onUnexpectedShutdown from server`)}static updateServer(t,e,o){return __awaiter(this,void 0,void 0,function*(){logger_1.default.debug("πŸ“± Update server with CLI Args: "+JSON.stringify(o)),(0,sample_1.deviceLogs)();var e=o.plugin;let i;if(i=void 0!==e["device-farm"]?Object.assign({},IPluginArgs_1.DefaultPluginArgs,e["device-farm"]):Object.assign({},IPluginArgs_1.DefaultPluginArgs),DevicePlugin.NODE_ID=(0,uuid_1.v4)(),logger_1.default.info("Cli Args: "+JSON.stringify(o)),DevicePlugin.nodeBasePath=o.basePath,void 0===i.bindHostOrIp&&(i.bindHostOrIp=ip_1.default.address()),logger_1.default.debug("πŸ“± Update server with Plugin Args: "+JSON.stringify(i)),i.removeDevicesFromDatabaseBeforeRunningThePlugin&&(logger_1.default.info("πŸ”΄ Removing all devices from database before running the plugin. You asked for it!"),yield(0,device_utils_1.initializeStorage)(),(yield db_1.ADTDatabase.DeviceModel).removeDataOnly()),platform=i.platform,androidDeviceType=i.androidDeviceType,iosDeviceType=i.iosDeviceType,void 0!==i.proxy?(logger_1.default.info("Adding proxy for axios: "+JSON.stringify(i.proxy)),proxy=i.proxy):logger_1.default.info("proxy is not required for axios"),hasEmulators=i.emulators&&0<i.emulators.length,t.use("/device-farm",(0,app_1.createRouter)(i)),(0,wd_command_proxy_1.registerProxyMiddlware)(t,o),!platform)throw new Error("πŸ”΄ πŸ”΄ πŸ”΄ Specify --plugin-device-farm-platform from CLI as android,iOS or both or use appium server config. Please refer πŸ”— https://github.com/appium/appium/blob/master/packages/appium/docs/en/guides/config.md πŸ”΄ πŸ”΄ πŸ”΄");if(hasEmulators&&"android"===i.platform.toLowerCase()){logger_1.default.info("Emulators will be booted!!");const s=yield appium_adb_1.ADB.createADB({});e=(i.emulators||[]).map(e=>__awaiter(this,void 0,void 0,function*(){yield Promise.all([yield s.launchAVD(e.avdName,e)])}));yield Promise.all(e)}var e=!1===i.skipChromeDownload?yield ChromeDriverManager_1.default.getInstance():void 0,r=(iosDeviceType=DevicePlugin.setIncludeSimulatorState(i,iosDeviceType),{androidDeviceType:androidDeviceType,iosDeviceType:iosDeviceType}),r=new device_managers_1.DeviceFarmManager(platform,r,o.port,i,DevicePlugin.NODE_ID),r=(typedi_1.Container.set(device_managers_1.DeviceFarmManager,r),e&&typedi_1.Container.set(ChromeDriverManager_1.default,e),yield(0,pluginArgs_1.addCLIArgs)(o),yield(0,device_utils_1.initializeStorage)(),logger_1.default.info(`πŸ“£πŸ“£πŸ“£ Device Farm Plugin will be served at πŸ”— http://${i.bindHostOrIp}:${o.port}/device-farm with id `+DevicePlugin.NODE_ID),i.hub),e=(void 0!==r?(logger_1.default.info("πŸ“£πŸ“£πŸ“£ I'm a node and my hub is "+r),yield(0,device_utils_1.setupCronUpdateDeviceList)(i.bindHostOrIp,r,i.sendNodeDevicesToHubIntervalMs)):(DevicePlugin.IS_HUB=!0,logger_1.default.info(`πŸ“£πŸ“£πŸ“£ I'm a hub and I'm listening on ${i.bindHostOrIp}:`+o.port)),null==i.cloud?(yield(0,device_utils_1.setupCronCheckStaleDevices)(i.checkStaleDevicesIntervalMs,i.bindHostOrIp),yield(0,device_utils_1.setupCronReleaseBlockedDevices)(i.checkBlockedDevicesIntervalMs,i.newCommandTimeoutSec),yield(0,device_utils_1.setupCronCleanPendingSessions)(i.checkBlockedDevicesIntervalMs,i.deviceAvailabilityTimeoutMs+1e4),yield(0,device_service_1.unblockDeviceMatchingFilter)({}),yield(0,device_utils_1.removeStaleDevices)(i.bindHostOrIp)):logger_1.default.info("πŸ“£πŸ“£πŸ“£ Cloud runner sessions dont require constant device checks"),yield(0,device_utils_1.updateDeviceList)(i.bindHostOrIp,r));(0,device_utils_1.isIOS)(i)&&(0,device_utils_1.deviceType)(i,"simulated")&&(yield(0,device_service_1.setSimulatorState)(e),yield(0,device_utils_1.refreshSimulatorState)(i,o.port))})}static setIncludeSimulatorState(e,i){return(0,helpers_1.hasCloudArgument)(e)&&(i="real",logger_1.default.info("ℹ️ Skipping Simulators as per the configuration ℹ️")),i}static waitForRemoteDeviceFarmToBeRunning(e){return __awaiter(this,void 0,void 0,function*(){yield(0,helpers_1.spinWith)(`Waiting for device farm server ${e} to be up and running
`,()=>__awaiter(this,void 0,void 0,function*(){return yield(0,helpers_1.isDeviceFarmRunning)(e)}),e=>{throw new Error("Failed: "+e)})})}createSession(e,l,i,r,d){return __awaiter(this,void 0,void 0,function*(){logger_1.default.debug("πŸ“± pluginArgs: "+JSON.stringify(this.pluginArgs)),logger_1.default.debug("Receiving session request at host: "+this.pluginArgs.bindHostOrIp);const i=(0,uuid_1.v4)();logger_1.default.debug("πŸ“± Creating temporary session capability_id: "+i);var{alwaysMatch:r={},firstMatch:s=[{}]}=d,r=((0,helpers_1.stripAppiumPrefixes)(r),(0,helpers_1.stripAppiumPrefixes)(s),yield(0,pending_sessions_service_1.addNewPendingSession)(Object.assign(Object.assign({},Object.assign({},d.firstMatch[0],d.alwaysMatch)),{capability_id:i,createdAt:(new Date).getTime()})),yield commandsQueueGuard.acquire(DEVICE_MANAGER_LOCK_NAME,()=>__awaiter(this,void 0,void 0,function*(){try{return yield(0,device_utils_1.allocateDeviceForSession)(d,this.pluginArgs.deviceAvailabilityTimeoutMs,this.pluginArgs.deviceAvailabilityQueryIntervalMs,this.pluginArgs)}catch(e){throw yield(0,pending_sessions_service_1.removePendingSession)(i),e}})));let t;s=!r.nodeId||r.nodeId!==DevicePlugin.NODE_ID;if(logger_1.default.debug(`device.host: ${r.host} and pluginArgs.bindHostOrIp: `+this.pluginArgs.bindHostOrIp),t=s?(logger_1.default.debug("πŸ“± Forwarding session request to "+r.host),yield this.forwardSessionRequest(r,d)):(logger_1.default.debug("πŸ“± Creating session on the same node"),yield e()),logger_1.default.debug("πŸ“± Session response: ",JSON.stringify(t)),logger_1.default.debug("πŸ“± Removing pending session with capability_id: "+i),yield(0,pending_sessions_service_1.removePendingSession)(i),this.isCreateSessionResponseInternal(t)){logger_1.default.debug("πŸ“± Session response is CreateSessionResponseInternal");var o=t.value[0],n=t.value[1],a=(0,CapabilityManager_1.getDeviceFarmCapabilities)(d);logger_1.default.info(`πŸ“± Device UDID ${r.udid} blocked for session `+o),yield(0,device_service_1.updatedAllocatedDevice)(r,{busy:!0,session_id:o,lastCmdExecutedAt:(new Date).getTime(),sessionStartTime:(new Date).getTime()}),s&&(0,wd_command_proxy_1.addProxyHandler)(o,r.host);let e;s={sessionId:o,device:r,sessionResponse:n,deviceFarmOption:a},n=(0,helpers_1.nodeUrl)(r,DevicePlugin.nodeBasePath),s=(e=r.nodeId===DevicePlugin.NODE_ID?new LocalSession_1.LocalSession(Object.assign(Object.assign({},s),{driver:l})):new(r.hasOwnProperty("cloud")?CloudSession_1.CloudSession:RemoteSession_1.RemoteSession)(Object.assign(Object.assign({},s),{baseUrl:n})),!!this.pluginArgs.enableDashboard),n=e.getType()!==SessionType_1.default.CLOUD;s&&n?(logger_1.default.debug(`Adding the session ${e.getId()} with type ${e.getType()} to session map`),SessionManager_1.SESSION_MANAGER.addSession(e.getId(),e),DevicePlugin.IS_HUB&&(yield event_manager_1.DASHBORD_EVENT_MANAGER.onSessionStarted(a,e,r))):logger_1.default.debug(`Not adding the session ${e.getId()} with type ${e.getType()} to session map. DashboardEnabled: ${s}, shouldSaveLogs: `+n),logger_1.default.info(`πŸ“± Updating Device ${r.udid} with session ID `+o)}else yield(0,device_service_1.unblockDevice)(r.udid,r.host),logger_1.default.info(`πŸ“± Device UDID ${r.udid} unblocked. Reason: Failed to create session`),this.throwProperError(t,r.host);return t})}throwProperError(e,i){var r;throw e instanceof Error?e:e.hasOwnProperty("error")&&(r=e.error)?new Error(r):new Error(`Unknown error while creating session: ${JSON.stringify(e)}.
Better look at appium log on the node: `+i)}isCreateSessionResponseInternal(e){return e.hasOwnProperty("value")&&3===e.value.length&&e.value[0]&&e.value[1]&&e.value[2]}forwardSessionRequest(r,s){return __awaiter(this,void 0,void 0,function*(){var e=(0,helpers_1.nodeUrl)(r,DevicePlugin.nodeBasePath)+"/session";let i={capabilities:s};r.hasOwnProperty("cloud")&&r.cloud.toLowerCase()===Cloud_1.default.LAMBDATEST&&(i=Object.assign(i,{desiredCapabilities:i.capabilities.alwaysMatch})),logger_1.default.info(`Creating session with desiredCapabilities: "${JSON.stringify(i)}"`);e={method:"post",url:e,headers:{"Content-Type":"application/json"},data:i},null!=proxy&&(logger_1.default.info("Added proxy to axios config: "+JSON.stringify(proxy)),e.httpsAgent=new https_proxy_agent_1.HttpsProxyAgent(proxy),e.httpAgent=new http_proxy_agent_1.HttpProxyAgent(proxy),e.proxy=!1),logger_1.default.info(`With axios config: "${JSON.stringify(e)}"`),e=yield this.invokeSessionRequest(e);return e instanceof Error?e:{protocol:"W3C",value:[e.value.sessionId,e.value.capabilities,"W3C"]}})}invokeSessionRequest(s){var t;return __awaiter(this,void 0,void 0,function*(){let e=null,i=null;try{var r=yield(0,axios_1.default)(s);logger_1.default.debug("remote node response",JSON.stringify(r.data)),"error"in(e=r.data).value&&(logger_1.default.error("Error while creating session: "+e.value.error),i=e.value.error)}catch(e){logger_1.default.debug("Received error from remote node: "+JSON.stringify(e)),i=e instanceof axios_1.AxiosError?JSON.stringify(null==(t=e.response)?void 0:t.data):e}return lodash_1.default.isNil(e)?(logger_1.default.error("Error while creating session: "+i),lodash_1.default.isNil(i)&&(i="Unknown error while creating session"),new Error(i)):(logger_1.default.debug("πŸ“± Session received with details: "+JSON.stringify(e||{})),this.isW3CNewSessionResponse(e)?e:new Error("Unknown error while creating session: "+JSON.stringify(e)))})}isW3CNewSessionResponse(e){return e.hasOwnProperty("value")&&e.value.hasOwnProperty("sessionId")&&e.value.hasOwnProperty("capabilities")}deleteSession(e,i,r){return __awaiter(this,void 0,void 0,function*(){return yield(0,device_service_1.unblockDeviceMatchingFilter)({session_id:r}),logger_1.default.info("πŸ“± Unblocking the device that is blocked for session "+r),yield e()})}}(exports.DevicePlugin=DevicePlugin).nodeBasePath="",DevicePlugin.IS_HUB=!1,Object.assign(DevicePlugin.prototype,index_1.default);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment