Skip to content

Commit 70ed7cf

Browse files
authored
feat: Let binding IP address to be configurable via USE_IP environment variable (#1066)
1 parent e81e614 commit 70ed7cf

10 files changed

Lines changed: 83 additions & 19 deletions

File tree

WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner.xcscheme

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@
6666
value = "$(USE_PORT)"
6767
isEnabled = "YES">
6868
</EnvironmentVariable>
69+
<EnvironmentVariable
70+
key = "USE_IP"
71+
value = "$(USE_IP)"
72+
isEnabled = "YES">
73+
</EnvironmentVariable>
6974
<EnvironmentVariable
7075
key = "UPGRADE_TIMESTAMP"
7176
value = "$(UPGRADE_TIMESTAMP)"

WebDriverAgent.xcodeproj/xcshareddata/xcschemes/WebDriverAgentRunner_tvOS.xcscheme

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@
7575
value = "$(USE_PORT)"
7676
isEnabled = "YES">
7777
</EnvironmentVariable>
78+
<EnvironmentVariable
79+
key = "USE_IP"
80+
value = "$(USE_IP)"
81+
isEnabled = "YES">
82+
</EnvironmentVariable>
7883
<EnvironmentVariable
7984
key = "UPGRADE_TIMESTAMP"
8085
value = "$(UPGRADE_TIMESTAMP)"

WebDriverAgentLib/Routing/FBWebServer.m

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ - (void)startHTTPServer
9292
[self registerServerKeyRouteHandlers];
9393

9494
NSRange serverPortRange = FBConfiguration.bindingPortRange;
95+
NSString *bindingIP = FBConfiguration.bindingIPAddress;
96+
if (bindingIP != nil) {
97+
[self.server setInterface:bindingIP];
98+
[FBLogger logFmt:@"Using custom binding IP address: %@", bindingIP];
99+
}
100+
95101
NSError *error;
96102
BOOL serverStarted = NO;
97103

@@ -111,7 +117,9 @@ - (void)startHTTPServer
111117
[FBLogger logFmt:@"Last attempt to start web server failed with error %@", [error description]];
112118
abort();
113119
}
114-
[FBLogger logFmt:@"%@http://%@:%d%@", FBServerURLBeginMarker, [XCUIDevice sharedDevice].fb_wifiIPAddress ?: @"localhost", [self.server port], FBServerURLEndMarker];
120+
121+
NSString *serverHost = bindingIP ?: ([XCUIDevice sharedDevice].fb_wifiIPAddress ?: @"127.0.0.1");
122+
[FBLogger logFmt:@"%@http://%@:%d%@", FBServerURLBeginMarker, serverHost, [self.server port], FBServerURLEndMarker];
115123
}
116124

117125
- (void)initScreenshotsBroadcaster

WebDriverAgentLib/Utilities/FBConfiguration.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ extern NSString *const FBSnapshotMaxDepthKey;
124124
*/
125125
+ (NSRange)bindingPortRange;
126126

127+
/**
128+
The IP address that the HTTP Server should bind to on launch.
129+
Returns nil if not specified, which causes the server to listen on all interfaces.
130+
*/
131+
+ (NSString * _Nullable)bindingIPAddress;
132+
127133
/**
128134
The port number where the background screenshots broadcaster is supposed to run
129135
*/

WebDriverAgentLib/Utilities/FBConfiguration.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,17 @@ + (NSRange)bindingPortRange
137137
return NSMakeRange(DefaultStartingPort, DefaultPortRange);
138138
}
139139

