Skip to content

Commit 031456c

Browse files
mach6lukeis
authored andcommitted
Fix #2727, combine -jettyThreads and -jettyMaxThreads (#2735)
- Revert BaseRemoteProxy configuration load behavior to Sel 2.x logic (seed from registry, then overlap with the remote request) - Combine -jettyThreads (hidden, used by standalone and node) and -jettyMaxThreads (not hidden, used by hub) into -jettyMaxThreads which is NOT hidden and is used by standalone, node, and hub Additional changes; - Fix for 'id' which should have a default value applied (according to its usage doc) - new GridHubConfiguration() - the role should always be "hub" - new GridNodeConfiguration() - the role should always be "node" - Configuration merge() behavior update/change; - don't merge null 'other' values (pre-existing) - don't merge empty collections or maps (new) - Add tests
1 parent 270e0c8 commit 031456c

15 files changed

+667
-172
lines changed

java/server/src/org/openqa/grid/common/RegistrationRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,11 @@ public static RegistrationRequest getNewInstance(String json) throws JsonSyntaxE
140140
GridNodeConfiguration configuration = GridNodeConfiguration.loadFromJSON(config);
141141
request.setConfiguration(configuration);
142142

143+
// make sure 'id' has a value
143144
if (o.has("id")) {
144145
request.configuration.id = o.get("id").getAsString();
146+
} else {
147+
request.configuration.id = request.configuration.getRemoteHost();
145148
}
146149

147150
JsonArray capabilities = o.get("capabilities").getAsJsonArray();

