diff --git a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java index 6035eac1d3a3d..76940a9511ea0 100644 --- a/java/src/org/openqa/selenium/remote/RemoteWebDriver.java +++ b/java/src/org/openqa/selenium/remote/RemoteWebDriver.java @@ -50,6 +50,8 @@ import org.openqa.selenium.interactions.Interactive; import org.openqa.selenium.interactions.Sequence; import org.openqa.selenium.internal.Require; +import org.openqa.selenium.json.Json; +import org.openqa.selenium.json.JsonException; import org.openqa.selenium.logging.LocalLogs; import org.openqa.selenium.logging.LogType; import org.openqa.selenium.logging.LoggingHandler; @@ -60,6 +62,9 @@ import org.openqa.selenium.remote.http.ClientConfig; import org.openqa.selenium.remote.http.ConnectionFailedException; import org.openqa.selenium.remote.http.HttpClient; +import org.openqa.selenium.remote.http.HttpMethod; +import org.openqa.selenium.remote.http.HttpRequest; +import org.openqa.selenium.remote.http.HttpResponse; import org.openqa.selenium.remote.internal.WebElementToJsonConverter; import org.openqa.selenium.remote.tracing.TracedHttpClient; import org.openqa.selenium.remote.tracing.Tracer; @@ -94,6 +99,7 @@ import static org.openqa.selenium.remote.CapabilityType.LOGGING_PREFS; import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME; import static org.openqa.selenium.remote.CapabilityType.SUPPORTS_JAVASCRIPT; +import static org.openqa.selenium.remote.http.Contents.string; @Augmentable public class RemoteWebDriver implements WebDriver, @@ -305,6 +311,20 @@ public Capabilities getCapabilities() { return capabilities; } + public static Status status(URL remoteAddress) { + HttpResponse response = new HttpResponse(); + try (HttpClient client = HttpClient.Factory.createDefault().createClient(remoteAddress)) { + HttpRequest request = new HttpRequest(HttpMethod.GET, "/status"); + response = client.execute(request); + Map responseMap = new Json().toType(string(response), Map.class); + Map value = (Map) responseMap.get("value"); + + return new Status((boolean) value.get("ready"), (String) value.get("message")); + } catch (JsonException e) { + throw new WebDriverException("Unable to parse remote response: " + string(response), e); + } + } + @Override public void get(String url) { execute(DriverCommand.GET(url)); diff --git a/java/src/org/openqa/selenium/remote/Status.java b/java/src/org/openqa/selenium/remote/Status.java new file mode 100644 index 0000000000000..5448e350b2272 --- /dev/null +++ b/java/src/org/openqa/selenium/remote/Status.java @@ -0,0 +1,36 @@ +// 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; + +public class Status { + private final boolean ready; + private final String message; + + public Status(boolean ready, String message) { + this.ready = ready; + this.message = message; + } + + public boolean isReady() { + return ready; + } + + public String getMessage() { + return message; + } +} diff --git a/java/test/org/openqa/selenium/grid/router/RemoteWebDriverStatusTest.java b/java/test/org/openqa/selenium/grid/router/RemoteWebDriverStatusTest.java new file mode 100644 index 0000000000000..ca83a81a4e46e --- /dev/null +++ b/java/test/org/openqa/selenium/grid/router/RemoteWebDriverStatusTest.java @@ -0,0 +1,47 @@ +// 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.grid.router; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.junit.jupiter.api.Test; +import org.openqa.selenium.grid.config.TomlConfig; +import org.openqa.selenium.grid.router.DeploymentTypes.Deployment; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.remote.Status; +import org.openqa.selenium.testing.drivers.Browser; + +import java.io.StringReader; + +class RemoteWebDriverStatusTest { + + @Test + void shouldBeAbleToGetRemoteEndStatus() { + Browser browser = Browser.FIREFOX; + + Deployment deployment = DeploymentTypes.STANDALONE.start( + browser.getCapabilities(), + new TomlConfig(new StringReader( + "[node]\n" + + "driver-implementation = " + browser.displayName()))); + + Status status = RemoteWebDriver.status(deployment.getServer().getUrl()); + assertThat(status.isReady()).isTrue(); + assertThat(status.getMessage()).isEqualTo("Selenium Grid ready."); + } +} diff --git a/java/test/org/openqa/selenium/remote/WebDriverStatusTest.java b/java/test/org/openqa/selenium/remote/WebDriverStatusTest.java new file mode 100644 index 0000000000000..9bce7d18b6201 --- /dev/null +++ b/java/test/org/openqa/selenium/remote/WebDriverStatusTest.java @@ -0,0 +1,76 @@ +// 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 org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.remote.service.DriverService; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URL; + +@Tag("UnitTests") +public class WebDriverStatusTest { + + @Test + public void shouldGetStatusForWebDriverInstance() throws IOException { + URI uri = URI.create("http://localhost:9898"); + URL url = uri.toURL(); + + DriverService service = new FakeDriverService() { + @Override + public URL getUrl() { + return url; + } + }; + + assertThrows(UncheckedIOException.class, + () -> FirefoxDriver.status(service.getUrl())); + } + + private static class FakeDriverService extends DriverService { + + private boolean started; + + FakeDriverService() throws IOException { + super(new File("."), 0, DEFAULT_TIMEOUT, null, null); + } + + @Override + public void start() { + started = true; + } + + @Override + public boolean isRunning() { + return started; + } + + @Override + protected void waitUntilAvailable() { + // return immediately + } + } +}