140+
+ (NSString *)bindingIPAddress
141+
{
142+
// Existence of USE_IP in the environment allows specifying which interface to bind to
143+
if (NSProcessInfo.processInfo.environment[@"USE_IP"] &&
144+
[NSProcessInfo.processInfo.environment[@"USE_IP"] length] > 0) {
145+
return NSProcessInfo.processInfo.environment[@"USE_IP"];
146+
}
147+
148+
return nil;
149+
}
150+
140151
+ (NSInteger)mjpegServerPort
141152
{
142153
if (self.mjpegServerPortFromArguments != NSNotFound) {

WebDriverAgentTests/UnitTests/FBConfigurationTests.m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ - (void)setUp
2020
{
2121
[super setUp];
2222
unsetenv("USE_PORT");
23+
unsetenv("USE_IP");
2324
unsetenv("VERBOSE_LOGGING");
2425
}
2526

@@ -45,4 +46,15 @@ - (void)testVerboseLoggingEnvironmentOverwrite
4546
XCTAssertTrue([FBConfiguration verboseLoggingEnabled]);
4647
}
4748

49+
- (void)testBindingIPDefault
50+
{
51+
XCTAssertNil([FBConfiguration bindingIPAddress]);
52+
}
53+
54+
- (void)testBindingIPEnvironmentOverwrite
55+
{
56+
setenv("USE_IP", "192.168.1.100", 1);
57+
XCTAssertEqualObjects([FBConfiguration bindingIPAddress], @"192.168.1.100");
58+
}
59+
4860
@end

lib/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export interface WebDriverAgentArgs {
6464
wdaLocalPort?: number;
6565
wdaRemotePort?: number;
6666
wdaBaseUrl?: string;
67+
wdaBindingIP?: string;
6768
prebuildWDA?: boolean;
6869
webDriverAgentUrl?: string;
6970
wdaConnectionTimeout?: number;
@@ -116,6 +117,7 @@ export interface XcodeBuildArgs {
116117
useXctestrunFile?: boolean;
117118
launchTimeout?: number;
118119
wdaRemotePort?: number;
120+
wdaBindingIP?: string;
119121
updatedWDABundleId?: string;
120122
derivedDataPath?: string;
121123
mjpegServerPort?: number;

lib/utils.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ async function setRealDeviceSecurity (keychainPath, keychainPassword) {
166166
* @property {string} platformVersion - The platform version of OS.
167167
* @property {string} platformName - The platform name of iOS, tvOS
168168
*/
169+
170+
/**
171+
* Arguments for setting xctestrun file
172+
* @typedef {Object} XctestrunFileArgs
173+
* @property {DeviceInfo} deviceInfo - Information of the device under test
174+
* @property {string} sdkVersion - The Xcode SDK version of OS.
175+
* @property {string} bootstrapPath - The folder path containing xctestrun file.
176+
* @property {number|string} wdaRemotePort - The remote port WDA is listening on.
177+
* @property {string} [wdaBindingIP] - The IP address to bind to. If not given, it binds to all interfaces.
178+
*/
169179
/**
170180
* Creates xctestrun file per device & platform version.
171181
* We expects to have WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device
@@ -174,19 +184,17 @@ async function setRealDeviceSecurity (keychainPath, keychainPassword) {
174184
* e.g. Xcode which has iOS SDK Version 12.2 on an intel Mac host machine generates WebDriverAgentRunner_iphonesimulator.2-x86_64.xctestrun
175185
* even if the cap has platform version 11.4
176186
*
177-
* @param {DeviceInfo} deviceInfo
178-
* @param {string} sdkVersion - The Xcode SDK version of OS.
179-
* @param {string} bootstrapPath - The folder path containing xctestrun file.
180-
* @param {number|string} wdaRemotePort - The remote port WDA is listening on.
187+
* @param {XctestrunFileArgs} args
181188
* @return {Promise<string>} returns xctestrunFilePath for given device
182189
* @throws if WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device
183190
* or WebDriverAgentRunner_iphonesimulator${sdkVersion|platformVersion}-x86_64.xctestrun for simulator is not found @bootstrapPath,
184-
* then it will throw file not found exception
191+
* then it will throw a file not found exception
185192
*/
186-
async function setXctestrunFile (deviceInfo, sdkVersion, bootstrapPath, wdaRemotePort) {
193+
async function setXctestrunFile (args) {
194+
const {deviceInfo, sdkVersion, bootstrapPath, wdaRemotePort, wdaBindingIP} = args;
187195
const xctestrunFilePath = await getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath);
188196
const xctestRunContent = await plist.parsePlistFile(xctestrunFilePath);
189-
const updateWDAPort = getAdditionalRunContent(deviceInfo.platformName, wdaRemotePort);
197+
const updateWDAPort = getAdditionalRunContent(deviceInfo.platformName, wdaRemotePort, wdaBindingIP);
190198
const newXctestRunContent = _.merge(xctestRunContent, updateWDAPort);
191199
await plist.updatePlistFile(xctestrunFilePath, newXctestRunContent, true);
192200

@@ -197,16 +205,17 @@ async function setXctestrunFile (deviceInfo, sdkVersion, bootstrapPath, wdaRemot
197205
* Return the WDA object which appends existing xctest runner content
198206
* @param {string} platformName - The name of the platform
199207
* @param {number|string} wdaRemotePort - The remote port number
200-
* @return {object} returns a runner object which has USE_PORT
208+
* @param {string} [wdaBindingIP] - The IP address to bind to. If not given, it binds to all interfaces.
209+
* @return {object} returns a runner object which has USE_PORT and optionally USE_IP
201210
*/
202-
function getAdditionalRunContent (platformName, wdaRemotePort) {
211+
function getAdditionalRunContent (platformName, wdaRemotePort, wdaBindingIP) {
203212
const runner = `WebDriverAgentRunner${isTvOS(platformName) ? '_tvOS' : ''}`;
204-
205213
return {
206214
[runner]: {
207215
EnvironmentVariables: {
208216
// USE_PORT must be 'string'
209-
USE_PORT: `${wdaRemotePort}`
217+
USE_PORT: `${wdaRemotePort}`,
218+
...(wdaBindingIP ? { USE_IP: wdaBindingIP } : {}),
210219
}
211220
}
212221
};

lib/webdriveragent.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export class WebDriverAgent {
6060
this.wdaRemotePort = ((this.isRealDevice ? args.wdaRemotePort : null) ?? args.wdaLocalPort)
6161
|| WDA_AGENT_PORT;
6262
this.wdaBaseUrl = args.wdaBaseUrl || WDA_BASE_URL;
63-
63+
this.wdaBindingIP = args.wdaBindingIP;
6464
this.prebuildWDA = args.prebuildWDA;
6565

6666
// this.args.webDriverAgentUrl guiarantees the capabilities acually
@@ -104,6 +104,7 @@ export class WebDriverAgent {
104104
updatedWDABundleId: this.updatedWDABundleId,
105105
launchTimeout: this.wdaLaunchTimeout,
106106
wdaRemotePort: this.wdaRemotePort,
107+
wdaBindingIP: this.wdaBindingIP,
107108
useXctestrunFile: this.useXctestrunFile,
108109
derivedDataPath: args.derivedDataPath,
109110
mjpegServerPort: this.mjpegServerPort,
@@ -390,6 +391,9 @@ export class WebDriverAgent {
390391
if (this.mjpegServerPort) {
391392
xctestEnv.MJPEG_SERVER_PORT = this.mjpegServerPort;
392393
}
394+
if (this.wdaBindingIP) {
395+
xctestEnv.USE_IP = this.wdaBindingIP;
396+
}
393397
this.log.info('Launching WebDriverAgent on the device without xcodebuild');
394398
if (this.isRealDevice) {
395399
// Current method to launch WDA process can be done via 'xcrun devicectl',

lib/xcodebuild.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export class XcodeBuild {
8383
this.launchTimeout = args.launchTimeout;
8484

8585
this.wdaRemotePort = args.wdaRemotePort;
86+
this.wdaBindingIP = args.wdaBindingIP;
8687

8788
this.updatedWDABundleId = args.updatedWDABundleId;
8889
this.derivedDataPath = args.derivedDataPath;
@@ -116,12 +117,13 @@ export class XcodeBuild {
116117
platformVersion: this.platformVersion || '',
117118
platformName: this.platformName || ''
118119
};
119-
this.xctestrunFilePath = await setXctestrunFile(
120-
deviceInfo,
121-
this.iosSdkVersion || '',
122-
this.bootstrapPath,
123-
this.wdaRemotePort || 8100
124-
);
120+
this.xctestrunFilePath = await setXctestrunFile({
121+
deviceInfo,
122+
sdkVersion: this.iosSdkVersion || '',
123+
bootstrapPath: this.bootstrapPath,
124+
wdaRemotePort: this.wdaRemotePort || 8100,
125+
wdaBindingIP: this.wdaBindingIP
126+
});
125127
return;
126128
}
127129

0 commit comments

Comments
 (0)