diff --git a/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme b/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme index 8857b934c..4c2919f78 100644 --- a/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme +++ b/WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme @@ -66,6 +66,11 @@ value = "$(USE_PORT)" isEnabled = "YES"> + + + + 0) { + return NSProcessInfo.processInfo.environment[@"USE_IP"]; + } + + return nil; +} + + (NSInteger)mjpegServerPort { if (self.mjpegServerPortFromArguments != NSNotFound) { diff --git a/WebDriverAgentTests/UnitTests/FBConfigurationTests.m b/WebDriverAgentTests/UnitTests/FBConfigurationTests.m index 05e53d65f..6d25ea6b0 100644 --- a/WebDriverAgentTests/UnitTests/FBConfigurationTests.m +++ b/WebDriverAgentTests/UnitTests/FBConfigurationTests.m @@ -20,6 +20,7 @@ - (void)setUp { [super setUp]; unsetenv("USE_PORT"); + unsetenv("USE_IP"); unsetenv("VERBOSE_LOGGING"); } @@ -45,4 +46,15 @@ - (void)testVerboseLoggingEnvironmentOverwrite XCTAssertTrue([FBConfiguration verboseLoggingEnabled]); } +- (void)testBindingIPDefault +{ + XCTAssertNil([FBConfiguration bindingIPAddress]); +} + +- (void)testBindingIPEnvironmentOverwrite +{ + setenv("USE_IP", "192.168.1.100", 1); + XCTAssertEqualObjects([FBConfiguration bindingIPAddress], @"192.168.1.100"); +} + @end diff --git a/lib/types.ts b/lib/types.ts index ee5cdf996..32a32493b 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -64,6 +64,7 @@ export interface WebDriverAgentArgs { wdaLocalPort?: number; wdaRemotePort?: number; wdaBaseUrl?: string; + wdaBindingIP?: string; prebuildWDA?: boolean; webDriverAgentUrl?: string; wdaConnectionTimeout?: number; @@ -116,6 +117,7 @@ export interface XcodeBuildArgs { useXctestrunFile?: boolean; launchTimeout?: number; wdaRemotePort?: number; + wdaBindingIP?: string; updatedWDABundleId?: string; derivedDataPath?: string; mjpegServerPort?: number; diff --git a/lib/utils.js b/lib/utils.js index 4ff845abd..3d0bb3ec0 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -166,6 +166,16 @@ async function setRealDeviceSecurity (keychainPath, keychainPassword) { * @property {string} platformVersion - The platform version of OS. * @property {string} platformName - The platform name of iOS, tvOS */ + +/** + * Arguments for setting xctestrun file + * @typedef {Object} XctestrunFileArgs + * @property {DeviceInfo} deviceInfo - Information of the device under test + * @property {string} sdkVersion - The Xcode SDK version of OS. + * @property {string} bootstrapPath - The folder path containing xctestrun file. + * @property {number|string} wdaRemotePort - The remote port WDA is listening on. + * @property {string} [wdaBindingIP] - The IP address to bind to. If not given, it binds to all interfaces. + */ /** * Creates xctestrun file per device & platform version. * We expects to have WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device @@ -174,19 +184,17 @@ async function setRealDeviceSecurity (keychainPath, keychainPassword) { * e.g. Xcode which has iOS SDK Version 12.2 on an intel Mac host machine generates WebDriverAgentRunner_iphonesimulator.2-x86_64.xctestrun * even if the cap has platform version 11.4 * - * @param {DeviceInfo} deviceInfo - * @param {string} sdkVersion - The Xcode SDK version of OS. - * @param {string} bootstrapPath - The folder path containing xctestrun file. - * @param {number|string} wdaRemotePort - The remote port WDA is listening on. + * @param {XctestrunFileArgs} args * @return {Promise} returns xctestrunFilePath for given device * @throws if WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device * or WebDriverAgentRunner_iphonesimulator${sdkVersion|platformVersion}-x86_64.xctestrun for simulator is not found @bootstrapPath, - * then it will throw file not found exception + * then it will throw a file not found exception */ -async function setXctestrunFile (deviceInfo, sdkVersion, bootstrapPath, wdaRemotePort) { +async function setXctestrunFile (args) { + const {deviceInfo, sdkVersion, bootstrapPath, wdaRemotePort, wdaBindingIP} = args; const xctestrunFilePath = await getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath); const xctestRunContent = await plist.parsePlistFile(xctestrunFilePath); - const updateWDAPort = getAdditionalRunContent(deviceInfo.platformName, wdaRemotePort); + const updateWDAPort = getAdditionalRunContent(deviceInfo.platformName, wdaRemotePort, wdaBindingIP); const newXctestRunContent = _.merge(xctestRunContent, updateWDAPort); await plist.updatePlistFile(xctestrunFilePath, newXctestRunContent, true); @@ -197,16 +205,17 @@ async function setXctestrunFile (deviceInfo, sdkVersion, bootstrapPath, wdaRemot * Return the WDA object which appends existing xctest runner content * @param {string} platformName - The name of the platform * @param {number|string} wdaRemotePort - The remote port number - * @return {object} returns a runner object which has USE_PORT + * @param {string} [wdaBindingIP] - The IP address to bind to. If not given, it binds to all interfaces. + * @return {object} returns a runner object which has USE_PORT and optionally USE_IP */ -function getAdditionalRunContent (platformName, wdaRemotePort) { +function getAdditionalRunContent (platformName, wdaRemotePort, wdaBindingIP) { const runner = `WebDriverAgentRunner${isTvOS(platformName) ? '_tvOS' : ''}`; - return { [runner]: { EnvironmentVariables: { // USE_PORT must be 'string' - USE_PORT: `${wdaRemotePort}` + USE_PORT: `${wdaRemotePort}`, + ...(wdaBindingIP ? { USE_IP: wdaBindingIP } : {}), } } }; diff --git a/lib/webdriveragent.js b/lib/webdriveragent.js index 7e3f88f07..a48f79626 100644 --- a/lib/webdriveragent.js +++ b/lib/webdriveragent.js @@ -60,7 +60,7 @@ export class WebDriverAgent { this.wdaRemotePort = ((this.isRealDevice ? args.wdaRemotePort : null) ?? args.wdaLocalPort) || WDA_AGENT_PORT; this.wdaBaseUrl = args.wdaBaseUrl || WDA_BASE_URL; - + this.wdaBindingIP = args.wdaBindingIP; this.prebuildWDA = args.prebuildWDA; // this.args.webDriverAgentUrl guiarantees the capabilities acually @@ -104,6 +104,7 @@ export class WebDriverAgent { updatedWDABundleId: this.updatedWDABundleId, launchTimeout: this.wdaLaunchTimeout, wdaRemotePort: this.wdaRemotePort, + wdaBindingIP: this.wdaBindingIP, useXctestrunFile: this.useXctestrunFile, derivedDataPath: args.derivedDataPath, mjpegServerPort: this.mjpegServerPort, @@ -390,6 +391,9 @@ export class WebDriverAgent { if (this.mjpegServerPort) { xctestEnv.MJPEG_SERVER_PORT = this.mjpegServerPort; } + if (this.wdaBindingIP) { + xctestEnv.USE_IP = this.wdaBindingIP; + } this.log.info('Launching WebDriverAgent on the device without xcodebuild'); if (this.isRealDevice) { // Current method to launch WDA process can be done via 'xcrun devicectl', diff --git a/lib/xcodebuild.js b/lib/xcodebuild.js index 8a25361d0..927987f8d 100644 --- a/lib/xcodebuild.js +++ b/lib/xcodebuild.js @@ -83,6 +83,7 @@ export class XcodeBuild { this.launchTimeout = args.launchTimeout; this.wdaRemotePort = args.wdaRemotePort; + this.wdaBindingIP = args.wdaBindingIP; this.updatedWDABundleId = args.updatedWDABundleId; this.derivedDataPath = args.derivedDataPath; @@ -116,12 +117,13 @@ export class XcodeBuild { platformVersion: this.platformVersion || '', platformName: this.platformName || '' }; - this.xctestrunFilePath = await setXctestrunFile( - deviceInfo, - this.iosSdkVersion || '', - this.bootstrapPath, - this.wdaRemotePort || 8100 - ); + this.xctestrunFilePath = await setXctestrunFile({ + deviceInfo, + sdkVersion: this.iosSdkVersion || '', + bootstrapPath: this.bootstrapPath, + wdaRemotePort: this.wdaRemotePort || 8100, + wdaBindingIP: this.wdaBindingIP + }); return; }