Skip to content

Commit db9aec0

Browse files
committed
Merge remote-tracking branch 'upstream/trunk' into dotnet-aot-classic
2 parents 287f1f6 + 798f3f9 commit db9aec0

File tree

33 files changed

+834
-162
lines changed

33 files changed

+834
-162
lines changed

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ maven.install(
173173
"com.github.spotbugs:spotbugs:4.8.6",
174174
"com.github.stephenc.jcip:jcip-annotations:1.0-1",
175175
"com.google.code.gson:gson:2.11.0",
176-
"com.google.guava:guava:33.3.0-jre",
176+
"com.google.guava:guava:33.3.1-jre",
177177
"com.google.auto:auto-common:1.2.2",
178178
"com.google.auto.service:auto-service:1.1.1",
179179
"com.google.auto.service:auto-service-annotations:1.1.1",

dotnet/src/webdriver/NetworkManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public NetworkManager(IWebDriver driver)
4545
this.session = new Lazy<DevToolsSession>(() =>
4646
{
4747
IDevTools devToolsDriver = driver as IDevTools;
48-
if (session == null)
48+
if (devToolsDriver == null)
4949
{
5050
throw new WebDriverException("Driver must implement IDevTools to use these features");
5151
}

dotnet/src/webdriver/SeleniumManager.cs

Lines changed: 29 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
using System.Text;
2626
using System.Text.Json;
2727
using System.Text.Json.Serialization;
28+
using static OpenQA.Selenium.SeleniumManagerResponse;
29+
30+
#nullable enable
2831

2932
namespace OpenQA.Selenium
3033
{
@@ -36,27 +39,25 @@ public static class SeleniumManager
3639
{
3740
private static readonly ILogger _logger = Log.GetLogger(typeof(SeleniumManager));
3841

39-
private static readonly string BinaryFullPath = Environment.GetEnvironmentVariable("SE_MANAGER_PATH");
40-
4142
private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNameCaseInsensitive = true, TypeInfoResolver = SeleniumManagerSerializerContext.Default };
4243

43-
static SeleniumManager()
44+
private static readonly Lazy<string> _lazyBinaryFullPath = new(() =>
4445
{
45-
46-
if (BinaryFullPath == null)
46+
string? binaryFullPath = Environment.GetEnvironmentVariable("SE_MANAGER_PATH");
47+
if (binaryFullPath == null)
4748
{
4849
var currentDirectory = AppContext.BaseDirectory;
4950
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
5051
{
51-
BinaryFullPath = Path.Combine(currentDirectory, "selenium-manager", "windows", "selenium-manager.exe");
52+
binaryFullPath = Path.Combine(currentDirectory, "selenium-manager", "windows", "selenium-manager.exe");
5253
}
5354
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
5455
{
55-
BinaryFullPath = Path.Combine(currentDirectory, "selenium-manager", "linux", "selenium-manager");
56+
binaryFullPath = Path.Combine(currentDirectory, "selenium-manager", "linux", "selenium-manager");
5657
}
5758
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
5859
{
59-
BinaryFullPath = Path.Combine(currentDirectory, "selenium-manager", "macos", "selenium-manager");
60+
binaryFullPath = Path.Combine(currentDirectory, "selenium-manager", "macos", "selenium-manager");
6061
}
6162
else
6263
{
@@ -65,11 +66,13 @@ static SeleniumManager()
6566
}
6667
}
6768

68-
if (!File.Exists(BinaryFullPath))
69+
if (!File.Exists(binaryFullPath))
6970
{
70-
throw new WebDriverException($"Unable to locate or obtain Selenium Manager binary at {BinaryFullPath}");
71+
throw new WebDriverException($"Unable to locate or obtain Selenium Manager binary at {binaryFullPath}");
7172
}
72-
}
73+
74+
return binaryFullPath;
75+
});
7376

7477
/// <summary>
7578
/// Determines the location of the browser and driver binaries.
@@ -88,7 +91,7 @@ public static Dictionary<string, string> BinaryPaths(string arguments)
8891
argsBuilder.Append(" --debug");
8992
}
9093

91-
var smCommandResult = RunCommand(BinaryFullPath, argsBuilder.ToString());
94+
var smCommandResult = RunCommand(_lazyBinaryFullPath.Value, argsBuilder.ToString());
9295
Dictionary<string, string> binaryPaths = new()
9396
{
9497
{ "browser_path", smCommandResult.BrowserPath },
@@ -112,10 +115,10 @@ public static Dictionary<string, string> BinaryPaths(string arguments)
112115
/// <returns>
113116
/// the standard output of the execution.
114117
/// </returns>
115-
private static SeleniumManagerResponse.ResultResponse RunCommand(string fileName, string arguments)
118+
private static ResultResponse RunCommand(string fileName, string arguments)
116119
{
117120
Process process = new Process();
118-
process.StartInfo.FileName = BinaryFullPath;
121+
process.StartInfo.FileName = _lazyBinaryFullPath.Value;
119122
process.StartInfo.Arguments = arguments;
120123
process.StartInfo.UseShellExecute = false;
121124
process.StartInfo.CreateNoWindow = true;
@@ -183,7 +186,7 @@ private static SeleniumManagerResponse.ResultResponse RunCommand(string fileName
183186

184187
try
185188
{
186-
jsonResponse = JsonSerializer.Deserialize<SeleniumManagerResponse>(output, _serializerOptions);
189+
jsonResponse = JsonSerializer.Deserialize<SeleniumManagerResponse>(output, _serializerOptions)!;
187190
}
188191
catch (Exception ex)
189192
{
@@ -222,32 +225,19 @@ private static SeleniumManagerResponse.ResultResponse RunCommand(string fileName
222225
}
223226
}
224227

225-
internal class SeleniumManagerResponse
228+
internal record SeleniumManagerResponse(IReadOnlyList<LogEntryResponse> Logs, ResultResponse Result)
226229
{
227-
public IReadOnlyList<LogEntryResponse> Logs { get; set; }
228-
229-
public ResultResponse Result { get; set; }
230-
231-
public class LogEntryResponse
232-
{
233-
public string Level { get; set; }
234-
235-
public string Message { get; set; }
236-
}
237-
238-
public class ResultResponse
239-
{
240-
[JsonPropertyName("driver_path")]
241-
public string DriverPath { get; set; }
242-
243-
[JsonPropertyName("browser_path")]
244-
public string BrowserPath { get; set; }
245-
}
230+
public record LogEntryResponse(string Level, string Message);
231+
232+
public record ResultResponse
233+
(
234+
[property: JsonPropertyName("driver_path")]
235+
string DriverPath,
236+
[property: JsonPropertyName("browser_path")]
237+
string BrowserPath
238+
);
246239
}
247240

248241
[JsonSerializable(typeof(SeleniumManagerResponse))]
249-
internal partial class SeleniumManagerSerializerContext : JsonSerializerContext
250-
{
251-
252-
}
242+
internal partial class SeleniumManagerSerializerContext : JsonSerializerContext;
253243
}

java/maven_install.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
3-
"__INPUT_ARTIFACTS_HASH": -1369959342,
4-
"__RESOLVED_ARTIFACTS_HASH": 2051378450,
3+
"__INPUT_ARTIFACTS_HASH": 1327312787,
4+
"__RESOLVED_ARTIFACTS_HASH": -2038995232,
55
"conflict_resolution": {
66
"com.google.code.gson:gson:2.8.9": "com.google.code.gson:gson:2.11.0",
77
"com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.28.0",
8-
"com.google.guava:guava:31.1-jre": "com.google.guava:guava:33.3.0-jre",
8+
"com.google.guava:guava:31.1-jre": "com.google.guava:guava:33.3.1-jre",
99
"com.google.j2objc:j2objc-annotations:1.3": "com.google.j2objc:j2objc-annotations:3.0.0",
1010
"org.mockito:mockito-core:4.3.1": "org.mockito:mockito-core:5.13.0"
1111
},
@@ -159,10 +159,10 @@
159159
},
160160
"com.google.guava:guava": {
161161
"shasums": {
162-
"jar": "dfadc3bce3101eff1452aae47d7c833fee443b47bdf9ef13311b6c7cab663ddf",
163-
"sources": "f91f8619f533db55f37d13369c2fee39d5e1d2f72cef7f69f735d5be1a601f14"
162+
"jar": "4bf0e2c5af8e4525c96e8fde17a4f7307f97f8478f11c4c8e35a0e3298ae4e90",
163+
"sources": "b7cbdad958b791f2a036abff7724570bf9836531c460966f8a3d0df8eaa1c21d"
164164
},
165-
"version": "33.3.0-jre"
165+
"version": "33.3.1-jre"
166166
},
167167
"com.google.guava:guava-testlib": {
168168
"shasums": {

java/src/org/openqa/selenium/grid/node/ForwardWebDriverCommand.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717

1818
package org.openqa.selenium.grid.node;
1919

20+
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
21+
import static org.openqa.selenium.remote.HttpSessionId.getSessionId;
22+
import static org.openqa.selenium.remote.http.Contents.asJson;
23+
24+
import com.google.common.collect.ImmutableMap;
2025
import org.openqa.selenium.internal.Require;
26+
import org.openqa.selenium.remote.SessionId;
2127
import org.openqa.selenium.remote.http.HttpHandler;
2228
import org.openqa.selenium.remote.http.HttpRequest;
2329
import org.openqa.selenium.remote.http.HttpResponse;
@@ -30,8 +36,22 @@ class ForwardWebDriverCommand implements HttpHandler {
3036
this.node = Require.nonNull("Node", node);
3137
}
3238

39+
public boolean matches(HttpRequest req) {
40+
return getSessionId(req.getUri())
41+
.map(id -> node.isSessionOwner(new SessionId(id)))
42+
.orElse(false);
43+
}
44+
3345
@Override
3446
public HttpResponse execute(HttpRequest req) {
35-
return node.executeWebDriverCommand(req);
47+
if (matches(req)) {
48+
return node.executeWebDriverCommand(req);
49+
}
50+
return new HttpResponse()
51+
.setStatus(HTTP_INTERNAL_ERROR)
52+
.setContent(
53+
asJson(
54+
ImmutableMap.of(
55+
"error", String.format("Session not found in node %s", node.getId()))));
3656
}
3757
}

java/src/org/openqa/selenium/grid/node/Node.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ protected Node(
152152
req ->
153153
getSessionId(req.getUri())
154154
.map(SessionId::new)
155-
.map(this::isSessionOwner)
155+
.map(sessionId -> this.getSession(sessionId) != null)
156156
.orElse(false))
157157
.to(() -> new ForwardWebDriverCommand(this))
158158
.with(spanDecorator("node.forward_command")),

java/src/org/openqa/selenium/grid/node/local/LocalNode.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,13 @@ protected LocalNode(
297297
heartbeatPeriod.getSeconds(),
298298
TimeUnit.SECONDS);
299299

300-
Runtime.getRuntime().addShutdownHook(new Thread(this::stopAllSessions));
300+
Runtime.getRuntime()
301+
.addShutdownHook(
302+
new Thread(
303+
() -> {
304+
stopAllSessions();
305+
drain();
306+
}));
301307
new JMXHelper().register(this);
302308
}
303309

@@ -316,7 +322,6 @@ private void stopTimedOutSession(RemovalNotification<SessionId, SessionSlot> not
316322
}
317323
// Attempt to stop the session
318324
slot.stop();
319-
this.sessionToDownloadsDir.invalidate(id);
320325
// Decrement pending sessions if Node is draining
321326
if (this.isDraining()) {
322327
int done = pendingSessions.decrementAndGet();
@@ -473,8 +478,6 @@ public Either<WebDriverException, CreateSessionResponse> newSession(
473478
sessionToDownloadsDir.put(session.getId(), uuidForSessionDownloads);
474479
currentSessions.put(session.getId(), slotToUse);
475480

476-
checkSessionCount();
477-
478481
SessionId sessionId = session.getId();
479482
Capabilities caps = session.getCapabilities();
480483
SESSION_ID.accept(span, sessionId);
@@ -513,6 +516,8 @@ public Either<WebDriverException, CreateSessionResponse> newSession(
513516
span.addEvent("Unable to create session with the driver", attributeMap);
514517
return Either.left(possibleSession.left());
515518
}
519+
} finally {
520+
checkSessionCount();
516521
}
517522
}
518523

@@ -765,6 +770,10 @@ public HttpResponse uploadFile(HttpRequest req, SessionId id) {
765770
public void stop(SessionId id) throws NoSuchSessionException {
766771
Require.nonNull("Session ID", id);
767772

773+
if (sessionToDownloadsDir.getIfPresent(id) != null) {
774+
sessionToDownloadsDir.invalidate(id);
775+
}
776+
768777
SessionSlot slot = currentSessions.getIfPresent(id);
769778
if (slot == null) {
770779
throw new NoSuchSessionException("Cannot find session with id: " + id);
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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.node;
19+
20+
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
import static org.mockito.Mockito.*;
23+
import static org.openqa.selenium.remote.http.Contents.asJson;
24+
25+
import com.google.common.collect.ImmutableMap;
26+
import java.util.UUID;
27+
import org.junit.jupiter.api.BeforeEach;
28+
import org.junit.jupiter.api.Test;
29+
import org.openqa.selenium.grid.data.NodeId;
30+
import org.openqa.selenium.remote.SessionId;
31+
import org.openqa.selenium.remote.http.HttpRequest;
32+
import org.openqa.selenium.remote.http.HttpResponse;
33+
34+
class ForwardWebDriverCommandTest {
35+
36+
private Node mockNode;
37+
private ForwardWebDriverCommand command;
38+
39+
@BeforeEach
40+
void setUp() {
41+
mockNode = mock(Node.class);
42+
when(mockNode.getId()).thenReturn(new NodeId(UUID.randomUUID()));
43+
command = new ForwardWebDriverCommand(mockNode);
44+
}
45+
46+
@Test
47+
void testExecuteWithValidSessionOwner() {
48+
HttpRequest mockRequest = mock(HttpRequest.class);
49+
when(mockRequest.getUri()).thenReturn("/session/1234");
50+
51+
SessionId sessionId = new SessionId("1234");
52+
when(mockNode.isSessionOwner(sessionId)).thenReturn(true);
53+
54+
HttpResponse expectedResponse = new HttpResponse();
55+
when(mockNode.executeWebDriverCommand(mockRequest)).thenReturn(expectedResponse);
56+
57+
HttpResponse actualResponse = command.execute(mockRequest);
58+
assertEquals(expectedResponse, actualResponse);
59+
}
60+
61+
@Test
62+
void testExecuteWithInvalidSessionOwner() {
63+
HttpRequest mockRequest = mock(HttpRequest.class);
64+
when(mockRequest.getUri()).thenReturn("/session/5678");
65+
66+
SessionId sessionId = new SessionId("5678");
67+
when(mockNode.isSessionOwner(sessionId)).thenReturn(false);
68+
69+
HttpResponse actualResponse = command.execute(mockRequest);
70+
HttpResponse expectResponse =
71+
new HttpResponse()
72+
.setStatus(HTTP_INTERNAL_ERROR)
73+
.setContent(
74+
asJson(
75+
ImmutableMap.of(
76+
"error", String.format("Session not found in node %s", mockNode.getId()))));
77+
assertEquals(expectResponse.getStatus(), actualResponse.getStatus());
78+
assertEquals(expectResponse.getContentEncoding(), actualResponse.getContentEncoding());
79+
}
80+
}

0 commit comments

Comments
 (0)