diff --git a/java/src/org/openqa/selenium/chromium/ChromiumDriver.java b/java/src/org/openqa/selenium/chromium/ChromiumDriver.java index 60f96c994fe9f..9add30b248000 100644 --- a/java/src/org/openqa/selenium/chromium/ChromiumDriver.java +++ b/java/src/org/openqa/selenium/chromium/ChromiumDriver.java @@ -85,7 +85,6 @@ public class ChromiumDriver extends RemoteWebDriver name -> CHROME.is(name) || EDGE.is(name) || OPERA.is(name); private static final Logger LOG = Logger.getLogger(ChromiumDriver.class.getName()); - private final Capabilities capabilities; private final HasNetworkConditions networkConditions; private final HasPermissions permissions; private final HasLaunchApp launch; diff --git a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java index 63d3b6bc6297f..ab6cb2de68e4c 100644 --- a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -19,6 +19,7 @@ import static java.util.Collections.singleton; import static java.util.Objects.requireNonNull; +import static java.util.Objects.requireNonNullElseGet; import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.logging.Level.SEVERE; import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME; @@ -150,7 +151,8 @@ public class RemoteWebDriver // For cglib @SuppressWarnings("DataFlowIssue") protected RemoteWebDriver() { - this.capabilities = init(new ImmutableCapabilities()); + this.capabilities = new ImmutableCapabilities(); + this.localLogs = initLocalLogs(); this.clientConfig = ClientConfig.defaultConfig(); this.executor = null; } @@ -204,7 +206,8 @@ public RemoteWebDriver( CommandExecutor executor, Capabilities capabilities, ClientConfig clientConfig) { this.clientConfig = Require.nonNull("Client config", clientConfig); this.executor = Require.nonNull("Command executor", executor); - this.capabilities = init(capabilities); + this.capabilities = requireNonNullElseGet(capabilities, () -> new ImmutableCapabilities()); + this.localLogs = initLocalLogs(); if (executor instanceof NeedsLocalLogs) { ((NeedsLocalLogs) executor).setLocalLogs(localLogs); @@ -252,14 +255,8 @@ public static RemoteWebDriverBuilder builder() { return new RemoteWebDriverBuilder(); } - private Capabilities init(Capabilities capabilities) { - capabilities = capabilities == null ? new ImmutableCapabilities() : capabilities; - initLocalLogs(); - return capabilities; - } - @SuppressWarnings("deprecation") - private void initLocalLogs() { + private static LocalLogs initLocalLogs() { LOG.addHandler(LoggingHandler.getInstance()); Set logTypesToIgnore = Set.of(); @@ -267,7 +264,7 @@ private void initLocalLogs() { LocalLogs performanceLogger = LocalLogs.getStoringLoggerInstance(logTypesToIgnore); LocalLogs clientLogs = LocalLogs.getHandlerBasedLoggerInstance(LoggingHandler.getInstance(), logTypesToIgnore); - localLogs = LocalLogs.getCombinedLogsHolder(clientLogs, performanceLogger); + return LocalLogs.getCombinedLogsHolder(clientLogs, performanceLogger); } @Nullable @@ -307,20 +304,7 @@ protected void startSession(Capabilities capabilities) { @SuppressWarnings("unchecked") Map rawCapabilities = (Map) responseValue; MutableCapabilities returnedCapabilities = new MutableCapabilities(rawCapabilities); - String platformString = (String) rawCapabilities.get(PLATFORM_NAME); - Platform platform; - try { - if (platformString == null || platformString.isEmpty()) { - platform = Platform.ANY; - } else { - platform = Platform.fromString(platformString); - } - } catch (WebDriverException e) { - // The server probably responded with a name matching the os.name - // system property. Try to recover and parse this. - platform = Platform.extractFromSysProperty(platformString); - } - returnedCapabilities.setCapability(PLATFORM_NAME, platform); + returnedCapabilities.setCapability(PLATFORM_NAME, resolvePlatform(rawCapabilities)); this.capabilities = returnedCapabilities; sessionId = new SessionId(response.getSessionId()); @@ -337,6 +321,21 @@ protected void startSession(Capabilities capabilities) { } } + static Platform resolvePlatform(Map rawCapabilities) { + String platformString = (String) rawCapabilities.get(PLATFORM_NAME); + try { + if (platformString == null || platformString.isEmpty()) { + return Platform.ANY; + } else { + return Platform.fromString(platformString); + } + } catch (WebDriverException e) { + // The server probably responded with a name matching the os.name + // system property. Try to recover and parse this. + return Platform.extractFromSysProperty(platformString); + } + } + public ErrorHandler getErrorHandler() { return errorHandler; } @@ -359,9 +358,6 @@ protected void setCommandExecutor(CommandExecutor executor) { @Override public Capabilities getCapabilities() { - if (capabilities == null) { - return new ImmutableCapabilities(); - } return capabilities; } diff --git a/java/src/org/openqa/selenium/support/ui/WebDriverWait.java b/java/src/org/openqa/selenium/support/ui/WebDriverWait.java index 30bf020a157a8..d14d26fde5c47 100644 --- a/java/src/org/openqa/selenium/support/ui/WebDriverWait.java +++ b/java/src/org/openqa/selenium/support/ui/WebDriverWait.java @@ -92,9 +92,7 @@ protected RuntimeException timeoutException(String message, @Nullable Throwable if (remote.getSessionId() != null) { ex.addInfo(WebDriverException.SESSION_ID, remote.getSessionId().toString()); } - if (remote.getCapabilities() != null) { - ex.addInfo("Capabilities", remote.getCapabilities().toString()); - } + ex.addInfo("Capabilities", remote.getCapabilities().toString()); } throw ex; } diff --git a/java/test/org/openqa/selenium/remote/AugmenterTest.java b/java/test/org/openqa/selenium/remote/AugmenterTest.java index 571a78cc4a85c..cc534e074fb5e 100644 --- a/java/test/org/openqa/selenium/remote/AugmenterTest.java +++ b/java/test/org/openqa/selenium/remote/AugmenterTest.java @@ -342,21 +342,16 @@ public interface MyInterface { } public static class DetonatingDriver extends RemoteWebDriver { - - private final Capabilities caps; - protected DetonatingDriver() { this(new MutableCapabilities()); } public DetonatingDriver(Capabilities caps) { - this.caps = caps; + super(caps); } @Override - public Capabilities getCapabilities() { - return caps; - } + protected void startSession(Capabilities capabilities) {} @NullMarked @Override diff --git a/java/test/org/openqa/selenium/remote/FakeWebDriverInfo.java b/java/test/org/openqa/selenium/remote/FakeWebDriverInfo.java index 7758de98b7839..9ba8b51f5df7c 100644 --- a/java/test/org/openqa/selenium/remote/FakeWebDriverInfo.java +++ b/java/test/org/openqa/selenium/remote/FakeWebDriverInfo.java @@ -86,7 +86,7 @@ public static class FakeWebDriver extends RemoteWebDriver { protected FakeWebDriver() {} public FakeWebDriver(Capabilities capabilities, ClientConfig clientConfig) { - super(command -> null, capabilities, clientConfig); + super(command -> new Response(), capabilities, clientConfig); } @Override diff --git a/java/test/org/openqa/selenium/remote/JsonToWebElementConverterTest.java b/java/test/org/openqa/selenium/remote/JsonToWebElementConverterTest.java index e5e745d7f7647..01bfa3af300e2 100644 --- a/java/test/org/openqa/selenium/remote/JsonToWebElementConverterTest.java +++ b/java/test/org/openqa/selenium/remote/JsonToWebElementConverterTest.java @@ -22,6 +22,7 @@ import static org.openqa.selenium.remote.Dialect.W3C; import java.util.UUID; +import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -38,6 +39,7 @@ class JsonToWebElementConverterTest { public void createIdleDriver() { driver = new RemoteWebDriver(cmd -> new Response(), new ImmutableCapabilities()) { + @NullMarked @Override protected void startSession(Capabilities capabilities) { // Do nothing diff --git a/java/test/org/openqa/selenium/remote/RemotableByTest.java b/java/test/org/openqa/selenium/remote/RemotableByTest.java index b8bd8f7885a3d..244172bfed7ca 100644 --- a/java/test/org/openqa/selenium/remote/RemotableByTest.java +++ b/java/test/org/openqa/selenium/remote/RemotableByTest.java @@ -29,6 +29,7 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.Capabilities; @@ -72,6 +73,7 @@ void shouldCallDownToSearchContextForNonRemotableLocators() { driver.findElement( new By() { @Override + @NullMarked public List findElements(SearchContext context) { return context.findElements(By.cssSelector("#foo")); } @@ -91,6 +93,7 @@ void shouldAttemptToUseRemotableParametersIfPresent() { return createResponse(new RemoteWebElement()); }); + @NullMarked class CustomBy extends By implements By.Remotable { @Override public Parameters getRemoteParameters() { @@ -120,6 +123,7 @@ void shouldFallBackToCallingSearchContextIfRemotableSearchReturnsInvalidArgument return createResponse(singletonList(new RemoteWebElement())); }); + @NullMarked class CustomBy extends By implements By.Remotable { @Override public Parameters getRemoteParameters() { @@ -164,6 +168,7 @@ void shouldUseMechanismUsedForFirstSuccessfulSearchInLaterCalls() { return createResponse(singletonList(new RemoteWebElement())); }); + @NullMarked class CustomBy extends By implements By.Remotable { private final String arg; @@ -206,6 +211,7 @@ private Response createError(Exception e) { return res; } + @NullMarked @SafeVarargs private WebDriver createDriver(Function... responses) { Iterator> iterator = Arrays.stream(responses).iterator(); diff --git a/java/test/org/openqa/selenium/remote/RemoteWebDriverBuilderTest.java b/java/test/org/openqa/selenium/remote/RemoteWebDriverBuilderTest.java index f01a601f7ffa4..4e9b885ccb008 100644 --- a/java/test/org/openqa/selenium/remote/RemoteWebDriverBuilderTest.java +++ b/java/test/org/openqa/selenium/remote/RemoteWebDriverBuilderTest.java @@ -47,6 +47,7 @@ import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.openqa.selenium.Capabilities; +import org.openqa.selenium.HasCapabilities; import org.openqa.selenium.ImmutableCapabilities; import org.openqa.selenium.Platform; import org.openqa.selenium.SessionNotCreatedException; @@ -235,7 +236,7 @@ void ifARemoteUrlIsGivenThatIsUsedForTheSession() { assertThat(seen).hasValue(uri); assertThat(webDriver).isInstanceOf(RemoteWebDriver.class); - assertThat(((RemoteWebDriver) webDriver).capabilities.asMap()) + assertThat(((HasCapabilities) webDriver).getCapabilities().asMap()) .containsEntry("se:cheese", "primula"); } diff --git a/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java b/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java index eb47607c6d99f..5759b4f253ea8 100644 --- a/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java +++ b/java/test/org/openqa/selenium/remote/RemoteWebDriverInitializationTest.java @@ -41,6 +41,7 @@ import java.time.Duration; import java.util.Map; import java.util.UUID; +import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -235,6 +236,7 @@ public void verifyNoCommands(CommandExecutor executor) { verifyNoMoreInteractions(executor); } + @NullMarked private class BadStartSessionRemoteWebDriver extends RemoteWebDriver { public BadStartSessionRemoteWebDriver( CommandExecutor executor, Capabilities desiredCapabilities) { diff --git a/java/test/org/openqa/selenium/remote/RemoteWebDriverTest.java b/java/test/org/openqa/selenium/remote/RemoteWebDriverTest.java new file mode 100644 index 0000000000000..be5f60d0d9700 --- /dev/null +++ b/java/test/org/openqa/selenium/remote/RemoteWebDriverTest.java @@ -0,0 +1,66 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.openqa.selenium.remote; + +import static java.util.Collections.emptyMap; +import static org.assertj.core.api.Assertions.assertThat; +import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME; + +import java.util.Map; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.openqa.selenium.Platform; + +class RemoteWebDriverTest { + + @Nested + class ResolvePlatform { + + @Test + void detectsPlatformByCapabilityValue() { + assertThat(RemoteWebDriver.resolvePlatform(Map.of(PLATFORM_NAME, "windows"))) + .isEqualTo(Platform.WINDOWS); + assertThat(RemoteWebDriver.resolvePlatform(Map.of(PLATFORM_NAME, "mac"))) + .isEqualTo(Platform.MAC); + assertThat(RemoteWebDriver.resolvePlatform(Map.of(PLATFORM_NAME, "Linux"))) + .isEqualTo(Platform.LINUX); + } + + @ParameterizedTest + @EnumSource(Platform.class) + void allKnownPlatforms(Platform platform) { + assertThat(RemoteWebDriver.resolvePlatform(Map.of(PLATFORM_NAME, platform.toString()))) + .isEqualTo(platform); + } + + @Test + void any_byDefault() { + assertThat(RemoteWebDriver.resolvePlatform(emptyMap())).isEqualTo(Platform.ANY); + assertThat(RemoteWebDriver.resolvePlatform(Map.of(PLATFORM_NAME, ""))) + .isEqualTo(Platform.ANY); + } + + @Test + void unix_byDefault() { + assertThat(RemoteWebDriver.resolvePlatform(Map.of(PLATFORM_NAME, "xxx"))) + .isEqualTo(Platform.UNIX); + } + } +} diff --git a/java/test/org/openqa/selenium/remote/ShadowDomTest.java b/java/test/org/openqa/selenium/remote/ShadowDomTest.java index 74328e18b6a17..c7e4365e20369 100644 --- a/java/test/org/openqa/selenium/remote/ShadowDomTest.java +++ b/java/test/org/openqa/selenium/remote/ShadowDomTest.java @@ -30,13 +30,13 @@ import java.util.Map; import java.util.UUID; import java.util.function.Function; +import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.Capabilities; import org.openqa.selenium.ImmutableCapabilities; -import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.NoSuchShadowRootException; import org.openqa.selenium.SearchContext; @@ -86,6 +86,7 @@ public void createDriver() { driver = new RemoteWebDriver(executor, new ImmutableCapabilities()) { + @NullMarked @Override protected void startSession(Capabilities capabilities) { setSessionId(id.toString()); @@ -223,8 +224,7 @@ void shouldBeAbleToGetShadowRootFromExecuteScript() { "value", singletonMap("shadow-6066-11e4-a52e-4f735466cecf", shadowId))))); ShadowRoot shadowContext = (ShadowRoot) element.getShadowRoot(); - ShadowRoot executeContext = - (ShadowRoot) ((JavascriptExecutor) driver).executeScript("return Arguments[0].shadowRoot"); + ShadowRoot executeContext = (ShadowRoot) driver.executeScript("return Arguments[0].shadowRoot"); assertThat(shadowContext).isEqualTo(executeContext); } } diff --git a/java/test/org/openqa/selenium/remote/WebElementToJsonConverterTest.java b/java/test/org/openqa/selenium/remote/WebElementToJsonConverterTest.java index 0f8d2ad7a4d9e..fcca76c5d27f1 100644 --- a/java/test/org/openqa/selenium/remote/WebElementToJsonConverterTest.java +++ b/java/test/org/openqa/selenium/remote/WebElementToJsonConverterTest.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import org.jspecify.annotations.NullMarked; import org.junit.jupiter.api.Test; import org.openqa.selenium.Capabilities; import org.openqa.selenium.ImmutableCapabilities; @@ -213,6 +214,7 @@ private static void assertIsWebElementObject(Object value, String expectedKey) { private static RemoteWebDriver createIdleDriver() { return new RemoteWebDriver(cmd -> new Response(), new ImmutableCapabilities()) { + @NullMarked @Override protected void startSession(Capabilities capabilities) { // Do nothing