Skip to content

Commit b6021bf

Browse files
committed
Merge remote-tracking branch 'origin/rb_add_guard_for_browser_version' into rb_add_guard_for_browser_version
2 parents e9459d6 + efac112 commit b6021bf

File tree

9 files changed

+1396
-18
lines changed

9 files changed

+1396
-18
lines changed

java/src/org/openqa/selenium/Proxy.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public String toString() {
6767
}
6868

6969
private static final String PROXY_TYPE = "proxyType";
70-
private static final String FTP_PROXY = "ftpProxy";
70+
@Deprecated private static final String FTP_PROXY = "ftpProxy";
7171
private static final String HTTP_PROXY = "httpProxy";
7272
private static final String NO_PROXY = "noProxy";
7373
private static final String SSL_PROXY = "sslProxy";
@@ -80,7 +80,7 @@ public String toString() {
8080

8181
private ProxyType proxyType = ProxyType.UNSPECIFIED;
8282
private boolean autodetect = false;
83-
private @Nullable String ftpProxy;
83+
@Deprecated private @Nullable String ftpProxy;
8484
private @Nullable String httpProxy;
8585
private @Nullable String noProxy;
8686
private @Nullable String sslProxy;
@@ -225,7 +225,9 @@ public Proxy setAutodetect(boolean autodetect) {
225225
* Gets the FTP proxy.
226226
*
227227
* @return the FTP proxy hostname if present, or null if not set
228+
* @deprecated getFtpProxy is deprecated and will be removed in a future release.
228229
*/
230+
@Deprecated
229231
public @Nullable String getFtpProxy() {
230232
return ftpProxy;
231233
}
@@ -235,7 +237,9 @@ public Proxy setAutodetect(boolean autodetect) {
235237
*
236238
* @param ftpProxy the proxy host, expected format is <code>hostname.com:1234</code>
237239
* @return reference to self
240+
* @deprecated setFtpProxy is deprecated and will be removed in a future release.
238241
*/
242+
@Deprecated
239243
public Proxy setFtpProxy(String ftpProxy) {
240244
verifyProxyTypeCompatibility(ProxyType.MANUAL);
241245
this.proxyType = ProxyType.MANUAL;

java/src/org/openqa/selenium/bidi/browsingcontext/BrowsingContext.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ public List<BrowsingContextInfo> getTree() {
148148
"browsingContext.getTree", Map.of("root", id), browsingContextInfoListMapper));
149149
}
150150

151+
public List<BrowsingContextInfo> getTree(String root) {
152+
return this.bidi.send(
153+
new Command<>(
154+
"browsingContext.getTree", Map.of("root", root), browsingContextInfoListMapper));
155+
}
156+
151157
public List<BrowsingContextInfo> getTree(int maxDepth) {
152158
return this.bidi.send(
153159
new Command<>(
@@ -158,6 +164,16 @@ public List<BrowsingContextInfo> getTree(int maxDepth) {
158164
browsingContextInfoListMapper));
159165
}
160166

167+
public List<BrowsingContextInfo> getTree(String root, int maxDepth) {
168+
return this.bidi.send(
169+
new Command<>(
170+
"browsingContext.getTree",
171+
Map.of(
172+
"root", root,
173+
"maxDepth", maxDepth),
174+
browsingContextInfoListMapper));
175+
}
176+
161177
public List<BrowsingContextInfo> getTopLevelContexts() {
162178
return this.bidi.send(
163179
new Command<>("browsingContext.getTree", new HashMap<>(), browsingContextInfoListMapper));

java/src/org/openqa/selenium/bidi/browsingcontext/BrowsingContextInfo.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ public class BrowsingContextInfo {
3030

3131
private final List<BrowsingContextInfo> children;
3232

33+
private final String clientWindow;
34+
35+
private final String originalOpener;
36+
37+
private final String userContext;
38+
3339
private final String parentBrowsingContext;
3440

3541
public String getId() {
@@ -44,22 +50,46 @@ public List<BrowsingContextInfo> getChildren() {
4450
return children;
4551
}
4652

53+
public String getClientWindow() {
54+
return clientWindow;
55+
}
56+
57+
public String getOriginalOpener() {
58+
return originalOpener;
59+
}
60+
61+
public String getUserContext() {
62+
return userContext;
63+
}
64+
4765
public String getParentBrowsingContext() {
4866
return parentBrowsingContext;
4967
}
5068

5169
public BrowsingContextInfo(
52-
String id, String url, List<BrowsingContextInfo> children, String parentBrowsingContext) {
70+
String id,
71+
String url,
72+
List<BrowsingContextInfo> children,
73+
String clientWindow,
74+
String originalOpener,
75+
String userContext,
76+
String parentBrowsingContext) {
5377
this.id = id;
5478
this.url = url;
5579
this.children = children;
80+
this.clientWindow = clientWindow;
81+
this.originalOpener = originalOpener;
82+
this.userContext = userContext;
5683
this.parentBrowsingContext = parentBrowsingContext;
5784
}
5885

5986
public static BrowsingContextInfo fromJson(JsonInput input) {
6087
String id = null;
6188
String url = null;
6289
List<BrowsingContextInfo> children = null;
90+
String clientWindow = null;
91+
String originalOpener = null;
92+
String userContext = null;
6393
String parentBrowsingContext = null;
6494

6595
input.beginObject();
@@ -81,6 +111,18 @@ public static BrowsingContextInfo fromJson(JsonInput input) {
81111
parentBrowsingContext = input.read(String.class);
82112
break;
83113

114+
case "clientWindow":
115+
clientWindow = input.read(String.class);
116+
break;
117+
118+
case "originalOpener":
119+
originalOpener = input.read(String.class);
120+
break;
121+
122+
case "userContext":
123+
userContext = input.read(String.class);
124+
break;
125+
84126
default:
85127
input.skipValue();
86128
break;
@@ -89,6 +131,7 @@ public static BrowsingContextInfo fromJson(JsonInput input) {
89131

90132
input.endObject();
91133

92-
return new BrowsingContextInfo(id, url, children, parentBrowsingContext);
134+
return new BrowsingContextInfo(
135+
id, url, children, clientWindow, originalOpener, userContext, parentBrowsingContext);
93136
}
94137
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.grid.distributor.selector;
19+
20+
import static com.google.common.collect.ImmutableSet.toImmutableSet;
21+
import static org.openqa.selenium.grid.data.Availability.UP;
22+
23+
import java.util.Comparator;
24+
import java.util.Set;
25+
import org.openqa.selenium.Capabilities;
26+
import org.openqa.selenium.grid.config.Config;
27+
import org.openqa.selenium.grid.data.NodeStatus;
28+
import org.openqa.selenium.grid.data.SemanticVersionComparator;
29+
import org.openqa.selenium.grid.data.Slot;
30+
import org.openqa.selenium.grid.data.SlotId;
31+
import org.openqa.selenium.grid.data.SlotMatcher;
32+
33+
/**
34+
* A greedy slot selector that aims to maximize node utilization by minimizing the number of
35+
* partially filled nodes. The algorithm works as follows: 1. Sort nodes by their utilization load
36+
* (descending). 2. Among nodes with the same utilization, prefer those with fewer total slots. 3.
37+
* Then sort by the last session created (oldest first). This approach helps to: - Fill up nodes
38+
* that are already partially utilized - Minimize the number of nodes that are partially filled -
39+
* Distribute load evenly across nodes
40+
*/
41+
public class GreedySlotSelector implements SlotSelector {
42+
43+
public static SlotSelector create(Config config) {
44+
return new GreedySlotSelector();
45+
}
46+
47+
@Override
48+
public Set<SlotId> selectSlot(
49+
Capabilities capabilities, Set<NodeStatus> nodes, SlotMatcher slotMatcher) {
50+
return nodes.stream()
51+
.filter(node -> node.hasCapacity(capabilities, slotMatcher) && node.getAvailability() == UP)
52+
.sorted(
53+
// First and foremost, sort by utilization ratio (descending)
54+
// This ensures we ALWAYS try to fill nodes that are already partially utilized first
55+
Comparator.comparingDouble(NodeStatus::getLoad)
56+
.reversed()
57+
// Then sort by total number of slots (ascending)
58+
// Among nodes with same utilization, prefer those with fewer total slots
59+
.thenComparingLong(node -> node.getSlots().size())
60+
// Then last session created (oldest first)
61+
.thenComparingLong(NodeStatus::getLastSessionCreated)
62+
// Then sort by stereotype browserVersion (descending order)
63+
.thenComparing(
64+
Comparator.comparing(
65+
NodeStatus::getBrowserVersion, new SemanticVersionComparator().reversed())))
66+
.flatMap(
67+
node ->
68+
node.getSlots().stream()
69+
.filter(slot -> slot.getSession() == null)
70+
.filter(slot -> slot.isSupporting(capabilities, slotMatcher))
71+
.map(Slot::getId))
72+
.collect(toImmutableSet());
73+
}
74+
}

java/test/org/openqa/selenium/bidi/browsingcontext/BrowsingContextTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,52 @@ void canGetTreeWithDepth() {
159159
BrowsingContextInfo info = contextInfoList.get(0);
160160
assertThat(info.getChildren()).isNull(); // since depth is 0
161161
assertThat(info.getId()).isEqualTo(referenceContextId);
162+
assertThat(info.getOriginalOpener()).isNull();
163+
assertThat(info.getClientWindow()).isNotNull();
164+
assertThat(info.getUserContext()).isEqualTo("default");
165+
}
166+
167+
@Test
168+
@NeedsFreshDriver
169+
void canGetTreeWithRootAndDepth() {
170+
String referenceContextId = driver.getWindowHandle();
171+
BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);
172+
173+
String url = appServer.whereIs("iframes.html");
174+
175+
parentWindow.navigate(url, ReadinessState.COMPLETE);
176+
177+
List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(referenceContextId, 1);
178+
179+
assertThat(contextInfoList.size()).isEqualTo(1);
180+
BrowsingContextInfo info = contextInfoList.get(0);
181+
assertThat(info.getChildren()).isNotNull(); // since depth is 1
182+
assertThat(info.getId()).isEqualTo(referenceContextId);
183+
assertThat(info.getOriginalOpener()).isNull();
184+
assertThat(info.getClientWindow()).isNotNull();
185+
assertThat(info.getUserContext()).isEqualTo("default");
186+
}
187+
188+
@Test
189+
@NeedsFreshDriver
190+
void canGetTreeWithRoot() {
191+
String referenceContextId = driver.getWindowHandle();
192+
BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);
193+
194+
String url = appServer.whereIs("iframes.html");
195+
196+
parentWindow.navigate(url, ReadinessState.COMPLETE);
197+
198+
BrowsingContext tab = new BrowsingContext(driver, WindowType.TAB);
199+
200+
List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(tab.getId());
201+
202+
assertThat(contextInfoList.size()).isEqualTo(1);
203+
BrowsingContextInfo info = contextInfoList.get(0);
204+
assertThat(info.getId()).isEqualTo(tab.getId());
205+
assertThat(info.getOriginalOpener()).isNull();
206+
assertThat(info.getClientWindow()).isNotNull();
207+
assertThat(info.getUserContext()).isEqualTo("default");
162208
}
163209

164210
@Test

0 commit comments

Comments
 (0)