java/server/src/org/openqa/grid/internal/BaseRemoteProxy.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,14 @@ public BaseRemoteProxy(RegistrationRequest request, Registry registry) {
104104
this.request = request;
105105
this.registry = registry;
106106
this.config = new GridNodeConfiguration();
107-
this.config.merge(request.getConfiguration());
108-
// the registry is the 'hub' configuration, which takes precedence.
109-
// merging last overrides any other values.
107+
// the registry is the 'hub' configuration, which is used as a seed.
110108
this.config.merge(registry.getConfiguration());
109+
// the proxy values must override any that the hub specify where an overlap occurs.
110+
// merging last causes the values to be overridden.
111+
this.config.merge(request.getConfiguration());
112+
// host and port are merge() protected values -- overrule this behavior
111113
this.config.host = request.getConfiguration().host;
112114
this.config.port = request.getConfiguration().port;
113-
// custom configurations from the remote need to 'override' the hub
114-
this.config.custom.putAll(request.getConfiguration().custom);
115115

116116
String url = config.getRemoteHost();
117117
String id = config.id;

java/server/src/org/openqa/grid/internal/utils/configuration/GridConfiguration.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,20 @@ public class GridConfiguration extends StandaloneConfiguration {
7373
public void merge(GridConfiguration other) {
7474
super.merge(other);
7575
// don't merge 'host'
76-
if (other.cleanUpCycle != null) {
76+
if (isMergeAble(other.cleanUpCycle, cleanUpCycle)) {
7777
cleanUpCycle = other.cleanUpCycle;
7878
}
79-
custom.putAll(other.custom);
80-
if (other.maxSession != 1) {
79+
if (isMergeAble(other.custom, custom)) {
80+
custom.putAll(other.custom);
81+
}
82+
if (isMergeAble(other.maxSession, maxSession) &&
83+
other.maxSession.intValue() > 0) {
8184
maxSession = other.maxSession;
8285
}
83-
if (other.servlets != null) {
86+
if (isMergeAble(other.servlets, servlets)) {
8487
servlets = other.servlets;
8588
}
86-
if (other.withoutServlets != null) {
89+
if (isMergeAble(other.withoutServlets, withoutServlets)) {
8790
withoutServlets = other.withoutServlets;
8891
}
8992
}

java/server/src/org/openqa/grid/internal/utils/configuration/GridHubConfiguration.java

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,6 @@ public class GridHubConfiguration extends GridConfiguration {
4444
)
4545
public String hubConfig;
4646

47-
@Parameter(
48-
names = "-jettyMaxThreads",
49-
description = "<Integer> : max number of thread for Jetty. Default is 255"
50-
)
51-
public Integer jettyMaxThreads;
52-
5347
@Parameter(
5448
names = {"-matcher", "-capabilityMatcher"},
5549
description = "<String> class name : a class implementing the CapabilityMatcher interface. Specifies the logic the hub will follow to define whether a request can be assigned to a node. For example, if you want to have the matching process use regular expressions instead of exact match when specifying browser version. ALL nodes of a grid ecosystem would then use the same capabilityMatcher, as defined here. Default is org.openqa.grid.internal.utils.DefaultCapabilityMatcher",
@@ -82,6 +76,7 @@ public class GridHubConfiguration extends GridConfiguration {
8276
* Init with built-in defaults
8377
*/
8478
public GridHubConfiguration() {
79+
role = "hub";
8580
if (DEFAULT_CONFIG != null) {
8681
merge(DEFAULT_CONFIG);
8782
}
@@ -139,17 +134,17 @@ public void merge(GridNodeConfiguration other) {
139134

140135
public void merge(GridHubConfiguration other) {
141136
super.merge(other);
142-
if (other.jettyMaxThreads != null) {
143-
jettyMaxThreads = other.jettyMaxThreads;
137+
138+
if (isMergeAble(other.capabilityMatcher, capabilityMatcher)) {
139+
capabilityMatcher = other.capabilityMatcher;
144140
}
145-
capabilityMatcher = other.capabilityMatcher;
146-
if (other.newSessionWaitTimeout != null) {
141+
if (isMergeAble(other.newSessionWaitTimeout, newSessionWaitTimeout)) {
147142
newSessionWaitTimeout = other.newSessionWaitTimeout;
148143
}
149-
if (other.prioritizer != null) {
144+
if (isMergeAble(other.prioritizer, prioritizer)) {
150145
prioritizer = other.prioritizer;
151146
}
152-
if (other.throwOnCapabilityNotPresent != throwOnCapabilityNotPresent) {
147+
if (isMergeAble(other.throwOnCapabilityNotPresent, throwOnCapabilityNotPresent)) {
153148
throwOnCapabilityNotPresent = other.throwOnCapabilityNotPresent;
154149
}
155150
}
@@ -159,7 +154,6 @@ public String toString(String format) {
159154
StringBuilder sb = new StringBuilder();
160155
sb.append(super.toString(format));
161156
sb.append(toString(format, "hubConfig", hubConfig));
162-
sb.append(toString(format, "jettyMaxThreads", jettyMaxThreads));
163157
sb.append(toString(format, "capabilityMatcher", capabilityMatcher.getClass().getCanonicalName()));
164158
sb.append(toString(format, "newSessionWaitTimeout", newSessionWaitTimeout));
165159
sb.append(toString(format, "prioritizer", prioritizer != null? prioritizer.getClass().getCanonicalName(): null));

java/server/src/org/openqa/grid/internal/utils/configuration/GridNodeConfiguration.java

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public class GridNodeConfiguration extends GridConfiguration {
4949

5050
@Parameter(
5151
names = "-id",
52-
description = "<String> : unique identifier for the node. Not required--by default, grid will use the url of the remoteHost"
52+
description = "<String> : optional unique identifier for the node. Defaults to the url of the remoteHost"
5353
)
5454
public String id;
5555

@@ -125,10 +125,17 @@ public class GridNodeConfiguration extends GridConfiguration {
125125

126126
@Parameter(
127127
names = "-unregisterIfStillDownAfter",
128-
description = "<Integer> in ms : if the node remains down for more than [unregisterIfStillDownAfter] ms, it will step attempting to re-register from the hub. Default is 6000 (1 minute)"
128+
description = "<Integer> in ms : if the node remains down for more than [unregisterIfStillDownAfter] ms, it will stop attempting to re-register from the hub. Default is 6000 (1 minute)"
129129
)
130130
public Integer unregisterIfStillDownAfter;
131131

132+
/**
133+
* Init with built-in defaults
134+
*/
135+
public GridNodeConfiguration() {
136+
role = "node";
137+
}
138+
132139
public String getHubHost() {
133140
if (hubHost == null) {
134141
if (hub == null) {
@@ -174,43 +181,43 @@ private void parseHubUrl() {
174181

175182
public void merge(GridNodeConfiguration other) {
176183
super.merge(other);
177-
if (other.browser != null) {
184+
if (isMergeAble(other.browser, browser)) {
178185
browser = other.browser;
179186
}
180-
if (other.downPollingLimit != null) {
187+
if (isMergeAble(other.downPollingLimit, downPollingLimit)) {
181188
downPollingLimit = other.downPollingLimit;
182189
}
183-
if (other.hub != null) {
190+
if (isMergeAble(other.hub, hub)) {
184191
hub = other.hub;
185192
}
186-
if (other.hubHost != null) {
193+
if (isMergeAble(other.hubHost, hubHost)) {
187194
hubHost = other.hubHost;
188195
}
189-
if (other.hubPort != null) {
196+
if (isMergeAble(other.hubPort, hubPort)) {
190197
hubPort = other.hubPort;
191198
}
192-
if (other.id != null) {
199+
if (isMergeAble(other.id, id)) {
193200
id = other.id;
194201
}
195-
if (other.nodePolling != null) {
202+
if (isMergeAble(other.nodePolling, nodePolling)) {
196203
nodePolling = other.nodePolling;
197204
}
198-
if (other.nodeStatusCheckTimeout != null) {
205+
if (isMergeAble(other.nodeStatusCheckTimeout, nodeStatusCheckTimeout)) {
199206
nodeStatusCheckTimeout = other.nodeStatusCheckTimeout;
200207
}
201-
if (other.proxy != null) {
208+
if (isMergeAble(other.proxy, proxy)) {
202209
proxy = other.proxy;
203210
}
204-
if (other.register != null) {
211+
if (isMergeAble(other.register, register)) {
205212
register = other.register;
206213
}
207-
if (other.registerCycle != null) {
214+
if (isMergeAble(other.registerCycle, registerCycle)) {
208215
registerCycle = other.registerCycle;
209216
}
210-
if (other.remoteHost != null) {
217+
if (isMergeAble(other.remoteHost, remoteHost)) {
211218
remoteHost = other.remoteHost;
212219
}
213-
if (other.unregisterIfStillDownAfter != null) {
220+
if (isMergeAble(other.unregisterIfStillDownAfter, unregisterIfStillDownAfter)) {
214221
unregisterIfStillDownAfter = other.unregisterIfStillDownAfter;
215222
}
216223
}

java/server/src/org/openqa/grid/internal/utils/configuration/StandaloneConfiguration.java

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ public class StandaloneConfiguration {
3838
@Parameter(
3939
names = "-browserSideLog",
4040
description = "DO NOT USE: Provided for compatibility with 2.0",
41-
hidden = true)
41+
hidden = true
42+
)
4243
public boolean browserSideLog;
4344

4445
@Parameter(
4546
names = "-captureLogsOnQuit",
4647
description = "DO NOT USE: Provided for compatibility with 2.0",
47-
hidden = true)
48+
hidden = true
49+
)
4850
public boolean captureLogsOnQuit;
4951

5052
@Parameter(
@@ -62,10 +64,10 @@ public class StandaloneConfiguration {
6264
public boolean help;
6365

6466
@Parameter(
65-
names = "-jettyThreads",
66-
hidden = true
67+
names = {"-jettyThreads", "-jettyMaxThreads"},
68+
description = "<Integer> : max number of threads for Jetty. Default is 200"
6769
)
68-
public Integer jettyThreads;
70+
public Integer jettyMaxThreads;
6971

7072
@Parameter(
7173
names = "-log",
@@ -93,40 +95,78 @@ public class StandaloneConfiguration {
9395

9496
@Parameter(
9597
names = {"-timeout", "-sessionTimeout"},
96-
description = "<Integer> in seconds : Specifies the timeout before the hub automatically kills a session that hasn't had any activity in the last X seconds. The test slot will then be released for another test to use. This is typically used to take care of client crashes. For grid hub/node roles, cleanUpCycle must also be set. Default is 1800 (30 minutes)"
98+
description = "<Integer> in seconds : Specifies the timeout before the server automatically kills a session that hasn't had any activity in the last X seconds. The test slot will then be released for another test to use. This is typically used to take care of client crashes. For grid hub/node roles, cleanUpCycle must also be set. Default is 1800 (30 minutes)"
9799
)
98100
public Integer timeout = 1800;
99101

100102
@Parameter(
101103
names = {"-avoidProxy"},
102-
description = "DO NOT USE. Hack to allow selenium 3.0 server run in SauceLabs",
104+
description = "DO NOT USE: Hack to allow selenium 3.0 server run in SauceLabs",
103105
hidden = true
104106
)
105-
private Boolean avoidProxy;
107+
private boolean avoidProxy;
106108

107109
/**
108110
* copy another configuration's values into this one if they are set.
109111
* @param other
110112
*/
111113
public void merge(StandaloneConfiguration other) {
112-
if (other.browserTimeout != null) {
114+
if (isMergeAble(other.browserTimeout, browserTimeout)) {
113115
browserTimeout = other.browserTimeout;
114116
}
115-
if (other.jettyThreads != null) {
116-
jettyThreads = other.jettyThreads;
117+
if (isMergeAble(other.jettyMaxThreads, jettyMaxThreads)) {
118+
jettyMaxThreads = other.jettyMaxThreads;
117119
}
118-
if (other.timeout != 1800) {
120+
if (isMergeAble(other.timeout, timeout)) {
119121
timeout = other.timeout;
120122
}
121123
// role, port, log, debug and help are not merged, they are only consumed by the immediately running node and can't affect a remote
122124
}
123125

126+
/**
127+
* Determines if one object can be merged onto another object. Checks for {@code null},
128+
* and empty (Collections & Maps) to make decision.
129+
*
130+
* @param other the object to merge. must be the same type as the 'target'
131+
* @param target the object to merge on to. must be the same type as the 'other'
132+
* @return whether the 'other' can be merged onto the 'target'
133+
*/
134+
protected boolean isMergeAble(Object other, Object target) {
135+
// don't merge a null value
136+
if (other == null) {
137+
return false;
138+
} else {
139+
// allow any non-null value to merge over a null target.
140+
if (target == null) {
141+
return true;
142+
}
143+
}
144+
145+
// we know we have two objects with value.. Make sure the types are the same and
146+
// perform additional checks.
147+
148+
if (! target.getClass().getSuperclass().getTypeName()
149+
.equals(other.getClass().getSuperclass().getTypeName())) {
150+
return false;
151+
}
152+
153+
if (target instanceof Collection) {
154+
return !((Collection) other).isEmpty();
155+
}
156+
157+
if (target instanceof Map) {
158+
return !((Map) other).isEmpty();
159+
}
160+
161+
return true;
162+
}
163+
124164
public String toString(String format) {
125165
StringBuilder sb = new StringBuilder();
126166
sb.append(toString(format, "browserTimeout", browserTimeout));
127167
sb.append(toString(format, "debug", debug));
128168
sb.append(toString(format, "help", help));
129-
sb.append(toString(format, "jettyThreads", jettyThreads));
169+
sb.append(toString(format, "jettyMaxThreads", jettyMaxThreads));
130170
sb.append(toString(format, "log", log));
131171
sb.append(toString(format, "logLongForm", logLongForm));
132172
sb.append(toString(format, "port", port));

java/server/src/org/openqa/grid/web/Hub.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private void addDefaultServlets(ServletContextHandler handler) {
140140

141141
private void initServer() {
142142
try {
143-
if (config.jettyMaxThreads>0) {
143+
if (config.jettyMaxThreads != null && config.jettyMaxThreads > 0) {
144144
QueuedThreadPool pool = new QueuedThreadPool();
145145
pool.setMaxThreads(config.jettyMaxThreads);
146146
server = new Server(pool);

java/server/src/org/openqa/selenium/remote/server/SeleniumServer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ public void setExtraServlets(Map<String, Class<? extends Servlet>> extraServlets
9999
}
100100

101101
public void boot() {
102-
if (configuration.jettyThreads != null && configuration.jettyThreads > 0) {
103-
server = new Server(new QueuedThreadPool(configuration.jettyThreads));
102+
if (configuration.jettyMaxThreads != null && configuration.jettyMaxThreads > 0) {
103+
server = new Server(new QueuedThreadPool(configuration.jettyMaxThreads));
104104
} else {
105105
server = new Server();
106106
}

java/server/test/org/openqa/grid/internal/BaseRemoteProxyTest.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,37 @@ public void create() {
8989
public void proxyConfigIsInheritedFromRegistry() {
9090
Registry registry = Registry.newInstance();
9191
registry.getConfiguration().cleanUpCycle = 42;
92-
registry.getConfiguration().timeout = 4200;
9392

9493
GridNodeConfiguration nodeConfiguration = new GridNodeConfiguration();
95-
new JCommander(nodeConfiguration, "-role", "webdriver", "-timeout", "100", "-cleanUpCycle", "100");
94+
new JCommander(nodeConfiguration, "-role", "webdriver");
9695
RegistrationRequest req = RegistrationRequest.build(nodeConfiguration);
9796
req.getConfiguration().proxy = null;
9897

9998
RemoteProxy p = BaseRemoteProxy.getNewInstance(req, registry);
10099

101-
assertEquals(42, p.getConfig().cleanUpCycle.longValue());
102-
assertEquals(4200, p.getConfig().timeout.longValue());
100+
// values which are not present in the registration request need to come
101+
// from the registry
102+
assertEquals(registry.getConfiguration().cleanUpCycle.longValue(),
103+
p.getConfig().cleanUpCycle.longValue());
104+
}
105+
106+
@Test
107+
public void proxyConfigOverwritesRegistryConfig() {
108+
Registry registry = Registry.newInstance();
109+
registry.getConfiguration().cleanUpCycle = 42;
110+
registry.getConfiguration().maxSession = 1;
111+
112+
GridNodeConfiguration nodeConfiguration = new GridNodeConfiguration();
113+
new JCommander(nodeConfiguration, "-role", "webdriver", "-cleanUpCycle", "100", "-maxSession", "50");
114+
RegistrationRequest req = RegistrationRequest.build(nodeConfiguration);
115+
req.getConfiguration().proxy = null;
116+
117+
RemoteProxy p = BaseRemoteProxy.getNewInstance(req, registry);
118+
119+
// values which are present in both the registration request and the registry need to
120+
// come from the registration request
121+
assertEquals(100L, p.getConfig().cleanUpCycle.longValue());
122+
assertEquals(50L, p.getConfig().maxSession.longValue());
103123
}
104124

105125
@Test

0 commit comments

Comments
 (0)